Contribute
Register

Some General HDA Questions (and Some Research)

Status
Not open for further replies.
Joined
Jun 12, 2012
Messages
349
Motherboard
...
CPU
...
Graphics
...
Hi,

I've managed to get the combo jack on my laptop (Dell XPS 15 9560 using Realtek ALC3266/298) to act as a manually switchable headphone/stereo line-in jack, but I know the jack also supports CTIA audio devices like the iPhone headset. I think I know how to get the best of both worlds--Apple's Late 2011 MacBook Pro has a single combo jack that does SPDIF-IN/OUT, Line-In/Out, and CTIA headsets (and it uses native layout 28)--but the capability to do this hinges on a couple general questions about the AppleHDA patching process:

1. Does anyone know if Mac OS supports two line-in devices?
I've been trying to use "ExtMic," and I've gone as far as setting all the right verbs to enable the "headset mic," but it seems like Mac OS in general has trouble with ExtMic being used as a line-in (my laptop has the combo jack wired in such a way that both the Headset mic in and stereo line in are both basically line-in devices sharing the same port).

2. If two line-ins can't be done for whatever reason, how does one properly set up ExtMic?

3. Does anyone know, in detail, what "MuteGPIO" actually does?
I know the pattern is usually VREF + 0100 + NodeID, but that doesn't tell me much. From my research (trying stuff, comparing 3 apple codec dumps, tracing pathmaps and layouts, and reading AppleHDA spec and Realtek datasheets) it looks related to setting Pin Control Widgets when a device is enabled/disabled. One of its functions seems to be to set VREF on the pin control widget as determined via hda-verb GET_PIN_WIDGET queries. However, that 0100 part I can't figure out, and I've noticed that 0100 is actually 0000 in some layouts, namely in MuteGPIO for the headphones that have IOMux like layout 28, 77, 2, etc.

>>Also worth noting is that I've found ExtMic either has MuteGPIO 262144 or no MuteGPIO, and seems to use a node that isn't actually physically present. At least, none of Cirrus codecs I've pulled from Macs with CTIA support have a Node 0x16 (they stop at 0x15 per the linux dumps), which is what the ExtMic is linked to in the PathMap.

4. What are the "Amp" sections in the pathmap actually doing?
I found that in plaforms.xml in the native AppleHDA, Apple basically left most of a "how to make a codec" guide (open platforms.xml in a text editor and search for <!--; there are also some comments in some of the layout XMLs), and it seems like the only thing it doesn't answer about the PathMap is what "Amp" does. Apple also only uses ONE amp on the output nodes, not 3 like every AppleHDA patching guide says to.

Here are some other things I've found, for the sake of documenting them somewhere:

IOMux on the "headphone" device in the Layout XML enables switching. There is a corresponding "RetaskDetectDelegate" key on Line-In's pathmap (it goes where "Boost" would go if it were a Mic) that takes the value of the node of the headphone playback switch. I still needed to send some verbs to get the switch to work, but it worked.
>>For reference, I need to send 0x18 SET_PIN_WIDGET 0x24 to remove distortion and make the headphone jack's CTIA pin go into VREF 80 (the MuteGPIO I have on ExtMic is not getting triggered, and 0x18 is "Headset Mic Boost Volume" for me), and then after plugging in the line-in device and switching to Line Input in SysPrefs, I need to send 0x21 SET_PIN_WIDGET 0x00 to stop the headphone output from interfering with the Line-In (0x21 is "Headphone Playback Switch" for me).

Shoehorning DetectDelegate (with value of headphone playback switch) onto the ExtMic pathmap causes Headphone and speaker audio to flip. In other words, sound gets routed to the headphone jack when headphone unplugged, and routed to the speakers when headphones are plugged in.

Various layouts:
  • Late 2013 MacBook Pro 15 (MBP11,3) uses Layout 94 (Built-In: Mic/IntSpeaker, Jack: ExtMic/Headphone/SPDIF-Out), Cirrus CS4208
  • Late 2011 MacBook Pro 13 (MBP8,1) uses Layout 28 (Built-In: Mic/IntSpeaker, Jack: ExtMic/Headphone/Line-In/SPDIF-Out/SPDIF-In), Cirrus CS4207
  • Mid 2010 MacBook Pro 15 (MBP6,3) uses layout 11 (2 jacks: Output: ExtMic/Headphone/SPDIF-Out, Input: Line-in/SPDIF-In, Built-in: Mic/Intspeaker), Cirrus CS4206
  • Here are some other layouts in use by real laptops.
