[alsa-devel] Surround speaker connection on Acer 8951G

Sergey 'Jin' Bostandzhyan jin at mediatomb.cc
Fri Aug 30 13:45:10 CEST 2019


Hi Takashi,

On Thu, Aug 29, 2019 at 01:29:13PM +0200, Takashi Iwai wrote:
> > > One possible way with the current code (and your latest patch) would
> > > be to create a UCM profile.  The driver should still provide the jack
> > > detection on the pin 0x1b as "Surround Jack", and this can be used as
> > > the headphone jack detection.
> > 
> > I gogled it up and I did find HDAudio-Gigabyte-ALC1220DualCodecs as an
> > example, so basically the solution in this case would be split between
> > the driver and alsa-lib?
> 
> Right.

I did some digging yesterday and found out that documentation on the UCM
profiles is sparse. I cloned your alsa-lib repo from github and looked
at the available profiles. One thing that is not clear to me:
the configurations have entries for JackControl and JackHWMute, however
unless I totally missed it - those strings are not being parsed anywhere
in the code? I first looked at parser.c as suggested by the man page and
later grepped through the whole tree - nothing.

>From various examples which I found when searching for answers I could see,
that in most cases the desired _verb section of the profile is activated
via a udev rule, but I was not able to find anything that would be
hooked to jack sense to switch between devices? 

I know it could be done via acpid, is this the way it is meant to be used or
am I missing something, especially in regard to those JackHWMute strings?

How exactly is card longname which can be set in the driver connected to all 
this, I understand there is no automatic mechanism and that everyone needs to 
set up their custom udev scripts anyway?

I more or less got things to behave using a custom profile with device
sections for Speakers and Headphones, which basically mutes everything
except surround in Headphone mode, so technically I could hook it up to
acpid and be done with it. To be honest, I'd be more happy with an "out of the
box" experience, which leads me back to the driver.

> > Are there any disadvantages to muting the other channels directly in the
> > driver? Or would it be a viable option to extend the auto-parser to
> > handle the remaining channels?
> 
> It's not so trivial to extend.  The logic of driver parser assumes the
> single purpose pins, and if they appear doubly, the behavior becomes
> confusing.  For example, if you just add the same pin to both
> speaker_pins[] and hp_pins[], all speaker_pins[] get muted by the
> auto-mute, hence you'll mute the headphone again.  OTOH, if you don't
> list up the pin in speaker_pins[], it won't be used for speakers for
> multi-channels, obviously.

This confirms what I have seen when trying things out last week, the pin could
be either a speaker or a headphone, but not both, meaning I would either "lose"
the ability to use 5.1 profiles or the system would not "see" the headphones
as headphones.

> > Personally, I would prefer a solution at one place, but I follow your lead here,
> > if you say that UCM is the way to go, then so be it.
> 
> We can give it a try.  If it doesn't work as expected, we'd need more
> extension in the driver side.


Would you accept a model-quirk solution that is purely in the driver, which 
monitors jack presence on 0x1b and simply mutes the remaining speakers directly?

This way it could simply work as expected without an additional userspace
setup of alsaucm, udev, acpid.

> > I played around with jack detection and I had the feeling that it did not work
> > reliably, or maybe I misunderstood something?

[...]

> > I kept watching dmesg, when nothing is playing the plugged in/unplugged
> > messages appear correctly, but if I start speaker test and replug during
> > the playback, nothing is printed.
> 
> Check rather "Speaker Surround Jack" state upon plugging the
> headphone.  Does it change reliably?

Check - where exactly? I did the following test:
- ran speaker test
- watched dmesg -wH with my printouts + ran alsa_listen in another terminal

While alsa_listen was correctly showing:
jack/lineout LINEOUT plug
jack/lineout LINEOUT unplug

dmesg remained silent. I figured that I may be hooking to the wrong function,
in the code I pasted earlier I was hooking up to the hp_automute_hook, so I
changed it to line_automute_hook, but the behavior is the same:

when something is playing, the automute hook is not being triggered upon
plugging/unplugging. When nothing is playing, its being called reliably and
the printouts are in sync with acpi_listen.

Which leads me to the following question: is the automute hook the right
place for jack sensing in the driver at all? I did search for examples, but
I failed at figuring out the proper way to hook up to jack state changes, or
rather, I coul dsee that hda_jack_callback is being hooked to automute
everywhere.

To make it clearer: at this point its not about the "correct state" of the jack,
but rather about being triggered at all when something gets physically plugged
into or unplugged from the port during an ongoing playback.

> Note that even if you set such flags manually like the above, it won't
> work, because of the reasons I already mentioned.

Right, makes sense. In my debug code I was mostly misusing
spec->gen.hp_jack_present as a "free" variable for remembering the state.

> > Turned out it was indeed a GPIO, I won't describe all the things I tried, in the
> > end it was a lucky click on the dir_out checkbox in hda-analyzer while I was
> > debugging the shared pin issue :)
> > 
> > The below HDA_FIXUP_VERBS does the trick, so I do have all 6 speakers working, 
> > finally!
> > 
> > {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}
> 
> Actually this must be paired with the corresponding bit of GPIO_DATA,
> too.  Is the bit 0x02 of GPIO_DATA set or cleared?  Usually setting it
> turns on the amp, but sometimes inverted.

If I understood everything correctly, then the bit is set, meaning that the
GPIO signal is configured as output. I'll be honest, I exported the
hda-analyzer setting as a python script (nice feature btw) and deducted the
fixup verb setting from there (relevant part of the hda-analyzer export below):

def set(nid, verb, param):
  verb = (nid << 24) | (verb << 8) | param
  res = ioctl(FD, IOCTL_VERB_WRITE, struct.pack('II', verb, 0))  

set(0x01, 0x717,   0x02) # 0x01071702 (SET_GPIO_DIRECTION)


> > The only thing that is not quite clear to me is - does LFE still have its
> > own pin and I was just not able to find it, but managed to unmute it via
> > the GPIO? Or is the LFE speaker somehow "intenrally managed"? It works
> > correctly though, alsa mixer is also capable of controlling LFE volume
> > separately so it's fine, everything is also working with pulseaudio and a 5.1
> > profile on top.
> 
> It's usually just the external amp controlled via GPIO, and the signal
> must go through the pin 0x18 as well as the center channel, I suppose.

Ah, I see, I could try confirming if 0x18 is indeed the LFE speaker or not
by "disconnecting" it in the pin configuration, I'd like to know for sure :)

To sum it up:

would you be OK with the "mute remaning channels upon jack sense
in the driver" approach?
 
If the above is a yes, could you please point me to the right way of getting 
triggered upon jack state changes in the driver, since automute hooks seem 
not to trigger while something is playing?

Kind regards,
Sergey



More information about the Alsa-devel mailing list