Integrate OS guessing quirk into uac2_speaker_fb example.
This commit is contained in:
@@ -31,6 +31,10 @@
|
|||||||
#include "usb_descriptors.h"
|
#include "usb_descriptors.h"
|
||||||
#include "common_types.h"
|
#include "common_types.h"
|
||||||
|
|
||||||
|
#ifdef CFG_QUIRK_OS_GUESSING
|
||||||
|
#include "quirk_os_guessing.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// MACRO CONSTANT TYPEDEF PROTOTYPES
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
// AUDIO Task
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
90
examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
Normal file
90
examples/device/uac2_speaker_fb/src/quirk_os_guessing.c
Normal file
@@ -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;
|
||||||
|
}
|
75
examples/device/uac2_speaker_fb/src/quirk_os_guessing.h
Normal file
75
examples/device/uac2_speaker_fb/src/quirk_os_guessing.h
Normal file
@@ -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_ */
|
@@ -87,6 +87,14 @@ extern "C" {
|
|||||||
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
#endif
|
#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
|
// DEVICE CONFIGURATION
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
@@ -28,6 +28,10 @@
|
|||||||
#include "usb_descriptors.h"
|
#include "usb_descriptors.h"
|
||||||
#include "common_types.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.
|
/* 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.
|
* 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),
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
.bcdUSB = 0x0200,
|
.bcdUSB = 0x0201,
|
||||||
|
|
||||||
// Use Interface Association Descriptor (IAD) for Audio
|
// 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)
|
// 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
|
// Application return pointer to descriptor
|
||||||
uint8_t const * tud_descriptor_device_cb(void)
|
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;
|
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
|
#define EPNUM_DEBUG 0x02
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t const desc_configuration[] =
|
uint8_t const desc_configuration_default[] =
|
||||||
{
|
{
|
||||||
// Config number, interface count, string index, total length, attribute, power in mA
|
// 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),
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||||
@@ -158,13 +165,63 @@ uint8_t const desc_configuration[] =
|
|||||||
#endif
|
#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
|
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||||
// Application return pointer to descriptor
|
// Application return pointer to descriptor
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||||
{
|
{
|
||||||
(void)index; // for multiple configurations
|
(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;
|
(void) langid;
|
||||||
size_t chr_count;
|
size_t chr_count;
|
||||||
|
|
||||||
|
#if CFG_QUIRK_OS_GUESSING
|
||||||
|
quirk_os_guessing_desc_string_cb();
|
||||||
|
#endif
|
||||||
|
|
||||||
switch ( index ) {
|
switch ( index ) {
|
||||||
case STRID_LANGID:
|
case STRID_LANGID:
|
||||||
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||||
|
Reference in New Issue
Block a user