Any insight would be hugely appreciated. I feel really close to getting this jack to basically do everything--as long as there's a way to get two line-ins to show up without sacrificing the internal mic. I'm attaching my Verbs, Layout, and Platform config for reference. I'm also including various ALSA codec dumps (Mid-2010 15" MBP6,3, Late 2013 15" MBP11,3, and Dell XPS 9560).

EDIT: Spellcheck & formatting because walls of text are ugly.

EDIT 326891: More grammar and formatting adjustments. Cause there's always something that gets missed...
 

Attachments

  • VerbsLayoutPlatform.zip
    15.5 KB · Views: 83
  • CodecDumps.zip
    63.6 KB · Views: 69
Last edited:
I can answer these questions myself now:

1. Yes, but it can only think it has 1

2. Nobody seems to know this

3. It sets Pin Widget VREF values, and that seems to be about it

4. They enable features like muting and volume control. You don't need 3 of them on every output; for my ALC3266, for example, it suffices to do this:
http://www.insanelymac.com/forum/to...-and-laptop-subwoofer-aka-21-audio/?p=2017967

And now for something new (quoted below):
http://www.insanelymac.com/forum/topic/311293-applealc-—-dynamic-applehda-patching/?p=2453130
I said:
I FIXED [white noise on my headset]!

hda-verb 0x20 SET_COEF_I 0x4f /* Realtek control widget control register */
hda-verb 0x20 SET_PROC_C 0xd400 /* This is what linux does for headset mic on my version of ALC3266 */
It works now
biggrin.png


What this also means is that, by using AlcPlugFix, we now have a way to exert complete control over audio codecs and can do things just like Linux. For ALC298, there is a control widget on 0x20 that has a TON of configuration registers, and we can set them just like Linux drivers do. I think this means we can pretty much port drivers from Linux now into just a simple shell script like AlcPlugFix and hda-verb, and expose the minimum we need to the OS through AppleALC. All we need are the control registers for each codec. I am soooo happy right now. :DDDDDDD

So, here's an idea: With AppleALC and ALCPlugFix, it should now be possible to make a little pop-up menu when something gets plugged in that asks "What did you just plug in?" and then you can pick Headphone, Headset, or Line-In, exactly like how Windows does it.

The key to making drivers is in this line in the codec dump:
(Example: Cirrus 4208)

Node 0x24 [Vendor Defined Widget] wcaps 0xf0e2c1: 16-Channels Digital
Unsolicited: tag=00, enabled=0
Processing caps: benign=0, ncoeff=128

This is the control register, which you can tell by the "ncoeff" part.

For the ALC298:

Node 0x20 [Vendor Defined Widget] wcaps 0xf00040: Mono
Processing caps: benign=0, ncoeff=150

Etc.

So now I should be able to make a perfect audio setup for my ALC3266 by using hda-verb and referencing these linux drivers:
https://github.com/torvalds/linux/b...8abd4ac2e17e36805b79/sound/soc/codecs/rt298.h /* this has the list of registers */
https://github.com/torvalds/linux/blob/master/sound/soc/codecs/rt298.c /* the full codec of the alc298 */
https://github.com/torvalds/linux/blob/master/sound/pci/hda/patch_realtek.c /* implementation-specific quirks, e.g. specific fixups and workarounds for custom Realtek codecs */

And I bet you could do it for your own codecs, too.
cool.png

@RehabMan
Would it be possible to add to CodecCommander the capability to execute verbs on headphone jack insertion/removal (which is what ALCPlugFix does)? I'm thinking that way, between AppleALC, CodecCommander, and one SSDT, we'd be able to port certain entire Linux codecs over, especially ones for laptops and combojacks, and wouldn't have to rely on any kind of watchdog script. And maybe even implement a "What did you just plug in?" prompt...
 
Last edited:
Would it be possible to add to CodecCommander the capability to execute verbs on headphone jack insertion/removal (which is what ALCPlugFix does)?

I haven't found any mechanism to capture the event.
Use ALCPlugFix.
 
Polling hda-verb 0x21 GET_PIN_SENSE 0x00 (raw command: 0x021f0900) for changes isn't sufficient?

It returns 0x00000000 for nothing, 0x80000000 for something (granted 0x21 would have to be changed to the headphone jack depending on the codec). With an interval of about 1 second, it shouldn't cause any harm to things like battery life.

