diff options
| author | hathach <[email protected]> | 2025-10-11 18:41:02 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2025-10-11 18:41:02 +0700 |
| commit | b19d86376265ab4be279a74a6573dbb8c6fc8c48 (patch) | |
| tree | bae17ec17520eff8db1ef83ac7de8674f6e8d387 /src/class | |
| parent | f69d89454ef4a57a1ff199d42cb24a7eff4f6d90 (diff) | |
| parent | 87523f2494109b45307644a36f035b5ad11d5ba9 (diff) | |
Merge branch 'master' into fork/adam-embedded/with-stm32l496nucleo
Diffstat (limited to 'src/class')
31 files changed, 2642 insertions, 394 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index bb906c7cf..7df177773 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -79,10 +79,9 @@ // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer // is available or driver is would need to be changed dramatically -// Only STM32 and dcd_transdimension use non-linear buffer for now -// dwc2 except esp32sx (since it may use dcd_esp32sx) +// Only STM32 and ChipIdea HS use non-linear buffer for now // Ring buffer is incompatible with dcache, since neither address nor size is aligned to cache line -#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \ +#if defined(TUP_USBIP_DWC2) || \ defined(TUP_USBIP_FSDEV) || \ CFG_TUSB_MCU == OPT_MCU_RX63X || \ CFG_TUSB_MCU == OPT_MCU_RX65X || \ @@ -192,17 +191,6 @@ tu_static CFG_TUD_MEM_SECTION struct { #endif } ctrl_buf; -// Active alternate setting of interfaces -tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]; - -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 -tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]; -#endif - -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 -tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]; -#endif - // Aligned buffer for feedback EP #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP tu_static CFG_TUD_MEM_SECTION struct { @@ -234,13 +222,14 @@ typedef struct uint8_t ep_in; // TX audio data EP. uint16_t ep_in_sz; // Current size of TX EP uint8_t ep_in_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) -#endif + uint8_t ep_in_alt; // Current alternate setting of TX EP + #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT uint8_t ep_out; // Incoming (into uC) audio data EP. uint16_t ep_out_sz; // Current size of RX EP uint8_t ep_out_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) - + uint8_t ep_out_alt; // Current alternate setting of RX EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP uint8_t ep_fb;// Feedback EP. #endif @@ -304,9 +293,6 @@ typedef struct uint8_t *ctrl_buf; uint8_t ctrl_buf_sz; - // Current active alternate settings - uint8_t *alt_setting;// We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! - // EP Transfer buffers and FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_OUT tu_fifo_t ep_out_ff; @@ -475,8 +461,6 @@ static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request); static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request); -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int); -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int); static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); @@ -529,11 +513,7 @@ tu_fifo_t *tud_audio_n_get_ep_out_ff(uint8_t func_id) { } static bool audiod_rx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received) { - uint8_t idxItf; - uint8_t const *dummy2; - uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2)); #if USE_LINEAR_BUFFER_RX // Data currently is in linear buffer, copy into EP OUT FIFO @@ -553,7 +533,7 @@ static bool audiod_rx_xfer_isr(uint8_t rhport, audiod_function_t* audio, uint16_ #endif // Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO - TU_VERIFY(tud_audio_rx_done_isr(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_rx_done_isr(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->ep_out_alt)); return true; } @@ -584,14 +564,10 @@ tu_fifo_t *tud_audio_n_get_ep_in_ff(uint8_t func_id) { } static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t * audio, uint16_t n_bytes_sent) { - uint8_t idxItf; - uint8_t const *dummy2; - uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio); - TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2)); // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications - if (audio->alt_setting[idxItf] == 0) { return false; } + if (audio->ep_in_alt == 0) { return false; } // Send everything in ISO EP FIFO uint16_t n_bytes_tx; @@ -611,7 +587,7 @@ static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t * audio, uint16 #endif // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer - TU_VERIFY(tud_audio_tx_done_isr(rhport, n_bytes_sent, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf])); + TU_VERIFY(tud_audio_tx_done_isr(rhport, n_bytes_sent, idx_audio_fct, audio->ep_in, audio->ep_in_alt)); return true; } @@ -704,25 +680,6 @@ void audiod_init(void) { #endif } - // Initialize active alternate interface buffers - switch (i) { -#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0 - case 0: - audio->alt_setting = alt_setting_1; - break; -#endif -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0 - case 1: - audio->alt_setting = alt_setting_2; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0 - case 2: - audio->alt_setting = alt_setting_3; - break; -#endif - } - // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_IN @@ -1029,13 +986,25 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p uint8_t const itf = tu_u16_low(p_request->wIndex); // Find index of audio streaming interface - uint8_t func_id, idxItf; - uint8_t const *dummy; + uint8_t func_id; + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); + + // Default to 0 if interface not yet activated + uint8_t alt = 0; +#if CFG_TUD_AUDIO_ENABLE_EP_IN + if (_audiod_fct[func_id].ep_in_as_intf_num == itf) { + alt = _audiod_fct[func_id].ep_in_alt; + } +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + if (_audiod_fct[func_id].ep_out_as_intf_num == itf) { + alt = _audiod_fct[func_id].ep_out_alt; + } +#endif - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy)); - TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1)); + TU_VERIFY(tud_control_xfer(rhport, p_request, &alt, 1)); - TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]); + TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, alt); return true; } @@ -1060,9 +1029,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt); // Find index of audio streaming interface and index of interface - uint8_t func_id, idxItf; - uint8_t const *p_desc; - TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc)); + uint8_t func_id; + TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); audiod_function_t *audio = &_audiod_fct[func_id]; @@ -1070,6 +1038,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #if CFG_TUD_AUDIO_ENABLE_EP_IN if (audio->ep_in_as_intf_num == itf) { audio->ep_in_as_intf_num = 0; + audio->ep_in_alt = 0; #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_in); #endif @@ -1093,6 +1062,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #if CFG_TUD_AUDIO_ENABLE_EP_OUT if (audio->ep_out_as_intf_num == itf) { audio->ep_out_as_intf_num = 0; + audio->ep_out_alt = 0; #ifndef TUP_DCD_EDPT_ISO_ALLOC usbd_edpt_close(rhport, audio->ep_out); #endif @@ -1116,10 +1086,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p } #endif// CFG_TUD_AUDIO_ENABLE_EP_OUT - // Save current alternative interface setting - audio->alt_setting[idxItf] = alt; - // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface + uint8_t const *p_desc = tu_desc_next(audio->p_desc); + // Skip entire AC descriptor block + p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; // Get pointer at end uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; @@ -1154,6 +1124,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p // Save address audio->ep_in = ep_addr; audio->ep_in_as_intf_num = itf; + audio->ep_in_alt = alt; audio->ep_in_sz = tu_edpt_packet_size(desc_ep); // If flow control is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters @@ -1176,6 +1147,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p // Save address audio->ep_out = ep_addr; audio->ep_out_as_intf_num = itf; + audio->ep_out_alt = alt; audio->ep_out_sz = tu_edpt_packet_size(desc_ep); // Prepare for incoming data @@ -1474,8 +1446,7 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint #if CFG_TUD_AUDIO_ENABLE_EP_IN // Data transmission of audio packet finished - if (audio->ep_in == ep_addr && audio->alt_setting != 0) - { + if (audio->ep_in == ep_addr) { // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified." // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available." // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP. @@ -1492,8 +1463,7 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint #if CFG_TUD_AUDIO_ENABLE_EP_OUT // New audio packet received - if (audio->ep_out == ep_addr) - { + if (audio->ep_out == ep_addr) { audiod_rx_xfer_isr(rhport, audio, (uint16_t) xferred_bytes); return true; } @@ -1694,53 +1664,6 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req return tud_control_xfer(rhport, p_request, (void *) _audiod_fct[func_id].ctrl_buf, len); } -// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int) { - if (audio->p_desc) { - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - // Advance past AC descriptors - uint8_t const *p_desc = tu_desc_next(audio->p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; - - uint8_t tmp = 0; - // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) { - // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero! - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bAlternateSetting == 0) { - if (((tusb_desc_interface_t const *) p_desc)->bInterfaceNumber == itf) { - *idxItf = tmp; - *pp_desc_int = p_desc; - return true; - } - // Increase index, bytes read, and pointer - tmp++; - } - p_desc = tu_desc_next(p_desc); - } - } - return false; -} - -// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function -// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and -// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero. -static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int) { - // Loop over audio driver interfaces - uint8_t i; - for (i = 0; i < CFG_TUD_AUDIO; i++) { - if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int)) { - *func_id = i; - return true; - } - } - - return false; -} - // Verify an entity with the given ID exists and returns also the corresponding driver index static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id) { uint8_t i; @@ -1754,8 +1677,8 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning while (p_desc_end - p_desc > 0) { - if (p_desc[3] == entityID)// Entity IDs are always at offset 3 - { + // Entity IDs are always at offset 3 + if (p_desc[3] == entityID) { *func_id = i; return true; } @@ -1775,7 +1698,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) { uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning while (p_desc_end - p_desc > 0) { - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) _audiod_fct[i].p_desc)->bInterfaceNumber == itf) { + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber == itf) { *func_id = i; return true; } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 6bcedc88c..fd47c649d 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -51,21 +51,6 @@ #endif #endif -// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces -#ifndef CFG_TUD_AUDIO_FUNC_1_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_N_AS_INT -#error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the audio function descriptor! -#endif -#endif - // Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors #ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ #error You must define an audio class control request buffer size! diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index 45cbf2d98..3f1529cb6 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -43,7 +43,7 @@ typedef struct { uint8_t ep_acl_in; uint16_t ep_acl_in_pkt_sz; uint8_t ep_acl_out; - uint8_t ep_voice[2]; // Not used yet + uint8_t ep_voice[2];// Not used yet uint8_t ep_voice_size[2][CFG_TUD_BTH_ISO_ALT_COUNT]; // Previous amount of bytes sent when issuing ZLP @@ -61,8 +61,7 @@ typedef struct { static btd_interface_t _btd_itf; CFG_TUD_MEM_SECTION static btd_epbuf_t _btd_epbuf; -static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) -{ +static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) { uint8_t const rhport = 0; // skip if previous transfer not complete @@ -74,6 +73,27 @@ static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) } //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) { + (void) hci_cmd; + (void) cmd_len; +} + +TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) { + (void) acl_data; + (void) data_len; +} + +TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes) { + (void) sent_bytes; +} + +TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes) { + (void) sent_bytes; +} + +//--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ @@ -82,13 +102,11 @@ static bool bt_tx_data(uint8_t ep, void *data, uint16_t len) // WRITE API //--------------------------------------------------------------------+ -bool tud_bt_event_send(void *event, uint16_t event_len) -{ +bool tud_bt_event_send(void *event, uint16_t event_len) { return bt_tx_data(_btd_itf.ep_ev, event, event_len); } -bool tud_bt_acl_data_send(void *event, uint16_t event_len) -{ +bool tud_bt_acl_data_send(void *event, uint16_t event_len) { return bt_tx_data(_btd_itf.ep_acl_in, event, event_len); } @@ -103,13 +121,11 @@ bool btd_deinit(void) { return true; } -void btd_reset(uint8_t rhport) -{ - (void)rhport; +void btd_reset(uint8_t rhport) { + (void) rhport; } -uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) -{ +uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { tusb_desc_endpoint_t const *desc_ep; uint16_t drv_len = 0; // Size of single alternative of ISO interface @@ -118,8 +134,9 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ const uint16_t hci_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); // Ensure this is BT Primary Controller TU_VERIFY(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, + 0); TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= hci_itf_size); @@ -131,10 +148,10 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); _btd_itf.ep_ev = desc_ep->bEndpointAddress; - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); // Open endpoint pair - TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *)desc_ep, 2, + TU_ASSERT(usbd_open_edpt_pair(rhport, (uint8_t const *) desc_ep, 2, TUSB_XFER_BULK, &_btd_itf.ep_acl_out, &_btd_itf.ep_acl_in), 0); @@ -146,10 +163,10 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ _btd_itf.ep_acl_in_pkt_sz = tu_edpt_packet_size(desc_ep_acl_in); break; } - desc_ep_acl_in = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep_acl_in); + desc_ep_acl_in = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep_acl_in); } - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep)); + itf_desc = (tusb_desc_interface_t const *) tu_desc_next(tu_desc_next(desc_ep)); // Prepare for incoming data from host TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0); @@ -158,13 +175,14 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ // Ensure this is still BT Primary Controller TU_ASSERT(TUSB_CLASS_WIRELESS_CONTROLLER == itf_desc->bInterfaceClass && - TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, 0); + TUD_BT_APP_SUBCLASS == itf_desc->bInterfaceSubClass && + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER == itf_desc->bInterfaceProtocol, + 0); TU_ASSERT(itf_desc->bNumEndpoints == 2 && max_len >= iso_alt_itf_size + drv_len); uint8_t dir; - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); dir = tu_edpt_dir(desc_ep->bEndpointAddress); @@ -172,7 +190,7 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ // Store endpoint size for alternative _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT, 0); dir = tu_edpt_dir(desc_ep->bEndpointAddress); _btd_itf.ep_voice[dir] = desc_ep->bEndpointAddress; @@ -182,29 +200,30 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ for (int i = 1; i < CFG_TUD_BTH_ISO_ALT_COUNT && drv_len + iso_alt_itf_size <= max_len; ++i) { // Make sure rest of alternatives matches - itf_desc = (tusb_desc_interface_t const *)tu_desc_next(desc_ep); + itf_desc = (tusb_desc_interface_t const *) tu_desc_next(desc_ep); if (itf_desc->bDescriptorType != TUSB_DESC_INTERFACE || TUSB_CLASS_WIRELESS_CONTROLLER != itf_desc->bInterfaceClass || TUD_BT_APP_SUBCLASS != itf_desc->bInterfaceSubClass || - TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) - { + TUD_BT_PROTOCOL_PRIMARY_CONTROLLER != itf_desc->bInterfaceProtocol) { // Not an Iso interface instance break; } TU_ASSERT(itf_desc->bAlternateSetting < CFG_TUD_BTH_ISO_ALT_COUNT, 0); - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(itf_desc); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); dir = tu_edpt_dir(desc_ep->bEndpointAddress); // Verify that alternative endpoint are same as first ones TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, + 0); _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); - desc_ep = (tusb_desc_endpoint_t const *)tu_desc_next(desc_ep); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); dir = tu_edpt_dir(desc_ep->bEndpointAddress); // Verify that alternative endpoint are same as first ones TU_ASSERT(desc_ep->bDescriptorType == TUSB_DESC_ENDPOINT && - _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, 0); + _btd_itf.ep_voice[dir] == desc_ep->bEndpointAddress, + 0); _btd_itf.ep_voice_size[dir][itf_desc->bAlternateSetting] = (uint8_t) tu_edpt_packet_size(desc_ep); drv_len += iso_alt_itf_size; } @@ -215,44 +234,32 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_ // Invoked when a control transfer occurred on an interface of this class // Driver response accordingly to the request and the transfer stage (setup/data/ack) // return false to stall control endpoint (e.g unsupported request) -bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) -{ - (void)rhport; +bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { + (void) rhport; - if ( stage == CONTROL_STAGE_SETUP ) - { + if (stage == CONTROL_STAGE_SETUP) { if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && - request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) - { + request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) { // HCI command packet addressing for single function Primary Controllers // also compatible with historical mode if enabled TU_VERIFY((request->bRequest == 0 && request->wValue == 0 && request->wIndex == 0) || (CFG_TUD_BTH_HISTORICAL_COMPATIBLE && request->bRequest == 0xe0)); - } - else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) - { - if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) - { + } else if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { + if (request->bRequest == TUSB_REQ_SET_INTERFACE && _btd_itf.itf_num + 1 == request->wIndex) { // TODO: Set interface it would involve changing size of endpoint size - } - else - { + } else { // HCI command packet for Primary Controller function in a composite device TU_VERIFY(request->bRequest == 0 && request->wValue == 0 && request->wIndex == _btd_itf.itf_num); } - } - else return false; + } else + return false; return tud_control_xfer(rhport, request, &_btd_epbuf.hci_cmd, sizeof(bt_hci_cmd_t)); - } - else if ( stage == CONTROL_STAGE_DATA ) - { + } else if (stage == CONTROL_STAGE_DATA) { // Handle class request only TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - if (tud_bt_hci_cmd_cb) { - tud_bt_hci_cmd_cb(&_btd_epbuf.hci_cmd, tu_min16(request->wLength, sizeof(bt_hci_cmd_t))); - } + tud_bt_hci_cmd_cb(&_btd_epbuf.hci_cmd, tu_min16(request->wLength, sizeof(bt_hci_cmd_t))); } return true; @@ -261,19 +268,14 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { // received new data from host - if (ep_addr == _btd_itf.ep_acl_out) - { - if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_epbuf.epout_buf, xferred_bytes); + if (ep_addr == _btd_itf.ep_acl_out) { + tud_bt_acl_data_received_cb(_btd_epbuf.epout_buf, xferred_bytes); // prepare for next data TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE)); - } - else if (ep_addr == _btd_itf.ep_ev) - { - if (tud_bt_event_sent_cb) tud_bt_event_sent_cb((uint16_t)xferred_bytes); - } - else if (ep_addr == _btd_itf.ep_acl_in) - { + } else if (ep_addr == _btd_itf.ep_ev) { + tud_bt_event_sent_cb((uint16_t) xferred_bytes); + } else if (ep_addr == _btd_itf.ep_acl_in) { if ((result == XFER_RESULT_SUCCESS) && (xferred_bytes > 0) && ((xferred_bytes & (_btd_itf.ep_acl_in_pkt_sz - 1)) == 0)) { // Save number of transferred bytes @@ -281,12 +283,12 @@ bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, // Send zero-length packet tud_bt_acl_data_send(NULL, 0); - } else if (tud_bt_acl_data_sent_cb) { + } else { if (xferred_bytes == 0) { xferred_bytes = _btd_itf.prev_xferred_bytes; _btd_itf.prev_xferred_bytes = 0; } - tud_bt_acl_data_sent_cb((uint16_t)xferred_bytes); + tud_bt_acl_data_sent_cb((uint16_t) xferred_bytes); } } diff --git a/src/class/bth/bth_device.h b/src/class/bth/bth_device.h index 4f6350839..68f073bff 100755 --- a/src/class/bth/bth_device.h +++ b/src/class/bth/bth_device.h @@ -67,23 +67,23 @@ typedef struct TU_ATTR_PACKED // Part E, 5.4.1. // Length of the command is from 3 bytes (2 bytes for OpCode, // 1 byte for parameter total length) to 258. -TU_ATTR_WEAK void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); +void tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len); // Invoked when ACL data was received over USB from Bluetooth host. // Detailed format is described in Bluetooth core specification Vol 2, // Part E, 5.4.2. // Length is from 4 bytes, (12 bits for Handle, 4 bits for flags // and 16 bits for data total length) to endpoint size. -TU_ATTR_WEAK void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); +void tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len); // Called when event sent with tud_bt_event_send() was delivered to BT stack. // Controller can release/reuse buffer with Event packet at this point. -TU_ATTR_WEAK void tud_bt_event_sent_cb(uint16_t sent_bytes); +void tud_bt_event_sent_cb(uint16_t sent_bytes); // Called when ACL data that was sent with tud_bt_acl_data_send() // was delivered to BT stack. // Controller can release/reuse buffer with ACL packet at this point. -TU_ATTR_WEAK void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); +void tud_bt_acl_data_sent_cb(uint16_t sent_bytes); // Bluetooth controller calls this function when it wants to send even packet // as described in Bluetooth core specification Vol 2, Part E, 5.4.4. diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 4e4e01eaf..f1c4a3bbf 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -120,6 +120,42 @@ static bool _prep_out_transaction(uint8_t itf) { } //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf) { + (void) itf; +} + +TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { + (void) itf; + (void) wanted_char; +} + +TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf) { + (void) itf; +} + +TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf) { + (void) itf; +} + +TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { + (void) itf; + (void) dtr; + (void) rts; +} + +TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) { + (void) itf; + (void) p_line_coding; +} + +TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { + (void) itf; + (void) duration_ms; +} + +//--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { @@ -419,9 +455,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ TU_LOG_DRV(" Set Line Coding\r\n"); tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); } else if (stage == CONTROL_STAGE_ACK) { - if (tud_cdc_line_coding_cb) { - tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); - } + tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); } break; @@ -456,9 +490,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); // Invoke callback - if (tud_cdc_line_state_cb) { - tud_cdc_line_state_cb(itf, dtr, rts); - } + tud_cdc_line_state_cb(itf, dtr, rts); } break; @@ -467,9 +499,7 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_requ tud_control_status(rhport, request); } else if (stage == CONTROL_STAGE_ACK) { TU_LOG_DRV(" Send Break\r\n"); - if (tud_cdc_send_break_cb) { - tud_cdc_send_break_cb(itf, request->wValue); - } + tud_cdc_send_break_cb(itf, request->wValue); } break; @@ -501,7 +531,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ tu_fifo_write_n(&p_cdc->rx_ff, p_epbuf->epout, (uint16_t) xferred_bytes); // Check for wanted char and invoke callback if needed - if (tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1)) { + if (((signed char) p_cdc->wanted_char) != -1) { for (uint32_t i = 0; i < xferred_bytes; i++) { if ((p_cdc->wanted_char == p_epbuf->epout[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) { tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char); @@ -510,7 +540,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } // invoke receive callback (if there is still data) - if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) { + if (!tu_fifo_empty(&p_cdc->rx_ff)) { tud_cdc_rx_cb(itf); } @@ -523,9 +553,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Though maybe the baudrate is not really important !!! if (ep_addr == p_cdc->ep_in) { // invoke transmit callback to possibly refill tx fifo - if (tud_cdc_tx_complete_cb) { - tud_cdc_tx_complete_cb(itf); - } + tud_cdc_tx_complete_cb(itf); if (0 == tud_cdc_n_write_flush(itf)) { // If there is no data left, a ZLP should be sent if @@ -540,9 +568,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Sent notification to host if (ep_addr == p_cdc->ep_notify) { - if (tud_cdc_notify_complete_cb) { - tud_cdc_notify_complete_cb(itf); - } + tud_cdc_notify_complete_cb(itf); } return true; diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index a34e07e1d..9673b9807 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -220,28 +220,28 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) { //--------------------------------------------------------------------+ // Invoked when received new data -TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); +void tud_cdc_rx_cb(uint8_t itf); // Invoked when received `wanted_char` -TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); +void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); // Invoked when a TX is complete and therefore space becomes available in TX buffer -TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); +void tud_cdc_tx_complete_cb(uint8_t itf); // Invoked when a notification is sent to host -TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf); +void tud_cdc_notify_complete_cb(uint8_t itf); // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE -TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); // Invoked when line coding is change via SET_LINE_CODING -TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); +void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); // Invoked when received send break // \param[in] itf interface for which send break was received. // \param[in] duration_ms the length of time, in milliseconds, of the break signal. If a value of FFFFh, then the // device will send a break until another SendBreak request is received with value 0000h. -TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); +void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms); //--------------------------------------------------------------------+ // INTERNAL USBD-CLASS DRIVER API diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f9a37ed35..beef03eff 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -392,6 +392,25 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep); //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx) { + (void) idx; +} + +TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx) { + (void) idx; +} + +TU_ATTR_WEAK void tuh_cdc_rx_cb(uint8_t idx) { + (void) idx; +} + +TU_ATTR_WEAK void tuh_cdc_tx_complete_cb(uint8_t idx) { + (void) idx; +} + +//--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ @@ -657,9 +676,7 @@ void cdch_close(uint8_t daddr) { TU_LOG_CDC(p_cdc, "close"); // Invoke application callback - if (tuh_cdc_umount_cb) { - tuh_cdc_umount_cb(idx); - } + tuh_cdc_umount_cb(idx); p_cdc->daddr = 0; p_cdc->bInterfaceNumber = 0; @@ -680,9 +697,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (ep_addr == p_cdc->stream.tx.ep_addr) { // invoke tx complete callback to possibly refill tx fifo - if (tuh_cdc_tx_complete_cb) { - tuh_cdc_tx_complete_cb(idx); - } + tuh_cdc_tx_complete_cb(idx); if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: @@ -697,18 +712,14 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (xferred_bytes > 2) { tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf + 2, xferred_bytes - 2); - if (tuh_cdc_rx_cb) { - tuh_cdc_rx_cb(idx); // invoke receive callback - } + tuh_cdc_rx_cb(idx); // invoke receive callback } } else #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - if (tuh_cdc_rx_cb) { - tuh_cdc_rx_cb(idx); // invoke receive callback - } + tuh_cdc_rx_cb(idx); // invoke receive callback } // prepare for next transfer if needed @@ -794,9 +805,7 @@ static void set_config_complete(cdch_interface_t *p_cdc, bool success) { if (success) { const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; - if (tuh_cdc_mount_cb) { - tuh_cdc_mount_cb(idx); - } + tuh_cdc_mount_cb(idx); // Prepare for incoming data tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); } else { diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 37bfca270..bf6711d7e 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -230,16 +230,16 @@ TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(u // Invoked when a device with CDC interface is mounted // idx is index of cdc interface in the internal pool. -TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx); +extern void tuh_cdc_mount_cb(uint8_t idx); // Invoked when a device with CDC interface is unmounted -TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx); +extern void tuh_cdc_umount_cb(uint8_t idx); // Invoked when received new data -TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx); +extern void tuh_cdc_rx_cb(uint8_t idx); // Invoked when a TX is complete and therefore space becomes available in TX buffer -TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx); +extern void tuh_cdc_tx_complete_cb(uint8_t idx); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c index 11a5355aa..e975ea440 100644 --- a/src/class/cdc/cdc_rndis_host.c +++ b/src/class/cdc/cdc_rndis_host.c @@ -103,7 +103,7 @@ static tusb_error_t rndis_body_subtask(void) } - osal_task_delay(100); + tusb_time_delay_ms_api(100); OSAL_SUBTASK_END } diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c index d9e2d3f2f..0d2b63b57 100644 --- a/src/class/dfu/dfu_device.c +++ b/src/class/dfu/dfu_device.c @@ -77,6 +77,24 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tus static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request); //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_dfu_detach_cb(void) { +} + +TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt) { + (void) alt; +} + +TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length) { + (void) alt; + (void) block_num; + (void) data; + (void) length; + return 0; +} + +//--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= 2 @@ -234,9 +252,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control if (stage == CONTROL_STAGE_SETUP) { tud_control_status(rhport, request); } else if (stage == CONTROL_STAGE_ACK) { - if (tud_dfu_detach_cb) { - tud_dfu_detach_cb(); - } + tud_dfu_detach_cb(); } break; @@ -258,16 +274,13 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control reset_state(); tud_control_status(rhport, request); } else if (stage == CONTROL_STAGE_ACK) { - if (tud_dfu_abort_cb) { - tud_dfu_abort_cb(_dfu_ctx.alt); - } + tud_dfu_abort_cb(_dfu_ctx.alt); } break; case DFU_REQUEST_UPLOAD: if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD); - TU_VERIFY(tud_dfu_upload_cb); TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE); const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_epbuf.transfer_buf, diff --git a/src/class/dfu/dfu_device.h b/src/class/dfu/dfu_device.h index 00c22ea8b..e59e61ce9 100644 --- a/src/class/dfu/dfu_device.h +++ b/src/class/dfu/dfu_device.h @@ -74,13 +74,13 @@ void tud_dfu_manifest_cb(uint8_t alt); // Invoked when received DFU_UPLOAD request // Application must populate data with up to length bytes and // Return the number of written bytes -TU_ATTR_WEAK uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); +uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length); // Invoked when a DFU_DETACH request is received -TU_ATTR_WEAK void tud_dfu_detach_cb(void); +void tud_dfu_detach_cb(void); // Invoked when the Host has terminated a download or upload transfer -TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt); +void tud_dfu_abort_cb(uint8_t alt); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index c2434c20d..b69f623a0 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -807,7 +807,9 @@ enum { HID_USAGE_PAGE_MEDICAL_INSTRUMENT = 0x40, HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59, HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83 - HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87 + HID_USAGE_PAGE_POWER = 0x84, + HID_USAGE_PAGE_BATTERY = 0x85, + // 0x86 - 0x87 is reserved for Power Device HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, HID_USAGE_PAGE_SCALE = 0x8d, HID_USAGE_PAGE_MSR = 0x8e, @@ -893,14 +895,51 @@ enum { /// HID Usage Table: Consumer Page (0x0C) /// Only contains controls that supported by Windows (whole list is too long) enum { + HID_USAGE_CONSUMER_UNASSIGNED = 0x0000, + // Generic Control HID_USAGE_CONSUMER_CONTROL = 0x0001, + HID_USAGE_CONSUMER_NUMERIC_KEY_PAD = 0x0002, + HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS = 0x0003, + HID_USAGE_CONSUMER_MICROPHONE = 0x0004, + HID_USAGE_CONSUMER_HEADPHONE = 0x0005, + HID_USAGE_CONSUMER_GRAPHIC_EQUALIZER = 0x0006, + // 07-1F Reserved + + HID_USAGE_CONSUMER_PLUS_10 = 0x0020, + HID_USAGE_CONSUMER_PLUS_100 = 0x0021, + HID_USAGE_CONSUMER_AM_PM = 0x0022, + // 23-3F Reserved // Power Control HID_USAGE_CONSUMER_POWER = 0x0030, HID_USAGE_CONSUMER_RESET = 0x0031, HID_USAGE_CONSUMER_SLEEP = 0x0032, + HID_USAGE_CONSUMER_SLEEP_AFTER = 0x0033, + HID_USAGE_CONSUMER_SLEEP_MODE = 0x0034, + HID_USAGE_CONSUMER_ILLUMINATION = 0x0035, + HID_USAGE_CONSUMER_FUNCTION_BUTTONS = 0x0036, + // 37-3F Reserved + HID_USAGE_CONSUMER_MENU = 0x0040, + HID_USAGE_CONSUMER_MENU_PICK = 0x0041, + HID_USAGE_CONSUMER_MENU_UP = 0x0042, + HID_USAGE_CONSUMER_MENU_DOWN = 0x0043, + HID_USAGE_CONSUMER_MENU_LEFT = 0x0044, + HID_USAGE_CONSUMER_MENU_RIGHT = 0x0045, + HID_USAGE_CONSUMER_MENU_ESCAPE = 0x0046, + HID_USAGE_CONSUMER_MENU_VALUE_INCREASE = 0x0047, + HID_USAGE_CONSUMER_MENU_VALUE_DECREASE = 0x0048, + // 49-5F Reserved + HID_USAGE_CONSUMER_DATA_ON_SCREEN = 0x0060, + HID_USAGE_CONSUMER_CLOSED_CAPTION = 0x0061, + HID_USAGE_CONSUMER_CLOSED_CAPTION_SELECT = 0x0062, + HID_USAGE_CONSUMER_VCR_TV = 0x0063, + HID_USAGE_CONSUMER_BROADCAST_MODE = 0x0064, + HID_USAGE_CONSUMER_SNAPSHOT = 0x0065, + HID_USAGE_CONSUMER_STILL = 0x0066, + + // 67-7F Reserved // Screen Brightness HID_USAGE_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F, HID_USAGE_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070, @@ -912,40 +951,382 @@ enum { HID_USAGE_CONSUMER_WIRELESS_RADIO_LED = 0x00C7, HID_USAGE_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8, + HID_USAGE_CONSUMER_SELECTION = 0x0080, + HID_USAGE_CONSUMER_ASSIGN_SELECTION = 0x0081, + HID_USAGE_CONSUMER_MODE_STEP = 0x0082, + HID_USAGE_CONSUMER_RECALL_LAST = 0x0083, + HID_USAGE_CONSUMER_ENTER_CHANNEL = 0x0084, + HID_USAGE_CONSUMER_ORDER_MOVIE = 0x0085, + HID_USAGE_CONSUMER_CHANNEL = 0x0086, + HID_USAGE_CONSUMER_MEDIA_SELECTION = 0x0087, + HID_USAGE_CONSUMER_MEDIA_SELECT_COMPUTER = 0x0088, + HID_USAGE_CONSUMER_MEDIA_SELECT_TV = 0x0089, + HID_USAGE_CONSUMER_MEDIA_SELECT_WWW = 0x008A, + HID_USAGE_CONSUMER_MEDIA_SELECT_DVD = 0x008B, + HID_USAGE_CONSUMER_MEDIA_SELECT_TELEPHONE = 0x008C, + HID_USAGE_CONSUMER_MEDIA_SELECT_PROGRAM_GUIDE = 0x008D, + HID_USAGE_CONSUMER_MEDIA_SELECT_VIDEO_PHONE = 0x008E, + HID_USAGE_CONSUMER_MEDIA_SELECT_GAMES = 0x008F, + HID_USAGE_CONSUMER_MEDIA_SELECT_MESSAGES = 0x0090, + HID_USAGE_CONSUMER_MEDIA_SELECT_CD = 0x0091, + HID_USAGE_CONSUMER_MEDIA_SELECT_VCR = 0x0092, + HID_USAGE_CONSUMER_MEDIA_SELECT_TUNER = 0x0093, + HID_USAGE_CONSUMER_QUIT = 0x0094, + HID_USAGE_CONSUMER_HELP = 0x0095, + HID_USAGE_CONSUMER_MEDIA_SELECT_TAPE = 0x0096, + HID_USAGE_CONSUMER_MEDIA_SELECT_CABLE = 0x0097, + HID_USAGE_CONSUMER_MEDIA_SELECT_SATELLITE = 0x0098, + HID_USAGE_CONSUMER_MEDIA_SELECT_SECURITY = 0x0099, + HID_USAGE_CONSUMER_MEDIA_SELECT_HOME = 0x009A, + HID_USAGE_CONSUMER_MEDIA_SELECT_CALL = 0x009B, + HID_USAGE_CONSUMER_CHANNEL_INCREMENT = 0x009C, + HID_USAGE_CONSUMER_CHANNEL_DECREMENT = 0x009D, + HID_USAGE_CONSUMER_MEDIA_SELECT_SAP = 0x009E, + // 9F Reserved + HID_USAGE_CONSUMER_VCR_PLUS = 0x00A0, + HID_USAGE_CONSUMER_ONCE = 0x00A1, + HID_USAGE_CONSUMER_DAILY = 0x00A2, + HID_USAGE_CONSUMER_WEEKLY = 0x00A3, + HID_USAGE_CONSUMER_MONTHLY = 0x00A4, + // A5-AF Reserved + + HID_USAGE_CONSUMER_PLAY = 0x00B0, + HID_USAGE_CONSUMER_PAUSE = 0x00B1, + HID_USAGE_CONSUMER_RECORD = 0x00B2, + HID_USAGE_CONSUMER_FAST_FORWARD = 0x00B3, + HID_USAGE_CONSUMER_REWIND = 0x00B4, + HID_USAGE_CONSUMER_SCAN_NEXT_TRACK = 0x00B5, + HID_USAGE_CONSUMER_SCAN_PREVIOUS_TRACK = 0x00B6, + HID_USAGE_CONSUMER_STOP = 0x00B7, + HID_USAGE_CONSUMER_EJECT = 0x00B8, + HID_USAGE_CONSUMER_RANDOM_PLAY = 0x00B9, + HID_USAGE_CONSUMER_SELECT_DISC = 0x00BA, + HID_USAGE_CONSUMER_ENTER_DISC = 0x00BB, + HID_USAGE_CONSUMER_REPEAT = 0x00BC, + HID_USAGE_CONSUMER_TRACKING = 0x00BD, + HID_USAGE_CONSUMER_TRACK_NORMAL = 0x00BE, + HID_USAGE_CONSUMER_SLOW_TRACKING = 0x00BF, + HID_USAGE_CONSUMER_FRAME_FORWARD = 0x00C0, + HID_USAGE_CONSUMER_FRAME_BACK = 0x00C1, + HID_USAGE_CONSUMER_MARK = 0x00C2, + HID_USAGE_CONSUMER_CLEAR_MARK = 0x00C3, + HID_USAGE_CONSUMER_REPEAT_FROM_MARK = 0x00C4, + HID_USAGE_CONSUMER_RETURN_TO_MARK = 0x00C5, + HID_USAGE_CONSUMER_SEARCH_MARK_FORWARD = 0x00C6, + HID_USAGE_CONSUMER_SEARCH_MARK_BACKWARDS = 0x00C7, + HID_USAGE_CONSUMER_COUNTER_RESET = 0x00C8, + HID_USAGE_CONSUMER_SHOW_COUNTER = 0x00C9, + HID_USAGE_CONSUMER_TRACKING_INCREMENT = 0x00CA, + HID_USAGE_CONSUMER_TRACKING_DECREMENT = 0x00CB, + HID_USAGE_CONSUMER_STOP_EJECT = 0x00CC, + + // Media Control HID_USAGE_CONSUMER_PLAY_PAUSE = 0x00CD, - HID_USAGE_CONSUMER_SCAN_NEXT = 0x00B5, - HID_USAGE_CONSUMER_SCAN_PREVIOUS = 0x00B6, - HID_USAGE_CONSUMER_STOP = 0x00B7, + + HID_USAGE_CONSUMER_PLAY_SKIP = 0x00CE, + + // CF-DF Reserved HID_USAGE_CONSUMER_VOLUME = 0x00E0, + HID_USAGE_CONSUMER_BALANCE = 0x00E1, HID_USAGE_CONSUMER_MUTE = 0x00E2, HID_USAGE_CONSUMER_BASS = 0x00E3, HID_USAGE_CONSUMER_TREBLE = 0x00E4, HID_USAGE_CONSUMER_BASS_BOOST = 0x00E5, + HID_USAGE_CONSUMER_SURROUND_MODE = 0x00E6, + HID_USAGE_CONSUMER_LOUDNESS = 0x00E7, + HID_USAGE_CONSUMER_MPX = 0x00E8, HID_USAGE_CONSUMER_VOLUME_INCREMENT = 0x00E9, HID_USAGE_CONSUMER_VOLUME_DECREMENT = 0x00EA, + // EB-EF Reserved + HID_USAGE_CONSUMER_SPEED_SELECT = 0x00F0, + HID_USAGE_CONSUMER_PLAYBACK_SPEED = 0x00F1, + HID_USAGE_CONSUMER_STANDARD_PLAY = 0x00F2, + HID_USAGE_CONSUMER_LONG_PLAY = 0x00F3, + HID_USAGE_CONSUMER_EXTENDED_PLAY = 0x00F4, + HID_USAGE_CONSUMER_SLOW = 0x00F5, + // F6-FF Reserved + HID_USAGE_CONSUMER_FAN_ENABLE = 0x0100, + HID_USAGE_CONSUMER_FAN_SPEED = 0x0101, + HID_USAGE_CONSUMER_LIGHT_ENABLE = 0x0102, + HID_USAGE_CONSUMER_LIGHT_ILLUMINATION_LEVEL = 0x0103, + HID_USAGE_CONSUMER_CLIMATE_CONTROL_ENABLE = 0x0104, + HID_USAGE_CONSUMER_ROOM_TEMPERATURE = 0x0105, + HID_USAGE_CONSUMER_SECURITY_ENABLE = 0x0106, + HID_USAGE_CONSUMER_FIRE_ALARM = 0x0107, + HID_USAGE_CONSUMER_POLICE_ALARM = 0x0108, + HID_USAGE_CONSUMER_PROXIMITY = 0x0109, + HID_USAGE_CONSUMER_MOTION = 0x010A, + HID_USAGE_CONSUMER_DURESS_ALARM = 0x010B, + HID_USAGE_CONSUMER_HOLDUP_ALARM = 0x010C, + HID_USAGE_CONSUMER_MEDICAL_ALARM = 0x010D, + // 10E-14F Reserved + HID_USAGE_CONSUMER_BALANCE_RIGHT = 0x0150, + HID_USAGE_CONSUMER_BALANCE_LEFT = 0x0151, HID_USAGE_CONSUMER_BASS_INCREMENT = 0x0152, HID_USAGE_CONSUMER_BASS_DECREMENT = 0x0153, HID_USAGE_CONSUMER_TREBLE_INCREMENT = 0x0154, HID_USAGE_CONSUMER_TREBLE_DECREMENT = 0x0155, - // Application Launcher + // 156-15F Reserved + HID_USAGE_CONSUMER_SPEAKER_SYSTEM = 0x0160, + HID_USAGE_CONSUMER_CHANNEL_LEFT = 0x0161, + HID_USAGE_CONSUMER_CHANNEL_RIGHT = 0x0162, + HID_USAGE_CONSUMER_CHANNEL_CENTER = 0x0163, + HID_USAGE_CONSUMER_CHANNEL_FRONT = 0x0164, + HID_USAGE_CONSUMER_CHANNEL_CENTER_FRONT = 0x0165, + HID_USAGE_CONSUMER_CHANNEL_SIDE = 0x0166, + HID_USAGE_CONSUMER_CHANNEL_SURROUND = 0x0167, + HID_USAGE_CONSUMER_CHANNEL_LOW_FREQUENCY = 0x0168, + // Enhancement + // CL 15.12.1 + HID_USAGE_CONSUMER_CHANNEL_TOP = 0x0169, + HID_USAGE_CONSUMER_CHANNEL_UNKNOWN = 0x016A, + // 16B-16F Reserved + HID_USAGE_CONSUMER_SUB_CHANNEL = 0x0170, + HID_USAGE_CONSUMER_SUB_CHANNEL_INCREMENT = 0x0171, + HID_USAGE_CONSUMER_SUB_CHANNEL_DECREMENT = 0x0172, + HID_USAGE_CONSUMER_ALTERNATE_AUDIO_INCREMENT = 0x0173, + HID_USAGE_CONSUMER_ALTERNATE_AUDIO_DECREMENT = 0x0174, + // 175-17F Reserved + HID_USAGE_CONSUMER_APPLICATION_LAUNCH_BUTTONS = 0x0180, + HID_USAGE_CONSUMER_AL_LAUNCH_BUTTON_CONFIGURATION = 0x0181, + // Tool + // Sel 15.15 + HID_USAGE_CONSUMER_AL_PROGRAMMABLE_BUTTON = 0x0182, + // Configuration + // Sel 15.15 HID_USAGE_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, + // Configuration + // Sel 15.15 + HID_USAGE_CONSUMER_AL_WORD_PROCESSOR = 0x0184, + HID_USAGE_CONSUMER_AL_TEXT_EDITOR = 0x0185, + HID_USAGE_CONSUMER_AL_SPREADSHEET = 0x0186, + HID_USAGE_CONSUMER_AL_GRAPHICS_EDITOR = 0x0187, + HID_USAGE_CONSUMER_AL_PRESENTATION_APP = 0x0188, + HID_USAGE_CONSUMER_AL_DATABASE_APP = 0x0189, HID_USAGE_CONSUMER_AL_EMAIL_READER = 0x018A, + HID_USAGE_CONSUMER_AL_NEWSREADER = 0x018B, + HID_USAGE_CONSUMER_AL_VOICEMAIL = 0x018C, + HID_USAGE_CONSUMER_AL_CONTACTS_ADDRESS_BOOK = 0x018D, + HID_USAGE_CONSUMER_AL_CALENDAR_SCHEDULE = 0x018E, + HID_USAGE_CONSUMER_AL_TASK_PROJECT_MANAGER = 0x018F, + HID_USAGE_CONSUMER_AL_LOG_JOURNAL_TIMECARD = 0x0190, + HID_USAGE_CONSUMER_AL_CHECKBOOK_FINANCE = 0x0191, HID_USAGE_CONSUMER_AL_CALCULATOR = 0x0192, - HID_USAGE_CONSUMER_AL_LOCAL_BROWSER = 0x0194, - + HID_USAGE_CONSUMER_AL_A_V_CAPTURE_PLAYBACK = 0x0193, + HID_USAGE_CONSUMER_AL_LOCAL_MACHINE_BROWSER = 0x0194, + HID_USAGE_CONSUMER_AL_LAN_WAN_BROWSER = 0x0195, + HID_USAGE_CONSUMER_AL_INTERNET_BROWSER = 0x0196, + HID_USAGE_CONSUMER_AL_REMOTE_NETWORKING_ISP = 0x0197, + // Connect + // Sel 15.15 + HID_USAGE_CONSUMER_AL_NETWORK_CONFERENCE = 0x0198, + HID_USAGE_CONSUMER_AL_NETWORK_CHAT = 0x0199, + HID_USAGE_CONSUMER_AL_TELEPHONY_DIALER = 0x019A, + HID_USAGE_CONSUMER_AL_LOGON = 0x019B, + HID_USAGE_CONSUMER_AL_LOGOFF = 0x019C, + HID_USAGE_CONSUMER_AL_LOGON_LOGOFF = 0x019D, + HID_USAGE_CONSUMER_AL_TERMINAL_LOCK_SCREENSAVER = 0x019E, + HID_USAGE_CONSUMER_AL_CONTROL_PANEL = 0x019F, + HID_USAGE_CONSUMER_AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0, + HID_USAGE_CONSUMER_AL_PROCESS_TASK_MANAGER = 0x01A1, + HID_USAGE_CONSUMER_AL_SELECT_TASK_APPLICATION = 0x01A2, + HID_USAGE_CONSUMER_AL_NEXT_TASK_APPLICATION = 0x01A3, + HID_USAGE_CONSUMER_AL_PREVIOUS_TASK_APPLICATION = 0x01A4, + HID_USAGE_CONSUMER_AL_PREEMPTIVE_HALT = 0x01A5, + // Task_Application + // Sel 15.15 + HID_USAGE_CONSUMER_AL_INTEGRATED_HELP_CENTER = 0x01A6, + HID_USAGE_CONSUMER_AL_DOCUMENTS = 0x01A7, + HID_USAGE_CONSUMER_AL_THESAURUS = 0x01A8, + HID_USAGE_CONSUMER_AL_DICTIONARY = 0x01A9, + HID_USAGE_CONSUMER_AL_DESKTOP = 0x01AA, + HID_USAGE_CONSUMER_AL_SPELL_CHECK = 0x01AB, + HID_USAGE_CONSUMER_AL_GRAMMAR_CHECK = 0x01AC, + HID_USAGE_CONSUMER_AL_WIRELESS_STATUS = 0x01AD, + HID_USAGE_CONSUMER_AL_KEYBOARD_LAYOUT = 0x01AE, + HID_USAGE_CONSUMER_AL_VIRUS_PROTECTION = 0x01AF, + HID_USAGE_CONSUMER_AL_ENCRYPTION = 0x01B0, + HID_USAGE_CONSUMER_AL_SCREEN_SAVER = 0x01B1, + HID_USAGE_CONSUMER_AL_ALARMS = 0x01B2, + HID_USAGE_CONSUMER_AL_CLOCK = 0x01B3, + HID_USAGE_CONSUMER_AL_FILE_BROWSER = 0x01B4, + HID_USAGE_CONSUMER_AL_POWER_STATUS = 0x01B5, + HID_USAGE_CONSUMER_AL_IMAGE_BROWSER = 0x01B6, + HID_USAGE_CONSUMER_AL_AUDIO_BROWSER = 0x01B7, + HID_USAGE_CONSUMER_AL_MOVIE_BROWSER = 0x01B8, + HID_USAGE_CONSUMER_AL_DIGITAL_RIGHTS_MANAGER = 0x01B9, + HID_USAGE_CONSUMER_AL_DIGITAL_WALLET = 0x01BA, + // 1BB Reserved + HID_USAGE_CONSUMER_AL_INSTANT_MESSAGING = 0x01BC, + HID_USAGE_CONSUMER_AL_OEM_FEATURES_TIPS_TUTORIAL = 0x01BD, + // Browser + // Sel 15.15 + HID_USAGE_CONSUMER_AL_OEM_HELP = 0x01BE, + HID_USAGE_CONSUMER_AL_ONLINE_COMMUNITY = 0x01BF, + HID_USAGE_CONSUMER_AL_ENTERTAINMENT_CONTENT = 0x01C0, + // Browser + // Sel 15.15 + HID_USAGE_CONSUMER_AL_ONLINE_SHOPPING_BROWSER = 0x01C1, + HID_USAGE_CONSUMER_AL_SMARTCARD_INFORMATION_HELP = 0x01C2, + HID_USAGE_CONSUMER_AL_MARKET_MONITOR_FINANCE = 0x01C3, + // Browser + // Sel 15.15 + HID_USAGE_CONSUMER_AL_CUSTOMIZED_CORPORATE_NEWS = 0x01C4, + // Browser + // Sel 15.15 + HID_USAGE_CONSUMER_AL_ONLINE_ACTIVITY_BROWSER = 0x01C5, + HID_USAGE_CONSUMER_AL_RESEARCH_SEARCH_BROWSER = 0x01C6, + HID_USAGE_CONSUMER_AL_AUDIO_PLAYER = 0x01C7, + // 1C8-1FF Reserved + HID_USAGE_CONSUMER_GENERIC_GUI_APPLICATION = 0x0200, + // ' Controls + // ' + HID_USAGE_CONSUMER_AC_NEW = 0x0201, + HID_USAGE_CONSUMER_AC_OPEN = 0x0202, + HID_USAGE_CONSUMER_AC_CLOSE = 0x0203, + HID_USAGE_CONSUMER_AC_EXIT = 0x0204, + HID_USAGE_CONSUMER_AC_MAXIMIZE = 0x0205, + HID_USAGE_CONSUMER_AC_MINIMIZE = 0x0206, + HID_USAGE_CONSUMER_AC_SAVE = 0x0207, + HID_USAGE_CONSUMER_AC_PRINT = 0x0208, + HID_USAGE_CONSUMER_AC_PROPERTIES = 0x0209, + HID_USAGE_CONSUMER_AC_UNDO = 0x021A, + HID_USAGE_CONSUMER_AC_COPY = 0x021B, + HID_USAGE_CONSUMER_AC_CUT = 0x021C, + HID_USAGE_CONSUMER_AC_PASTE = 0x021D, + HID_USAGE_CONSUMER_AC_SELECT_ALL = 0x021E, + HID_USAGE_CONSUMER_AC_FIND = 0x021F, + HID_USAGE_CONSUMER_AC_FIND_AND_REPLACE = 0x0220, // Browser/Explorer Specific HID_USAGE_CONSUMER_AC_SEARCH = 0x0221, + HID_USAGE_CONSUMER_AC_GO_TO = 0x0222, HID_USAGE_CONSUMER_AC_HOME = 0x0223, HID_USAGE_CONSUMER_AC_BACK = 0x0224, HID_USAGE_CONSUMER_AC_FORWARD = 0x0225, HID_USAGE_CONSUMER_AC_STOP = 0x0226, HID_USAGE_CONSUMER_AC_REFRESH = 0x0227, + HID_USAGE_CONSUMER_AC_PREVIOUS_LINK = 0x0228, + HID_USAGE_CONSUMER_AC_NEXT_LINK = 0x0229, HID_USAGE_CONSUMER_AC_BOOKMARKS = 0x022A, - + HID_USAGE_CONSUMER_AC_HISTORY = 0x022B, + HID_USAGE_CONSUMER_AC_SUBSCRIPTIONS = 0x022C, + HID_USAGE_CONSUMER_AC_ZOOM_IN = 0x022D, + HID_USAGE_CONSUMER_AC_ZOOM_OUT = 0x022E, + HID_USAGE_CONSUMER_AC_ZOOM = 0x022F, + HID_USAGE_CONSUMER_AC_FULL_SCREEN_VIEW = 0x0230, + HID_USAGE_CONSUMER_AC_NORMAL_VIEW = 0x0231, + HID_USAGE_CONSUMER_AC_VIEW_TOGGLE = 0x0232, + HID_USAGE_CONSUMER_AC_SCROLL_UP = 0x0233, + HID_USAGE_CONSUMER_AC_SCROLL_DOWN = 0x0234, + HID_USAGE_CONSUMER_AC_SCROLL = 0x0235, + HID_USAGE_CONSUMER_AC_PAN_LEFT = 0x0236, + HID_USAGE_CONSUMER_AC_PAN_RIGHT = 0x0237, // Mouse Horizontal scroll HID_USAGE_CONSUMER_AC_PAN = 0x0238, + HID_USAGE_CONSUMER_AC_NEW_WINDOW = 0x0239, + HID_USAGE_CONSUMER_AC_TILE_HORIZONTALLY = 0x023A, + HID_USAGE_CONSUMER_AC_TILE_VERTICALLY = 0x023B, + HID_USAGE_CONSUMER_AC_FORMAT = 0x023C, + HID_USAGE_CONSUMER_AC_EDIT = 0x023D, + HID_USAGE_CONSUMER_AC_BOLD = 0x023E, + HID_USAGE_CONSUMER_AC_ITALICS = 0x023F, + HID_USAGE_CONSUMER_AC_UNDERLINE = 0x0240, + HID_USAGE_CONSUMER_AC_STRIKETHROUGH = 0x0241, + HID_USAGE_CONSUMER_AC_SUBSCRIPT = 0x0242, + HID_USAGE_CONSUMER_AC_SUPERSCRIPT = 0x0243, + HID_USAGE_CONSUMER_AC_ALL_CAPS = 0x0244, + HID_USAGE_CONSUMER_AC_ROTATE = 0x0245, + HID_USAGE_CONSUMER_AC_RESIZE = 0x0246, + HID_USAGE_CONSUMER_AC_FLIP_HORIZONTAL = 0x0247, + HID_USAGE_CONSUMER_AC_FLIP_VERTICAL = 0x0248, + HID_USAGE_CONSUMER_AC_MIRROR_HORIZONTAL = 0x0249, + HID_USAGE_CONSUMER_AC_MIRROR_VERTICAL = 0x024A, + HID_USAGE_CONSUMER_AC_FONT_SELECT = 0x024B, + HID_USAGE_CONSUMER_AC_FONT_COLOR = 0x024C, + HID_USAGE_CONSUMER_AC_FONT_SIZE = 0x024D, + HID_USAGE_CONSUMER_AC_JUSTIFY_LEFT = 0x024E, + HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_H = 0x024F, + HID_USAGE_CONSUMER_AC_JUSTIFY_RIGHT = 0x0250, + HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_H = 0x0251, + HID_USAGE_CONSUMER_AC_JUSTIFY_TOP = 0x0252, + HID_USAGE_CONSUMER_AC_JUSTIFY_CENTER_V = 0x0253, + HID_USAGE_CONSUMER_AC_JUSTIFY_BOTTOM = 0x0254, + HID_USAGE_CONSUMER_AC_JUSTIFY_BLOCK_V = 0x0255, + HID_USAGE_CONSUMER_AC_INDENT_DECREASE = 0x0256, + HID_USAGE_CONSUMER_AC_INDENT_INCREASE = 0x0257, + HID_USAGE_CONSUMER_AC_NUMBERED_LIST = 0x0258, + HID_USAGE_CONSUMER_AC_RESTART_NUMBERING = 0x0259, + HID_USAGE_CONSUMER_AC_BULLETED_LIST = 0x025A, + HID_USAGE_CONSUMER_AC_PROMOTE = 0x025B, + HID_USAGE_CONSUMER_AC_DEMOTE = 0x025C, + HID_USAGE_CONSUMER_AC_YES = 0x025D, + HID_USAGE_CONSUMER_AC_NO = 0x025E, + HID_USAGE_CONSUMER_AC_CANCEL = 0x025F, + HID_USAGE_CONSUMER_AC_CATALOG = 0x0260, + HID_USAGE_CONSUMER_AC_BUY_CHECKOUT = 0x0261, + HID_USAGE_CONSUMER_AC_ADD_TO_CART = 0x0262, + HID_USAGE_CONSUMER_AC_EXPAND = 0x0263, + HID_USAGE_CONSUMER_AC_EXPAND_ALL = 0x0264, + HID_USAGE_CONSUMER_AC_COLLAPSE = 0x0265, + HID_USAGE_CONSUMER_AC_COLLAPSE_ALL = 0x0266, + HID_USAGE_CONSUMER_AC_PRINT_PREVIEW = 0x0267, + HID_USAGE_CONSUMER_AC_PASTE_SPECIAL = 0x0268, + HID_USAGE_CONSUMER_AC_INSERT_MODE = 0x0269, + HID_USAGE_CONSUMER_AC_DELETE = 0x026A, + HID_USAGE_CONSUMER_AC_LOCK = 0x026B, + HID_USAGE_CONSUMER_AC_UNLOCK = 0x026C, + HID_USAGE_CONSUMER_AC_PROTECT = 0x026D, + HID_USAGE_CONSUMER_AC_UNPROTECT = 0x026E, + HID_USAGE_CONSUMER_AC_ATTACH_COMMENT = 0x026F, + HID_USAGE_CONSUMER_AC_DELETE_COMMENT = 0x0270, + HID_USAGE_CONSUMER_AC_VIEW_COMMENT = 0x0271, + HID_USAGE_CONSUMER_AC_SELECT_WORD = 0x0272, + HID_USAGE_CONSUMER_AC_SELECT_SENTENCE = 0x0273, + HID_USAGE_CONSUMER_AC_SELECT_PARAGRAPH = 0x0274, + HID_USAGE_CONSUMER_AC_SELECT_COLUMN = 0x0275, + HID_USAGE_CONSUMER_AC_SELECT_ROW = 0x0276, + HID_USAGE_CONSUMER_AC_SELECT_TABLE = 0x0277, + HID_USAGE_CONSUMER_AC_SELECT_OBJECT = 0x0278, + HID_USAGE_CONSUMER_AC_REDO_REPEAT = 0x0279, + HID_USAGE_CONSUMER_AC_SORT = 0x027A, + HID_USAGE_CONSUMER_AC_SORT_ASCENDING = 0x027B, + HID_USAGE_CONSUMER_AC_SORT_DESCENDING = 0x027C, + HID_USAGE_CONSUMER_AC_FILTER = 0x027D, + HID_USAGE_CONSUMER_AC_SET_CLOCK = 0x027E, + HID_USAGE_CONSUMER_AC_VIEW_CLOCK = 0x027F, + HID_USAGE_CONSUMER_AC_SELECT_TIME_ZONE = 0x0280, + HID_USAGE_CONSUMER_AC_EDIT_TIME_ZONES = 0x0281, + HID_USAGE_CONSUMER_AC_SET_ALARM = 0x0282, + HID_USAGE_CONSUMER_AC_CLEAR_ALARM = 0x0283, + HID_USAGE_CONSUMER_AC_SNOOZE_ALARM = 0x0284, + HID_USAGE_CONSUMER_AC_RESET_ALARM = 0x0285, + HID_USAGE_CONSUMER_AC_SYNCHRONIZE = 0x0286, + HID_USAGE_CONSUMER_AC_SEND_RECEIVE = 0x0287, + HID_USAGE_CONSUMER_AC_SEND_TO = 0x0288, + HID_USAGE_CONSUMER_AC_REPLY = 0x0289, + HID_USAGE_CONSUMER_AC_REPLY_ALL = 0x028A, + HID_USAGE_CONSUMER_AC_FORWARD_MSG = 0x028B, + HID_USAGE_CONSUMER_AC_SEND = 0x028C, + HID_USAGE_CONSUMER_AC_ATTACH_FILE = 0x028D, + HID_USAGE_CONSUMER_AC_UPLOAD = 0x028E, + HID_USAGE_CONSUMER_AC_DOWNLOAD_SAVE_TARGET_AS = 0x028F, + HID_USAGE_CONSUMER_AC_SET_BORDERS = 0x0290, + HID_USAGE_CONSUMER_AC_INSERT_ROW = 0x0291, + HID_USAGE_CONSUMER_AC_INSERT_COLUMN = 0x0292, + HID_USAGE_CONSUMER_AC_INSERT_FILE = 0x0293, + HID_USAGE_CONSUMER_AC_INSERT_PICTURE = 0x0294, + HID_USAGE_CONSUMER_AC_INSERT_OBJECT = 0x0295, + HID_USAGE_CONSUMER_AC_INSERT_SYMBOL = 0x0296, + HID_USAGE_CONSUMER_AC_SAVE_AND_CLOSE = 0x0297, + HID_USAGE_CONSUMER_AC_RENAME = 0x0298, + HID_USAGE_CONSUMER_AC_MERGE = 0x0299, + HID_USAGE_CONSUMER_AC_SPLIT = 0x029A, + HID_USAGE_CONSUMER_AC_DISRIBUTE_HORIZONTALLY = 0x029B, + HID_USAGE_CONSUMER_AC_DISTRIBUTE_VERTICALLY = 0x029C, + // 29D-FFFF Reserved + }; /// HID Usage Table: Digitizer Page (0x0D) @@ -1216,6 +1597,200 @@ enum { HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71, }; +/// HID Usage Table: Power Device Page (0x84) +enum { + HID_USAGE_POWER_UNDEFINED = 0x00, + HID_USAGE_POWER_I_NAME = 0x01, + HID_USAGE_POWER_PRESENT_STATUS = 0x02, + HID_USAGE_POWER_CHANGED_STATUS = 0x03, + HID_USAGE_POWER_UPS = 0x04, + HID_USAGE_POWER_POWER_SUPPLY = 0x05, + // 06-0F Reserved + HID_USAGE_POWER_BATTERY_SYSTEM = 0x10, + HID_USAGE_POWER_BATTERY_SYSTEM_ID = 0x11, + HID_USAGE_POWER_BATTERY = 0x12, + HID_USAGE_POWER_BATTERY_ID = 0x13, + HID_USAGE_POWER_CHARGER = 0x14, + HID_USAGE_POWER_CHARGER_ID = 0x15, + HID_USAGE_POWER_POWER_CONVERTER = 0x16, + HID_USAGE_POWER_POWER_CONVERTER_ID = 0x17, + HID_USAGE_POWER_OUTLET_SYSTEM = 0x18, + HID_USAGE_POWER_OUTLET_SYSTEM_ID = 0x19, + HID_USAGE_POWER_INPUT = 0x1A, + HID_USAGE_POWER_INPUT_ID = 0x1B, + HID_USAGE_POWER_OUTPUT = 0x1C, + HID_USAGE_POWER_OUTPUT_ID = 0x1D, + HID_USAGE_POWER_FLOW = 0x1E, + HID_USAGE_POWER_FLOW_ID = 0x1F, + HID_USAGE_POWER_OUTLET = 0x20, + HID_USAGE_POWER_OUTLET_ID = 0x21, + HID_USAGE_POWER_GANG = 0x22, + HID_USAGE_POWER_GANG_ID = 0x23, + HID_USAGE_POWER_POWER_SUMMARY = 0x24, + HID_USAGE_POWER_POWER_SUMMARY_ID = 0x25, + // 26-2F Reserved + HID_USAGE_POWER_VOLTAGE = 0x30, + HID_USAGE_POWER_CURRENT = 0x31, + HID_USAGE_POWER_FREQUENCY = 0x32, + HID_USAGE_POWER_APPARENT_POWER = 0x33, + HID_USAGE_POWER_ACTIVE_POWER = 0x34, + HID_USAGE_POWER_PERCENT_LOAD = 0x35, + HID_USAGE_POWER_TEMPERATURE = 0x36, + HID_USAGE_POWER_HUMIDITY = 0x37, + HID_USAGE_POWER_BAD_COUNT = 0x38, + // 39-3F Reserved + HID_USAGE_POWER_CONFIG_VOLTAGE = 0x40, + HID_USAGE_POWER_CONFIG_CURRENT = 0x41, + HID_USAGE_POWER_CONFIG_FREQUENCY = 0x42, + HID_USAGE_POWER_CONFIG_APPARENT_POWER = 0x43, + HID_USAGE_POWER_CONFIG_ACTIVE_POWER = 0x44, + HID_USAGE_POWER_CONFIG_PERCENT_LOAD = 0x45, + HID_USAGE_POWER_CONFIG_TEMPERATURE = 0x46, + HID_USAGE_POWER_CONFIG_HUMIDITY = 0x47, + // 48-4F Reserved + HID_USAGE_POWER_SWITCH_ON_CONTROL = 0x50, + HID_USAGE_POWER_SWITCH_OFF_CONTROL = 0x51, + HID_USAGE_POWER_TOGGLE_CONTROL = 0x52, + HID_USAGE_POWER_LOW_VOLTAGE_TRANSFER = 0x53, + HID_USAGE_POWER_HIGH_VOLTAGE_TRANSFER = 0x54, + HID_USAGE_POWER_DELAY_BEFORE_REBOOT = 0x55, + HID_USAGE_POWER_DELAY_BEFORE_STARTUP = 0x56, + HID_USAGE_POWER_DELAY_BEFORE_SHUTDOWN = 0x57, + HID_USAGE_POWER_TEST = 0x58, + HID_USAGE_POWER_MODULE_RESET = 0x59, + HID_USAGE_POWER_AUDIBLE_ALARM_CONTROL = 0x5A, + // 5B-5F Reserved + HID_USAGE_POWER_PRESENT = 0x60, + HID_USAGE_POWER_GOOD = 0x61, + HID_USAGE_POWER_INTERNAL_FAILURE = 0x62, + HID_USAGE_POWER_VOLTAGE_OUT_OF_RANGE = 0x63, + HID_USAGE_POWER_FREQUENCY_OUT_OF_RANGE = 0x64, + HID_USAGE_POWER_OVERLOAD = 0x65, + HID_USAGE_POWER_OVER_CHARGED = 0x66, + HID_USAGE_POWER_OVER_TEMPERATURE = 0x67, + HID_USAGE_POWER_SHUTDOWN_REQUESTED = 0x68, + HID_USAGE_POWER_SHUTDOWN_IMMINENT = 0x69, + // 6A Reserved + HID_USAGE_POWER_SWITCH_ON_OFF = 0x6B, + HID_USAGE_POWER_SWITCHABLE = 0x6C, + HID_USAGE_POWER_USED = 0x6D, + HID_USAGE_POWER_BOOST = 0x6E, + HID_USAGE_POWER_BUCK = 0x6F, + HID_USAGE_POWER_INITIALIZED = 0x70, + HID_USAGE_POWER_TESTED = 0x71, + HID_USAGE_POWER_AWAITING_POWER = 0x72, + HID_USAGE_POWER_COMMUNICATION_LOST = 0x73, + // 74-FC Reserved + HID_USAGE_POWER_I_MANUFACTURER = 0xFD, + HID_USAGE_POWER_I_PRODUCT = 0xFE, + HID_USAGE_POWER_I_SERIAL_NUMBER = 0xFF +}; + +/// HID Usage Table: Battery System Page (0x85) +enum { + HID_USAGE_BATTERY_UNDEFINED = 0x00, + HID_USAGE_BATTERY_SMB_BATTERY_MODE = 0x01, + HID_USAGE_BATTERY_SMB_BATTERY_STATUS = 0x02, + HID_USAGE_BATTERY_SMB_ALARM_WARNING = 0x03, + HID_USAGE_BATTERY_SMB_CHARGER_MODE = 0x04, + HID_USAGE_BATTERY_SMB_CHARGER_STATUS = 0x05, + HID_USAGE_BATTERY_SMB_CHARGER_SPEC_INFO = 0x06, + HID_USAGE_BATTERY_SMB_SELECTOR_STATE = 0x07, + HID_USAGE_BATTERY_SMB_SELECTOR_PRESETS = 0x08, + HID_USAGE_BATTERY_SMB_SELECTOR_INFO = 0x09, + // 0A-0F Reserved + HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_1 = 0x10, + HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_2 = 0x11, + HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_3 = 0x12, + HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_4 = 0x13, + HID_USAGE_BATTERY_OPTIONAL_MFG_FUNCTION_5 = 0x14, + HID_USAGE_BATTERY_CONNECTION_TO_SMBUS = 0x15, + HID_USAGE_BATTERY_OUTPUT_CONNECTION = 0x16, + HID_USAGE_BATTERY_CHARGER_CONNECTION = 0x17, + HID_USAGE_BATTERY_BATTERY_INSERTION = 0x18, + HID_USAGE_BATTERY_USE_NEXT = 0x19, + HID_USAGE_BATTERY_OK_TO_USE = 0x1A, + HID_USAGE_BATTERY_BATTERY_SUPPORTED = 0x1B, + HID_USAGE_BATTERY_SELECTOR_REVISION = 0x1C, + HID_USAGE_BATTERY_CHARGING_INDICATOR = 0x1D, + // 1E-27 Reserved + HID_USAGE_BATTERY_MANUFACTURER_ACCESS = 0x28, + HID_USAGE_BATTERY_REMAINING_CAPACITY_LIMIT = 0x29, + HID_USAGE_BATTERY_REMAINING_TIME_LIMIT = 0x2A, + HID_USAGE_BATTERY_AT_RATE = 0x2B, + HID_USAGE_BATTERY_CAPACITY_MODE = 0x2C, + HID_USAGE_BATTERY_BROADCAST_TO_CHARGER = 0x2D, + HID_USAGE_BATTERY_PRIMARY_BATTERY = 0x2E, + HID_USAGE_BATTERY_CHARGE_CONTROLLER = 0x2F, + // 30-3F Reserved + HID_USAGE_BATTERY_TERMINATE_CHARGE = 0x40, + HID_USAGE_BATTERY_TERMINATE_DISCHARGE = 0x41, + HID_USAGE_BATTERY_BELOW_REMAINING_CAPACITY_LIMIT = 0x42, + HID_USAGE_BATTERY_REMAINING_TIME_LIMIT_EXPIRED = 0x43, + HID_USAGE_BATTERY_CHARGING = 0x44, + HID_USAGE_BATTERY_DISCHARGING = 0x45, + HID_USAGE_BATTERY_FULLY_CHARGED = 0x46, + HID_USAGE_BATTERY_FULLY_DISCHARGED = 0x47, + HID_USAGE_BATTERY_CONDITIONING_FLAG = 0x48, + HID_USAGE_BATTERY_AT_RATE_OK = 0x49, + HID_USAGE_BATTERY_SMB_ERROR_CODE = 0x4A, + HID_USAGE_BATTERY_NEED_REPLACEMENT = 0x4B, + // 4C-5F Reserved + HID_USAGE_BATTERY_AT_RATE_TIME_TO_FULL = 0x60, + HID_USAGE_BATTERY_AT_RATE_TIME_TO_EMPTY = 0x61, + HID_USAGE_BATTERY_AVERAGE_CURRENT = 0x62, + HID_USAGE_BATTERY_MAX_ERROR = 0x63, + HID_USAGE_BATTERY_RELATIVE_STATE_OF_CHARGE = 0x64, + HID_USAGE_BATTERY_ABSOLUTE_STATE_OF_CHARGE = 0x65, + HID_USAGE_BATTERY_REMAINING_CAPACITY = 0x66, + HID_USAGE_BATTERY_FULL_CHARGE_CAPACITY = 0x67, + HID_USAGE_BATTERY_RUN_TIME_TO_EMPTY = 0x68, + HID_USAGE_BATTERY_AVERAGE_TIME_TO_EMPTY = 0x69, + HID_USAGE_BATTERY_AVERAGE_TIME_TO_FULL = 0x6A, + HID_USAGE_BATTERY_CYCLE_COUNT = 0x6B, + // 6C-7F Reserved + HID_USAGE_BATTERY_BATT_PACK_MODEL_LEVEL = 0x80, + HID_USAGE_BATTERY_INTERNAL_CHARGE_CONTROLLER = 0x81, + HID_USAGE_BATTERY_PRIMARY_BATTERY_SUPPORT = 0x82, + HID_USAGE_BATTERY_DESIGN_CAPACITY = 0x83, + HID_USAGE_BATTERY_SPECIFICATION_INFO = 0x84, + HID_USAGE_BATTERY_MANUFACTURER_DATE = 0x85, + HID_USAGE_BATTERY_SERIAL_NUMBER = 0x86, + HID_USAGE_BATTERY_I_MANUFACTURER_NAME = 0x87, + HID_USAGE_BATTERY_I_DEVICE_NAME = 0x88, + HID_USAGE_BATTERY_I_DEVICE_CHEMISTRY = 0x89, + HID_USAGE_BATTERY_MANUFACTURER_DATA = 0x8A, + HID_USAGE_BATTERY_RECHARGEABLE = 0x8B, + HID_USAGE_BATTERY_WARNING_CAPACITY_LIMIT = 0x8C, + HID_USAGE_BATTERY_CAPACITY_GRANULARITY_1 = 0x8D, + HID_USAGE_BATTERY_CAPACITY_GRANULARITY_2 = 0x8E, + HID_USAGE_BATTERY_I_OEMINFORMATION = 0x8F, + // 90-BF Reserved + HID_USAGE_BATTERY_INHIBIT_CHARGE = 0xC0, + HID_USAGE_BATTERY_ENABLE_POLLING = 0xC1, + HID_USAGE_BATTERY_RESET_TO_ZERO = 0xC2, + // C3-CF Reserved + HID_USAGE_BATTERY_AC_PRESENT = 0xD0, + HID_USAGE_BATTERY_BATTERY_PRESENT = 0xD1, + HID_USAGE_BATTERY_POWER_FAIL = 0xD2, + HID_USAGE_BATTERY_ALARM_INHIBITED = 0xD3, + HID_USAGE_BATTERY_THERMISTOR_UNDER_RANGE = 0xD4, + HID_USAGE_BATTERY_THERMISTOR_HOT = 0xD5, + HID_USAGE_BATTERY_THERMISTOR_COLD = 0xD6, + HID_USAGE_BATTERY_THERMISTOR_OVER_RANGE = 0xD7, + HID_USAGE_BATTERY_VOLTAGE_OUT_OF_RANGE = 0xD8, + HID_USAGE_BATTERY_CURRENT_OUT_OF_RANGE = 0xD9, + HID_USAGE_BATTERY_CURRENT_NOT_REGULATED = 0xDA, + HID_USAGE_BATTERY_VOLTAGE_NOT_REGULATED = 0xDB, + HID_USAGE_BATTERY_MASTER_MODE = 0xDC, + // DD-EF Reserved + HID_USAGE_BATTERY_CHARGER_SELECTOR_SUPPORT = 0xF0, + HID_USAGE_BATTERY_CHARGER_SPEC = 0xF1, + HID_USAGE_BATTERY_LEVEL_2 = 0xF2, + HID_USAGE_BATTERY_LEVEL_3 = 0xF3 + // F4-FF Reserved +}; + /// HID Usage Table: FIDO Alliance Page (0xF1D0) enum { HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index fc1dbcbd8..32b572973 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -267,14 +267,14 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u // Stylus Pen Report Descriptor Template #define TUD_HID_REPORT_DESC_STYLUS_PEN(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DIGITIZER ) , \ - HID_USAGE ( HID_USAGE_DIGITIZER_TOUCH_SCREEN ) , \ + HID_USAGE ( HID_USAGE_DIGITIZER_PEN ) , \ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) , \ /* Report ID if any */\ __VA_ARGS__ \ - HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ) , \ - HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) , \ - HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ) , \ - HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_IN_RANGE ) , \ + HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ), \ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ), \ + HID_USAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ), \ + HID_USAGE ( HID_USAGE_DIGITIZER_IN_RANGE ), \ HID_LOGICAL_MIN ( 0 ), \ HID_LOGICAL_MAX ( 1 ), \ HID_REPORT_SIZE ( 1 ), \ diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 56fccdd22..da776d04c 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -71,6 +71,50 @@ CFG_TUH_MEM_SECTION static hidh_epbuf_t _hidh_epbuf[CFG_TUH_HID]; static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT; //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len) { + (void) dev_addr; + (void) idx; + (void) report_desc; + (void) desc_len; +} + +TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx) { + (void) dev_addr; + (void) idx; +} + +TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len) { + (void) dev_addr; + (void) idx; + (void) report; + (void) len; +} + +TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len) { + (void) dev_addr; + (void) idx; + (void) report_id; + (void) report_type; + (void) len; +} + +TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len) { + (void) dev_addr; + (void) idx; + (void) report_id; + (void) report_type; + (void) len; +} + +TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol) { + (void) dev_addr; + (void) idx; + (void) protocol; +} + +//--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr, uint8_t idx) { @@ -183,9 +227,7 @@ static void set_protocol_complete(tuh_xfer_t* xfer) { p_hid->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue); } - if (tuh_hid_set_protocol_complete_cb) { - tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); - } + tuh_hid_set_protocol_complete_cb(daddr, idx, p_hid->protocol_mode); } void tuh_hid_set_default_protocol(uint8_t protocol) { @@ -230,16 +272,14 @@ bool tuh_hid_set_protocol(uint8_t daddr, uint8_t idx, uint8_t protocol) { static void get_report_complete(tuh_xfer_t* xfer) { TU_LOG_DRV("HID Get Report complete\r\n"); - if (tuh_hid_get_report_complete_cb) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); - uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type, - (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); - } + tuh_hid_get_report_complete_cb(xfer->daddr, idx, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { @@ -274,16 +314,14 @@ bool tuh_hid_get_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t r static void set_report_complete(tuh_xfer_t* xfer) { TU_LOG_DRV("HID Set Report complete\r\n"); - if (tuh_hid_set_report_complete_cb) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_hid_itf_get_index(xfer->daddr, itf_num); - uint8_t const report_type = tu_u16_high(xfer->setup->wValue); - uint8_t const report_id = tu_u16_low(xfer->setup->wValue); + uint8_t const report_type = tu_u16_high(xfer->setup->wValue); + uint8_t const report_id = tu_u16_low(xfer->setup->wValue); - tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, - (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); - } + tuh_hid_set_report_complete_cb(xfer->daddr, idx, report_id, report_type, + (xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0); } bool tuh_hid_set_report(uint8_t daddr, uint8_t idx, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) { @@ -448,9 +486,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes); } else { - if (tuh_hid_report_sent_cb) { - tuh_hid_report_sent_cb(daddr, idx, epbuf->epout, (uint16_t) xferred_bytes); - } + tuh_hid_report_sent_cb(daddr, idx, epbuf->epout, (uint16_t) xferred_bytes); } return true; @@ -461,9 +497,7 @@ void hidh_close(uint8_t daddr) { hidh_interface_t* p_hid = &_hidh_itf[i]; if (p_hid->daddr == daddr) { TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i); - if (tuh_hid_umount_cb) { - tuh_hid_umount_cb(daddr, i); - } + tuh_hid_umount_cb(daddr, i); tu_memclr(p_hid, sizeof(hidh_interface_t)); } } @@ -519,7 +553,8 @@ bool hidh_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const* desc_ // Assume bNumDescriptors = 1 p_hid->report_desc_type = desc_hid->bReportType; - p_hid->report_desc_len = tu_unaligned_read16(&desc_hid->wReportLength); + // Use offsetof to avoid pointer to the odd/misaligned address + p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*)desc_hid + offsetof(tusb_hid_descriptor_hid_t, wReportLength)); // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config p_hid->protocol_mode = _hidh_default_protocol; @@ -624,7 +659,7 @@ static void config_driver_mount_complete(uint8_t daddr, uint8_t idx, uint8_t con p_hid->mounted = true; // enumeration is complete - if (tuh_hid_mount_cb) tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); + tuh_hid_mount_cb(daddr, idx, desc_report, desc_len); // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(daddr, p_hid->itf_num); diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 9681c704b..032827af1 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -145,28 +145,28 @@ bool tuh_hid_send_report(uint8_t dev_addr, uint8_t idx, uint8_t report_id, const // can be used to parse common/simple enough descriptor. // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped // therefore report_desc = NULL, desc_len = 0 -TU_ATTR_WEAK void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report_desc, uint16_t desc_len); // Invoked when device with hid interface is un-mounted -TU_ATTR_WEAK void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t idx); // Invoked when received report from device via interrupt endpoint // Note: if there is report ID (composite), it is 1st byte of report void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when sent report to device successfully via interrupt endpoint -TU_ATTR_WEAK void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); +void tuh_hid_report_sent_cb(uint8_t dev_addr, uint8_t idx, uint8_t const* report, uint16_t len); // Invoked when Get Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); +void tuh_hid_get_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); // Invoked when Sent Report to device via either control endpoint // len = 0 indicate there is error in the transfer e.g stalled response -TU_ATTR_WEAK void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); +void tuh_hid_set_report_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t report_id, uint8_t report_type, uint16_t len); // Invoked when Set Protocol request is complete -TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); +void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t idx, uint8_t protocol); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 0bbb3caf4..7dac7c4a5 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -107,6 +107,14 @@ static void _prep_out_transaction(uint8_t idx) { } } + +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf) { + (void) itf; +} + //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ @@ -528,9 +536,7 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32 tu_fifo_write_n(&p_midi->rx_ff, _midid_epbuf[idx].epout, (uint16_t)xferred_bytes); // invoke receive callback if available - if (tud_midi_rx_cb) { - tud_midi_rx_cb(idx); - } + tud_midi_rx_cb(idx); // prepare for next // TODO for now ep_out is not used by public API therefore there is no race condition, diff --git a/src/class/midi/midi_device.h b/src/class/midi/midi_device.h index 3e89cc0a3..c2c6e9859 100644 --- a/src/class/midi/midi_device.h +++ b/src/class/midi/midi_device.h @@ -116,9 +116,9 @@ static inline bool tud_midi_receive(uint8_t packet[4]) } //--------------------------------------------------------------------+ -// Application Callback API (weak is optional) +// Application Callback API (optional) //--------------------------------------------------------------------+ -TU_ATTR_WEAK void tud_midi_rx_cb(uint8_t itf); +void tud_midi_rx_cb(uint8_t itf); //--------------------------------------------------------------------+ // Inline Functions diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 50bda1e36..e6ace316c 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -575,6 +575,11 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff } } } + else { + // bad packet discard + nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4); + continue; + } } else if (status < MIDI_STATUS_SYSEX_START) { // then it is a channel message either three bytes or two uint8_t fake_cin = (status & 0xf0) >> 4; @@ -617,6 +622,11 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff bytes_to_add_to_stream = 1; } } + else { + // bad packet discard + nread = tu_edpt_stream_read(p_midi->daddr, &p_midi->ep_stream.rx, p_midi->stream_read.buffer, 4); + continue; + } for (uint8_t i = 1; i <= bytes_to_add_to_stream; i++) { *p_buffer++ = p_midi->stream_read.buffer[i]; diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index a32014c2d..b0eafd5da 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -224,6 +224,53 @@ static bool proc_stage_status(mscd_interface_t *p_msc) { } //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun) { + (void) lun; +} + +TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun) { + (void) lun; +} + +TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]) { + (void) lun; + (void) scsi_cmd; +} + +TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void) { + return 1; +} + +TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + (void) lun; + (void) power_condition; + (void) start; + (void) load_eject; + return true; +} + +TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control) { + (void) lun; + (void) prohibit_removal; + (void) control; + return true; +} + +TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize) { + (void) lun; + (void) buffer; + (void) bufsize; + return sizeof(scsi_sense_fixed_resp_t); +} + +TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun) { + (void) lun; + return true; +} + +//--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ #if CFG_TUSB_DEBUG >= CFG_TUD_MSC_LOG_LEVEL @@ -403,10 +450,7 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t TU_LOG_DRV(" MSC Get Max Lun\r\n"); TU_VERIFY(request->wValue == 0 && request->wLength == 1); - uint8_t maxlun = 1; - if (tud_msc_get_maxlun_cb) { - maxlun = tud_msc_get_maxlun_cb(); - } + uint8_t maxlun = tud_msc_get_maxlun_cb(); TU_VERIFY(maxlun); maxlun--; // MAX LUN is minus 1 by specs tud_control_xfer(rhport, request, &maxlun, 1); @@ -584,21 +628,15 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t // if complete_cb() is invoked after queuing the status. switch (p_cbw->command[0]) { case SCSI_CMD_READ_10: - if (tud_msc_read10_complete_cb) { - tud_msc_read10_complete_cb(p_cbw->lun); - } + tud_msc_read10_complete_cb(p_cbw->lun); break; case SCSI_CMD_WRITE_10: - if (tud_msc_write10_complete_cb) { - tud_msc_write10_complete_cb(p_cbw->lun); - } + tud_msc_write10_complete_cb(p_cbw->lun); break; default: - if (tud_msc_scsi_complete_cb) { - tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); - } + tud_msc_scsi_complete_cb(p_cbw->lun, p_cbw->command); break; } @@ -648,16 +686,14 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ case SCSI_CMD_START_STOP_UNIT: resplen = 0; - if (tud_msc_start_stop_cb) { - scsi_start_stop_unit_t const* start_stop = (scsi_start_stop_unit_t const*)scsi_cmd; - if (!tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject)) { - // Failed status response - resplen = -1; + scsi_start_stop_unit_t const* start_stop = (scsi_start_stop_unit_t const*)scsi_cmd; + if (!tud_msc_start_stop_cb(lun, start_stop->power_condition, start_stop->start, start_stop->load_eject)) { + // Failed status response + resplen = -1; - // set default sense if not set by callback - if (p_msc->sense_key == 0) { - set_sense_medium_not_present(lun); - } + // set default sense if not set by callback + if (p_msc->sense_key == 0) { + set_sense_medium_not_present(lun); } } break; @@ -665,16 +701,14 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: resplen = 0; - if (tud_msc_prevent_allow_medium_removal_cb) { - scsi_prevent_allow_medium_removal_t const* prevent_allow = (scsi_prevent_allow_medium_removal_t const*)scsi_cmd; - if (!tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control)) { - // Failed status response - resplen = -1; + scsi_prevent_allow_medium_removal_t const* prevent_allow = (scsi_prevent_allow_medium_removal_t const*)scsi_cmd; + if (!tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control)) { + // Failed status response + resplen = -1; - // set default sense if not set by callback - if (p_msc->sense_key == 0) { - set_sense_medium_not_present(lun); - } + // set default sense if not set by callback + if (p_msc->sense_key == 0) { + set_sense_medium_not_present(lun); } } break; @@ -767,10 +801,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ .block_descriptor_len = 0 // no block descriptor are included }; - bool writable = true; - if (tud_msc_is_writable_cb) { - writable = tud_msc_is_writable_cb(lun); - } + bool writable = tud_msc_is_writable_cb(lun); mode_resp.write_protected = !writable; @@ -794,9 +825,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ TU_VERIFY(0 == tu_memcpy_s(buffer, bufsize, &sense_rsp, (size_t) resplen)); // request sense callback could overwrite the sense data - if (tud_msc_request_sense_cb) { - resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t)bufsize); - } + resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t)bufsize); // Clear sense data after copy tud_msc_set_sense(lun, 0, 0, 0); @@ -854,11 +883,7 @@ static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { static void proc_write10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; - bool writable = true; - - if (tud_msc_is_writable_cb) { - writable = tud_msc_is_writable_cb(p_cbw->lun); - } + bool writable = tud_msc_is_writable_cb(p_cbw->lun); if (!writable) { // Not writable, complete this SCSI op with error diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 144b74f71..7d898e988 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -128,30 +128,30 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, /*------------- Optional callbacks -------------*/ // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation -TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void); +uint8_t tud_msc_get_maxlun_cb(void); // Invoked when received Start Stop Unit command // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage -TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject); //Invoked when we receive the Prevent / Allow Medium Removal command -TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control); +bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control); // Invoked when received REQUEST_SENSE -TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); +int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize); // Invoked when Read10 command is complete -TU_ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); +void tud_msc_read10_complete_cb(uint8_t lun); // Invoke when Write10 command is complete, can be used to flush flash caching -TU_ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); +void tud_msc_write10_complete_cb(uint8_t lun); // Invoked when command in tud_msc_scsi_cb is complete -TU_ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); +void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]); // Invoked to check if device is writable as part of SCSI WRITE10 -TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun); +bool tud_msc_is_writable_cb(uint8_t lun); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index ef0635bbe..eb69ae400 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -88,6 +88,17 @@ TU_ATTR_ALWAYS_INLINE static inline msch_epbuf_t* get_epbuf(uint8_t daddr) { } //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr) { + (void) dev_addr; +} + +TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr) { + (void) dev_addr; +} + +//--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) { @@ -304,9 +315,7 @@ void msch_close(uint8_t dev_addr) { // invoke Application Callback if (p_msc->mounted) { - if (tuh_msc_umount_cb) { - tuh_msc_umount_cb(dev_addr); - } + tuh_msc_umount_cb(dev_addr); } tu_memclr(p_msc, sizeof(msch_interface_t)); @@ -497,9 +506,7 @@ static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_dat // Mark enumeration is complete p_msc->mounted = true; - if (tuh_msc_mount_cb) { - tuh_msc_mount_cb(dev_addr); - } + tuh_msc_mount_cb(dev_addr); // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 09d777066..b5fd55547 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -109,10 +109,10 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r //------------- Application Callback -------------// // Invoked when a device with MassStorage interface is mounted -TU_ATTR_WEAK void tuh_msc_mount_cb(uint8_t dev_addr); +void tuh_msc_mount_cb(uint8_t dev_addr); // Invoked when a device with MassStorage interface is unmounted -TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr); +void tuh_msc_umount_cb(uint8_t dev_addr); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/class/mtp/mtp.h b/src/class/mtp/mtp.h new file mode 100644 index 000000000..40b6dd8b0 --- /dev/null +++ b/src/class/mtp/mtp.h @@ -0,0 +1,888 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MTP_H_ +#define TUSB_MTP_H_ + +#include "common/tusb_common.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MTP) + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Media Transfer Protocol Class Constant +//--------------------------------------------------------------------+ + +// Media Transfer Protocol Subclass +typedef enum { + MTP_SUBCLASS_STILL_IMAGE = 1 +} mtp_subclass_type_t; + +// MTP Protocol. +typedef enum { + MTP_PROTOCOL_PIMA_15470 = 1, ///< Picture Transfer Protocol (PIMA 15470) +} mtp_protocol_type_t; + +// PTP/MTP protocol phases +typedef enum { + MTP_PHASE_COMMAND = 0, + MTP_PHASE_DATA, + MTP_PHASE_RESPONSE, + MTP_PHASE_ERROR +} mtp_phase_type_t; + +// PTP/MTP Class requests, PIMA 15740-2000: D.5.2 +typedef enum { + MTP_REQ_CANCEL = 0x64, + MTP_REQ_GET_EXT_EVENT_DATA = 0x65, + MTP_REQ_RESET = 0x66, + MTP_REQ_GET_DEVICE_STATUS = 0x67, +} mtp_class_request_t; + +// PTP/MTP Container type +typedef enum { + MTP_CONTAINER_TYPE_UNDEFINED = 0, + MTP_CONTAINER_TYPE_COMMAND_BLOCK = 1, + MTP_CONTAINER_TYPE_DATA_BLOCK = 2, + MTP_CONTAINER_TYPE_RESPONSE_BLOCK = 3, + MTP_CONTAINER_TYPE_EVENT_BLOCK = 4, +} mtp_container_type_t; + +// MTP 1.1 Appendix A: Object formats +typedef enum { + // ---- Base formats ---- + MTP_OBJ_FORMAT_UNDEFINED = 0x3000u, // Undefined object + MTP_OBJ_FORMAT_ASSOCIATION = 0x3001u, // Association (for example, a folder) + MTP_OBJ_FORMAT_SCRIPT = 0x3002u, // Device model-specific script + MTP_OBJ_FORMAT_EXECUTABLE = 0x3003u, // Device model-specific binary executable + MTP_OBJ_FORMAT_TEXT = 0x3004u, // Text file + MTP_OBJ_FORMAT_HTML = 0x3005u, // Hypertext Markup Language file (text) + MTP_OBJ_FORMAT_DPOF = 0x3006u, // Digital Print Order Format file (text) + MTP_OBJ_FORMAT_AIFF = 0x3007u, // Audio clip (AIFF) + MTP_OBJ_FORMAT_WAV = 0x3008u, // Audio clip (WAV) + MTP_OBJ_FORMAT_MP3 = 0x3009u, // MPEG-1 Layer III audio (ISO/IEC 13818-3) + MTP_OBJ_FORMAT_AVI = 0x300Au, // Video clip (AVI) + MTP_OBJ_FORMAT_MPEG = 0x300Bu, // Video clip (MPEG) + MTP_OBJ_FORMAT_ASF = 0x300Cu, // Microsoft Advanced Streaming Format (video) + + // ---- Image formats ---- + MTP_OBJ_FORMAT_UNDEFINED_IMAGE = 0x3800u, // Undefined image object + MTP_OBJ_FORMAT_EXIF_JPEG = 0x3801u, // Exchangeable Image Format, JEIDA standard + MTP_OBJ_FORMAT_TIFF_EP = 0x3802u, // Tag Image File Format for Electronic Photography + MTP_OBJ_FORMAT_FLASHPIX = 0x3803u, // Structured Storage Image Format (FlashPix) + MTP_OBJ_FORMAT_BMP = 0x3804u, // Microsoft Windows Bitmap file + MTP_OBJ_FORMAT_CIFF = 0x3805u, // Canon Camera Image File Format + MTP_OBJ_FORMAT_UNDEFINED_3806 = 0x3806u, // Reserved / Undefined + MTP_OBJ_FORMAT_GIF = 0x3807u, // Graphics Interchange Format + MTP_OBJ_FORMAT_JFIF = 0x3808u, // JPEG File Interchange Format + MTP_OBJ_FORMAT_CD = 0x3809u, // PhotoCD Image Pac + MTP_OBJ_FORMAT_PICT = 0x380Au, // Quickdraw Image Format + MTP_OBJ_FORMAT_PNG = 0x380Bu, // Portable Network Graphics + MTP_OBJ_FORMAT_UNDEFINED_380C = 0x380Cu, // Reserved / Undefined + MTP_OBJ_FORMAT_TIFF = 0x380Du, // Tag Image File Format (baseline) + MTP_OBJ_FORMAT_TIFF_IT = 0x380Eu, // Tag Image File Format for IT (graphic arts) + MTP_OBJ_FORMAT_JP2 = 0x380Fu, // JPEG2000 Baseline File Format + MTP_OBJ_FORMAT_JPX = 0x3810u, // JPEG2000 Extended File Format + + // ---- Firmware & misc ---- + MTP_OBJ_FORMAT_UNDEFINED_FIRMWARE = 0xB802u, // Undefined Firmware + MTP_OBJ_FORMAT_WBMP = 0xB803u, // Wireless Application Protocol Bitmap Format (.wbmp) + MTP_OBJ_FORMAT_WINDOWS_IMAGE = 0xB881u, // Windows Image Format + MTP_OBJ_FORMAT_JPEGXR = 0xB804u, // JPEG XR (.hdp, .jxr, .wdp) + + // ---- Audio formats ---- + MTP_OBJ_FORMAT_UNDEFINED_AUDIO = 0xB900u, // Undefined audio object + MTP_OBJ_FORMAT_WMA = 0xB901u, // Windows Media Audio + MTP_OBJ_FORMAT_OGG = 0xB902u, // OGG container + MTP_OBJ_FORMAT_AAC = 0xB903u, // Advanced Audio Coding (.aac) + MTP_OBJ_FORMAT_AUDIBLE = 0xB904u, // Audible format + MTP_OBJ_FORMAT_FLAC = 0xB906u, // Free Lossless Audio Codec + MTP_OBJ_FORMAT_QCELP = 0xB907u, // Qualcomm Code Excited Linear Prediction (.qcp) + MTP_OBJ_FORMAT_AMR = 0xB908u, // Adaptive Multi-Rate audio (.amr) + + // ---- Video formats ---- + MTP_OBJ_FORMAT_UNDEFINED_VIDEO = 0xB980u, // Undefined video object + MTP_OBJ_FORMAT_WMV = 0xB981u, // Windows Media Video + MTP_OBJ_FORMAT_MP4 = 0xB982u, // MP4 Container (ISO 14496-1) + MTP_OBJ_FORMAT_MP2 = 0xB983u, // MPEG-1 Layer II audio + MTP_OBJ_FORMAT_3GP = 0xB984u, // 3GP Container + MTP_OBJ_FORMAT_3G2 = 0xB985u, // 3GPP2 Container + MTP_OBJ_FORMAT_AVCHD = 0xB986u, // AVCHD (MPEG-4 AVC + Dolby Digital) + MTP_OBJ_FORMAT_ATSC_TS = 0xB987u, // ATSC-compliant MPEG-2 Transport Stream + MTP_OBJ_FORMAT_DVB_TS = 0xB988u, // DVB-compliant MPEG-2 Transport Stream + + // ---- Collections ---- + MTP_OBJ_FORMAT_UNDEFINED_COLLECTION = 0xBA00u, // Undefined collection + MTP_OBJ_FORMAT_ABSTRACT_MULTIMEDIA_ALBUM = 0xBA01u, // Abstract Multimedia Album + MTP_OBJ_FORMAT_ABSTRACT_IMAGE_ALBUM = 0xBA02u, // Abstract Image Album + MTP_OBJ_FORMAT_ABSTRACT_AUDIO_ALBUM = 0xBA03u, // Abstract Audio Album + MTP_OBJ_FORMAT_ABSTRACT_VIDEO_ALBUM = 0xBA04u, // Abstract Video Album + MTP_OBJ_FORMAT_ABSTRACT_AV_PLAYLIST = 0xBA05u, // Abstract Audio & Video Playlist + MTP_OBJ_FORMAT_ABSTRACT_CONTACT_GROUP = 0xBA06u, // Abstract Contact Group + MTP_OBJ_FORMAT_ABSTRACT_MESSAGE_FOLDER = 0xBA07u, // Abstract Message Folder + MTP_OBJ_FORMAT_ABSTRACT_CHAPTERED_PRODUCTION = 0xBA08u, // Abstract Chaptered Production + MTP_OBJ_FORMAT_ABSTRACT_AUDIO_PLAYLIST = 0xBA09u, // Abstract Audio Playlist + MTP_OBJ_FORMAT_ABSTRACT_VIDEO_PLAYLIST = 0xBA0Au, // Abstract Video Playlist + MTP_OBJ_FORMAT_ABSTRACT_MEDIACAST = 0xBA0Bu, // Abstract Mediacast (RSS enclosure) + + // ---- Playlist formats ---- + MTP_OBJ_FORMAT_WPL_PLAYLIST = 0xBA10u, // Windows Media Player Playlist (.wpl) + MTP_OBJ_FORMAT_M3U_PLAYLIST = 0xBA11u, // M3U Playlist + MTP_OBJ_FORMAT_MPL_PLAYLIST = 0xBA12u, // MPL Playlist + MTP_OBJ_FORMAT_ASX_PLAYLIST = 0xBA13u, // ASX Playlist + MTP_OBJ_FORMAT_PLS_PLAYLIST = 0xBA14u, // PLS Playlist + + // ---- Document formats ---- + MTP_OBJ_FORMAT_UNDEFINED_DOC = 0xBA80u, // Undefined Document + MTP_OBJ_FORMAT_ABSTRACT_DOC = 0xBA81u, // Abstract Document + MTP_OBJ_FORMAT_XML_DOC = 0xBA82u, // XML Document + MTP_OBJ_FORMAT_DOC = 0xBA83u, // Microsoft Word Document + MTP_OBJ_FORMAT_MHT_DOC = 0xBA84u, // MHT Compiled HTML Document + MTP_OBJ_FORMAT_XLS = 0xBA85u, // Microsoft Excel Spreadsheet + MTP_OBJ_FORMAT_PPT = 0xBA86u, // Microsoft PowerPoint Presentation + + // ---- Messaging ---- + MTP_OBJ_FORMAT_UNDEFINED_MSG = 0xBB00u, // Undefined Message + MTP_OBJ_FORMAT_ABSTRACT_MSG = 0xBB01u, // Abstract Message + + // ---- Bookmarks ---- + MTP_OBJ_FORMAT_UNDEFINED_BOOKMARK = 0xBB10u, // Undefined Bookmark + MTP_OBJ_FORMAT_ABSTRACT_BOOKMARK = 0xBB11u, // Abstract Bookmark + + // ---- Appointments ---- + MTP_OBJ_FORMAT_UNDEFINED_APPT = 0xBB20u, // Undefined Appointment + MTP_OBJ_FORMAT_ABSTRACT_APPT = 0xBB21u, // Abstract Appointment + MTP_OBJ_FORMAT_VCALENDAR1 = 0xBB22u, // vCalendar 1.0 + + // ---- Tasks ---- + MTP_OBJ_FORMAT_UNDEFINED_TASK = 0xBB40u, // Undefined Task + MTP_OBJ_FORMAT_ABSTRACT_TASK = 0xBB41u, // Abstract Task + MTP_OBJ_FORMAT_ICALENDAR = 0xBB42u, // iCalendar + + // ---- Notes ---- + MTP_OBJ_FORMAT_UNDEFINED_NOTE = 0xBB60u, // Undefined Note + MTP_OBJ_FORMAT_ABSTRACT_NOTE = 0xBB61u, // Abstract Note + + // ---- Contacts ---- + MTP_OBJ_FORMAT_UNDEFINED_CONTACT= 0xBB80u, // Undefined Contact + MTP_OBJ_FORMAT_ABSTRACT_CONTACT = 0xBB81u, // Abstract Contact + MTP_OBJ_FORMAT_VCARD2 = 0xBB82u, // vCard 2.1 + MTP_OBJ_FORMAT_VCARD3 = 0xBB83u, // vCard 3.0 +} mtp_object_formats_t; + +// MTP 1.1 Appendix B: Object Properties +typedef enum { + MTP_OBJ_PROP_STORAGE_ID = 0xDC01u, // StorageID + MTP_OBJ_PROP_OBJECT_FORMAT = 0xDC02u, // Object Format + MTP_OBJ_PROP_PROTECTION_STATUS = 0xDC03u, // Protection Status + MTP_OBJ_PROP_OBJECT_SIZE = 0xDC04u, // Object Size + MTP_OBJ_PROP_ASSOCIATION_TYPE = 0xDC05u, // Association Type + MTP_OBJ_PROP_ASSOCIATION_DESC = 0xDC06u, // Association Description + MTP_OBJ_PROP_OBJECT_FILE_NAME = 0xDC07u, // Object File Name + MTP_OBJ_PROP_DATE_CREATED = 0xDC08u, // Date Created + MTP_OBJ_PROP_DATE_MODIFIED = 0xDC09u, // Date Modified + MTP_OBJ_PROP_KEYWORDS = 0xDC0Au, // Keywords + MTP_OBJ_PROP_PARENT_OBJECT = 0xDC0Bu, // Parent Object + MTP_OBJ_PROP_ALLOWED_FOLDER_CONTENTS = 0xDC0Cu, // Allowed Folder Contents + MTP_OBJ_PROP_HIDDEN = 0xDC0Du, // Hidden + MTP_OBJ_PROP_SYSTEM_OBJECT = 0xDC0Eu, // System Object + // 0xDC0F-0xDC40 is reserved + + MTP_OBJ_PROP_PERSISTENT_UID = 0xDC41u, // Persistent Unique Object Identifier + MTP_OBJ_PROP_SYNC_ID = 0xDC42u, // SyncID + MTP_OBJ_PROP_PROPERTY_BAG = 0xDC43u, // Property Bag + MTP_OBJ_PROP_NAME = 0xDC44u, // Name + MTP_OBJ_PROP_CREATED_BY = 0xDC45u, // Created By + MTP_OBJ_PROP_ARTIST = 0xDC46u, // Artist + MTP_OBJ_PROP_DATE_AUTHORED = 0xDC47u, // Date Authored + MTP_OBJ_PROP_DESCRIPTION = 0xDC48u, // Description + MTP_OBJ_PROP_URL_REFERENCE = 0xDC49u, // URL Reference + MTP_OBJ_PROP_LANGUAGE_LOCALE = 0xDC4Au, // Language-Locale + MTP_OBJ_PROP_COPYRIGHT_INFO = 0xDC4Bu, // Copyright Information + MTP_OBJ_PROP_SOURCE = 0xDC4Cu, // Source + MTP_OBJ_PROP_ORIGIN_LOCATION = 0xDC4Du, // Origin Location + MTP_OBJ_PROP_DATE_ADDED = 0xDC4Eu, // Date Added + MTP_OBJ_PROP_NON_CONSUMABLE = 0xDC4Fu, // Non-Consumable + MTP_OBJ_PROP_CORRUPT_UNPLAYABLE = 0xDC50u, // Corrupt/Unplayable + MTP_OBJ_PROP_PRODUCER_SERIAL_NUMBER = 0xDC51u, // ProducerSerialNumber + // 0xDC52-0xDC80 is reserved + + MTP_OBJ_PROP_REP_SAMPLE_FORMAT = 0xDC81u, // Representative Sample Format + MTP_OBJ_PROP_REP_SAMPLE_SIZE = 0xDC82u, // Representative Sample Size + MTP_OBJ_PROP_REP_SAMPLE_HEIGHT = 0xDC83u, // Representative Sample Height + MTP_OBJ_PROP_REP_SAMPLE_WIDTH = 0xDC84u, // Representative Sample Width + MTP_OBJ_PROP_REP_SAMPLE_DURATION = 0xDC85u, // Representative Sample Duration + MTP_OBJ_PROP_REP_SAMPLE_DATA = 0xDC86u, // Representative Sample Data + MTP_OBJ_PROP_WIDTH = 0xDC87u, // Width + MTP_OBJ_PROP_HEIGHT = 0xDC88u, // Height + MTP_OBJ_PROP_DURATION = 0xDC89u, // Duration + MTP_OBJ_PROP_RATING = 0xDC8Au, // Rating + MTP_OBJ_PROP_TRACK = 0xDC8Bu, // Track + MTP_OBJ_PROP_GENRE = 0xDC8Cu, // Genre + MTP_OBJ_PROP_CREDITS = 0xDC8Du, // Credits + MTP_OBJ_PROP_LYRICS = 0xDC8Eu, // Lyrics + MTP_OBJ_PROP_SUBSCRIPTION_CONTENT_ID = 0xDC8Fu, // Subscription Content ID + MTP_OBJ_PROP_PRODUCED_BY = 0xDC90u, // Produced By + MTP_OBJ_PROP_USE_COUNT = 0xDC91u, // Use Count + MTP_OBJ_PROP_SKIP_COUNT = 0xDC92u, // Skip Count + MTP_OBJ_PROP_LAST_ACCESSED = 0xDC93u, // Last Accessed + MTP_OBJ_PROP_PARENTAL_RATING = 0xDC94u, // Parental Rating + MTP_OBJ_PROP_META_GENRE = 0xDC95u, // Meta Genre + MTP_OBJ_PROP_COMPOSER = 0xDC96u, // Composer + MTP_OBJ_PROP_EFFECTIVE_RATING = 0xDC97u, // Effective Rating + MTP_OBJ_PROP_SUBTITLE = 0xDC98u, // Subtitle + MTP_OBJ_PROP_ORIGINAL_RELEASE_DATE = 0xDC99u, // Original Release Date + MTP_OBJ_PROP_ALBUM_NAME = 0xDC9Au, // Album Name + MTP_OBJ_PROP_ALBUM_ARTIST = 0xDC9Bu, // Album Artist + MTP_OBJ_PROP_MOOD = 0xDC9Cu, // Mood + MTP_OBJ_PROP_DRM_STATUS = 0xDC9Du, // DRM Status + MTP_OBJ_PROP_SUB_DESCRIPTION = 0xDC9Eu, // Sub Description + // 0xDC9F-0xDCD0 is reserved + + MTP_OBJ_PROP_IS_CROPPED = 0xDCD1u, // Is Cropped + MTP_OBJ_PROP_IS_COLOUR_CORRECTED = 0xDCD2u, // Is Colour Corrected + MTP_OBJ_PROP_IMAGE_BIT_DEPTH = 0xDCD3u, // Image Bit Depth + MTP_OBJ_PROP_FNUMBER = 0xDCD4u, // Fnumber (aperture ×100) + MTP_OBJ_PROP_EXPOSURE_TIME = 0xDCD5u, // Exposure Time (sec ×10,000) + MTP_OBJ_PROP_EXPOSURE_INDEX = 0xDCD6u, // Exposure Index (ISO) + // 0xDCD7-0xDCDF is reserved + + MTP_OBJ_PROP_DISPLAY_NAME = 0xDCE0u, // Display Name + MTP_OBJ_PROP_BODY_TEXT = 0xDCE1u, // Body Text + MTP_OBJ_PROP_SUBJECT = 0xDCE2u, // Subject + MTP_OBJ_PROP_PRIORITY = 0xDCE3u, // Priority + // 0xDCE4-0xDCFF is reserved + + MTP_OBJ_PROP_GIVEN_NAME = 0xDD00u, // Given Name + MTP_OBJ_PROP_MIDDLE_NAMES = 0xDD01u, // Middle Names + MTP_OBJ_PROP_FAMILY_NAME = 0xDD02u, // Family Name + MTP_OBJ_PROP_PREFIX = 0xDD03u, // Prefix + MTP_OBJ_PROP_SUFFIX = 0xDD04u, // Suffix + MTP_OBJ_PROP_PHONETIC_GIVEN_NAME = 0xDD05u, // Phonetic Given Name + MTP_OBJ_PROP_PHONETIC_FAMILY_NAME = 0xDD06u, // Phonetic Family Name + MTP_OBJ_PROP_EMAIL_PRIMARY = 0xDD07u, // Email Primary + MTP_OBJ_PROP_EMAIL_PERSONAL_1 = 0xDD08u, // Email Personal 1 + MTP_OBJ_PROP_EMAIL_PERSONAL_2 = 0xDD09u, // Email Personal 2 + MTP_OBJ_PROP_EMAIL_BUSINESS_1 = 0xDD0Au, // Email Business 1 + MTP_OBJ_PROP_EMAIL_BUSINESS_2 = 0xDD0Bu, // Email Business 2 + MTP_OBJ_PROP_EMAIL_OTHERS = 0xDD0Cu, // Email Others + MTP_OBJ_PROP_PHONE_PRIMARY = 0xDD0Du, // Phone Number Primary + MTP_OBJ_PROP_PHONE_PERSONAL_1 = 0xDD0Eu, // Phone Number Personal + MTP_OBJ_PROP_PHONE_PERSONAL_2 = 0xDD0Fu, // Phone Number Personal 2 + MTP_OBJ_PROP_PHONE_BUSINESS_1 = 0xDD10u, // Phone Number Business + MTP_OBJ_PROP_PHONE_BUSINESS_2 = 0xDD11u, // Phone Number Business 2 + MTP_OBJ_PROP_PHONE_MOBILE_1 = 0xDD12u, // Phone Number Mobile + MTP_OBJ_PROP_PHONE_MOBILE_2 = 0xDD13u, // Phone Number Mobile 2 + MTP_OBJ_PROP_FAX_PRIMARY = 0xDD14u, // Fax Number Primary + MTP_OBJ_PROP_FAX_PERSONAL = 0xDD15u, // Fax Number Personal + MTP_OBJ_PROP_FAX_BUSINESS = 0xDD16u, // Fax Number Business + MTP_OBJ_PROP_PAGER_NUMBER = 0xDD17u, // Pager Number + MTP_OBJ_PROP_PHONE_OTHERS = 0xDD18u, // Phone Number Others + MTP_OBJ_PROP_WEB_PRIMARY = 0xDD19u, // Primary Web Address + MTP_OBJ_PROP_WEB_PERSONAL = 0xDD1Au, // Personal Web Address + MTP_OBJ_PROP_WEB_BUSINESS = 0xDD1Bu, // Business Web Address + MTP_OBJ_PROP_IM_ADDRESS_1 = 0xDD1Cu, // Instant Messenger Address + MTP_OBJ_PROP_IM_ADDRESS_2 = 0xDD1Du, // Instant Messenger Address 2 + MTP_OBJ_PROP_IM_ADDRESS_3 = 0xDD1Eu, // Instant Messenger Address 3 + MTP_OBJ_PROP_ADDR_PERSONAL_FULL = 0xDD1Fu, // Postal Address Personal Full + MTP_OBJ_PROP_ADDR_PERSONAL_LINE1 = 0xDD20u, // Postal Address Personal Line 1 + MTP_OBJ_PROP_ADDR_PERSONAL_LINE2 = 0xDD21u, // Postal Address Personal Line 2 + MTP_OBJ_PROP_ADDR_PERSONAL_CITY = 0xDD22u, // Postal Address Personal City + MTP_OBJ_PROP_ADDR_PERSONAL_REGION = 0xDD23u, // Postal Address Personal Region + MTP_OBJ_PROP_ADDR_PERSONAL_POSTAL_CODE = 0xDD24u, // Postal Address Personal Postal Code + MTP_OBJ_PROP_ADDR_PERSONAL_COUNTRY = 0xDD25u, // Postal Address Personal Country + MTP_OBJ_PROP_ADDR_BUSINESS_FULL = 0xDD26u, // Postal Address Business Full + MTP_OBJ_PROP_ADDR_BUSINESS_LINE1 = 0xDD27u, // Postal Address Business Line 1 + MTP_OBJ_PROP_ADDR_BUSINESS_LINE2 = 0xDD28u, // Postal Address Business Line 2 + MTP_OBJ_PROP_ADDR_BUSINESS_CITY = 0xDD29u, // Postal Address Business City + MTP_OBJ_PROP_ADDR_BUSINESS_REGION = 0xDD2Au, // Postal Address Business Region + MTP_OBJ_PROP_ADDR_BUSINESS_POSTAL_CODE = 0xDD2Bu, // Postal Address Business Postal Code + MTP_OBJ_PROP_ADDR_BUSINESS_COUNTRY = 0xDD2Cu, // Postal Address Business Country + MTP_OBJ_PROP_ADDR_OTHER_FULL = 0xDD2Du, // Postal Address Other Full + MTP_OBJ_PROP_ADDR_OTHER_LINE1 = 0xDD2Eu, // Postal Address Other Line 1 + MTP_OBJ_PROP_ADDR_OTHER_LINE2 = 0xDD2Fu, // Postal Address Other Line 2 + MTP_OBJ_PROP_ADDR_OTHER_CITY = 0xDD30u, // Postal Address Other City + MTP_OBJ_PROP_ADDR_OTHER_REGION = 0xDD31u, // Postal Address Other Region + MTP_OBJ_PROP_ADDR_OTHER_POSTAL_CODE = 0xDD32u, // Postal Address Other Postal Code + MTP_OBJ_PROP_ADDR_OTHER_COUNTRY = 0xDD33u, // Postal Address Other Country + MTP_OBJ_PROP_ORGANIZATION_NAME = 0xDD34u, // Organization Name + MTP_OBJ_PROP_PHONETIC_ORG_NAME = 0xDD35u, // Phonetic Organization Name + MTP_OBJ_PROP_ROLE = 0xDD36u, // Role + MTP_OBJ_PROP_BIRTHDATE = 0xDD37u, // Birthdate + // 0xDD38-0xDD3F is reserved + + MTP_OBJ_PROP_MESSAGE_TO = 0xDD40u, // Message To + MTP_OBJ_PROP_MESSAGE_CC = 0xDD41u, // Message CC + MTP_OBJ_PROP_MESSAGE_BCC = 0xDD42u, // Message BCC + MTP_OBJ_PROP_MESSAGE_READ = 0xDD43u, // Message Read + MTP_OBJ_PROP_MESSAGE_RECEIVED_TIME = 0xDD44u, // Message Received Time + MTP_OBJ_PROP_MESSAGE_SENDER = 0xDD45u, // Message Sender + // 0xDD46-0xDD4F is reserved + + MTP_OBJ_PROP_ACTIVITY_BEGIN_TIME = 0xDD50u, // Activity Begin Time + MTP_OBJ_PROP_ACTIVITY_END_TIME = 0xDD51u, // Activity End Time + MTP_OBJ_PROP_ACTIVITY_LOCATION = 0xDD52u, // Activity Location + // 0xDD53 is reserved + MTP_OBJ_PROP_ACTIVITY_REQUIRED_ATTENDEES= 0xDD54u, // Activity Required Attendees + MTP_OBJ_PROP_ACTIVITY_OPTIONAL_ATTENDEES= 0xDD55u, // Activity Optional Attendees + MTP_OBJ_PROP_ACTIVITY_RESOURCES = 0xDD56u, // Activity Resources + MTP_OBJ_PROP_ACTIVITY_ACCEPTED = 0xDD57u, // Activity Accepted + MTP_OBJ_PROP_ACTIVITY_TENTATIVE = 0xDD58u, // Activity Tentative + MTP_OBJ_PROP_ACTIVITY_DECLINED = 0xDD59u, // Activity Declined + MTP_OBJ_PROP_ACTIVITY_REMINDER_TIME = 0xDD5Au, // Activity Reminder Time + MTP_OBJ_PROP_ACTIVITY_OWNER = 0xDD5Bu, // Activity Owner + MTP_OBJ_PROP_ACTIVITY_STATUS = 0xDD5Cu, // Activity Status + MTP_OBJ_PROP_OWNER = 0xDD5Du, // Owner + MTP_OBJ_PROP_EDITOR = 0xDD5Eu, // Editor + MTP_OBJ_PROP_WEBMASTER = 0xDD5Fu, // Webmaster + + MTP_OBJ_PROP_URL_SOURCE = 0xDD60u, // URL Source + MTP_OBJ_PROP_URL_DESTINATION = 0xDD61u, // URL Destination + MTP_OBJ_PROP_TIME_BOOKMARK = 0xDD62u, // Time Bookmark + MTP_OBJ_PROP_OBJECT_BOOKMARK = 0xDD63u, // Object Bookmark + MTP_OBJ_PROP_BYTE_BOOKMARK = 0xDD64u, // Byte Bookmark + // 0xDD65-0xDD6F is reserved + + MTP_OBJ_PROP_LAST_BUILD_DATE = 0xDD70u, // Last Build Date + MTP_OBJ_PROP_TIME_TO_LIVE = 0xDD71u, // Time to Live (minutes) + MTP_OBJ_PROP_MEDIA_GUID = 0xDD72u, // Media GUID + // 0xDD73-0xDDFF is reserved + + // media encoding + MTP_OBJ_PROP_TOTAL_BITRATE = 0xDE91u, // Total BitRate + MTP_OBJ_PROP_BITRATE_TYPE = 0xDE92u, // Bitrate Type + MTP_OBJ_PROP_SAMPLE_RATE = 0xDE93u, // Sample Rate + MTP_OBJ_PROP_NUM_CHANNELS = 0xDE94u, // Number Of Channels + MTP_OBJ_PROP_AUDIO_BITDEPTH = 0xDE95u, // Audio BitDepth + // 0xDE96 is reserved + MTP_OBJ_PROP_SCAN_TYPE = 0xDE97u, // Scan Type + // 0xDE98 is reserved + MTP_OBJ_PROP_AUDIO_WAVE_CODEC = 0xDE99u, // Audio WAVE Codec + MTP_OBJ_PROP_AUDIO_BITRATE = 0xDE9Au, // Audio BitRate + MTP_OBJ_PROP_VIDEO_FOURCC_CODEC = 0xDE9Bu, // Video FourCC Codec + MTP_OBJ_PROP_VIDEO_BITRATE = 0xDE9Cu, // Video BitRate + MTP_OBJ_PROP_FRAMES_PER_KSEC = 0xDE9Du, // Frames Per Thousand Seconds + MTP_OBJ_PROP_KEYFRAME_DISTANCE = 0xDE9Eu, // KeyFrame Distance (ms) + MTP_OBJ_PROP_BUFFER_SIZE = 0xDE9Fu, // Buffer Size + MTP_OBJ_PROP_ENCODING_QUALITY = 0xDEA0u, // Encoding Quality + MTP_OBJ_PROP_ENCODING_PROFILE = 0xDEA1u // Encoding Profile +} mtp_object_properties_t; + + +// MTP 1.1 Appendeix C: Device Properties +typedef enum { + MTP_DEV_PROP_UNDEFINED = 0x5000u, + MTP_DEV_PROP_BATTERY_LEVEL = 0x5001u, + MTP_DEV_PROP_FUNCTIONAL_MODE = 0x5002u, + MTP_DEV_PROP_IMAGE_SIZE = 0x5003u, + MTP_DEV_PROP_COMPRESSION_SETTING = 0x5004u, + MTP_DEV_PROP_WHITE_BALANCE = 0x5005u, + MTP_DEV_PROP_RGB_GAIN = 0x5006u, + MTP_DEV_PROP_F_NUMBER = 0x5007u, + MTP_DEV_PROP_FOCAL_LENGTH = 0x5008u, + MTP_DEV_PROP_FOCUS_DISTANCE = 0x5009u, + MTP_DEV_PROP_FOCUS_MODE = 0x500Au, + MTP_DEV_PROP_EXPOSURE_METERING_MODE = 0x500Bu, + MTP_DEV_PROP_FLASH_MODE = 0x500Cu, + MTP_DEV_PROP_EXPOSURE_TIME = 0x500Du, + MTP_DEV_PROP_EXPOSURE_PROGRAM_MODE = 0x500Eu, + MTP_DEV_PROP_EXPOSURE_INDEX = 0x500Fu, + MTP_DEV_PROP_EXPOSURE_BIAS_COMPENSATION = 0x5010u, + MTP_DEV_PROP_DATE_TIME = 0x5011u, + MTP_DEV_PROP_CAPTURE_DELAY = 0x5012u, + MTP_DEV_PROP_STILL_CAPTURE_MODE = 0x5013u, + MTP_DEV_PROP_CONTRAST = 0x5014u, + MTP_DEV_PROP_SHARPNESS = 0x5015u, + MTP_DEV_PROP_DIGITAL_ZOOM = 0x5016u, + MTP_DEV_PROP_EFFECT_MODE = 0x5017u, + MTP_DEV_PROP_BURST_NUMBER = 0x5018u, + MTP_DEV_PROP_BURST_INTERVAL = 0x5019u, + MTP_DEV_PROP_TIMELAPSE_NUMBER = 0x501Au, + MTP_DEV_PROP_TIMELAPSE_INTERVAL = 0x501Bu, + MTP_DEV_PROP_FOCUS_METERING_MODE = 0x501Cu, + MTP_DEV_PROP_UPLOAD_URL = 0x501Du, + MTP_DEV_PROP_ARTIST = 0x501Eu, + MTP_DEV_PROP_COPYRIGHT_INFO = 0x501Fu, + MTP_DEV_PROP_SYNCHRONIZTION_PARTNER = 0xD401, + MTP_DEV_PROP_DEVICE_FRIENDLY_NAME = 0xD402u, + MTP_DEV_PROP_VOLUME = 0xD403u, + MTP_DEV_PROP_SUPPORTED_FORMATS_ORDERED = 0xD404u, + MTP_DEV_PROP_DEVICE_ICON = 0xD405u, + MTP_DEV_PROP_SECTION_INITIATOR_VERSION_INFO = 0xD406u, + MTP_DEV_PROP_PERCEIVED_DEVICE_TYPE = 0xD407u, + MTP_DEV_PROP_PLAYBACK_RATE = 0xD410u, + MTP_DEV_PROP_PLAYBACK_OBJECT = 0xD411u, + MTP_DEV_PROP_PLAYBACK_CONTAINER_INDEX = 0xD412u, +} mtp_event_properties_t; + +// MTP 1.1 Appendix D: Operations +typedef enum { + MTP_OP_UNDEFINED = 0x1000u, + MTP_OP_GET_DEVICE_INFO = 0x1001u, + MTP_OP_OPEN_SESSION = 0x1002u, + MTP_OP_CLOSE_SESSION = 0x1003u, + MTP_OP_GET_STORAGE_IDS = 0x1004u, + MTP_OP_GET_STORAGE_INFO = 0x1005u, + MTP_OP_GET_NUM_OBJECTS = 0x1006u, + MTP_OP_GET_OBJECT_HANDLES = 0x1007u, + MTP_OP_GET_OBJECT_INFO = 0x1008u, + MTP_OP_GET_OBJECT = 0x1009u, + MTP_OP_GET_THUMB = 0x100Au, + MTP_OP_DELETE_OBJECT = 0x100Bu, + MTP_OP_SEND_OBJECT_INFO = 0x100Cu, + MTP_OP_SEND_OBJECT = 0x100Du, + MTP_OP_INITIATE_CAPTURE = 0x100Eu, + MTP_OP_FORMAT_STORE = 0x100Fu, + MTP_OP_RESET_DEVICE = 0x1010u, + MTP_OP_SELF_TEST = 0x1011u, + MTP_OP_SET_OBJECT_PROTECTION = 0x1012u, + MTP_OP_POWER_DOWN = 0x1013u, + MTP_OP_GET_DEVICE_PROP_DESC = 0x1014u, + MTP_OP_GET_DEVICE_PROP_VALUE = 0x1015u, + MTP_OP_SET_DEVICE_PROP_VALUE = 0x1016u, + MTP_OP_RESET_DEVICE_PROP_VALUE = 0x1017u, + MTP_OP_TERMINATE_OPEN_CAPTURE = 0x1018u, + MTP_OP_MOVE_OBJECT = 0x1019u, + MTP_OP_COPY_OBJECT = 0x101Au, + MTP_OP_GET_PARTIAL_OBJECT = 0x101Bu, + MTP_OP_INITIATE_OPEN_CAPTURE = 0x101Bu, + MTP_OP_GET_OBJECT_PROPS_SUPPORTED = 0x9801u, + MTP_OP_GET_OBJECT_PROP_DESC = 0x9802u, + MTP_OP_GET_OBJECT_PROP_VALUE = 0x9803u, + MTP_OP_SET_OBJECT_PROP_VALUE = 0x9804u, + MTP_OP_GET_OBJECT_PROPLIST = 0x9805u, + MTP_OP_GET_OBJECT_PROP_REFERENCES = 0x9810u, + + MTP_OP_GET_SERVICE_IDS = 0x9301u, + MTP_OP_GET_SERVICE_INFO = 0x9302u, + MTP_OP_GET_SERVICE_CAPABILITIES = 0x9303u, + MTP_OP_GET_SERVICE_PROP_DESC = 0x9304u, + + // Appendix E: Enhanced Operations + MTP_OP_GET_OBJECT_PROP_LIST = 0x9805u, + MTP_OP_SET_OBJECT_PROP_LIST = 0x9806u, + MTP_OP_GET_INTERDEPENDENT_PROP_DESC = 0x9807u, + MTP_OP_SEND_OBJECT_PROP_LIST = 0x9808u, +} mtp_operation_code_t; + +// Appendix F: Responses +typedef enum { + MTP_RESP_UNDEFINED = 0x2000u, + MTP_RESP_OK = 0x2001u, + MTP_RESP_GENERAL_ERROR = 0x2002u, + MTP_RESP_SESSION_NOT_OPEN = 0x2003u, + MTP_RESP_INVALID_TRANSACTION_ID = 0x2004u, + MTP_RESP_OPERATION_NOT_SUPPORTED = 0x2005u, + MTP_RESP_PARAMETER_NOT_SUPPORTED = 0x2006u, + MTP_RESP_INCOMPLETE_TRANSFER = 0x2007u, + MTP_RESP_INVALID_STORAGE_ID = 0x2008u, + MTP_RESP_INVALID_OBJECT_HANDLE = 0x2009u, + MTP_RESP_DEVICE_PROP_NOT_SUPPORTED = 0x200Au, + MTP_RESP_INVALID_OBJECT_FORMAT_CODE = 0x200Bu, + MTP_RESP_STORE_FULL = 0x200Cu, + MTP_RESP_OBJECT_WRITE_PROTECTED = 0x200Du, + MPT_RESC_STORE_READ_ONLY = 0x200Eu, + MTP_RESP_ACCESS_DENIED = 0x200Fu, + MTP_RESP_NO_THUMBNAIL_PRESENT = 0x2010u, + MTP_RESP_SELF_TEST_FAILED = 0x2011u, + MTP_RESP_PARTIAL_DELETION = 0x2012u, + MTP_RESP_STORE_NOT_AVAILABLE = 0x2013u, + MTP_RESP_SPECIFICATION_BY_FORMAT_UNSUPPORTED = 0x2014u, + MTP_RESP_NO_VALID_OBJECTINFO = 0x2015u, + MTP_RESP_INVALID_CODE_FORMAT = 0x2016u, + MTP_RESP_UNKNOWN_VENDOR_CODE = 0x2017u, + MTP_RESP_CAPTURE_ALREADY_TERMINATED = 0x2018u, + MTP_RESP_DEVICE_BUSY = 0x2019u, + MTP_RESP_INVALID_PARENT_OBJECT = 0x201Au, + MTP_RESP_INVALID_DEVICE_PROP_FORMAT = 0x201Bu, + MTP_RESP_INVALID_DEVICE_PROP_VALUE = 0x201Cu, + MTP_RESP_INVALID_PARAMETER = 0x201Du, + MTP_RESP_SESSION_ALREADY_OPEN = 0x201Eu, + MTP_RESP_TRANSACTION_CANCELLED = 0x201Fu, + MTP_RESP_SPEC_OF_DESTINATION_UNSUPPORTED = 0x2020u, + + MTP_RESP_INVALID_OBJECT_PROP_CODE = 0xA801u, + MTP_RESP_INVALID_OBJECT_PROP_FORMAT = 0xA802u, + MTP_RESP_INVALID_OBJECT_PROP_VALUE = 0xA803u, + MTP_RESP_INVALID_OBJECT_REFERENCE = 0xA804u, + MTP_RESP_GROUP_NOT_SUPPORTED = 0xA805u, + MTP_RESP_INVALID_DATASET = 0xA806u, + MTP_RESP_SPEC_BY_GROUP_UNSUPPORTED = 0xA807u, + MTP_RESP_SPEC_BY_DEPTH_UNSUPPORTED = 0xA808u, + MTP_RESP_OBJECT_TOO_LARGE = 0xA809u, + MTP_RESP_OBJECT_PROP_NOT_SUPPORTED = 0xA80Au, +} mtp_response_t; + +// Appendix G: Events +typedef enum { + MTP_EVENT_UNDEFINED = 0x4000, + MTP_EVENT_CANCEL_TRANSACTION = 0x4001, + MTP_EVENT_OBJECT_ADDED = 0x4002, + MTP_EVENT_OBJECT_REMOVED = 0x4003, + MTP_EVENT_STORE_ADDED = 0x4004, + MTP_EVENT_STORE_REMOVED = 0x4005, + MTP_EVENT_DEVICE_PROP_CHANGED = 0x4006, + MTP_EVENT_OBJECT_INFO_CHANGED = 0x4007, + MTP_EVENT_DEVICE_INFO_CHANGED = 0x4008, + MTP_EVENT_REQUEST_OBJECT_TRANSFER = 0x4009, + MTP_EVENT_STORE_FULL = 0x400Au, + MTP_EVENT_DEVICE_RESET = 0x400Bu, + MTP_EVENT_STORAGE_INFO_CHANGED = 0x400Cu, + MTP_EVENT_CAPTURE_COMPLETE = 0x400Du, + MTP_EVENT_UNREPORTED_STATUS = 0x400Eu, + MTP_EVENT_OBJECT_PROP_CHANGED = 0xC801u, + MTP_EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802u, + MTP_EVENT_OBJECT_REFERENCES_CHANGED = 0xC803u, +} mtp_event_code_t; + +// Datatypes +typedef enum { + MTP_DATA_TYPE_UNDEFINED = 0x0000u, + // scalars + MTP_DATA_TYPE_INT8 = 0x0001u, + MTP_DATA_TYPE_UINT8 = 0x0002u, + MTP_DATA_TYPE_INT16 = 0x0003u, + MTP_DATA_TYPE_UINT16 = 0x0004u, + MTP_DATA_TYPE_INT32 = 0x0005u, + MTP_DATA_TYPE_UINT32 = 0x0006u, + MTP_DATA_TYPE_INT64 = 0x0007u, + MTP_DATA_TYPE_UINT64 = 0x0008u, + MTP_DATA_TYPE_INT128 = 0x0009u, + MTP_DATA_TYPE_UINT128 = 0x000Au, + // array + MTP_DATA_TYPE_AINT8 = 0x4001u, + MTP_DATA_TYPE_AUINT8 = 0x4002u, + MTP_DATA_TYPE_AINT16 = 0x4003u, + MTP_DATA_TYPE_AUINT16 = 0x4004u, + MTP_DATA_TYPE_AINT32 = 0x4005u, + MTP_DATA_TYPE_AUINT32 = 0x4006u, + MTP_DATA_TYPE_AINT64 = 0x4007u, + MTP_DATA_TYPE_AUINT64 = 0x4008u, + MTP_DATA_TYPE_AINT128 = 0x4009u, + MTP_DATA_TYPE_AUINT128 = 0x400Au, + MTP_DATA_TYPE_STR = 0xFFFFu, +} mtp_data_type_t; + +// Get/Set +typedef enum { + MTP_MODE_GET = 0x00u, + MTP_MODE_GET_SET = 0x01u, +} mtp_mode_get_set_t; + +typedef enum { + MTP_STORAGE_TYPE_UNDEFINED = 0x0000u, + MTP_STORAGE_TYPE_FIXED_ROM = 0x0001u, + MTP_STORAGE_TYPE_REMOVABLE_ROM = 0x0002u, + MTP_STORAGE_TYPE_FIXED_RAM = 0x0003u, + MTP_STORAGE_TYPE_REMOVABLE_RAM = 0x0004u, +} mtp_storage_type_t; + +typedef enum { + MTP_FILESYSTEM_TYPE_UNDEFINED = 0x0000u, + MTP_FILESYSTEM_TYPE_GENERIC_FLAT = 0x0001u, + MTP_FILESYSTEM_TYPE_GENERIC_HIERARCHICAL = 0x0002u, + MTP_FILESYSTEM_TYPE_DCF = 0x0003u, +} mtp_filesystem_type_t; + +typedef enum { + MTP_ACCESS_CAPABILITY_READ_WRITE = 0x0000u, + MTP_ACCESS_CAPABILITY_READ_ONLY_WITHOUT_OBJECT_DELETION = 0x0001u, + MTP_ACCESS_CAPABILITY_READ_ONLY_WITH_OBJECT_DELETION = 0x0002u, +} mtp_access_capability_t; + +typedef enum { + MTP_PROTECTION_STATUS_NO_PROTECTION = 0x0000u, + MTP_PROTECTION_STATUS_READ_ONLY = 0x0001u, + MTP_PROTECTION_STATUS_READ_ONLY_DATA = 0x8002u, + MTP_PROTECTION_NON_TRANSFERABLE_DATA = 0x8003u, +} mtp_protection_status_t; + +typedef enum { + MTP_ASSOCIATION_UNDEFINED = 0x0000u, + MTP_ASSOCIATION_GENERIC_FOLDER = 0x0001u, + MTP_ASSOCIATION_ALBUM = 0x0002u, + MTP_ASSOCIATION_TIME_SEQUENCE = 0x0003u, + MTP_ASSOCIATION_HORIZONTAL_PANORAMIC = 0x0004u, + MTP_ASSOCIATION_VERTICAL_PANORAMIC = 0x0005u, + MTP_ASSOCIATION_2D_PANORAMIC = 0x0006u, + MTP_ASSOCIATION_ANCILLARY_DATA = 0x0007u, +} mtp_association_t; + +//--------------------------------------------------------------------+ +// Data structures +//--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED { + uint32_t len; + uint16_t type; + uint16_t code; + uint32_t transaction_id; +} 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 { + mtp_container_header_t header; + uint8_t payload[(CFG_TUD_MTP_EP_BUFSIZE - sizeof(mtp_container_header_t))]; +} mtp_generic_container_t; + +typedef struct { + mtp_container_header_t* header; + union { + uint8_t* payload; + uint16_t* payload16; + uint32_t* payload32; + }; + 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 */ \ + uint16_t utf16[_nchars]; \ + } + +#define mtp_array_t(_type, _count) \ + struct TU_ATTR_PACKED { \ + uint32_t count; \ + _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) +#define mtp_auint32_t(_count) mtp_array_t(uint32_t, _count) +#define mtp_auint64_t(_count) mtp_array_t(uint64_t, _count) + +#define MTP_STORAGE_INFO_STRUCT(_storage_desc_chars, _volume_id_chars) \ + struct TU_ATTR_PACKED { \ + uint16_t storage_type; \ + uint16_t filesystem_type; \ + uint16_t access_capability; \ + uint64_t max_capacity_in_bytes; \ + uint64_t free_space_in_bytes; \ + uint32_t free_space_in_objects; \ + mtp_string_t(_storage_desc_chars) storage_description; \ + mtp_string_t(_volume_id_chars) volume_identifier; \ + } + +// Object Info Dataset without dynamic string: filename, date_created, date_modified, keywords +typedef struct TU_ATTR_PACKED { + uint32_t storage_id; + uint16_t object_format; + uint16_t protection_status; + uint32_t object_compressed_size; + uint16_t thumb_format; + uint32_t thumb_compressed_size; + uint32_t thumb_pix_width; + uint32_t thumb_pix_height; + uint32_t image_pix_width; + uint32_t image_pix_height; + uint32_t image_bit_depth; + uint32_t parent_object; // 0: root + uint16_t association_type; + uint32_t association_desc; + uint32_t sequence_number; + // mtp_string_t() filename + // mtp_string_t() date_created + // mtp_string_t() date_modified + // mtp_string_t() keywords +} mtp_object_info_header_t; + +// Device property desc up to get/set +typedef struct TU_ATTR_PACKED { + uint16_t device_property_code; + uint16_t datatype; + uint8_t get_set; +} mtp_device_prop_desc_header_t; + +// The following fields will be dynamically added to the struct at runtime: +// - wstring factory_def_value; +// - wstring current_value_len; +// - uint8_t form_flag; + +// no form +#define MTP_DEVICE_PROPERTIES_STRUCT(_type) \ + struct TU_ATTR_PACKED { \ + uint16_t device_property_code; \ + uint16_t datatype; \ + uint8_t get_set; \ + _type factory_default; \ + _type current_value; \ + uint8_t form_flag; /* 0: none, 1: range, 2: enum */ \ + }; + +typedef struct TU_ATTR_PACKED { + uint16_t code; + uint32_t transaction_id; +} mtp_request_reset_cancel_data_t; +TU_VERIFY_STATIC(sizeof(mtp_request_reset_cancel_data_t) == 6, "size is not correct"); + +//--------------------------------------------------------------------+ +// Container helper function +// return number of bytes added +//--------------------------------------------------------------------+ + +// return payload buffer for next write +TU_ATTR_ALWAYS_INLINE static inline uint8_t* mtp_container_payload_ptr(mtp_container_info_t* p_container) { + // only 1st packet include header + uint32_t pos = p_container->header->len - sizeof(mtp_container_header_t); + while (pos > CFG_TUD_MTP_EP_BUFSIZE) { + pos -= CFG_TUD_MTP_EP_BUFSIZE; + } + return p_container->payload + pos; +} + +// only add_raw does partial copy +TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_add_raw(mtp_container_info_t* p_container, const void* data, uint32_t len) { + uint8_t* buf = mtp_container_payload_ptr(p_container); + const uint32_t added_len = tu_min32(len, CFG_TUD_MTP_EP_BUFSIZE - p_container->header->len); + if (added_len > 0) { + memcpy(buf, data, added_len); + } + p_container->header->len += len; // always increase len, even partial copy + return added_len; +} + +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->header->len + added_len < CFG_TUD_MTP_EP_BUFSIZE, 0); + uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t); + + tu_unaligned_write32(buf, count); + p_container->header->len += 4; + buf += 4; + + 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_container_info_t* p_container, uint16_t* utf16) { + uint8_t count = 0; + while (utf16[count]) { + count++; + } + const uint32_t added_len = 1u + 2u * count; + TU_ASSERT(p_container->header->len + added_len < CFG_TUD_MTP_EP_BUFSIZE, 0); + uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t); + + *buf++ = count; + p_container->header->len++; + + 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_container_info_t* p_container, const char* str) { + const uint8_t len = (uint8_t) (strlen(str) + 1); // include null + TU_ASSERT(p_container->header->len + 1 + 2 * len < CFG_TUD_MTP_EP_BUFSIZE, 0); + uint8_t* buf = p_container->payload + p_container->header->len - sizeof(mtp_container_header_t); + + if (len == 1) { + // 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++) { + buf[0] = str[i]; + buf[1] = 0; + buf += 2; + p_container->header->len += 2; + } + return 1u + 2u * len; + } +} + +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_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_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_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_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_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_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_container_info_t* p_container, uint32_t count, const uint32_t* data) { + return mtp_container_add_array(p_container, sizeof(uint32_t), count, data); +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline uint32_t mtp_container_get_string(uint8_t* buf, uint16_t utf16[]) { + uint8_t nchars = *buf++; + memcpy(utf16, buf, 2 * nchars); + return 1u + 2u * nchars; +} + +#ifdef __cplusplus + } +#endif + +#endif +#endif diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c new file mode 100644 index 000000000..04bde9415 --- /dev/null +++ b/src/class/mtp/mtp_device.c @@ -0,0 +1,540 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MTP) + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "device/dcd.h" +#include "device/usbd.h" +#include "device/usbd_pvt.h" + +#include "mtp_device.h" + +// Level where CFG_TUSB_DEBUG must be at least for this driver is logged +#ifndef CFG_TUD_MTP_LOG_LEVEL + #define CFG_TUD_MTP_LOG_LEVEL CFG_TUD_LOG_LEVEL +#endif + +#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_MTP_LOG_LEVEL, __VA_ARGS__) + +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data) { + (void) cb_data; + return false; +} +TU_ATTR_WEAK bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data) { + (void) cb_data; + return false; +} +TU_ATTR_WEAK int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data) { + (void) cb_data; + return -1; +} +TU_ATTR_WEAK int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data) { + (void) cb_data; + return -1; +} +TU_ATTR_WEAK bool tud_mtp_request_vendor_cb(tud_mtp_request_cb_data_t* cb_data) { + (void) cb_data; + return false; +} +TU_ATTR_WEAK int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data) { + (void) cb_data; + return -1; +} +TU_ATTR_WEAK int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data) { + (void) cb_data; + return -1; +} +TU_ATTR_WEAK int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data) { + (void) cb_data; + return -1; +} +TU_ATTR_WEAK int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data) { + (void) cb_data; + return -1; +} + +//--------------------------------------------------------------------+ +// STRUCT +//--------------------------------------------------------------------+ +typedef struct { + uint8_t rhport; + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + uint8_t ep_event; + + // Bulk Only Transfer (BOT) Protocol + uint8_t phase; + + uint32_t total_len; + uint32_t xferred_len; + + uint32_t session_id; + mtp_container_command_t command; + mtp_container_header_t io_header; + + TU_ATTR_ALIGNED(4) uint8_t control_buf[CFG_TUD_MTP_EP_CONTROL_BUFSIZE]; +} mtpd_interface_t; + +typedef struct { + TUD_EPBUF_DEF(buf, CFG_TUD_MTP_EP_BUFSIZE); + TUD_EPBUF_TYPE_DEF(mtp_event_t, buf_event); +} mtpd_epbuf_t; + +//--------------------------------------------------------------------+ +// INTERNAL FUNCTION DECLARATION +//--------------------------------------------------------------------+ +static mtpd_interface_t _mtpd_itf; +CFG_TUD_MEM_SECTION static mtpd_epbuf_t _mtpd_epbuf; + +static void preprocess_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data); + +//--------------------------------------------------------------------+ +// Debug +//--------------------------------------------------------------------+ +#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL + +TU_ATTR_UNUSED static tu_lookup_entry_t const _mpt_op_lookup[] = { +{.key = MTP_OP_UNDEFINED , .data = "Undefined" } , +{.key = MTP_OP_GET_DEVICE_INFO , .data = "GetDeviceInfo" } , +{.key = MTP_OP_OPEN_SESSION , .data = "OpenSession" } , +{.key = MTP_OP_CLOSE_SESSION , .data = "CloseSession" } , +{.key = MTP_OP_GET_STORAGE_IDS , .data = "GetStorageIDs" } , +{.key = MTP_OP_GET_STORAGE_INFO , .data = "GetStorageInfo" } , +{.key = MTP_OP_GET_NUM_OBJECTS , .data = "GetNumObjects" } , +{.key = MTP_OP_GET_OBJECT_HANDLES , .data = "GetObjectHandles" } , +{.key = MTP_OP_GET_OBJECT_INFO , .data = "GetObjectInfo" } , +{.key = MTP_OP_GET_OBJECT , .data = "GetObject" } , +{.key = MTP_OP_GET_THUMB , .data = "GetThumb" } , +{.key = MTP_OP_DELETE_OBJECT , .data = "DeleteObject" } , +{.key = MTP_OP_SEND_OBJECT_INFO , .data = "SendObjectInfo" } , +{.key = MTP_OP_SEND_OBJECT , .data = "SendObject" } , +{.key = MTP_OP_INITIATE_CAPTURE , .data = "InitiateCapture" } , +{.key = MTP_OP_FORMAT_STORE , .data = "FormatStore" } , +{.key = MTP_OP_RESET_DEVICE , .data = "ResetDevice" } , +{.key = MTP_OP_SELF_TEST , .data = "SelfTest" } , +{.key = MTP_OP_SET_OBJECT_PROTECTION , .data = "SetObjectProtection" } , +{.key = MTP_OP_POWER_DOWN , .data = "PowerDown" } , +{.key = MTP_OP_GET_DEVICE_PROP_DESC , .data = "GetDevicePropDesc" } , +{.key = MTP_OP_GET_DEVICE_PROP_VALUE , .data = "GetDevicePropValue" } , +{.key = MTP_OP_SET_DEVICE_PROP_VALUE , .data = "SetDevicePropValue" } , +{.key = MTP_OP_RESET_DEVICE_PROP_VALUE , .data = "ResetDevicePropValue" } , +{.key = MTP_OP_TERMINATE_OPEN_CAPTURE , .data = "TerminateOpenCapture" } , +{.key = MTP_OP_MOVE_OBJECT , .data = "MoveObject" } , +{.key = MTP_OP_COPY_OBJECT , .data = "CopyObject" } , +{.key = MTP_OP_GET_PARTIAL_OBJECT , .data = "GetPartialObject" } , +{.key = MTP_OP_INITIATE_OPEN_CAPTURE , .data = "InitiateOpenCapture" } , +{.key = MTP_OP_GET_OBJECT_PROPS_SUPPORTED , .data = "GetObjectPropsSupported" } , +{.key = MTP_OP_GET_OBJECT_PROP_DESC , .data = "GetObjectPropDesc" } , +{.key = MTP_OP_GET_OBJECT_PROP_VALUE , .data = "GetObjectPropValue" } , +{.key = MTP_OP_SET_OBJECT_PROP_VALUE , .data = "SetObjectPropValue" } , +{.key = MTP_OP_GET_OBJECT_PROPLIST , .data = "GetObjectPropList" } , +{.key = MTP_OP_GET_OBJECT_PROP_REFERENCES , .data = "GetObjectPropReferences" } , +{.key = MTP_OP_GET_SERVICE_IDS , .data = "GetServiceIDs" } , +{.key = MTP_OP_GET_SERVICE_INFO , .data = "GetServiceInfo" } , +{.key = MTP_OP_GET_SERVICE_CAPABILITIES , .data = "GetServiceCapabilities" } , +{.key = MTP_OP_GET_SERVICE_PROP_DESC , .data = "GetServicePropDesc" } , +{.key = MTP_OP_GET_OBJECT_PROP_LIST , .data = "GetObjectPropList" } , +{.key = MTP_OP_SET_OBJECT_PROP_LIST , .data = "SetObjectPropList" } , +{.key = MTP_OP_GET_INTERDEPENDENT_PROP_DESC , .data = "GetInterdependentPropDesc" } , +{.key = MTP_OP_SEND_OBJECT_PROP_LIST , .data = "SendObjectPropList" } +}; + +TU_ATTR_UNUSED static tu_lookup_table_t const _mtp_op_table = { + .count = TU_ARRAY_SIZE(_mpt_op_lookup), + .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_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.header.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 = (uint16_t) tu_min32(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_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr)); + 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.header.transaction_id; + TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_in)); + return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, (uint16_t)p_container->header->len); +} + +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 +//--------------------------------------------------------------------+ +void mtpd_init(void) { + tu_memclr(&_mtpd_itf, sizeof(mtpd_interface_t)); +} + +bool mtpd_deinit(void) { + return true; // nothing to do +} + +void mtpd_reset(uint8_t rhport) { + (void) rhport; + tu_memclr(&_mtpd_itf, sizeof(mtpd_interface_t)); +} + +uint16_t mtpd_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { + // only support PIMA 15470 protocol + TU_VERIFY(TUSB_CLASS_IMAGE == itf_desc->bInterfaceClass && + MTP_SUBCLASS_STILL_IMAGE == itf_desc->bInterfaceSubClass && + MTP_PROTOCOL_PIMA_15470 == itf_desc->bInterfaceProtocol, 0); + + // mtp driver length is fixed + const uint16_t mtpd_itf_size = sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t); + + // Max length must be at least 1 interface + 3 endpoints + TU_ASSERT(itf_desc->bNumEndpoints == 3 && max_len >= mtpd_itf_size); + mtpd_interface_t* p_mtp = &_mtpd_itf; + tu_memclr(p_mtp, sizeof(mtpd_interface_t)); + p_mtp->rhport = rhport; + p_mtp->itf_num = itf_desc->bInterfaceNumber; + + // Open interrupt IN endpoint + const tusb_desc_endpoint_t* ep_desc = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc); + TU_ASSERT(ep_desc->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0); + TU_ASSERT(usbd_edpt_open(rhport, ep_desc), 0); + p_mtp->ep_event = ep_desc->bEndpointAddress; + + // Open endpoint pair + TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(ep_desc), 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0); + TU_ASSERT(prepare_new_command(p_mtp), 0); + + return mtpd_itf_size; +} + +// Invoked when a control transfer occurred on an interface of this class +// Driver response accordingly to the request and the transfer stage (setup/data/ack) +// return false to stall control endpoint (e.g unsupported request) +bool mtpd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { + mtpd_interface_t* p_mtp = &_mtpd_itf; + tud_mtp_request_cb_data_t cb_data = { + .idx = 0, + .stage = stage, + .session_id = p_mtp->session_id, + .request = request, + .buf = p_mtp->control_buf, + .bufsize = tu_le16toh(request->wLength), + }; + + switch (request->bRequest) { + case MTP_REQ_CANCEL: + TU_LOG_DRV(" MTP request: Cancel\n"); + if (stage == CONTROL_STAGE_SETUP) { + return tud_control_xfer(rhport, request, p_mtp->control_buf, CFG_TUD_MTP_EP_CONTROL_BUFSIZE); + } else if (stage == CONTROL_STAGE_ACK) { + return tud_mtp_request_cancel_cb(&cb_data); + } + break; + + case MTP_REQ_GET_EXT_EVENT_DATA: + TU_LOG_DRV(" MTP request: Get Extended Event Data\n"); + if (stage == CONTROL_STAGE_SETUP) { + const int32_t len = tud_mtp_request_get_extended_event_cb(&cb_data); + TU_VERIFY(len > 0); + return tud_control_xfer(rhport,request, p_mtp->control_buf, (uint16_t) len); + } + break; + + case MTP_REQ_RESET: + TU_LOG_DRV(" MTP request: Device Reset\n"); + // used by the host to return the Still Image Capture Device to the Idle state after the Bulk-pipe has stalled + if (stage == CONTROL_STAGE_SETUP) { + // clear stalled + if (usbd_edpt_stalled(rhport, p_mtp->ep_out)) { + usbd_edpt_clear_stall(rhport, p_mtp->ep_out); + } + if (usbd_edpt_stalled(rhport, p_mtp->ep_in)) { + usbd_edpt_clear_stall(rhport, p_mtp->ep_in); + } + } else if (stage == CONTROL_STAGE_ACK) { + prepare_new_command(p_mtp); + return tud_mtp_request_device_reset_cb(&cb_data); + } + break; + + case MTP_REQ_GET_DEVICE_STATUS: { + TU_LOG_DRV(" MTP request: Get Device Status\n"); + if (stage == CONTROL_STAGE_SETUP) { + const int32_t len = tud_mtp_request_get_device_status_cb(&cb_data); + TU_VERIFY(len > 0); + return tud_control_xfer(rhport, request, p_mtp->control_buf, (uint16_t) len); + } + break; + } + + default: + return tud_mtp_request_vendor_cb(&cb_data); + } + + 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) { + // nothing to do + return true; + } + + mtpd_interface_t* p_mtp = &_mtpd_itf; + mtp_generic_container_t* p_container = (mtp_generic_container_t*) _mtpd_epbuf.buf; + +#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL + tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code); + TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code), + _mtp_phase_str[p_mtp->phase]); +#endif + + const mtp_container_info_t headered_packet = { + .header = &p_container->header, + .payload = p_container->payload, + .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.phase = p_mtp->phase; + cb_data.session_id = p_mtp->session_id; + cb_data.command_container = &p_mtp->command; + cb_data.io_container = headered_packet; + cb_data.total_xferred_bytes = 0; + cb_data.xfer_result = event; + + switch (p_mtp->phase) { + case MTP_PHASE_COMMAND: { + // received new command + TU_VERIFY(ep_addr == p_mtp->ep_out && p_container->header.type == MTP_CONTAINER_TYPE_COMMAND_BLOCK); + 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 + preprocess_cmd(p_mtp, &cb_data); + if (tud_mtp_command_received_cb(&cb_data) < 0) { + p_mtp->phase = MTP_PHASE_ERROR; + } + break; + } + + 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.total_xferred_bytes = p_mtp->xferred_len; + + bool is_complete = false; + // complete if ZLP or short packet or overflow + if (xferred_bytes == 0 || // ZLP + (xferred_bytes & (bulk_mps - 1)) || // short packet + p_mtp->xferred_len > p_mtp->total_len) { + is_complete = true; + } + + if (ep_addr == p_mtp->ep_in) { + // Data In + if (is_complete) { + cb_data.io_container.header->len = sizeof(mtp_container_header_t); + tud_mtp_data_complete_cb(&cb_data); + } else { + // 2nd+ packet: payload only + cb_data.io_container = headerless_packet; + tud_mtp_data_xfer_cb(&cb_data); + } + } else { + // Data Out + 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); + } + } + break; + } + + 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_ERROR: + // handled after switch, supposedly to be empty + break; + default: return false; + } + + if (p_mtp->phase == MTP_PHASE_ERROR) { + // stall both IN & OUT endpoints + usbd_edpt_stall(rhport, p_mtp->ep_out); + usbd_edpt_stall(rhport, p_mtp->ep_in); + } + + return true; +} + + +//--------------------------------------------------------------------+ +// MTPD Internal functionality +//--------------------------------------------------------------------+ + +// pre-processed commands +void preprocess_cmd(mtpd_interface_t* p_mtp, tud_mtp_cb_data_t* cb_data) { + switch (p_mtp->command.header.code) { + case MTP_OP_GET_DEVICE_INFO: { + tud_mtp_device_info_t dev_info = { + .standard_version = 100, + .mtp_vendor_extension_id = 6, // MTP specs say 0xFFFFFFFF but libMTP check for value 6 + .mtp_version = 100, + .mtp_extensions = { + .count = sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), + .utf16 = { 0 } + }, + .functional_mode = 0x0000, + .supported_operations = { + .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), + .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS } + }, + .supported_events = { + .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), + .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS } + }, + .supported_device_properties = { + .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), + .arr = { CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES } + }, + .capture_formats = { + .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), + .arr = { CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS } + }, + .playback_formats = { + .count = TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS), + .arr = { CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS } + } + }; + + for (uint8_t i=0; i < dev_info.mtp_extensions.count; i++) { + dev_info.mtp_extensions.utf16[i] = (uint16_t)CFG_TUD_MTP_DEVICEINFO_EXTENSIONS[i]; + } + + mtp_container_add_raw(&cb_data->io_container, &dev_info, sizeof(tud_mtp_device_info_t)); + break; + } + + default: + break; + } +} + +#endif diff --git a/src/class/mtp/mtp_device.h b/src/class/mtp/mtp_device.h new file mode 100644 index 000000000..397fbbbce --- /dev/null +++ b/src/class/mtp/mtp_device.h @@ -0,0 +1,167 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 Ennebi Elettronica (https://ennebielettronica.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN0 + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef TUSB_MTP_DEVICE_H_ +#define TUSB_MTP_DEVICE_H_ + +#include "common/tusb_common.h" +#include "mtp.h" + +#if (CFG_TUD_ENABLED && CFG_TUD_MTP) + +#ifdef __cplusplus + extern "C" { +#endif + +// callback data for Bulk Only Transfer (BOT) protocol +typedef struct { + uint8_t idx; // mtp instance + uint8_t phase; // current phase + uint32_t session_id; + + const mtp_container_command_t* command_container; + mtp_container_info_t io_container; + + tusb_xfer_result_t xfer_result; + uint32_t total_xferred_bytes; // number of bytes transferred so far in this phase +} tud_mtp_cb_data_t; + +// callback data for Control requests +typedef struct { + uint8_t idx; + uint8_t stage; // control stage + uint32_t session_id; + + const tusb_control_request_t* request; + // buffer for data stage + uint8_t* buf; + uint16_t bufsize; +} tud_mtp_request_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 +#define MTP_DEVICE_INFO_STRUCT(_extension_nchars, _op_count, _event_count, _devprop_count, _capture_count, _playback_count) \ + struct TU_ATTR_PACKED { \ + uint16_t standard_version; \ + uint32_t mtp_vendor_extension_id; \ + uint16_t mtp_version; \ + mtp_string_t(_extension_nchars) mtp_extensions; \ + uint16_t functional_mode; \ + mtp_auint16_t(_op_count) supported_operations; \ + mtp_auint16_t(_event_count) supported_events; \ + mtp_auint16_t(_devprop_count) supported_device_properties; \ + mtp_auint16_t(_capture_count) capture_formats; \ + mtp_auint16_t(_playback_count) playback_formats; \ + /* string fields will be added using append function */ \ + } + +typedef MTP_DEVICE_INFO_STRUCT( + sizeof(CFG_TUD_MTP_DEVICEINFO_EXTENSIONS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_OPERATIONS), + TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_EVENTS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_SUPPORTED_DEVICE_PROPERTIES), + TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_CAPTURE_FORMATS), TU_ARGS_NUM(CFG_TUD_MTP_DEVICEINFO_PLAYBACK_FORMATS) +) tud_mtp_device_info_t; + +//--------------------------------------------------------------------+ +// 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); + +// receive data phase +bool tud_mtp_data_receive(mtp_container_info_t* p_container); + +// send response +bool tud_mtp_response_send(mtp_container_info_t* p_container); + +// send event notification on event endpoint +bool tud_mtp_event_send(mtp_event_t* event); + +//--------------------------------------------------------------------+ +// Control request Callbacks +//--------------------------------------------------------------------+ + +// Invoked when received Cancel request. Data is available in callback data's buffer +// return false to stall the request +bool tud_mtp_request_cancel_cb(tud_mtp_request_cb_data_t* cb_data); + +// Invoked when received Device Reset request +// return false to stall the request +bool tud_mtp_request_device_reset_cb(tud_mtp_request_cb_data_t* cb_data); + +// Invoked when received Get Extended Event request. Application fill callback data's buffer for response +// return negative to stall the request +int32_t tud_mtp_request_get_extended_event_cb(tud_mtp_request_cb_data_t* cb_data); + +// Invoked when received Get DeviceStatus request. Application fill callback data's buffer for response +// return negative to stall the request +int32_t tud_mtp_request_get_device_status_cb(tud_mtp_request_cb_data_t* cb_data); + +// Invoked when received vendor-specific request not in the above standard MTP requests +// return false to stall the request +bool tud_mtp_request_vendor_cb(tud_mtp_request_cb_data_t* cb_data); + +//--------------------------------------------------------------------+ +// Bulk only protocol Callbacks +//--------------------------------------------------------------------+ + +// Invoked when new command is received. Application fill the cb_data->io_container and call tud_mtp_data_send() or +// tud_mtp_response_send() for Data or Response phase. +// Return negative to stall the endpoints +int32_t tud_mtp_command_received_cb(tud_mtp_cb_data_t * cb_data); + +// Invoked when a data packet is transferred. If data spans over multiple packets, application can use +// total_xferred_bytes and io_container's payload_bytes to determine the offset and remaining bytes to be transferred. +// Return negative to stall the endpoints +int32_t tud_mtp_data_xfer_cb(tud_mtp_cb_data_t* cb_data); + +// Invoked when all bytes in DATA phase is complete. A response packet is expected +// Return negative to stall the endpoints +int32_t tud_mtp_data_complete_cb(tud_mtp_cb_data_t* cb_data); + +// Invoked when response phase is complete +// Return negative to stall the endpoints +int32_t tud_mtp_response_complete_cb(tud_mtp_cb_data_t* cb_data); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void mtpd_init (void); +bool mtpd_deinit (void); +void mtpd_reset (uint8_t rhport); +uint16_t mtpd_open (uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len); +bool mtpd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *p_request); +bool mtpd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); + +#ifdef __cplusplus + } +#endif + +#endif +#endif diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 7ec939b64..3f6bedd4c 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -159,6 +159,25 @@ TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u, "USBTMC dev buffer size too small") static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len); static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen); + +// USBTMC Device Callbacks weak implementations +TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void) { + return true; +} + +TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult) { + (void) msg; + (void) tmcResult; + return true; +} + +#if (CFG_TUD_USBTMC_ENABLE_488) +TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg) { + (void) msg; + return true; +} +#endif + #ifndef NDEBUG tu_static uint8_t termChar; #endif @@ -262,16 +281,10 @@ void usbtmcd_init_cb(void) { usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); #ifndef NDEBUG #if CFG_TUD_USBTMC_ENABLE_488 - if (usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger) { - TU_ASSERT(&tud_usbtmc_msg_trigger_cb != NULL, ); - } // Per USB488 spec: table 8 TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.listenOnly, ); TU_ASSERT(!usbtmc_state.capabilities->bmIntfcCapabilities.talkOnly, ); #endif - if (usbtmc_state.capabilities->bmIntfcCapabilities.supportsIndicatorPulse) { - TU_ASSERT(&tud_usbtmc_indicator_pulse_cb != NULL, ); - } #endif usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); @@ -587,9 +600,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint TU_ASSERT(false); } } else if (ep_addr == usbtmc_state.ep_int_in) { - if (tud_usbtmc_notification_complete_cb) { - TU_VERIFY(tud_usbtmc_notification_complete_cb()); - } + TU_VERIFY(tud_usbtmc_notification_complete_cb()); return true; } return false; diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index b85ef12b5..235f1276e 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -75,15 +75,14 @@ bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); // The interrupt-IN endpoint buffer was transmitted to the host. Use // tud_usbtmc_transmit_notification_data to send another notification. -TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void); +bool tud_usbtmc_notification_complete_cb(void); // Indicator pulse should be 0.5 to 1.0 seconds long -TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); +bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); #if (CFG_TUD_USBTMC_ENABLE_488) uint8_t tud_usbtmc_get_stb_cb(uint8_t *tmcResult); -TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); -//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); +bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); #endif // Called from app diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index b0332b0fe..27724b194 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -67,6 +67,20 @@ typedef struct { CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR]; +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) { + (void) itf; + (void) buffer; + (void) bufsize; +} + +TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) { + (void) itf; + (void) sent_bytes; +} + //-------------------------------------------------------------------- // Application API //-------------------------------------------------------------------- @@ -259,16 +273,12 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint tu_edpt_stream_read_xfer_complete(&p_vendor->rx.stream, xferred_bytes); // Invoked callback if any - if (tud_vendor_rx_cb) { - tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes); - } + tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes); tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream); } else if ( ep_addr == p_vendor->tx.stream.ep_addr ) { // Send complete - if (tud_vendor_tx_cb) { - tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); - } + tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 // try to send more if possible diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index 149ae2d56..5fe4fc9ff 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -119,9 +119,9 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) { //--------------------------------------------------------------------+ // Invoked when received new data -TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize); +void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize); // Invoked when last rx transfer finished -TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); +void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); //--------------------------------------------------------------------+ // Inline Functions diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 3124d5596..5c00cc358 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -193,6 +193,28 @@ static char const* const tu_str_video_vs_control_selector[] = { #endif //--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) { + (void) ctl_idx; + (void) stm_idx; +} + +TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod) { + (void) ctl_idx; + (void) power_mod; + return VIDEO_ERROR_NONE; +} + +TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, + video_probe_and_commit_control_t const *parameters) { + (void) ctl_idx; + (void) stm_idx; + (void) parameters; + return VIDEO_ERROR_NONE; +} + +//--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -902,7 +924,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN); TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN); } else if (stage == CONTROL_STAGE_DATA) { - if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode); + return tud_video_power_mode_cb(ctl_idx, self->power_mode); } return VIDEO_ERROR_NONE; @@ -1104,10 +1126,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, TU_VERIFY(_update_streaming_parameters(stm, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); /* Set the negotiated value */ stm->max_payload_transfer_size = param->dwMaxPayloadTransferSize; - int ret = VIDEO_ERROR_NONE; - if (tud_video_commit_cb) { - ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param); - } + int ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param); if (VIDEO_ERROR_NONE == ret) { stm->state = VS_STATE_COMMITTED; stm->buffer = NULL; @@ -1419,9 +1438,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 stm->buffer = NULL; stm->bufsize = 0; stm->offset = 0; - if (tud_video_frame_xfer_complete_cb) { - tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); - } + tud_video_frame_xfer_complete_cb(stm->index_vc, stm->index_vs); } return true; } diff --git a/src/class/video/video_device.h b/src/class/video/video_device.h index 648a221d5..2b41c3bfe 100644 --- a/src/class/video/video_device.h +++ b/src/class/video/video_device.h @@ -61,7 +61,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu * * @param[in] ctl_idx Destination control interface index * @param[in] stm_idx Destination streaming interface index */ -TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); +void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx); //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -72,7 +72,7 @@ TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fa * @param[in] ctl_idx Destination control interface index * @param[in] stm_idx Destination streaming interface index * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); +int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod); /** Invoked when VS_COMMIT_CONTROL(SET_CUR) request received * @@ -80,7 +80,7 @@ TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod * @param[in] stm_idx Destination streaming interface index * @param[in] parameters Video streaming parameters * @return video_error_code_t */ -TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, +int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, video_probe_and_commit_control_t const *parameters); //--------------------------------------------------------------------+ |
