add tuh_midi_descriptor_cb()
This commit is contained in:
		| @@ -661,6 +661,7 @@ typedef struct TU_ATTR_PACKED | ||||
|   uint16_t wTotalLength      ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. | ||||
|   uint8_t bmControls         ; ///< See: audio_cs_ac_interface_control_pos_t. | ||||
| } audio_desc_cs_ac_interface_t; | ||||
| TU_VERIFY_STATIC(sizeof(audio_desc_cs_ac_interface_t) == 9, "size is not correct"); | ||||
|  | ||||
| /// AUDIO Clock Source Descriptor (4.7.2.1) | ||||
| typedef struct TU_ATTR_PACKED | ||||
|   | ||||
| @@ -628,10 +628,6 @@ static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio); | ||||
|  | ||||
| #if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING) | ||||
| static void audiod_parse_for_AS_params(audiod_function_t *audio, uint8_t const *p_desc, uint8_t const *p_desc_end, uint8_t const as_itf); | ||||
|  | ||||
| static inline uint8_t tu_desc_subtype(void const *desc) { | ||||
|   return ((uint8_t const *) desc)[2]; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL | ||||
|   | ||||
| @@ -150,27 +150,6 @@ typedef midi_desc_out_jack_n_t(1)  midi_desc_out_jack_1in_t; // 1 input | ||||
| typedef midi_desc_out_jack_1in_t midi_desc_out_jack_t; // backward compatible | ||||
| TU_VERIFY_STATIC(sizeof(midi_desc_out_jack_1in_t) == 7 + 2 * 1, "size is not correct"); | ||||
|  | ||||
| /// MIDI Element Descriptor | ||||
| typedef struct TU_ATTR_PACKED { | ||||
|   uint8_t bLength            ; ///< Size of this descriptor in bytes. | ||||
|   uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific | ||||
|   uint8_t bDescriptorSubType ; ///< Descriptor SubType | ||||
|   uint8_t bElementID; | ||||
|  | ||||
|   uint8_t bNrInputPins; | ||||
|   uint8_t baSourceID; | ||||
|   uint8_t baSourcePin; | ||||
|  | ||||
|   uint8_t bNrOutputPins; | ||||
|   uint8_t bInTerminalLink; | ||||
|   uint8_t bOutTerminalLink; | ||||
|   uint8_t bElCapsSize; | ||||
|  | ||||
|   uint16_t bmElementCaps; | ||||
|   uint8_t  iElement; | ||||
| } midi_desc_element_t; | ||||
| TU_VERIFY_STATIC(sizeof(midi_desc_element_t) == 14, "size is not correct"); | ||||
|  | ||||
| /// MIDI Element Descriptor with multiple pins | ||||
| #define midi_desc_element_n_t(input_num) \ | ||||
|   struct TU_ATTR_PACKED {       \ | ||||
|   | ||||
| @@ -194,123 +194,108 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d | ||||
|  | ||||
|   midih_interface_t *p_midi = find_new_midi(); | ||||
|   TU_VERIFY(p_midi != NULL); | ||||
|  | ||||
|   TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); | ||||
|   // There can be just a MIDI interface or an audio and a MIDI interface. Only open the MIDI interface | ||||
|  | ||||
|   // There can be just a MIDI or an Audio + MIDI interface | ||||
|   // const uint8_t* p_start = ((uint8_t const*) desc_itf); | ||||
|   const uint8_t* p_end = ((uint8_t const*) desc_itf) + max_len; | ||||
|   uint8_t const *p_desc = (uint8_t const *) desc_itf; | ||||
|   uint16_t len_parsed = 0; | ||||
|  | ||||
|   tuh_midi_descriptor_cb_t desc_cb = { 0 }; | ||||
|   desc_cb.jack_num = 0; | ||||
|  | ||||
|   // If there is Audio Control Interface + Audio Header descriptor, skip it | ||||
|   if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { | ||||
|     // This driver does not support audio streaming. However, if this is the audio control interface | ||||
|     // there might be a MIDI interface following it. Search through every descriptor until a MIDI | ||||
|     // interface is found or the end of the descriptor is found | ||||
|     while (len_parsed < max_len && | ||||
|           (desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) { | ||||
|       len_parsed += desc_itf->bLength; | ||||
|     TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t)); | ||||
|  | ||||
|     p_desc = tu_desc_next(p_desc); | ||||
|     TU_VERIFY(tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && | ||||
|               tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_HEADER); | ||||
|  | ||||
|     p_desc = tu_desc_next(p_desc); | ||||
|     desc_itf = (tusb_desc_interface_t const *)p_desc; | ||||
|     } | ||||
|  | ||||
|     TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); | ||||
|   } | ||||
|   TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass); | ||||
|   desc_cb.desc_interface = desc_itf; | ||||
|  | ||||
|   len_parsed += desc_itf->bLength; | ||||
|  | ||||
|   TU_LOG_DRV("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); | ||||
|   p_midi->itf_num = desc_itf->bInterfaceNumber; | ||||
|  | ||||
|   // CS Header descriptor | ||||
|   p_desc = tu_desc_next(p_desc); | ||||
|   midi_desc_header_t const *p_mdh = (midi_desc_header_t const *) p_desc; | ||||
|   TU_VERIFY(p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE && | ||||
|             p_mdh->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER); | ||||
|  | ||||
|   bool found_new_interface = false; | ||||
|   while ((p_desc < p_end) && (tu_desc_next(p_desc) <= p_end) && !found_new_interface) { | ||||
|     switch (tu_desc_type(p_desc)) { | ||||
|       case TUSB_DESC_INTERFACE: | ||||
|         found_new_interface = true; | ||||
|         break; | ||||
|  | ||||
|       case TUSB_DESC_CS_INTERFACE: | ||||
|         switch (tu_desc_subtype(p_desc)) { | ||||
|           case MIDI_CS_INTERFACE_HEADER: | ||||
|             TU_LOG_DRV("  Interface Header descriptor\r\n"); | ||||
|             desc_cb.desc_header = p_desc; | ||||
|             break; | ||||
|  | ||||
|   // p_desc = tu_desc_next(p_desc); | ||||
|   uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor | ||||
|   tusb_desc_endpoint_t const* in_desc = NULL; | ||||
|   tusb_desc_endpoint_t const* out_desc = NULL; | ||||
|   while (len_parsed < max_len) { | ||||
|     TU_VERIFY((p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) || | ||||
|               (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) || | ||||
|               p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT); | ||||
|  | ||||
|     if (p_mdh->bDescriptorType == TUSB_DESC_CS_INTERFACE) { | ||||
|       // The USB host doesn't really need this information unless it uses | ||||
|       // the string descriptor for a jack or Element | ||||
|  | ||||
|       // assume it is an input jack | ||||
|       midi_desc_in_jack_t const *p_mdij = (midi_desc_in_jack_t const *) p_desc; | ||||
|       if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_HEADER) { | ||||
|         TU_LOG_DRV("  Interface Header descriptor\r\n"); | ||||
|       } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) { | ||||
|         // Then it is an in jack. | ||||
|         TU_LOG_DRV("  IN Jack %s descriptor \r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); | ||||
|       } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) { | ||||
|         // then it is an out jack | ||||
|         TU_LOG_DRV("  OUT Jack %s descriptor\r\n", p_mdij->bJackType == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); | ||||
|       } else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) { | ||||
|         // the it is an element; | ||||
|         TU_LOG_DRV("Found element\r\n"); | ||||
|       } else { | ||||
|         TU_LOG_DRV("  Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType); | ||||
|         TU_VERIFY(false);// unknown CS Interface sub-type | ||||
|           case MIDI_CS_INTERFACE_IN_JACK: | ||||
|           case MIDI_CS_INTERFACE_OUT_JACK: { | ||||
|             TU_LOG_DRV("  Jack %s %s descriptor \r\n", | ||||
|                        tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_IN_JACK ? "IN" : "OUT", | ||||
|                        p_desc[3] == MIDI_JACK_EXTERNAL ? "External" : "Embedded"); | ||||
|             desc_cb.desc_jack[desc_cb.jack_num++] = p_desc; | ||||
|             break; | ||||
|           } | ||||
|       len_parsed += p_mdij->bLength; | ||||
|     } else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) { | ||||
|       TU_LOG_DRV("  CS_ENDPOINT descriptor\r\n"); | ||||
|       TU_VERIFY(prev_ep_addr != 0); | ||||
|       // parse out the mapping between the device's embedded jacks and the endpoints | ||||
|       // Each embedded IN jack is associated with an OUT endpoint | ||||
|       midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_mdh; | ||||
|       if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) { | ||||
|         TU_VERIFY(p_midi->ep_out == prev_ep_addr); | ||||
|         TU_VERIFY(p_midi->num_cables_tx == 0); | ||||
|         p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; | ||||
|       } else { | ||||
|         TU_VERIFY(p_midi->ep_in == prev_ep_addr); | ||||
|         TU_VERIFY(p_midi->num_cables_rx == 0); | ||||
|         p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; | ||||
|  | ||||
|           case MIDI_CS_INTERFACE_ELEMENT: | ||||
|             TU_LOG_DRV("  Element descriptor\r\n"); | ||||
|             desc_cb.desc_element = p_desc; | ||||
|             break; | ||||
|  | ||||
|           default: | ||||
|             TU_LOG_DRV("  Unknown CS Interface sub-type %u\r\n", tu_desc_subtype(p_desc)); | ||||
|             break; | ||||
|         } | ||||
|       len_parsed += p_csep->bLength; | ||||
|       prev_ep_addr = 0; | ||||
|     } else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) { | ||||
|       // parse out the bulk endpoint info | ||||
|       tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_mdh; | ||||
|       TU_LOG_DRV("  Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); | ||||
|         break; | ||||
|  | ||||
|       case TUSB_DESC_ENDPOINT: { | ||||
|         tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_desc; | ||||
|         p_desc = tu_desc_next(p_desc); // next to CS endpoint | ||||
|         TU_VERIFY(p_desc < p_end && tu_desc_next(p_desc) <= p_end); | ||||
|         midi_desc_cs_endpoint_t const *p_csep = (midi_desc_cs_endpoint_t const *) p_desc; | ||||
|  | ||||
|         TU_LOG_DRV("  Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); | ||||
|         if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { | ||||
|         TU_VERIFY(p_midi->ep_out == 0); | ||||
|         TU_VERIFY(p_midi->num_cables_tx == 0); | ||||
|           p_midi->ep_out = p_ep->bEndpointAddress; | ||||
|         prev_ep_addr = p_midi->ep_out; | ||||
|         out_desc = p_ep; | ||||
|           p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; | ||||
|           desc_cb.desc_epout = p_ep; | ||||
|  | ||||
|           TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); | ||||
|           tu_edpt_stream_open(&p_midi->ep_stream.tx, p_ep); | ||||
|         } else { | ||||
|         TU_VERIFY(p_midi->ep_in == 0); | ||||
|         TU_VERIFY(p_midi->num_cables_rx == 0); | ||||
|           p_midi->ep_in = p_ep->bEndpointAddress; | ||||
|         prev_ep_addr = p_midi->ep_in; | ||||
|         in_desc = p_ep; | ||||
|           p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; | ||||
|           desc_cb.desc_epin = p_ep; | ||||
|  | ||||
|           TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); | ||||
|           tu_edpt_stream_open(&p_midi->ep_stream.rx, p_ep); | ||||
|         } | ||||
|       len_parsed += p_mdh->bLength; | ||||
|         break; | ||||
|       } | ||||
|  | ||||
|       default: break; // skip unknown descriptor | ||||
|     } | ||||
|     p_desc = tu_desc_next(p_desc); | ||||
|     p_mdh = (midi_desc_header_t const *) p_desc; | ||||
|   } | ||||
|   TU_VERIFY((p_midi->ep_out != 0 && p_midi->num_cables_tx != 0) || | ||||
|             (p_midi->ep_in != 0 && p_midi->num_cables_rx != 0)); | ||||
|   desc_cb.desc_interface_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); | ||||
|  | ||||
|   if (in_desc) { | ||||
|     TU_ASSERT(tuh_edpt_open(dev_addr, in_desc)); | ||||
|     tu_edpt_stream_open(&p_midi->ep_stream.rx, in_desc); | ||||
|   } | ||||
|   if (out_desc) { | ||||
|     TU_ASSERT(tuh_edpt_open(dev_addr, out_desc)); | ||||
|     tu_edpt_stream_open(&p_midi->ep_stream.tx, out_desc); | ||||
|   } | ||||
|   p_midi->dev_addr = dev_addr; | ||||
|  | ||||
|   // if (tuh_midi_interface_descriptor_cb) { | ||||
|   //   tuh_midi_interface_descriptor_cb(dev_addr, desc_itf, ); | ||||
|   // } | ||||
|   if (tuh_midi_descriptor_cb) { | ||||
|     tuh_midi_descriptor_cb(dev_addr, &desc_cb); | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|   | ||||
| @@ -62,6 +62,18 @@ | ||||
| //--------------------------------------------------------------------+ | ||||
| // Application API | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct { | ||||
|   const tusb_desc_interface_t* desc_interface; // start of whole midi interface descriptor | ||||
|   uint16_t desc_interface_len; | ||||
|  | ||||
|   const uint8_t* desc_header; | ||||
|   const uint8_t* desc_element; | ||||
|   const tusb_desc_endpoint_t* desc_epin;  // endpoint IN descriptor, CS_ENDPOINT is right after | ||||
|   const tusb_desc_endpoint_t* desc_epout; // endpoint OUT descriptor, CS_ENDPOINT is right after | ||||
|  | ||||
|   uint8_t jack_num; | ||||
|   const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external) | ||||
| } tuh_midi_descriptor_cb_t; | ||||
|  | ||||
| // Check if MIDI interface is mounted | ||||
| bool tuh_midi_mounted(uint8_t dev_addr); | ||||
| @@ -134,7 +146,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t * | ||||
|  | ||||
| // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. | ||||
| // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. | ||||
| // TU_ATTR_WEAK void tuh_midi_interface_descriptor_cb(uint8_t dev_addr, const uint8_t* desc_itf, uint16_t desc_len); | ||||
| TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t dev_addr, tuh_midi_descriptor_cb_t const* desc_cb); | ||||
|  | ||||
| // Invoked when device with MIDI interface is mounted. | ||||
| TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t dev_addr, uint8_t num_cables_rx, uint16_t num_cables_tx); | ||||
|   | ||||
| @@ -281,7 +281,8 @@ typedef enum { | ||||
| // TODO remove | ||||
| enum { | ||||
|   DESC_OFFSET_LEN  = 0, | ||||
|   DESC_OFFSET_TYPE = 1 | ||||
|   DESC_OFFSET_TYPE = 1, | ||||
|   DESC_OFFSET_SUBTYPE = 2 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
| @@ -570,14 +571,19 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* des | ||||
|   return desc8 + desc8[DESC_OFFSET_LEN]; | ||||
| } | ||||
|  | ||||
| // get descriptor length | ||||
| TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { | ||||
|   return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; | ||||
| } | ||||
|  | ||||
| // get descriptor type | ||||
| TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) { | ||||
|   return ((uint8_t const*) desc)[DESC_OFFSET_TYPE]; | ||||
| } | ||||
|  | ||||
| // get descriptor length | ||||
| TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) { | ||||
|   return ((uint8_t const*) desc)[DESC_OFFSET_LEN]; | ||||
| // get descriptor subtype | ||||
| TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_subtype(void const* desc) { | ||||
|   return ((uint8_t const*) desc)[DESC_OFFSET_SUBTYPE]; | ||||
| } | ||||
|  | ||||
| // find descriptor that match byte1 (type) | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/tusb.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/tusb.c
									
									
									
									
									
								
							| @@ -142,7 +142,9 @@ void tusb_int_handler(uint8_t rhport, bool in_isr) { | ||||
|  | ||||
| uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1) { | ||||
|   while (desc + 1 < end) { | ||||
|     if (desc[1] == byte1) return desc; | ||||
|     if (desc[1] == byte1) { | ||||
|       return desc; | ||||
|     } | ||||
|     desc += desc[DESC_OFFSET_LEN]; | ||||
|   } | ||||
|   return NULL; | ||||
| @@ -150,7 +152,9 @@ uint8_t const* tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byt | ||||
|  | ||||
| uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2) { | ||||
|   while (desc + 2 < end) { | ||||
|     if (desc[1] == byte1 && desc[2] == byte2) return desc; | ||||
|     if (desc[1] == byte1 && desc[2] == byte2) { | ||||
|       return desc; | ||||
|     } | ||||
|     desc += desc[DESC_OFFSET_LEN]; | ||||
|   } | ||||
|   return NULL; | ||||
| @@ -158,7 +162,9 @@ uint8_t const* tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t by | ||||
|  | ||||
| uint8_t const* tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3) { | ||||
|   while (desc + 3 < end) { | ||||
|     if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) return desc; | ||||
|     if (desc[1] == byte1 && desc[2] == byte2 && desc[3] == byte3) { | ||||
|       return desc; | ||||
|     } | ||||
|     desc += desc[DESC_OFFSET_LEN]; | ||||
|   } | ||||
|   return NULL; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach