summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-09-23 15:23:16 +0700
committerhathach <[email protected]>2025-09-23 15:23:16 +0700
commit3c39f60f63109f7828009ebda135fc675288d610 (patch)
tree9fd51d9556b78587f66cdfb2752f074436473b69 /src
parent1ab45bc52557a85f488566ee89ef48b7332b7ef0 (diff)
refactor API
Diffstat (limited to 'src')
-rw-r--r--src/class/mtp/mtp.h111
-rw-r--r--src/class/mtp/mtp_device.c67
-rw-r--r--src/class/mtp/mtp_device.h33
3 files changed, 122 insertions, 89 deletions
diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h
index c44b99fda..8e519bdc0 100644
--- a/src/class/mtp/mtp.h
+++ b/src/class/mtp/mtp.h
@@ -658,7 +658,6 @@ typedef enum {
// Data structures
//--------------------------------------------------------------------+
-#define MTP_CONTAINER_HEADER_LENGTH 12
#define MTP_MAX_PACKET_SIZE 512
typedef struct TU_ATTR_PACKED {
@@ -669,14 +668,33 @@ typedef struct TU_ATTR_PACKED {
} mtp_container_header_t;
TU_VERIFY_STATIC(sizeof(mtp_container_header_t) == 12, "size is not correct");
+typedef struct TU_ATTR_PACKED {
+ mtp_container_header_t header;
+ uint32_t params[5];
+} mtp_container_command_t;
+TU_VERIFY_STATIC(sizeof(mtp_container_command_t) == 32, "size is not correct");
+
// PTP/MTP Generic container
typedef struct TU_ATTR_PACKED {
uint32_t len;
uint16_t type;
uint16_t code;
uint32_t transaction_id;
- uint32_t data[MTP_MAX_PACKET_SIZE / sizeof(uint32_t)];
+ // union {
+ uint32_t data[(CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t)) / sizeof(uint32_t)];
+ // uint8_t data[CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t)];
+ // };
} mtp_generic_container_t;
+TU_VERIFY_STATIC(sizeof(mtp_generic_container_t) == CFG_TUD_MTP_EP_BUFSIZE, "size is not correct");
+
+typedef struct {
+ mtp_container_header_t* header;
+ union {
+ uint8_t* payload;
+ uint16_t* payload16;
+ uint32_t* payload32;
+ };
+} mtp_container_info_t;
#define mtp_string_t(_nchars) \
struct TU_ATTR_PACKED { \
@@ -690,12 +708,10 @@ typedef struct TU_ATTR_PACKED {
_type arr[_count];\
}
+#define mtp_aint8_t(_count) mtp_array_t(int8_t, _count)
#define mtp_auint16_t(_count) mtp_array_t(uint16_t, _count)
-
-typedef struct TU_ATTR_PACKED {
- uint8_t count;
- uint16_t utf16[];
-} mtp_flexible_string_t;
+#define mtp_auint32_t(_count) mtp_array_t(uint32_t, _count)
+#define mtp_auint64_t(_count) mtp_array_t(uint64_t, _count)
typedef union TU_ATTR_PACKED {
struct {
@@ -775,95 +791,100 @@ typedef struct TU_ATTR_PACKED {
} mtp_basic_object_info_t;
//--------------------------------------------------------------------+
-// Generic Container function
+// Container helper function
+// return number of bytes added
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_generic_container_t* p_container, const void* data, uint32_t len) {
- TU_ASSERT(p_container->len + len < sizeof(mtp_generic_container_t), 0);
- memcpy((uint8_t*) p_container + p_container->len, data, len);
- p_container->len += len;
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_container_info_t* p_container, const void* data, uint32_t len) {
+ TU_ASSERT(p_container->header->len + len < sizeof(mtp_generic_container_t), 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
+ memcpy(buf, data, len);
+ p_container->header->len += len;
return len;
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_generic_container_t* p_container, uint8_t scalar_size, uint32_t count, const void* data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_array(mtp_container_info_t* p_container, uint8_t scalar_size, uint32_t count, const void* data) {
const uint32_t added_len = 4 + count * scalar_size;
- TU_ASSERT(p_container->len + added_len < sizeof(mtp_generic_container_t), 0);
- uint8_t* container8 = (uint8_t*)p_container;
+ TU_ASSERT(p_container->header->len + added_len < sizeof(mtp_generic_container_t), 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
- tu_unaligned_write32(container8 + p_container->len, count);
- p_container->len += 4;
+ tu_unaligned_write32(buf, count);
+ p_container->header->len += 4;
+ buf += 4;
- memcpy(container8 + p_container->len, data, count * scalar_size);
- p_container->len += count * scalar_size;
+ memcpy(buf, data, count * scalar_size);
+ p_container->header->len += count * scalar_size;
return added_len;
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_generic_container_t* p_container, uint8_t count, uint16_t* utf16) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_string(mtp_container_info_t* p_container, uint8_t count, uint16_t* utf16) {
const uint32_t added_len = 1 + 2 * count;
- TU_ASSERT(p_container->len + added_len < sizeof(mtp_generic_container_t), 0);
- uint8_t* container8 = (uint8_t*) p_container;
+ TU_ASSERT(p_container->header->len + added_len < sizeof(mtp_generic_container_t), 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
- container8[p_container->len] = count;
- p_container->len++;
+ *buf++ = count;
+ p_container->header->len++;
- memcpy(container8 + p_container->len, utf16, 2 * count);
- p_container->len += 2 * count;
+ memcpy(buf, utf16, 2 * count);
+ p_container->header->len += 2 * count;
return added_len;
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_generic_container_t* p_container, const char* str) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_cstring(mtp_container_info_t* p_container, const char* str) {
const uint8_t len = (uint8_t) (strlen(str) + 1); // include null
- TU_ASSERT(p_container->len + 1 + 2 * len < sizeof(mtp_generic_container_t), 0);
-
- uint8_t* container8 = (uint8_t*) p_container;
- container8[p_container->len] = len;
- p_container->len++;
+ TU_ASSERT(p_container->header->len + 1 + 2 * len < sizeof(mtp_generic_container_t), 0);
+ uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t);
if (len == 1) {
- // empty string (null only)
- container8[p_container->len] = 0;
+ // empty string (null only): single zero byte
+ *buf = 0;
+ p_container->header->len++;
return 1;
} else {
+ *buf++ = len;
+ p_container->header->len++;
+
for (uint8_t i = 0; i < len; i++) {
- container8[p_container->len] = str[i];
- container8[p_container->len + 1] = 0;
- p_container->len += 2;
+ buf[0] = str[i];
+ buf[1] = 0;
+ buf += 2;
+ p_container->header->len += 2;
}
return 1 + 2 * len;
}
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint8(mtp_generic_container_t* p_container, uint8_t data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint8(mtp_container_info_t* p_container, uint8_t data) {
return mtp_container_add_raw(p_container, &data, 1);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint16(mtp_generic_container_t* p_container, uint16_t data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint16(mtp_container_info_t* p_container, uint16_t data) {
return mtp_container_add_raw(p_container, &data, 2);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint32(mtp_generic_container_t* p_container, uint32_t data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint32(mtp_container_info_t* p_container, uint32_t data) {
return mtp_container_add_raw(p_container, &data, 4);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint64(mtp_generic_container_t* p_container, uint64_t data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint64(mtp_container_info_t* p_container, uint64_t data) {
return mtp_container_add_raw(p_container, &data, 8);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint128(mtp_generic_container_t* p_container, const void* data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_uint128(mtp_container_info_t* p_container, const void* data) {
return mtp_container_add_raw(p_container, data, 16);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint8(mtp_generic_container_t* p_container, uint32_t count, const uint8_t* data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint8(mtp_container_info_t* p_container, uint32_t count, const uint8_t* data) {
return mtp_container_add_array(p_container, sizeof(uint8_t), count, data);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint16(mtp_generic_container_t* p_container, uint32_t count, const uint16_t* data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint16(mtp_container_info_t* p_container, uint32_t count, const uint16_t* data) {
return mtp_container_add_array(p_container, sizeof(uint16_t), count, data);
}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_generic_container_t* p_container, uint32_t count, const uint32_t* data) {
+TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_auint32(mtp_container_info_t* p_container, uint32_t count, const uint32_t* data) {
return mtp_container_add_array(p_container, sizeof(uint32_t), count, data);
}
diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c
index 91df13111..71ead732d 100644
--- a/src/class/mtp/mtp_device.c
+++ b/src/class/mtp/mtp_device.c
@@ -67,7 +67,8 @@ typedef struct {
bool xfer_completed; // true when DATA-IN/DATA-OUT transfer is completed
uint32_t session_id;
- mtp_container_header_t cmd_header;
+ mtp_container_command_t command;
+ // mtp_container_header_t reply_header;
} mtpd_interface_t;
typedef struct {
@@ -81,7 +82,7 @@ typedef struct {
static mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, const uint16_t ret_code, const char *message);
// MTP commands
-static mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp);
+static mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data);
static mtp_phase_type_t mtpd_handle_data(void);
static mtp_phase_type_t mtpd_handle_cmd_delete_object(void);
static mtp_phase_type_t mtpd_handle_cmd_send_object_info(void);
@@ -265,26 +266,24 @@ bool mtpd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
return true;
}
-bool tud_mtp_data_send(mtp_generic_container_t* data_block) {
+bool tud_mtp_data_send(mtp_container_info_t* p_container) {
mtpd_interface_t* p_mtp = &_mtpd_itf;
p_mtp->phase = MTP_PHASE_DATA;
- p_mtp->total_len = data_block->len;
+ p_mtp->total_len = p_container->header->len;
p_mtp->xferred_len = 0;
p_mtp->handled_len = 0;
p_mtp->xfer_completed = false;
- data_block->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
- data_block->transaction_id = p_mtp->cmd_header.transaction_id;
- TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t*) data_block, (uint16_t)data_block->len));
+ p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t *)(&_mtpd_epbuf.container), (uint16_t)p_container->header->len));
return true;
}
-bool tud_mtp_response_send(mtp_generic_container_t* resp_block) {
+bool tud_mtp_response_send(mtp_container_info_t* p_container) {
mtpd_interface_t* p_mtp = &_mtpd_itf;
p_mtp->phase = MTP_PHASE_RESPONSE_QUEUED;
- resp_block->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
- resp_block->transaction_id = p_mtp->cmd_header.transaction_id;
- TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t*) resp_block, (uint16_t)resp_block->len));
+ p_container->header->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, (uint8_t *)(&_mtpd_epbuf.container), (uint16_t)p_container->header->len));
return true;
}
@@ -300,6 +299,13 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
mtpd_interface_t* p_mtp = &_mtpd_itf;
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
+ tud_mtp_cb_data_t cb_data;
+ cb_data.idx = 0;
+ cb_data.command = &p_mtp->command;
+ cb_data.reply.header = (mtp_container_header_t*) p_container;
+ cb_data.reply.payload32 = p_container->data;
+ cb_data.offset = 0;
+
switch (p_mtp->phase) {
case MTP_PHASE_IDLE:
// received new command
@@ -308,7 +314,8 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
TU_ATTR_FALLTHROUGH; // handle in the next case
case MTP_PHASE_COMMAND: {
- mtpd_handle_cmd(p_mtp);
+ memcpy(&p_mtp->command, p_container, sizeof(mtp_container_command_t)); // copy new command
+ mtpd_handle_cmd(p_mtp, &cb_data);
break;
}
@@ -320,7 +327,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
if (xferred_bytes == 0 || // ZLP
(xferred_bytes & (bulk_mps - 1)) || // short packet
p_mtp->xferred_len > p_mtp->total_len) {
- tud_mtp_data_complete_cb(0, &p_mtp->cmd_header, p_container, event, p_mtp->xferred_len);
+ tud_mtp_data_complete_cb(&cb_data);
} else {
TU_ASSERT(false);
}
@@ -404,7 +411,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
case MTP_PHASE_RESPONSE_QUEUED:
// response phase is complete -> prepare for new command
TU_ASSERT(ep_addr == p_mtp->ep_in);
- tud_mtp_response_complete_cb(0, &p_mtp->cmd_header, p_container, event, xferred_bytes);
+ tud_mtp_response_complete_cb(&cb_data);
prepare_new_command(p_mtp);
break;
@@ -429,23 +436,15 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
//--------------------------------------------------------------------+
// Decode command and prepare response
-mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
+mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) {
mtp_generic_container_t* p_container = &_mtpd_epbuf.container;
+ p_container->len = sizeof(mtp_container_header_t); // default data/response length
- mtp_generic_container_t cmd_block; // copy command block for callback
- memcpy(&cmd_block, p_container, p_container->len);
- memcpy(&p_mtp->cmd_header, p_container, sizeof(mtp_container_header_t));
- p_container->len = MTP_CONTAINER_HEADER_LENGTH; // default data/response length
-
- if (p_container->code != MTP_OP_SEND_OBJECT) {
- _mtpd_soi.object_handle = 0;
- }
-
- tu_lookup_find(&_mtp_op_table, cmd_block.code);
- TU_LOG_DRV(" MTP command: %s\r\n", (char const*) tu_lookup_find(&_mtp_op_table, cmd_block.code));
+ tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code);
+ TU_LOG_DRV(" MTP command: %s\r\n", (char const*) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code));
- mtp_phase_type_t ret = MTP_PHASE_RESPONSE;
- switch (cmd_block.code) {
+ // pre-processed commands
+ switch (p_mtp->command.header.code) {
case MTP_OP_GET_DEVICE_INFO: {
tud_mtp_device_info_t dev_info = {
.standard_version = 100,
@@ -486,12 +485,8 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i];
}
#endif
- p_container->len = MTP_CONTAINER_HEADER_LENGTH + sizeof(tud_mtp_device_info_t);
+ mtp_container_add_raw(&cb_data->reply, &dev_info, sizeof(tud_mtp_device_info_t));
p_container->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
- p_container->code = MTP_OP_GET_DEVICE_INFO;
- memcpy(p_container->data, &dev_info, sizeof(tud_mtp_device_info_t));
-
- ret = MTP_PHASE_RESPONSE;
break;
}
@@ -499,8 +494,8 @@ mtp_phase_type_t mtpd_handle_cmd(mtpd_interface_t* p_mtp) {
break;
}
- tud_mtp_command_received_cb(0, &cmd_block, p_container);
- return ret;
+ tud_mtp_command_received_cb(cb_data);
+ return MTP_PHASE_RESPONSE;
}
#if 0
@@ -640,7 +635,7 @@ mtp_phase_type_t mtpd_chk_generic(const char *func_name, const bool err_cd, cons
TU_LOG_DRV(" MTP error in %s: (%x) %s\n", func_name, ret_code, message);
p_container->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
p_container->code = ret_code;
- p_container->len = MTP_CONTAINER_HEADER_LENGTH;
+ p_container->len = sizeof(mtp_container_header_t);
return MTP_PHASE_RESPONSE;
}
return MTP_PHASE_NONE;
diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h
index b85b1706e..0524edcf6 100644
--- a/src/class/mtp/mtp_device.h
+++ b/src/class/mtp/mtp_device.h
@@ -37,10 +37,22 @@
#endif
typedef struct {
- const mtp_container_header_t* cmd_header;
+ uint8_t idx; // mtp instance
+ const mtp_container_command_t* command;
+ mtp_container_info_t reply;
+
+ union {
+ uint8_t* buffer;
+ uint16_t* buffer16;
+ uint32_t* buffer32;
+ };
+ uint32_t bufsize;
+ uint32_t offset; // offset from start of header, since data can span multiple xfers
+
+
tusb_xfer_result_t xfer_result;
uint32_t xferred_bytes;
-} tud_mtp_cb_complete_data_t;
+} tud_mtp_cb_data_t;
// Number of supported operations, events, device properties, capture formats, playback formats
// and max number of characters for strings manufacturer, model, device_version, serial_number
@@ -91,23 +103,28 @@ typedef struct {
//--------------------------------------------------------------------+
// Application API
//--------------------------------------------------------------------+
-bool tud_mtp_data_send(mtp_generic_container_t* data_block);
+bool tud_mtp_data_send(mtp_container_info_t* p_container);
// bool tud_mtp_block_data_receive();
-bool tud_mtp_response_send(mtp_generic_container_t* resp_block);
+bool tud_mtp_response_send(mtp_container_info_t* p_container);
+
+//--------------------------------------------------------------------+
+// Control request Callbacks
+//--------------------------------------------------------------------+
+// bool tud_mtp_control_xfer_cb(uint8_t idx, uint8_t stage, tusb_control_request_t const *p_request);
//--------------------------------------------------------------------+
-// Application Callbacks
+// Bulk only protocol Callbacks
//--------------------------------------------------------------------+
// Invoked when new command is received. Application fill the out_block with either DATA or RESPONSE container
// return MTP response code
-int32_t tud_mtp_command_received_cb(uint8_t idx, mtp_generic_container_t* cmd_block, mtp_generic_container_t* out_block);
+int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data);
// Invoked when data phase is complete
-int32_t tud_mtp_data_complete_cb(uint8_t idx, mtp_container_header_t* cmd_header, mtp_generic_container_t* resp_block, tusb_xfer_result_t xfer_result, uint32_t xferred_bytes);
+int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data);
// Invoked when response phase is complete
-int32_t tud_mtp_response_complete_cb(uint8_t idx, mtp_container_header_t* cmd_header, mtp_generic_container_t* resp_block, tusb_xfer_result_t xfer_result, uint32_t xferred_bytes);
+int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data);
//--------------------------------------------------------------------+
// Helper functions