Could add an option in the SSDT to manually set the headphone node and enable/disable polling.
ALCPlugFix just checks for whether or not the sound output device is headphone or speaker, which would break line-in devices.

I mean, I could make a new watchdog in C, but CodecCommander would definitely be much nicer...

EDIT:
Perhaps worth noting here is that this is the correct way to set processing coefficients, per Linux source. I've bolded the most important part and striken out the part that doesn't matter (they're not really volatile).
https://github.com/torvalds/linux/blob/master/drivers/base/regmap/regmap.c
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change, bool force_write)
{
int ret;
unsigned int tmp, orig;

if (change)
*change = false;
if (regmap_volatile(map, reg) && map->reg_update_bits)

{
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
if (ret == 0 && change)
*change = true;​
}

else
{
ret = _regmap_read(map, reg, &orig);
if (ret != 0)
return ret;
tmp = orig & ~mask;
tmp |= val & mask;


if (force_write || (tmp != orig))
{
ret = _regmap_write(map, reg, tmp);
if (ret == 0 && change)
*change = true;​
}​
}
return ret;​
}
The bolded sequence prevents overwriting important existing settings, and the masks to use are defined in the codec's .c file (example in rt298.c from here: https://github.com/torvalds/linux/tree/master/sound/soc/codecs):

Code:
regmap_update_bits(rt298->regmap,
                RT298_CBJ_CTRL1, 0xfcc0, 0xd400);
 
Last edited:
Polling hda-verb 0x21 GET_PIN_SENSE 0x00 (raw command: 0x021f0900) for changes isn't sufficient?

Polling is not something I want to do. It is horribly inefficient.
ALCPlugFix is tuning into some notifications, therefore efficient.
 
You must not be a hardware programmer. ;)

It might seem efficient, but it's terribly, terribly hacky. Realtek's own drivers poll. Intel's drivers poll:
https://www.freebsd.org/cgi/man.cgi?query=snd_hda&sektion=4&manpath=FreeBSD+8.1-RELEASE
Code:
      dev.hdac.%d.polling_interval
               Controller/Jack    Sense polling interval (1-1000
               ms)
For all intents and purposes, CodecCommander is basically an extension to a driver. If it does everything a driver would do, what makes it exempt from treating it like one?

All the embedded programming I have to do contains some amount of polling. How do you think USB hot plug works? There's no way for the software to know something happened unless it's polling the bus or using interrupts, and good luck finding an interrupt that does this (the closest thing is what ALCfix does). Here's a reasonable answer as to why polling is useful for this purpose:

https://stackoverflow.com/questions/4813368/usb-polling-mechanism

Polling once every second to a modern machine is like asking a person to fetch a cup of tea once every 1 million years. Well, ok, when we're running at 4 GHz and we're executing more than one instruction every 2.5 * 10^-10 seconds (0.25 nanoseconds!), it would be more like getting a cup of tea, at minimum, every 16 billion seconds, or ~507 years. Hardly what I'd call inefficient!

Heck, even polling once a second, or even a half-second, on an old MS-DOS machine running on a 25MHz 486DX would be peanuts. And that was in 1992!

I bet your OS is running no less than at least 100 polling operations right this second. And in the time it took to read this sentence it just ran another thousand. Going off the notifications is like being picky over a difference of 5 when you're adding 2 billion plus 2 billion, and that kind of accuracy only matters for interstellar travel.
 
For all intents and purposes, CodecCommander is basically an extension to a driver. If it does everything a driver would do, what makes it exempt from treating it like one?

Currently, CodecCommander does not poll.
I'd rather not add polling to it...
You're welcome to implement your solution and submit a PR.
Such polling should be optional, and the actions taken should be completely configurable...

All the embedded programming I have to do contains some amount of polling. How do you think USB hot plug works?

Proper drivers/hardware design allows everything to be done based on interrupts.... no polling.
 
Currently, CodecCommander does not poll.
I'd rather not add polling to it...
You're welcome to implement your solution and submit a PR.
Such polling should be optional, and the actions taken should be completely configurable...
Of course!

Proper drivers/hardware design allows everything to be done based on interrupts.... no polling.
The entire TCP/IP protocol says hi.
 
Last edited:
No (constant) polling in RealtekRTL8111.kext (for "good" hardware).
I see what you did there... :p

Anyways, yeah, it would absolutely be totally optional and totally configurable. 100% agreed. Should also have as minimal impact on the overall system as possible.

Off to learn Objective-C...
 
Status
Not open for further replies.
Back
Top