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;
}
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)
{
static uint32_t prev_cycles = 0;

Wyświetl plik

@ -27,6 +27,23 @@
#include "settings.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
//--------------------------------------------------------------------+
@ -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.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;
}
@ -125,57 +144,65 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
AIOC_DFU_RT_DESC_LEN \
)
uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(
/* config_num */ 1,
/* _itfcount */ ITF_NUM_TOTAL,
/* _stridx */ 0x00,
/* _total_len */ CONFIG_TOTAL_LEN,
/* _attribute */ 0x00,
/* _power_ma */ 100
),
AIOC_AUDIO_DESCRIPTOR(
/* _itfnum */ ITF_NUM_AUDIO_CONTROL,
/* _stridx */ STR_IDX_AUDIOITF,
/* _nBytesPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE,
/* _nBitsUsedPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8,
/* _epin */ EPNUM_AUDIO_IN,
/* _epinsize */ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX,
/* _epout */ EPNUM_AUDIO_OUT,
/* _epoutsize */ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX,
/* _epfb */ EPNUM_AUDIO_FB
),
AIOC_HID_DESCRIPTOR(
/* _itfnum */ ITF_NUM_HID,
/* _stridx */ STR_IDX_HIDITF,
/* _boot_protocol */HID_ITF_PROTOCOL_NONE,
/*_report_desc_len*/sizeof(desc_hid_report),
/* _epin */ EPNUM_HID_IN,
/* _epsize */ CFG_TUD_HID_EP_BUFSIZE,
/* _ep_interval */ 0x20
),
AIOC_CDC_DESCRIPTOR(
/* _itfnum */ ITF_NUM_CDC_0,
/* _stridx */ STR_IDX_CDCITF,
/* _ep_notif */ EPNUM_CDC_0_NOTIF,
/* _ep_notif_size */ 8,
/* _epout */ EPNUM_CDC_0_OUT,
/* _epin */ EPNUM_CDC_0_IN,
/* _epsize */ CFG_TUD_CDC_EP_BUFSIZE
),
AIOC_DFU_RT_DESCRIPTOR(
/* _itfnum */ ITF_NUM_DFU_RT,
/* _stridx */ STR_IDX_DFU_RT,
/* Make this as template, due to quirks necessary in feedback endpoint size */
#define CONFIG_DESC(_quirk) \
TUD_CONFIG_DESCRIPTOR( \
/* config_num */ 1, \
/* _itfcount */ ITF_NUM_TOTAL, \
/* _stridx */ 0x00, \
/* _total_len */ CONFIG_TOTAL_LEN, \
/* _attribute */ 0x00, \
/* _power_ma */ 100 \
), \
AIOC_AUDIO_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_AUDIO_CONTROL, \
/* _stridx */ STR_IDX_AUDIOITF, \
/* _nBytesPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE, \
/* _nBitsUsedPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8, \
/* _epin */ EPNUM_AUDIO_IN, \
/* _epinsize */ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX, \
/* _epout */ EPNUM_AUDIO_OUT, \
/* _epoutsize */ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, \
/* _epfb */ EPNUM_AUDIO_FB, \
/* epfbsize */ ((_quirk) ? 4 : 3) \
), \
AIOC_HID_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_HID, \
/* _stridx */ STR_IDX_HIDITF, \
/* _boot_protocol */HID_ITF_PROTOCOL_NONE, \
/*_report_desc_len*/sizeof(desc_hid_report), \
/* _epin */ EPNUM_HID_IN, \
/* _epsize */ CFG_TUD_HID_EP_BUFSIZE, \
/* _ep_interval */ 0x20 \
), \
AIOC_CDC_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_CDC_0, \
/* _stridx */ STR_IDX_CDCITF, \
/* _ep_notif */ EPNUM_CDC_0_NOTIF, \
/* _ep_notif_size */ 8, \
/* _epout */ EPNUM_CDC_0_OUT, \
/* _epin */ EPNUM_CDC_0_IN, \
/* _epsize */ CFG_TUD_CDC_EP_BUFSIZE \
), \
AIOC_DFU_RT_DESCRIPTOR( \
/* _itfnum */ ITF_NUM_DFU_RT, \
/* _stridx */ STR_IDX_DFU_RT, \
/* _attr */ DFU_ATTR_WILL_DETACH | \
DFU_ATTR_CAN_UPLOAD | \
DFU_ATTR_CAN_DOWNLOAD,
/* _timeout */ 255, /* not used if WILL_DETACH */
/* _xfer_size */ 2048 /* max size for stm32 dfu bootloader */
DFU_ATTR_CAN_DOWNLOAD, \
/* _timeout */ 255, /* not used if WILL_DETACH */ \
/* _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
@ -185,7 +212,15 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
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;
}
}
//--------------------------------------------------------------------+
@ -312,5 +347,18 @@ const uint16_t * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
buffer[0] = len + 2;
buffer[1] = TUSB_DESC_STRING;
quirk_host_os_hint_desc_cb(TUSB_DESC_STRING);
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_
#define USB_DESCRIPTORS_H_
#include <stdbool.h>
/* Interfaces */
enum USB_DESCRIPTORS_ITF {
ITF_NUM_AUDIO_CONTROL = 0,
@ -104,7 +106,7 @@ enum USB_STRING_IDX {
TUD_AUDIO_DESC_STD_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) */ \
TUD_AUDIO_DESC_IAD(_itfnum, AUDIO_NUM_INTERFACES, /*_stridx*/ 0x00), \
/* Audio Control Interface */ \
@ -138,7 +140,7 @@ enum USB_STRING_IDX {
/* 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), \
/* 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 */ \
/* Standard AS Interface Descriptor(4.9.1) */ \
/* 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
bool USB_DescUAC2Quirk(void);
#endif /* USB_DESCRIPTORS_H_ */