Implemented a rudimentary Host OS detection for better MacOS support for UAC2.0

pull/102/head
Simon Kueppers 2024-09-19 11:19:40 +02:00 zatwierdzone przez Simon Küppers
rodzic bb71ef3d28
commit ea57a6b2d9
3 zmienionych plików z 114 dodań i 51 usunięć

Wyświetl plik

@ -651,6 +651,17 @@ void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedba
feedback_param->method = AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED; feedback_param->method = AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED;
} }
bool tud_audio_feedback_format_correction_cb(uint8_t func_id)
{
/* Use the quirk detection to detect whether we need format correction (10.14) according to the USB specification (MacOS)
* or whether we use no correction (16.16) as a quirk (Windows). Linux works either way. */
if (tud_speed_get() == TUSB_SPEED_FULL) {
return USB_DescUAC2Quirk() ? false : true;
} else {
return false;
}
}
TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift)
{ {
static uint32_t prev_cycles = 0; static uint32_t prev_cycles = 0;

Wyświetl plik

@ -27,6 +27,23 @@
#include "settings.h" #include "settings.h"
#include "stm32f3xx_hal.h" #include "stm32f3xx_hal.h"
/* For quirk detection, borrowed from tinyusb uac2_speaker_fb example */
static tusb_desc_type_t desc_req_buf[2];
static int desc_req_idx = 0;
void quirk_host_os_hint_desc_cb(tusb_desc_type_t desc) {
if (desc == TUSB_DESC_DEVICE) {
desc_req_idx = 0;
} else if (desc_req_idx < 2 && (desc == TUSB_DESC_CONFIGURATION || desc == TUSB_DESC_BOS || desc == TUSB_DESC_STRING)) {
// Skip redundant request
if (desc_req_idx == 0 || (desc_req_idx > 0 && desc_req_buf[desc_req_idx - 1] != desc)) {
desc_req_buf[desc_req_idx++] = desc;
}
}
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Device Descriptors // Device Descriptors
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -54,6 +71,8 @@ uint8_t const* tud_descriptor_device_cb(void) {
desc_device.idVendor = (settingsRegMap[SETTINGS_REG_USBID] & SETTINGS_REG_USBID_VID_MASK) >> SETTINGS_REG_USBID_VID_OFFS; desc_device.idVendor = (settingsRegMap[SETTINGS_REG_USBID] & SETTINGS_REG_USBID_VID_MASK) >> SETTINGS_REG_USBID_VID_OFFS;
desc_device.idProduct = (settingsRegMap[SETTINGS_REG_USBID] & SETTINGS_REG_USBID_PID_MASK) >> SETTINGS_REG_USBID_PID_OFFS; desc_device.idProduct = (settingsRegMap[SETTINGS_REG_USBID] & SETTINGS_REG_USBID_PID_MASK) >> SETTINGS_REG_USBID_PID_OFFS;
quirk_host_os_hint_desc_cb(TUSB_DESC_DEVICE);
return (uint8_t const*) &desc_device; return (uint8_t const*) &desc_device;
} }
@ -125,57 +144,65 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
AIOC_DFU_RT_DESC_LEN \ AIOC_DFU_RT_DESC_LEN \
) )
uint8_t const desc_fs_configuration[] = { /* Make this as template, due to quirks necessary in feedback endpoint size */
// Config number, interface count, string index, total length, attribute, power in mA #define CONFIG_DESC(_quirk) \
TUD_CONFIG_DESCRIPTOR( TUD_CONFIG_DESCRIPTOR( \
/* config_num */ 1, /* config_num */ 1, \
/* _itfcount */ ITF_NUM_TOTAL, /* _itfcount */ ITF_NUM_TOTAL, \
/* _stridx */ 0x00, /* _stridx */ 0x00, \
/* _total_len */ CONFIG_TOTAL_LEN, /* _total_len */ CONFIG_TOTAL_LEN, \
/* _attribute */ 0x00, /* _attribute */ 0x00, \
/* _power_ma */ 100 /* _power_ma */ 100 \
), ), \
AIOC_AUDIO_DESCRIPTOR( \
AIOC_AUDIO_DESCRIPTOR( /* _itfnum */ ITF_NUM_AUDIO_CONTROL, \
/* _itfnum */ ITF_NUM_AUDIO_CONTROL, /* _stridx */ STR_IDX_AUDIOITF, \
/* _stridx */ STR_IDX_AUDIOITF, /* _nBytesPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE, \
/* _nBytesPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE, /* _nBitsUsedPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8, \
/* _nBitsUsedPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8, /* _epin */ EPNUM_AUDIO_IN, \
/* _epin */ EPNUM_AUDIO_IN, /* _epinsize */ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX, \
/* _epinsize */ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX, /* _epout */ EPNUM_AUDIO_OUT, \
/* _epout */ EPNUM_AUDIO_OUT, /* _epoutsize */ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, \
/* _epoutsize */ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, /* _epfb */ EPNUM_AUDIO_FB, \
/* _epfb */ EPNUM_AUDIO_FB /* epfbsize */ ((_quirk) ? 4 : 3) \
), ), \
AIOC_HID_DESCRIPTOR( AIOC_HID_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_HID, /* _itfnum */ ITF_NUM_HID, \
/* _stridx */ STR_IDX_HIDITF, /* _stridx */ STR_IDX_HIDITF, \
/* _boot_protocol */HID_ITF_PROTOCOL_NONE, /* _boot_protocol */HID_ITF_PROTOCOL_NONE, \
/*_report_desc_len*/sizeof(desc_hid_report), /*_report_desc_len*/sizeof(desc_hid_report), \
/* _epin */ EPNUM_HID_IN, /* _epin */ EPNUM_HID_IN, \
/* _epsize */ CFG_TUD_HID_EP_BUFSIZE, /* _epsize */ CFG_TUD_HID_EP_BUFSIZE, \
/* _ep_interval */ 0x20 /* _ep_interval */ 0x20 \
), ), \
AIOC_CDC_DESCRIPTOR( \
AIOC_CDC_DESCRIPTOR( /* _itfnum */ ITF_NUM_CDC_0, \
/* _itfnum */ ITF_NUM_CDC_0, /* _stridx */ STR_IDX_CDCITF, \
/* _stridx */ STR_IDX_CDCITF, /* _ep_notif */ EPNUM_CDC_0_NOTIF, \
/* _ep_notif */ EPNUM_CDC_0_NOTIF, /* _ep_notif_size */ 8, \
/* _ep_notif_size */ 8, /* _epout */ EPNUM_CDC_0_OUT, \
/* _epout */ EPNUM_CDC_0_OUT, /* _epin */ EPNUM_CDC_0_IN, \
/* _epin */ EPNUM_CDC_0_IN, /* _epsize */ CFG_TUD_CDC_EP_BUFSIZE \
/* _epsize */ CFG_TUD_CDC_EP_BUFSIZE ), \
), AIOC_DFU_RT_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_DFU_RT, \
AIOC_DFU_RT_DESCRIPTOR( /* _stridx */ STR_IDX_DFU_RT, \
/* _itfnum */ ITF_NUM_DFU_RT,
/* _stridx */ STR_IDX_DFU_RT,
/* _attr */ DFU_ATTR_WILL_DETACH | \ /* _attr */ DFU_ATTR_WILL_DETACH | \
DFU_ATTR_CAN_UPLOAD | \ DFU_ATTR_CAN_UPLOAD | \
DFU_ATTR_CAN_DOWNLOAD, DFU_ATTR_CAN_DOWNLOAD, \
/* _timeout */ 255, /* not used if WILL_DETACH */ /* _timeout */ 255, /* not used if WILL_DETACH */ \
/* _xfer_size */ 2048 /* max size for stm32 dfu bootloader */ /* _xfer_size */ 2048 /* max size for stm32 dfu bootloader */ \
) )
uint8_t const desc_fs_configuration_quirk[] = {
/* quirk is required for Windows, Linux doesn't care.
* (see https://github.com/hathach/tinyusb/pull/2328/commits/6a67bac47c0f83eebd63ca99654ed26e51b21145) */
CONFIG_DESC(/* quirk */1)
};
uint8_t const desc_fs_configuration[] = {
/* no quirk is required for MacOS, Linux doesn't care */
CONFIG_DESC(/* quirk */0)
}; };
// Invoked when received GET CONFIGURATION DESCRIPTOR // Invoked when received GET CONFIGURATION DESCRIPTOR
@ -185,8 +212,16 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations (void) index; // for multiple configurations
TU_ASSERT(!TUD_OPT_HIGH_SPEED); TU_ASSERT(!TUD_OPT_HIGH_SPEED);
quirk_host_os_hint_desc_cb(TUSB_DESC_CONFIGURATION);
/* Try to guess the host OS so we can apply the quirk where needed */
if (USB_DescUAC2Quirk()) {
return desc_fs_configuration_quirk;
} else {
return desc_fs_configuration; return desc_fs_configuration;
} }
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// String Descriptors // String Descriptors
@ -312,5 +347,18 @@ const uint16_t * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
buffer[0] = len + 2; buffer[0] = len + 2;
buffer[1] = TUSB_DESC_STRING; buffer[1] = TUSB_DESC_STRING;
quirk_host_os_hint_desc_cb(TUSB_DESC_STRING);
return (void *) buffer; return (void *) buffer;
} }
bool USB_DescUAC2Quirk(void)
{
if ( (desc_req_buf[0] == TUSB_DESC_STRING) && (desc_req_buf[1] == TUSB_DESC_BOS || desc_req_buf[1] == TUSB_DESC_CONFIGURATION) ) {
/* This pattern of descriptor requests is only found on MacOS devices. MacOS needs the non-quirked descriptor */
return false;
} else {
/* Other patterns hint to Windows, which requires the quirk. Or Linux, which doesn't care and works either way */
return true;
}
}

