summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-07-28 13:23:48 +0200
committerHiFiPhile <[email protected]>2024-07-28 13:25:57 +0200
commit6a67bac47c0f83eebd63ca99654ed26e51b21145 (patch)
tree35eb6054b978b722090c2c654d724d2373585c3a
parent4a48544aebf362e77095c52ddcfcde6a65876acf (diff)
Integrate OS guessing quirk into uac2_speaker_fb example.
-rw-r--r--examples/device/uac2_speaker_fb/src/main.c16
-rw-r--r--examples/device/uac2_speaker_fb/src/quirk_os_guessing.c90
-rw-r--r--examples/device/uac2_speaker_fb/src/quirk_os_guessing.h75
-rw-r--r--examples/device/uac2_speaker_fb/src/tusb_config.h8
-rw-r--r--examples/device/uac2_speaker_fb/src/usb_descriptors.c67
5 files changed, 253 insertions, 3 deletions
diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c
index 8573dfa4c..0a8529a61 100644
--- a/examples/device/uac2_speaker_fb/src/main.c
+++ b/examples/device/uac2_speaker_fb/src/main.c
@@ -31,6 +31,10 @@
#include "usb_descriptors.h"
#include "common_types.h"
+#ifdef CFG_QUIRK_OS_GUESSING
+#include "quirk_os_guessing.h"
+#endif
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTOTYPES
//--------------------------------------------------------------------+
@@ -385,6 +389,18 @@ bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, u
return true;
}
#endif
+
+#if CFG_QUIRK_OS_GUESSING
+bool tud_audio_feedback_format_correction_cb(uint8_t func_id)
+{
+ (void)func_id;
+ if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) {
+ return true;
+ } else {
+ return false;
+ }
+}
+#endif
//--------------------------------------------------------------------+
// AUDIO Task
//--------------------------------------------------------------------+
diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
new file mode 100644
index 000000000..965bbd6cf
--- /dev/null
+++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
@@ -0,0 +1,90 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 HiFiPhile
+ *
+ * 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.
+ *
+ */
+
+#include "quirk_os_guessing.h"
+
+static tusb_desc_type_t desc_req_buf[2];
+static int desc_req_idx = 0;
+
+// Place at the start of tud_descriptor_device_cb()
+void quirk_os_guessing_desc_device_cb() {
+ desc_req_idx = 0;
+}
+
+// Place at the start of tud_descriptor_configuration_cb()
+void quirk_os_guessing_desc_configuration_cb() {
+ // Skip redundant request
+ if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) {
+ desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION;
+ }
+}
+
+// Place at the start of tud_descriptor_bos_cb()
+void quirk_os_guessing_desc_bos_cb() {
+ // Skip redundant request
+ if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) {
+ desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS;
+ }
+}
+
+// Place at the start of tud_descriptor_string_cb()
+void quirk_os_guessing_desc_string_cb() {
+ // Skip redundant request
+ if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) {
+ desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING;
+ }
+}
+
+// Each OS request descriptors differently:
+// Windows 10 - 11
+// Device Desc
+// Config Desc
+// BOS Desc
+// String Desc
+// Linux 3.16 - 6.8
+// Device Desc
+// BOS Desc
+// Config Desc
+// String Desc
+// OS X Ventura - Sonoma
+// Device Desc
+// String Desc
+// Config Desc || BOS Desc
+// BOS Desc || Config Desc
+quirk_os_guessing_t quirk_os_guessing_get(void) {
+ if (desc_req_idx < 2) {
+ return QUIRK_OS_GUESSING_UNKNOWN;
+ }
+
+ if (desc_req_buf[0] == TUSB_DESC_BOS && desc_req_buf[1] == TUSB_DESC_CONFIGURATION) {
+ return QUIRK_OS_GUESSING_LINUX;
+ } else if (desc_req_buf[0] == TUSB_DESC_CONFIGURATION && desc_req_buf[1] == TUSB_DESC_BOS) {
+ return QUIRK_OS_GUESSING_WINDOWS;
+ } else if (desc_req_buf[0] == TUSB_DESC_STRING && (desc_req_buf[1] == TUSB_DESC_BOS || desc_req_buf[1] == TUSB_DESC_CONFIGURATION)) {
+ return QUIRK_OS_GUESSING_OSX;
+ }
+
+ return QUIRK_OS_GUESSING_UNKNOWN;
+}
diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h
new file mode 100644
index 000000000..1120355c9
--- /dev/null
+++ b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h
@@ -0,0 +1,75 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 HiFiPhile
+ *
+ * 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.
+ *
+ */
+
+#ifndef _QUIRK_OS_GUESSING_H_
+#define _QUIRK_OS_GUESSING_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "tusb.h"
+
+//================================== !!! WARNING !!! ====================================
+// This quirk operate out of USB specification in order to workaround specific issues.
+// It may not work on your platform.
+//=======================================================================================
+//
+// Prerequisites:
+// - Set USB version to at least 2.01 in Device Descriptor
+// - Has a valid BOS Descriptor, refer to webusb_serial example
+//
+// Attention:
+// Windows detection result comes out after Configuration Descriptor request,
+// meaning it will be too late to do descriptor adjustment. It's advised to make
+// Windows as default configuration and adjust to other OS accordingly.
+
+typedef enum {
+ QUIRK_OS_GUESSING_UNKNOWN,
+ QUIRK_OS_GUESSING_LINUX,
+ QUIRK_OS_GUESSING_OSX,
+ QUIRK_OS_GUESSING_WINDOWS,
+} quirk_os_guessing_t;
+
+// Get Host OS type
+quirk_os_guessing_t quirk_os_guessing_get(void);
+
+// Place at the start of tud_descriptor_device_cb()
+void quirk_os_guessing_desc_device_cb(void);
+
+// Place at the start of tud_descriptor_configuration_cb()
+void quirk_os_guessing_desc_configuration_cb(void);
+
+// Place at the start of tud_descriptor_bos_cb()
+void quirk_os_guessing_desc_bos_cb(void);
+
+// Place at the start of tud_descriptor_string_cb()
+void quirk_os_guessing_desc_string_cb(void);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _QUIRK_OS_GUESSING_H_ */
diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h
index 1cc1031c1..fd4925c7f 100644
--- a/examples/device/uac2_speaker_fb/src/tusb_config.h
+++ b/examples/device/uac2_speaker_fb/src/tusb_config.h
@@ -87,6 +87,14 @@ extern "C" {
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
+/* (Needed for Full-Speed only)
+ * Enable host OS guessing to workaround UAC2 compatibility issues between Windows and OS X
+ * The default configuration only support Windows and Linux, enable this option for OS X
+ * support. Otherwise if you don't need Windows support you can make OS X's configuration as
+ * default.
+ */
+#define CFG_QUIRK_OS_GUESSING 1
+
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.c b/examples/device/uac2_speaker_fb/src/usb_descriptors.c
index fa307674d..31c5e116d 100644
--- a/examples/device/uac2_speaker_fb/src/usb_descriptors.c
+++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.c
@@ -28,6 +28,10 @@
#include "usb_descriptors.h"
#include "common_types.h"
+#ifdef CFG_QUIRK_OS_GUESSING
+#include "quirk_os_guessing.h"
+#endif
+
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
@@ -45,7 +49,7 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
- .bcdUSB = 0x0200,
+ .bcdUSB = 0x0201,
// Use Interface Association Descriptor (IAD) for Audio
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
@@ -69,6 +73,9 @@ tusb_desc_device_t const desc_device =
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
+#if CFG_QUIRK_OS_GUESSING
+ quirk_os_guessing_desc_device_cb();
+#endif
return (uint8_t const *)&desc_device;
}
@@ -144,7 +151,7 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
#define EPNUM_DEBUG 0x02
#endif
-uint8_t const desc_configuration[] =
+uint8_t const desc_configuration_default[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
@@ -158,13 +165,63 @@ uint8_t const desc_configuration[] =
#endif
};
+#if CFG_QUIRK_OS_GUESSING
+// OS X needs 3 bytes feedback endpoint on FS
+uint8_t const desc_configuration_osx_fs[] =
+{
+ // Config number, interface count, string index, total length, attribute, power in mA
+ TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
+
+ // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size,
+ TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 3),
+
+#if CFG_AUDIO_DEBUG
+ // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
+ TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7)
+#endif
+};
+#endif
+
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void)index; // for multiple configurations
- return desc_configuration;
+
+#if CFG_QUIRK_OS_GUESSING
+ quirk_os_guessing_desc_configuration_cb();
+ if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) {
+ return desc_configuration_osx_fs;
+ }
+#endif
+ return desc_configuration_default;
+}
+
+//--------------------------------------------------------------------+
+// BOS Descriptor, required for OS guessing quirk
+//--------------------------------------------------------------------+
+
+#define TUD_BOS_USB20_EXT_DESC_LEN 7
+
+#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_USB20_EXT_DESC_LEN)
+
+// BOS Descriptor is required for webUSB
+uint8_t const desc_bos[] =
+{
+ // total length, number of device caps
+ TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1),
+
+ // USB 2.0 Extension Descriptor
+ 0x07, TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_USB20_EXTENSION, 0x00, 0x00, 0x00,0x00
+};
+
+uint8_t const * tud_descriptor_bos_cb(void)
+{
+#if CFG_QUIRK_OS_GUESSING
+ quirk_os_guessing_desc_bos_cb();
+#endif
+ return desc_bos;
}
//--------------------------------------------------------------------+
@@ -197,6 +254,10 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void) langid;
size_t chr_count;
+#if CFG_QUIRK_OS_GUESSING
+ quirk_os_guessing_desc_string_cb();
+#endif
+
switch ( index ) {
case STRID_LANGID:
memcpy(&_desc_str[1], string_desc_arr[0], 2);