|
|
|
@@ -36,14 +36,6 @@
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// MACRO CONSTANT TYPEDEF
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
#ifndef CFG_TUH_MAX_CABLES
|
|
|
|
|
#define CFG_TUH_MAX_CABLES 16
|
|
|
|
|
#endif
|
|
|
|
|
#define CFG_TUH_MIDI_RX_BUFSIZE 64
|
|
|
|
|
#define CFG_TUH_MIDI_TX_BUFSIZE 64
|
|
|
|
|
#ifndef CFG_TUH_MIDI_EP_BUFSIZE
|
|
|
|
|
#define CFG_TUH_MIDI_EP_BUFSIZE 64
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// TODO: refactor to share code with the MIDI Device driver
|
|
|
|
|
typedef struct
|
|
|
|
@@ -117,34 +109,44 @@ typedef struct
|
|
|
|
|
#endif
|
|
|
|
|
}midih_interface_t;
|
|
|
|
|
|
|
|
|
|
static midih_interface_t _midi_host[CFG_TUH_DEVICE_MAX];
|
|
|
|
|
|
|
|
|
|
static midih_interface_t *get_midi_host(uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
TU_VERIFY(dev_addr >0 && dev_addr <= CFG_TUH_DEVICE_MAX);
|
|
|
|
|
return (_midi_host + dev_addr - 1);
|
|
|
|
|
}
|
|
|
|
|
static midih_interface_t _midi_host[CFG_TUH_MIDI];
|
|
|
|
|
|
|
|
|
|
//------------- Internal prototypes -------------//
|
|
|
|
|
static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi);
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// Helper
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_midi_by_daddr(uint8_t dev_addr) {
|
|
|
|
|
for (uint8_t i = 0; i < CFG_TUH_MIDI; i++) {
|
|
|
|
|
if (_midi_host[i].dev_addr == dev_addr) {
|
|
|
|
|
return &_midi_host[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TU_ATTR_ALWAYS_INLINE static inline midih_interface_t* find_new_midi(void) {
|
|
|
|
|
return find_midi_by_daddr(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// USBH API
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
bool midih_init(void)
|
|
|
|
|
{
|
|
|
|
|
bool midih_init(void) {
|
|
|
|
|
tu_memclr(&_midi_host, sizeof(_midi_host));
|
|
|
|
|
// config fifos
|
|
|
|
|
for (int inst = 0; inst < CFG_TUH_DEVICE_MAX; inst++)
|
|
|
|
|
{
|
|
|
|
|
for (int inst = 0; inst < CFG_TUH_MIDI; inst++) {
|
|
|
|
|
midih_interface_t *p_midi_host = &_midi_host[inst];
|
|
|
|
|
tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false); // true, true
|
|
|
|
|
tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false); // OBVS.
|
|
|
|
|
tu_fifo_config(&p_midi_host->rx_ff, p_midi_host->rx_ff_buf, CFG_TUH_MIDI_RX_BUFSIZE, 1, false);// true, true
|
|
|
|
|
tu_fifo_config(&p_midi_host->tx_ff, p_midi_host->tx_ff_buf, CFG_TUH_MIDI_TX_BUFSIZE, 1, false);// OBVS.
|
|
|
|
|
|
|
|
|
|
#if CFG_FIFO_MUTEX
|
|
|
|
|
#if CFG_FIFO_MUTEX
|
|
|
|
|
tu_fifo_config_mutex(&p_midi_host->rx_ff, NULL, osal_mutex_create(&p_midi_host->rx_ff_mutex));
|
|
|
|
|
tu_fifo_config_mutex(&p_midi_host->tx_ff, osal_mutex_create(&p_midi_host->tx_ff_mutex), NULL);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@@ -152,7 +154,7 @@ bool midih_init(void)
|
|
|
|
|
bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
|
|
|
|
{
|
|
|
|
|
(void)result;
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
if ( ep_addr == p_midi_host->ep_in)
|
|
|
|
|
{
|
|
|
|
@@ -211,13 +213,14 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void midih_close(uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
if (p_midi_host == NULL)
|
|
|
|
|
void midih_close(uint8_t dev_addr) {
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
if (p_midi_host == NULL) {
|
|
|
|
|
return;
|
|
|
|
|
if (tuh_midi_umount_cb)
|
|
|
|
|
}
|
|
|
|
|
if (tuh_midi_umount_cb) {
|
|
|
|
|
tuh_midi_umount_cb(dev_addr, 0);
|
|
|
|
|
}
|
|
|
|
|
tu_fifo_clear(&p_midi_host->rx_ff);
|
|
|
|
|
tu_fifo_clear(&p_midi_host->tx_ff);
|
|
|
|
|
p_midi_host->ep_in = 0;
|
|
|
|
@@ -240,24 +243,24 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
|
|
|
|
|
{
|
|
|
|
|
(void) rhport;
|
|
|
|
|
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
|
|
|
|
|
midih_interface_t *p_midi_host = find_new_midi();
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
|
|
|
|
|
p_midi_host->num_string_indices = 0;
|
|
|
|
|
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
|
|
|
|
|
uint8_t const *p_desc = (uint8_t const *) desc_itf;
|
|
|
|
|
uint16_t len_parsed = 0;
|
|
|
|
|
if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass)
|
|
|
|
|
{
|
|
|
|
|
if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) {
|
|
|
|
|
// Keep track of any string descriptor that might be here
|
|
|
|
|
if (desc_itf->iInterface != 0)
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface;
|
|
|
|
|
if (desc_itf->iInterface != 0) {
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface;
|
|
|
|
|
}
|
|
|
|
|
// 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))
|
|
|
|
|
{
|
|
|
|
|
while (len_parsed < max_len &&
|
|
|
|
|
(desc_itf->bInterfaceClass != TUSB_CLASS_AUDIO || desc_itf->bInterfaceSubClass != AUDIO_SUBCLASS_MIDI_STREAMING)) {
|
|
|
|
|
len_parsed += desc_itf->bLength;
|
|
|
|
|
p_desc = tu_desc_next(p_desc);
|
|
|
|
|
desc_itf = (tusb_desc_interface_t const *)p_desc;
|
|
|
|
@@ -269,8 +272,9 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
|
|
|
|
|
len_parsed += desc_itf->bLength;
|
|
|
|
|
|
|
|
|
|
// Keep track of any string descriptor that might be here
|
|
|
|
|
if (desc_itf->iInterface != 0)
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface;
|
|
|
|
|
if (desc_itf->iInterface != 0) {
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = desc_itf->iInterface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_desc = tu_desc_next(p_desc);
|
|
|
|
|
TU_LOG1("MIDI opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
|
|
|
|
@@ -282,195 +286,169 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
|
|
|
|
|
// assume it is an interface header
|
|
|
|
|
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) ||
|
|
|
|
|
(p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) ||
|
|
|
|
|
p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT);
|
|
|
|
|
(p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT && p_mdh->bDescriptorSubType == MIDI_CS_ENDPOINT_GENERAL) ||
|
|
|
|
|
p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT);
|
|
|
|
|
|
|
|
|
|
uint8_t prev_ep_addr = 0; // the CS endpoint descriptor is associated with the previous endpoint descriptor
|
|
|
|
|
p_midi_host->itf_num = desc_itf->bInterfaceNumber;
|
|
|
|
|
tusb_desc_endpoint_t const* in_desc = NULL;
|
|
|
|
|
tusb_desc_endpoint_t const* out_desc = NULL;
|
|
|
|
|
while (len_parsed < max_len)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
(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)
|
|
|
|
|
{
|
|
|
|
|
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_LOG2("Found MIDI Interface Header\r\b");
|
|
|
|
|
}
|
|
|
|
|
else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK)
|
|
|
|
|
{
|
|
|
|
|
} else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_IN_JACK) {
|
|
|
|
|
// Then it is an in jack.
|
|
|
|
|
TU_LOG2("Found in jack\r\n");
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
if (p_midi_host->next_in_jack < MAX_IN_JACKS)
|
|
|
|
|
{
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
if (p_midi_host->next_in_jack < MAX_IN_JACKS) {
|
|
|
|
|
p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_id = p_mdij->bJackID;
|
|
|
|
|
p_midi_host->in_jack_info[p_midi_host->next_in_jack].jack_type = p_mdij->bJackType;
|
|
|
|
|
p_midi_host->in_jack_info[p_midi_host->next_in_jack].string_index = p_mdij->iJack;
|
|
|
|
|
++p_midi_host->next_in_jack;
|
|
|
|
|
// Keep track of any string descriptor that might be here
|
|
|
|
|
if (p_mdij->iJack != 0)
|
|
|
|
|
if (p_mdij->iJack != 0) {
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdij->iJack;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK)
|
|
|
|
|
{
|
|
|
|
|
#endif
|
|
|
|
|
} else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_OUT_JACK) {
|
|
|
|
|
// then it is an out jack
|
|
|
|
|
TU_LOG2("Found out jack\r\n");
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
if (p_midi_host->next_out_jack < MAX_OUT_JACKS)
|
|
|
|
|
{
|
|
|
|
|
midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *)p_desc;
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
if (p_midi_host->next_out_jack < MAX_OUT_JACKS) {
|
|
|
|
|
midi_desc_out_jack_t const *p_mdoj = (midi_desc_out_jack_t const *) p_desc;
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_id = p_mdoj->bJackID;
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].jack_type = p_mdoj->bJackType;
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].num_source_ids = p_mdoj->bNrInputPins;
|
|
|
|
|
const struct associated_jack_s {
|
|
|
|
|
uint8_t id;
|
|
|
|
|
uint8_t pin;
|
|
|
|
|
} *associated_jack = (const struct associated_jack_s *)(p_desc+6);
|
|
|
|
|
uint8_t id;
|
|
|
|
|
uint8_t pin;
|
|
|
|
|
} *associated_jack = (const struct associated_jack_s *) (p_desc + 6);
|
|
|
|
|
int jack;
|
|
|
|
|
for (jack = 0; jack < p_mdoj->bNrInputPins; jack++)
|
|
|
|
|
{
|
|
|
|
|
for (jack = 0; jack < p_mdoj->bNrInputPins; jack++) {
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].source_ids[jack] = associated_jack->id;
|
|
|
|
|
}
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc+6+p_mdoj->bNrInputPins*2);
|
|
|
|
|
p_midi_host->out_jack_info[p_midi_host->next_out_jack].string_index = *(p_desc + 6 + p_mdoj->bNrInputPins * 2);
|
|
|
|
|
++p_midi_host->next_out_jack;
|
|
|
|
|
if (p_mdoj->iJack != 0)
|
|
|
|
|
if (p_mdoj->iJack != 0) {
|
|
|
|
|
p_midi_host->all_string_indices[p_midi_host->num_string_indices++] = p_mdoj->iJack;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT)
|
|
|
|
|
{
|
|
|
|
|
#endif
|
|
|
|
|
} else if (p_mdij->bDescriptorSubType == MIDI_CS_INTERFACE_ELEMENT) {
|
|
|
|
|
// the it is an element;
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
TU_LOG1("Found element; strings not supported\r\n");
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
TU_LOG2("Found element\r\n");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
TU_LOG2("Unknown CS Interface sub-type %u\r\n", p_mdij->bDescriptorSubType);
|
|
|
|
|
TU_VERIFY(false); // unknown CS Interface sub-type
|
|
|
|
|
TU_VERIFY(false);// unknown CS Interface sub-type
|
|
|
|
|
}
|
|
|
|
|
len_parsed += p_mdij->bLength;
|
|
|
|
|
}
|
|
|
|
|
else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT)
|
|
|
|
|
{
|
|
|
|
|
} else if (p_mdh->bDescriptorType == TUSB_DESC_CS_ENDPOINT) {
|
|
|
|
|
TU_LOG2("found CS_ENDPOINT Descriptor for %u\r\n", prev_ep_addr);
|
|
|
|
|
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_cs_desc_endpoint_t const* p_csep = (midi_cs_desc_endpoint_t const*)p_mdh;
|
|
|
|
|
if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT)
|
|
|
|
|
{
|
|
|
|
|
midi_cs_desc_endpoint_t const *p_csep = (midi_cs_desc_endpoint_t const *) p_mdh;
|
|
|
|
|
if (tu_edpt_dir(prev_ep_addr) == TUSB_DIR_OUT) {
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_out == prev_ep_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host->num_cables_tx == 0);
|
|
|
|
|
p_midi_host->num_cables_tx = p_csep->bNumEmbMIDIJack;
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
uint8_t jack;
|
|
|
|
|
uint8_t max_jack = p_midi_host->num_cables_tx;
|
|
|
|
|
if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks))
|
|
|
|
|
{
|
|
|
|
|
max_jack = sizeof(p_midi_host->ep_out_associated_jacks);
|
|
|
|
|
if (max_jack > sizeof(p_midi_host->ep_out_associated_jacks)) {
|
|
|
|
|
max_jack = sizeof(p_midi_host->ep_out_associated_jacks);
|
|
|
|
|
}
|
|
|
|
|
for (jack = 0; jack < max_jack; jack++)
|
|
|
|
|
{
|
|
|
|
|
for (jack = 0; jack < max_jack; jack++) {
|
|
|
|
|
p_midi_host->ep_out_associated_jacks[jack] = p_csep->baAssocJackID[jack];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_in == prev_ep_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host->num_cables_rx == 0);
|
|
|
|
|
p_midi_host->num_cables_rx = p_csep->bNumEmbMIDIJack;
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
#if CFG_MIDI_HOST_DEVSTRINGS
|
|
|
|
|
uint8_t jack;
|
|
|
|
|
uint8_t max_jack = p_midi_host->num_cables_rx;
|
|
|
|
|
if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks))
|
|
|
|
|
{
|
|
|
|
|
max_jack = sizeof(p_midi_host->ep_in_associated_jacks);
|
|
|
|
|
if (max_jack > sizeof(p_midi_host->ep_in_associated_jacks)) {
|
|
|
|
|
max_jack = sizeof(p_midi_host->ep_in_associated_jacks);
|
|
|
|
|
}
|
|
|
|
|
for (jack = 0; jack < max_jack; jack++)
|
|
|
|
|
{
|
|
|
|
|
for (jack = 0; jack < max_jack; jack++) {
|
|
|
|
|
p_midi_host->ep_in_associated_jacks[jack] = p_csep->baAssocJackID[jack];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
len_parsed += p_csep->bLength;
|
|
|
|
|
prev_ep_addr = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (p_mdh->bDescriptorType == TUSB_DESC_ENDPOINT) {
|
|
|
|
|
} 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;
|
|
|
|
|
tusb_desc_endpoint_t const *p_ep = (tusb_desc_endpoint_t const *) p_mdh;
|
|
|
|
|
TU_LOG2("found ENDPOINT Descriptor for %u\r\n", p_ep->bEndpointAddress);
|
|
|
|
|
if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT)
|
|
|
|
|
{
|
|
|
|
|
if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) {
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_out == 0);
|
|
|
|
|
TU_VERIFY(p_midi_host->num_cables_tx == 0);
|
|
|
|
|
p_midi_host->ep_out = p_ep->bEndpointAddress;
|
|
|
|
|
p_midi_host->ep_out_max = p_ep->wMaxPacketSize;
|
|
|
|
|
if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE)
|
|
|
|
|
if (p_midi_host->ep_out_max > CFG_TUH_MIDI_TX_BUFSIZE) {
|
|
|
|
|
p_midi_host->ep_out_max = CFG_TUH_MIDI_TX_BUFSIZE;
|
|
|
|
|
}
|
|
|
|
|
prev_ep_addr = p_midi_host->ep_out;
|
|
|
|
|
out_desc = p_ep;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
} else {
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_in == 0);
|
|
|
|
|
TU_VERIFY(p_midi_host->num_cables_rx == 0);
|
|
|
|
|
p_midi_host->ep_in = p_ep->bEndpointAddress;
|
|
|
|
|
p_midi_host->ep_in_max = p_ep->wMaxPacketSize;
|
|
|
|
|
if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE)
|
|
|
|
|
if (p_midi_host->ep_in_max > CFG_TUH_MIDI_RX_BUFSIZE) {
|
|
|
|
|
p_midi_host->ep_in_max = CFG_TUH_MIDI_RX_BUFSIZE;
|
|
|
|
|
}
|
|
|
|
|
prev_ep_addr = p_midi_host->ep_in;
|
|
|
|
|
in_desc = p_ep;
|
|
|
|
|
}
|
|
|
|
|
len_parsed += p_mdh->bLength;
|
|
|
|
|
}
|
|
|
|
|
p_desc = tu_desc_next(p_desc);
|
|
|
|
|
p_mdh = (midi_desc_header_t const *)p_desc;
|
|
|
|
|
p_mdh = (midi_desc_header_t const *) p_desc;
|
|
|
|
|
}
|
|
|
|
|
TU_VERIFY((p_midi_host->ep_out != 0 && p_midi_host->num_cables_tx != 0) ||
|
|
|
|
|
(p_midi_host->ep_in != 0 && p_midi_host->num_cables_rx != 0));
|
|
|
|
|
TU_LOG1("MIDI descriptor parsed successfully\r\n");
|
|
|
|
|
// remove duplicate string indices
|
|
|
|
|
for (int idx=0; idx < p_midi_host->num_string_indices; idx++) {
|
|
|
|
|
for (int jdx = idx+1; jdx < p_midi_host->num_string_indices; jdx++) {
|
|
|
|
|
while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) {
|
|
|
|
|
// delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1
|
|
|
|
|
p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices-1];
|
|
|
|
|
--p_midi_host->num_string_indices;
|
|
|
|
|
}
|
|
|
|
|
for (int idx = 0; idx < p_midi_host->num_string_indices; idx++) {
|
|
|
|
|
for (int jdx = idx + 1; jdx < p_midi_host->num_string_indices; jdx++) {
|
|
|
|
|
while (jdx < p_midi_host->num_string_indices && p_midi_host->all_string_indices[idx] == p_midi_host->all_string_indices[jdx]) {
|
|
|
|
|
// delete the duplicate by overwriting it with the last entry and reducing the number of entries by 1
|
|
|
|
|
p_midi_host->all_string_indices[jdx] = p_midi_host->all_string_indices[p_midi_host->num_string_indices - 1];
|
|
|
|
|
--p_midi_host->num_string_indices;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (in_desc)
|
|
|
|
|
{
|
|
|
|
|
if (in_desc) {
|
|
|
|
|
TU_ASSERT(tuh_edpt_open(dev_addr, in_desc));
|
|
|
|
|
// Some devices always return exactly the request length so transfers won't complete
|
|
|
|
|
// unless you assume every transfer is the last one.
|
|
|
|
|
// TODO usbh_edpt_force_last_buffer(dev_addr, p_midi_host->ep_in, true);
|
|
|
|
|
}
|
|
|
|
|
if (out_desc)
|
|
|
|
|
{
|
|
|
|
|
if (out_desc) {
|
|
|
|
|
TU_ASSERT(tuh_edpt_open(dev_addr, out_desc));
|
|
|
|
|
}
|
|
|
|
|
p_midi_host->dev_addr = dev_addr;
|
|
|
|
|
|
|
|
|
|
if (tuh_midi_mount_cb)
|
|
|
|
|
{
|
|
|
|
|
if (tuh_midi_mount_cb) {
|
|
|
|
|
tuh_midi_mount_cb(dev_addr, p_midi_host->ep_in, p_midi_host->ep_out, p_midi_host->num_cables_rx, p_midi_host->num_cables_tx);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
@@ -478,7 +456,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d
|
|
|
|
|
|
|
|
|
|
bool tuh_midi_configured(uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
return p_midi_host->configured;
|
|
|
|
|
}
|
|
|
|
@@ -486,7 +464,7 @@ bool tuh_midi_configured(uint8_t dev_addr)
|
|
|
|
|
bool midih_set_config(uint8_t dev_addr, uint8_t itf_num)
|
|
|
|
|
{
|
|
|
|
|
(void) itf_num;
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
p_midi_host->configured = true;
|
|
|
|
|
|
|
|
|
@@ -498,43 +476,36 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num)
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// Stream API
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi)
|
|
|
|
|
{
|
|
|
|
|
static uint32_t write_flush(uint8_t dev_addr, midih_interface_t* midi) {
|
|
|
|
|
// No data to send
|
|
|
|
|
if ( !tu_fifo_count(&midi->tx_ff) ) return 0;
|
|
|
|
|
if ( !tu_fifo_count(&midi->tx_ff) ) { return 0; }
|
|
|
|
|
|
|
|
|
|
// skip if previous transfer not complete
|
|
|
|
|
TU_VERIFY( usbh_edpt_claim(dev_addr, midi->ep_out) );
|
|
|
|
|
|
|
|
|
|
uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epout_buf, midi->ep_out_max);
|
|
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
|
{
|
|
|
|
|
TU_ASSERT( usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0 );
|
|
|
|
|
if (count) {
|
|
|
|
|
TU_ASSERT(usbh_edpt_xfer(dev_addr, midi->ep_out, midi->epout_buf, count), 0);
|
|
|
|
|
return count;
|
|
|
|
|
}else
|
|
|
|
|
{
|
|
|
|
|
} else {
|
|
|
|
|
// Release endpoint since we don't make any transfer
|
|
|
|
|
usbh_edpt_release(dev_addr, midi->ep_out);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool tuh_midi_read_poll( uint8_t dev_addr )
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
bool tuh_midi_read_poll(uint8_t dev_addr) {
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
bool in_edpt_not_busy = !usbh_edpt_busy(dev_addr, p_midi_host->ep_in);
|
|
|
|
|
if (in_edpt_not_busy)
|
|
|
|
|
{
|
|
|
|
|
if (in_edpt_not_busy) {
|
|
|
|
|
TU_LOG2("Requesting poll IN endpoint %d\r\n", p_midi_host->ep_in);
|
|
|
|
|
TU_ASSERT(usbh_edpt_xfer(p_midi_host->dev_addr, p_midi_host->ep_in, p_midi_host->epin_buf, p_midi_host->ep_in_max), 0);
|
|
|
|
|
result = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
} else {
|
|
|
|
|
// Maybe the IN endpoint is only busy because the RP2040 host hardware
|
|
|
|
|
// is retrying a NAK'd IN transfer forever. Try aborting the NAK'd
|
|
|
|
|
// transfer to allow other transfers to happen on the one shared
|
|
|
|
@@ -546,7 +517,7 @@ bool tuh_midi_read_poll( uint8_t dev_addr )
|
|
|
|
|
|
|
|
|
|
uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
TU_VERIFY(cable_num < p_midi_host->num_cables_tx);
|
|
|
|
|
midi_stream_t *stream = &p_midi_host->stream_write;
|
|
|
|
@@ -673,7 +644,7 @@ uint32_t tuh_midi_stream_write (uint8_t dev_addr, uint8_t cable_num, uint8_t con
|
|
|
|
|
|
|
|
|
|
bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4])
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
|
|
|
|
|
if (tu_fifo_remaining(&p_midi_host->tx_ff) < 4)
|
|
|
|
@@ -688,7 +659,7 @@ bool tuh_midi_packet_write (uint8_t dev_addr, uint8_t const packet[4])
|
|
|
|
|
|
|
|
|
|
uint32_t tuh_midi_stream_flush( uint8_t dev_addr )
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
|
|
|
|
|
uint32_t bytes_flushed = 0;
|
|
|
|
@@ -703,7 +674,7 @@ uint32_t tuh_midi_stream_flush( uint8_t dev_addr )
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_out != 0); // returns 0 if fails
|
|
|
|
|
return p_midi_host->num_cables_tx;
|
|
|
|
@@ -711,7 +682,7 @@ uint8_t tuh_midih_get_num_tx_cables (uint8_t dev_addr)
|
|
|
|
|
|
|
|
|
|
uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
TU_VERIFY(p_midi_host->ep_in != 0); // returns 0 if fails
|
|
|
|
|
return p_midi_host->num_cables_rx;
|
|
|
|
@@ -719,7 +690,7 @@ uint8_t tuh_midih_get_num_rx_cables (uint8_t dev_addr)
|
|
|
|
|
|
|
|
|
|
bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4])
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
TU_VERIFY(tu_fifo_count(&p_midi_host->rx_ff) >= 4);
|
|
|
|
|
return tu_fifo_read_n(&p_midi_host->rx_ff, packet, 4) == 4;
|
|
|
|
@@ -727,7 +698,7 @@ bool tuh_midi_packet_read (uint8_t dev_addr, uint8_t packet[4])
|
|
|
|
|
|
|
|
|
|
uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *p_buffer, uint16_t bufsize)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
uint32_t bytes_buffered = 0;
|
|
|
|
|
TU_ASSERT(p_cable_num);
|
|
|
|
@@ -848,7 +819,7 @@ uint32_t tuh_midi_stream_read (uint8_t dev_addr, uint8_t *p_cable_num, uint8_t *
|
|
|
|
|
|
|
|
|
|
uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
uint8_t num_cables = 0;
|
|
|
|
|
if (p_midi_host)
|
|
|
|
@@ -860,7 +831,7 @@ uint8_t tuh_midi_get_num_rx_cables(uint8_t dev_addr)
|
|
|
|
|
|
|
|
|
|
uint8_t tuh_midi_get_num_tx_cables(uint8_t dev_addr)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
uint8_t num_cables = 0;
|
|
|
|
|
if (p_midi_host)
|
|
|
|
@@ -897,7 +868,7 @@ static uint8_t find_string_index(midih_interface_t *ptr, uint8_t jack_id)
|
|
|
|
|
uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings)
|
|
|
|
|
{
|
|
|
|
|
uint8_t nstrings = 0;
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
nstrings = p_midi_host->num_cables_rx;
|
|
|
|
|
if (nstrings > max_istrings)
|
|
|
|
@@ -916,7 +887,7 @@ uint8_t tuh_midi_get_rx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint
|
|
|
|
|
uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint8_t max_istrings)
|
|
|
|
|
{
|
|
|
|
|
uint8_t nstrings = 0;
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
nstrings = p_midi_host->num_cables_tx;
|
|
|
|
|
if (nstrings > max_istrings)
|
|
|
|
@@ -935,7 +906,7 @@ uint8_t tuh_midi_get_tx_cable_istrings(uint8_t dev_addr, uint8_t* istrings, uint
|
|
|
|
|
|
|
|
|
|
uint8_t tuh_midi_get_all_istrings(uint8_t dev_addr, const uint8_t** istrings)
|
|
|
|
|
{
|
|
|
|
|
midih_interface_t *p_midi_host = get_midi_host(dev_addr);
|
|
|
|
|
midih_interface_t *p_midi_host = find_midi_by_daddr(dev_addr);
|
|
|
|
|
TU_VERIFY(p_midi_host != NULL);
|
|
|
|
|
uint8_t nstrings = p_midi_host->num_string_indices;
|
|
|
|
|
if (nstrings)
|
|
|
|
|