Wyświetl plik

@ -1,6 +1,8 @@
#ifndef USB_DESCRIPTORS_H_ #ifndef USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_ #define USB_DESCRIPTORS_H_
#include <stdbool.h>
/* Interfaces */ /* Interfaces */
enum USB_DESCRIPTORS_ITF { enum USB_DESCRIPTORS_ITF {
ITF_NUM_AUDIO_CONTROL = 0, ITF_NUM_AUDIO_CONTROL = 0,
@ -104,7 +106,7 @@ enum USB_STRING_IDX {
TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN + \ TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN + \
TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
#define AIOC_AUDIO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epinsize, _epout, _epoutsize, _epfb) \ #define AIOC_AUDIO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epinsize, _epout, _epoutsize, _epfb, _epfbsize) \
/* Standard Interface Association Descriptor (IAD) */ \ /* Standard Interface Association Descriptor (IAD) */ \
TUD_AUDIO_DESC_IAD(_itfnum, AUDIO_NUM_INTERFACES, /*_stridx*/ 0x00), \ TUD_AUDIO_DESC_IAD(_itfnum, AUDIO_NUM_INTERFACES, /*_stridx*/ 0x00), \
/* Audio Control Interface */ \ /* Audio Control Interface */ \
@ -138,7 +140,7 @@ enum USB_STRING_IDX {
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
TUD_AUDIO_DESC_CS_AS_ISO_EP(AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO_CTRL_NONE, AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, 0x0000), \ TUD_AUDIO_DESC_CS_AS_ISO_EP(AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO_CTRL_NONE, AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, 0x0000), \
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ \ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ \
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_epfb, 1), \ TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_epfb, _epfbsize, 1), \
/* Microphone Interface */ \ /* Microphone Interface */ \
/* Standard AS Interface Descriptor(4.9.1) */ \ /* Standard AS Interface Descriptor(4.9.1) */ \
/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \
@ -174,4 +176,6 @@ enum USB_STRING_IDX {
#define AIOC_DFU_RT_DESCRIPTOR TUD_DFU_RT_DESCRIPTOR #define AIOC_DFU_RT_DESCRIPTOR TUD_DFU_RT_DESCRIPTOR
bool USB_DescUAC2Quirk(void);
#endif /* USB_DESCRIPTORS_H_ */ #endif /* USB_DESCRIPTORS_H_ */