hda: subsystem is from the codec, not the PCI bus.

* Refactors so that we look for a codec subsystem ID, then the
  Audio Function Group subsystem ID if not found.
* Moves the order around a bit so that the quirks are set early
  enough.
* Also adds a quirk for MacBookAir 6,2, allows speakers to work.

Change-Id: I4c64f96936a82a5d7187d86d8558f28516fd4ecb
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4654
Reviewed-by: Adrien Destugues <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Jessica Hamilton
2021-10-24 09:58:55 +00:00
parent b594d76c81
commit 69958ca2ef
3 changed files with 38 additions and 19 deletions
@@ -292,6 +292,7 @@ struct hda_audio_group {
struct hda_codec { struct hda_codec {
uint16 vendor_id; uint16 vendor_id;
uint16 product_id; uint16 product_id;
uint32 subsystem_id;
uint8 major; uint8 major;
uint8 minor; uint8 minor;
uint8 revision; uint8 revision;
@@ -95,6 +95,8 @@ static const struct {
HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0}, // MacBook HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0}, // MacBook
{ 0x106b, 0x00a3, REALTEK_VENDORID, 0x0885, { 0x106b, 0x00a3, REALTEK_VENDORID, 0x0885,
HDA_QUIRK_GPIO0, 0}, // MacBook HDA_QUIRK_GPIO0, 0}, // MacBook
{ 0x106b, 0x7200, CIRRUSLOGIC_VENDORID, 0x4208,
HDA_QUIRK_GPIO0, 0}, // MacBookAir 6,2
{ HDA_ALL, HDA_ALL, IDT_VENDORID, 0x76b2, HDA_QUIRK_GPIO0, 0}, { HDA_ALL, HDA_ALL, IDT_VENDORID, 0x76b2, HDA_QUIRK_GPIO0, 0},
}; };
@@ -363,9 +365,8 @@ hda_codec_get_quirks(hda_codec* codec)
{ {
codec->quirks = 0; codec->quirks = 0;
uint32 subSystemID = codec->controller->pci_info.u.h0.subsystem_id; uint32 subSystemID = codec->subsystem_id & 0xffff;
uint32 subSystemVendorID uint32 subSystemVendorID = codec->subsystem_id >> 16;
= codec->controller->pci_info.u.h0.subsystem_vendor_id;
for (uint32 i = 0; for (uint32 i = 0;
i < (sizeof(kCodecQuirks) / sizeof(kCodecQuirks[0])); i++) { i < (sizeof(kCodecQuirks) / sizeof(kCodecQuirks[0])); i++) {
@@ -1496,6 +1497,7 @@ hda_codec_new(hda_controller* controller, uint32 codecAddress)
struct { struct {
uint32 device : 16; uint32 device : 16;
uint32 vendor : 16; uint32 vendor : 16;
uint32 subsystem : 32;
uint32 stepping : 8; uint32 stepping : 8;
uint32 revision : 8; uint32 revision : 8;
uint32 minor : 4; uint32 minor : 4;
@@ -1507,13 +1509,14 @@ hda_codec_new(hda_controller* controller, uint32 codecAddress)
uint32 _reserved2 : 8; uint32 _reserved2 : 8;
} response; } response;
corb_t verbs[3]; corb_t verbs[4];
verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID); verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID); verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUBSYSTEM_ID);
verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
verbs[3] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER,
PID_SUB_NODE_COUNT); PID_SUB_NODE_COUNT);
status = hda_send_verbs(codec, verbs, (uint32*)&response, 3); status = hda_send_verbs(codec, verbs, (uint32*)&response, 4);
if (status != B_OK) { if (status != B_OK) {
ERROR("Failed to get vendor and revision parameters: %s\n", ERROR("Failed to get vendor and revision parameters: %s\n",
strerror(status)); strerror(status));
@@ -1521,6 +1524,7 @@ hda_codec_new(hda_controller* controller, uint32 codecAddress)
} }
codec->vendor_id = response.vendor; codec->vendor_id = response.vendor;
codec->subsystem_id = response.subsystem;
codec->product_id = response.device; codec->product_id = response.device;
codec->stepping = response.stepping; codec->stepping = response.stepping;
codec->revision = response.revision; codec->revision = response.revision;
@@ -1528,29 +1532,30 @@ hda_codec_new(hda_controller* controller, uint32 codecAddress)
codec->major = response.major; codec->major = response.major;
hda_codec_get_quirks(codec); hda_codec_get_quirks(codec);
TRACE("Codec %" B_PRIu32 " Vendor: %04" B_PRIx32 " "
"Product: %04" B_PRIx32 ", "
"Revision: %" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 " "
"Quirks: %04" B_PRIx32 "\n",
codecAddress, response.vendor,
response.device,
response.major, response.minor, response.revision, response.stepping,
codec->quirks);
for (uint32 nodeID = response.start; for (uint32 nodeID = response.start;
nodeID < response.start + response.count; nodeID++) { nodeID < response.start + response.count; nodeID++) {
uint32 groupType; struct {
uint32 groupType;
uint32 subsystem;
} functionResponse;
verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER, verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER,
PID_FUNCTION_GROUP_TYPE); PID_FUNCTION_GROUP_TYPE);
verbs[1] = MAKE_VERB(codecAddress, nodeID, VID_GET_SUBSYSTEMID, 0);
if (hda_send_verbs(codec, verbs, &groupType, 1) != B_OK) { if (hda_send_verbs(codec, verbs, (uint32*)&functionResponse, 2) != B_OK) {
ERROR("Failed to get function group type\n"); ERROR("Failed to get function group type\n");
goto err; goto err;
} }
if ((groupType & FUNCTION_GROUP_NODETYPE_MASK) if ((functionResponse.groupType & FUNCTION_GROUP_NODETYPE_MASK)
== FUNCTION_GROUP_NODETYPE_AUDIO) { == FUNCTION_GROUP_NODETYPE_AUDIO) {
// Found an Audio Function Group! // Found an Audio Function Group!
if (response.subsystem == 0 && functionResponse.subsystem != 0) {
// Update our subsystem, and re-check quirks for this codec
codec->subsystem_id = functionResponse.subsystem;
hda_codec_get_quirks(codec);
}
status_t status = hda_codec_new_audio_group(codec, nodeID); status_t status = hda_codec_new_audio_group(codec, nodeID);
if (status != B_OK) { if (status != B_OK) {
ERROR("Failed to setup new audio function group (%s)!\n", ERROR("Failed to setup new audio function group (%s)!\n",
@@ -1560,6 +1565,18 @@ hda_codec_new(hda_controller* controller, uint32 codecAddress)
} }
} }
TRACE("Codec %" B_PRIu32 " Vendor: %04" B_PRIx32 " "
"Product: %04" B_PRIx32 " "
"Subsystem: %08" B_PRIx32 ", "
"Revision: %" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 " "
"Quirks: %04" B_PRIx32 "\n",
codecAddress,
response.vendor,
response.device,
codec->subsystem_id,
response.major, response.minor, response.revision, response.stepping,
codec->quirks);
codec->unsol_response_thread = spawn_kernel_thread( codec->unsol_response_thread = spawn_kernel_thread(
(status_t(*)(void*))hda_codec_switch_handler, (status_t(*)(void*))hda_codec_switch_handler,
"hda_codec_unsol_thread", B_LOW_PRIORITY, codec); "hda_codec_unsol_thread", B_LOW_PRIORITY, codec);
@@ -143,6 +143,7 @@ enum pin_dev_type {
/* Parameter IDs */ /* Parameter IDs */
#define PID_VENDOR_ID 0x00 #define PID_VENDOR_ID 0x00
#define PID_SUBSYSTEM_ID 0x01
#define PID_REVISION_ID 0x02 #define PID_REVISION_ID 0x02
#define PID_SUB_NODE_COUNT 0x04 #define PID_SUB_NODE_COUNT 0x04
#define PID_FUNCTION_GROUP_TYPE 0x05 #define PID_FUNCTION_GROUP_TYPE 0x05