summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2025-09-26 15:52:37 +0700
committerhathach <[email protected]>2025-09-26 15:52:37 +0700
commitf9d4bc798177e63532cd5a2ef058400d6f0ef5e4 (patch)
tree4c3c709331b1e515907ea75297f8c513552357be
parent5c630ee0d0d6ba53a7329da0361dfb33a902a290 (diff)
implement tud_mtp_mounted() and tud_mtp_event_send()
refactor phase state
-rw-r--r--src/class/mtp/mtp.h33
-rw-r--r--src/class/mtp/mtp_device.c132
-rw-r--r--src/class/mtp/mtp_device.h5
3 files changed, 94 insertions, 76 deletions
diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h
index 073e6c470..b73bd200a 100644
--- a/src/class/mtp/mtp.h
+++ b/src/class/mtp/mtp.h
@@ -56,18 +56,14 @@ typedef enum {
// PTP/MTP protocol phases
typedef enum {
- MTP_PHASE_IDLE = 0,
- MTP_PHASE_COMMAND,
+ MTP_PHASE_COMMAND = 0,
MTP_PHASE_DATA,
MTP_PHASE_RESPONSE,
- MTP_PHASE_RESPONSE_QUEUED,
- MTP_PHASE_ERROR,
- MTP_PHASE_NONE,
+ MTP_PHASE_ERROR
} mtp_phase_type_t;
// PTP/MTP Class requests, PIMA 15740-2000: D.5.2
-typedef enum
-{
+typedef enum {
MTP_REQ_CANCEL = 0x64,
MTP_REQ_GET_EXT_EVENT_DATA = 0x65,
MTP_REQ_RESET = 0x66,
@@ -75,8 +71,7 @@ typedef enum
} mtp_class_request_t;
// PTP/MTP Container type
-typedef enum
-{
+typedef enum {
MTP_CONTAINER_TYPE_UNDEFINED = 0,
MTP_CONTAINER_TYPE_COMMAND_BLOCK = 1,
MTP_CONTAINER_TYPE_DATA_BLOCK = 2,
@@ -85,8 +80,7 @@ typedef enum
} mtp_container_type_t;
// MTP 1.1 Appendix A: Object formats
-typedef enum
-{
+typedef enum {
// ---- Base formats ----
MTP_OBJ_FORMAT_UNDEFINED = 0x3000u, // Undefined object
MTP_OBJ_FORMAT_ASSOCIATION = 0x3001u, // Association (for example, a folder)
@@ -572,12 +566,6 @@ typedef enum {
MTP_EVENT_OBJECT_REFERENCES_CHANGED = 0xC803u,
} mtp_event_code_t;
-// Predefined Object handles
-typedef enum
-{
- MTP_OBJH_ROOT = 0x0000,
-} mtp_object_handles_t;
-
// Datatypes
typedef enum {
MTP_DATA_TYPE_UNDEFINED = 0x0000u,
@@ -607,8 +595,7 @@ typedef enum {
} mtp_data_type_t;
// Get/Set
-typedef enum
-{
+typedef enum {
MTP_MODE_GET = 0x00u,
MTP_MODE_GET_SET = 0x01u,
} mtp_mode_get_set_t;
@@ -688,6 +675,14 @@ typedef struct {
uint32_t payload_bytes; // available bytes for read/write
} mtp_container_info_t;
+typedef struct TU_ATTR_PACKED {
+ uint16_t code;
+ uint32_t session_id;
+ uint32_t transaction_id;
+ uint32_t params[3];
+} mtp_event_t;
+TU_VERIFY_STATIC(sizeof(mtp_event_t) == 22, "size is not correct");
+
#define mtp_string_t(_nchars) \
struct TU_ATTR_PACKED { \
uint8_t count; /* in characters including null */ \
diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c
index b3d982323..4e468458d 100644
--- a/src/class/mtp/mtp_device.c
+++ b/src/class/mtp/mtp_device.c
@@ -70,6 +70,7 @@ typedef struct {
typedef struct {
TUD_EPBUF_DEF(buf, CFG_TUD_MTP_EP_BUFSIZE);
+ TUD_EPBUF_TYPE_DEF(mtp_event_t, buf_event);
} mtpd_epbuf_t;
//--------------------------------------------------------------------+
@@ -142,18 +143,84 @@ TU_ATTR_UNUSED static tu_lookup_table_t const _mtp_op_table = {
.items = _mpt_op_lookup
};
+TU_ATTR_UNUSED static const char* _mtp_phase_str[] = {
+ "Command",
+ "Data",
+ "Response",
+ "Error"
+};
+
#endif
//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
-
static bool prepare_new_command(mtpd_interface_t* p_mtp) {
- p_mtp->phase = MTP_PHASE_IDLE;
+ p_mtp->phase = MTP_PHASE_COMMAND;
return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, CFG_TUD_MTP_EP_BUFSIZE);
}
+static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ if (p_mtp->phase == MTP_PHASE_COMMAND) {
+ // 1st data block: header + payload
+ p_mtp->phase = MTP_PHASE_DATA;
+ p_mtp->xferred_len = 0;
+
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+ p_mtp->total_len = p_container->header->len;
+ p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.transaction_id;
+ p_mtp->io_header = *p_container->header; // save header for subsequent data
+ } else {
+ // 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
+ TU_ASSERT(p_mtp->phase == MTP_PHASE_DATA);
+ }
+
+ const uint16_t xact_len = tu_min16((uint16_t) (p_mtp->total_len - p_mtp->xferred_len), CFG_TUD_MTP_EP_BUFSIZE);
+ 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;
+}
+
+bool tud_mtp_data_send(mtp_container_info_t* p_container) {
+ return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
+}
+
+bool tud_mtp_data_receive(mtp_container_info_t* p_container) {
+ return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
+}
+
+bool tud_mtp_response_send(mtp_container_info_t* p_container) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ p_mtp->phase = MTP_PHASE_RESPONSE;
+ p_container->header->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.transaction_id;
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, (uint16_t)p_container->header->len));
+ return true;
+}
+
+bool tud_mtp_mounted(void) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ return p_mtp->ep_out != 0 && p_mtp->ep_in != 0;
+}
+
+bool tud_mtp_event_send(mtp_event_t* event) {
+ mtpd_interface_t* p_mtp = &_mtpd_itf;
+ TU_VERIFY(p_mtp->ep_event != 0);
+ _mtpd_epbuf.buf_event = *event;
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_event)); // Claim the endpoint
+
+ return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_event, (uint8_t*) &_mtpd_epbuf.buf_event, sizeof(mtp_event_t));
+}
+
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
@@ -246,52 +313,6 @@ bool mtpd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
return true;
}
-static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
- mtpd_interface_t* p_mtp = &_mtpd_itf;
- if (p_mtp->phase == MTP_PHASE_COMMAND) {
- // 1st data block: header + payload
- p_mtp->phase = MTP_PHASE_DATA;
- p_mtp->xferred_len = 0;
-
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
- p_mtp->total_len = p_container->header->len;
- p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
- p_container->header->transaction_id = p_mtp->command.transaction_id;
- p_mtp->io_header = *p_container->header; // save header for subsequent data
- } else {
- // 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
- TU_ASSERT(p_mtp->phase == MTP_PHASE_DATA);
- }
-
- const uint16_t xact_len = tu_min16((uint16_t) (p_mtp->total_len - p_mtp->xferred_len), CFG_TUD_MTP_EP_BUFSIZE);
- 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;
-}
-
-bool tud_mtp_data_send(mtp_container_info_t* p_container) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
-}
-
-bool tud_mtp_data_receive(mtp_container_info_t* p_container) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
-}
-
-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;
- p_container->header->type = MTP_CONTAINER_TYPE_RESPONSE_BLOCK;
- p_container->header->transaction_id = p_mtp->command.transaction_id;
- TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, (uint16_t)p_container->header->len));
- return true;
-}
-
// Transfer on bulk endpoints
bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
if (ep_addr == _mtpd_itf.ep_event) {
@@ -304,7 +325,8 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
tu_lookup_find(&_mtp_op_table, p_mtp->command.code);
- TU_LOG_DRV(" MTP %s phase = %u\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.code), p_mtp->phase);
+ TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.code),
+ _mtp_phase_str[p_mtp->phase]);
#endif
const mtp_container_info_t headered_packet = {
@@ -327,13 +349,9 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
cb_data.xfer_result = event;
switch (p_mtp->phase) {
- case MTP_PHASE_IDLE:
+ case MTP_PHASE_COMMAND: {
// received new command
TU_VERIFY(ep_addr == p_mtp->ep_out && p_container->header.type == MTP_CONTAINER_TYPE_COMMAND_BLOCK);
- p_mtp->phase = MTP_PHASE_COMMAND;
- TU_ATTR_FALLTHROUGH; // handle in the next case
-
- case MTP_PHASE_COMMAND: {
memcpy(&p_mtp->command, p_container, sizeof(mtp_container_command_t)); // save new command
p_container->header.len = sizeof(mtp_container_header_t); // default container to header only
process_cmd(p_mtp, &cb_data);
@@ -389,16 +407,15 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
break;
}
- case MTP_PHASE_RESPONSE_QUEUED:
+ case MTP_PHASE_RESPONSE:
// response phase is complete -> prepare for new command
TU_ASSERT(ep_addr == p_mtp->ep_in);
tud_mtp_response_complete_cb(&cb_data);
prepare_new_command(p_mtp);
break;
- case MTP_PHASE_RESPONSE:
case MTP_PHASE_ERROR:
- // supposedly to be empty
+ // handled after switch, supposedly to be empty
break;
default: return false;
}
@@ -412,6 +429,7 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
return true;
}
+
//--------------------------------------------------------------------+
// MTPD Internal functionality
//--------------------------------------------------------------------+
diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h
index b10c3abda..4956628d3 100644
--- a/src/class/mtp/mtp_device.h
+++ b/src/class/mtp/mtp_device.h
@@ -72,6 +72,9 @@ typedef MTP_DEVICE_INFO_STRUCT(
// Application API
//--------------------------------------------------------------------+
+// check if mtp interface is mounted
+bool tud_mtp_mounted(void);
+
// send data phase
bool tud_mtp_data_send(mtp_container_info_t* p_container);
@@ -81,6 +84,8 @@ bool tud_mtp_data_receive(mtp_container_info_t* p_container);
// send response
bool tud_mtp_response_send(mtp_container_info_t* p_container);
+bool tud_mtp_event_send(mtp_event_t* event);
+
//--------------------------------------------------------------------+
// Control request Callbacks
//--------------------------------------------------------------------+