ado_pcm_config_t and frags count

Hello, All!

ado_pcm_config_t has union ‘mode’ and structure ‘block’:

int32_t frag_size;
int32_t frags_min;
int32_t frags_max;
int32_t frags_total;

Debugging my driver (with phplay) I got:

frag_size = 4096
frags_min = 1
frags_max = 63
frags_total = 64

So I have question what is frags_min and frags_max for ?

frag_sizefrags_total = dmabuf.size, frags_max is maximum fragment sizes
that the client wants, but how may client wants frags_max is less then
frags_total ? So one frag is 4096 bytes length is out and dma buffer was
filled only with 63
4096 bytes ? Or dma buffer will filled with 644096
bytes ? As practice shows dma buffer filled with 64
4096 bytes.

Can I change the frags policy ? E.g. set frag_size = 8192 and frags_total =
32 ? Is that correct or client doesn’t saw my changes ?

Do I need call the dma_interrupt() function after each completed frag or
after the all completed frags ?

With best regards, Mike Gorchak.

As far as I understand frags_max and frags_min are supposed to be
driver-specific. It advertizes them in ‘capabilities’ structure (afair).
Clients are supposed to check what driver is capable of before trying to
request frag size (otherwise driver should force some valid frag size).

In reality much of this appears to be just legacy of ALSA. I think the only
things that really matter at the driver side are DMA size and interrupt
rate. Note that ALSA drivers used fixed DMA buffer size. In QNX size of DMA
buffer will be dynamic and application dependent - i think io-audio will try
to calculate DMA buffer size based on frag_size, frags_min, frags_max,
max_dma and min_dma advertized by driver. You’re fine as long as interrupt
rate can be set high enough to handle minimum possible DMA buffer size.

If interrupt rate is not high enough and DMA size is small enough, buffer
may be over before next interrupt comes in and then it will wrap around.
Then your next position in DMA buffer (calculated by ‘position’ callback)
will be smaller than previous and that will do bad things to all further
calculations (you’ll get false UNDERRUNS and OVERRUNS causing buffer flushes
and jerky sound).

Trouble is, some audio chips apparently can not set interrupt rate
independently of audio sampling frequency. Which means you need to set
min_dma big enough. That should avoid trouble with wraparounds at the cost
of higher latency.

Worst of all, this is not really explained anywhere and above is just my
speculation based on some experience.
– igor

“Mike Gorchak” <mike@malva.ua.remove.this.for.no.spam> wrote in message
news:aiqlaq$9l1$1@inn.qnx.com

Hello, All!

ado_pcm_config_t has union ‘mode’ and structure ‘block’:

int32_t frag_size;
int32_t frags_min;
int32_t frags_max;
int32_t frags_total;

Debugging my driver (with phplay) I got:

frag_size = 4096
frags_min = 1
frags_max = 63
frags_total = 64

So I have question what is frags_min and frags_max for ?

frag_sizefrags_total = dmabuf.size, frags_max is maximum fragment sizes
that the client wants, but how may client wants frags_max is less then
frags_total ? So one frag is 4096 bytes length is out and dma buffer was
filled only with 63
4096 bytes ? Or dma buffer will filled with 644096
bytes ? As practice shows dma buffer filled with 64
4096 bytes.

Can I change the frags policy ? E.g. set frag_size = 8192 and frags_total

32 ? Is that correct or client doesn’t saw my changes ?

Do I need call the dma_interrupt() function after each completed frag or
after the all completed frags ?

With best regards, Mike Gorchak.

Hello Igor !

Worst of all, this is not really explained anywhere and above is just my
speculation based on some experience.

Yes, the Audio DDK has very poor explanation, so some stuff I understood
after writting the second driver, some stuff I do like newborn blind kitten
or like the sapper: one mistake → hangup → reboot → chkfsys → do again
:slight_smile: And all this movements in do {} while(1) loop :slight_smile:

… and thanks for your explanation … :slight_smile:

Mike Gorchak <mike@malva.ua.remove.this.for.no.spam> wrote:
: Hello Igor !

:> Worst of all, this is not really explained anywhere and above is just my
:> speculation based on some experience.

: Yes, the Audio DDK has very poor explanation, so some stuff I understood
: after writting the second driver, some stuff I do like newborn blind kitten
: or like the sapper: one mistake → hangup → reboot → chkfsys → do again
: :slight_smile: And all this movements in do {} while(1) loop :slight_smile:

: … and thanks for your explanation … :slight_smile:

I’d like to thank Igor as well. I’ll check his explanation with the
developers and add it to the docs.

Mike: could you please let me know about the stuff you had trouble with?
I’d like to fix them. Thanks.


Steve Reid stever@qnx.com
TechPubs (Technical Publications)
QNX Software Systems

Hello, Steve!

SR> Mike: could you please let me know about the stuff you had trouble
SR> with? I’d like to fix them. Thanks.

You are the first who offer me official help :slight_smile:

  1. The docs nothing says about PCI Bus Master auto enabling. Hugh Brown and
    Igor believes in that ado_pci_device function when internally call the
    pci_attach_device function uses the undocumented (for now) PCI_MASTER_ENABLE
    flag. Is that correct ?

  2. ado_mixer_element_muxX() function set is not well documented (I mean
    control callback for this element, callback’s function args is not
    documented at all).

  3. I can’t build full capture group. ado_mixer_capture_group_create function
    uses cap_elem and mux_in_elem as last two args. This args is not documented
    at all. The docs says ‘if the cap_elem is multiplexer’, but I trying to
    create all elements, but only multiplexer type is usefull in this case. So
    what does mean the word ‘if’ ? I need the good example of creating full
    capture group when cap_elem and mux_in_elem is not NULL. I spent too many
    hours to understand this mux’es, the result is always unsuccessfull, I
    always get errors from ado_mixer_capture_group_create function or io-audio
    is core dumped or input switch element doesn’t occurs in photon mixer. This
    is for my CMI8738 audio driver, this audio doesn’t have AC’97 codec, so I
    need manually create all mixer elements. ALSA architecture has more clear
    interface for this things.

Thanks !

With best regards, Mike Gorchak.

Mike Gorchak <mike@malva.ua.remove.this.for.no.spam> wrote:
: Hello, Steve!

: SR> Mike: could you please let me know about the stuff you had trouble
: SR> with? I’d like to fix them. Thanks.

: You are the first who offer me official help :slight_smile:

I’ve asked the developers to look at your questions.


Steve Reid stever@qnx.com
TechPubs (Technical Publications)
QNX Software Systems

Mike Gorchak <mike@malva.ua.remove.this.for.no.spam> wrote:

Hello, All!

ado_pcm_config_t has union ‘mode’ and structure ‘block’:

int32_t frag_size;
int32_t frags_min;
int32_t frags_max;
int32_t frags_total;

Debugging my driver (with phplay) I got:

frag_size = 4096
frags_min = 1
frags_max = 63
frags_total = 64

So I have question what is frags_min and frags_max for ?

It’s really only frag_size and frags_total the driver needs
to be interested in, the others are there as reference for
special cases.

frag_sizefrags_total = dmabuf.size, frags_max is maximum fragment sizes
that the client wants, but how may client wants frags_max is less then
frags_total ? So one frag is 4096 bytes length is out and dma buffer was
filled only with 63
4096 bytes ? Or dma buffer will filled with 644096
bytes ? As practice shows dma buffer filled with 64
4096 bytes.

Correct io-audio sizes the dma buffer as
frags_total*frag_size. And frags_total = frags_max (client
request) + 1.

Can I change the frags policy ? E.g. set frag_size = 8192 and frags_total =
32 ? Is that correct or client doesn’t saw my changes ?

Yes you can, these are the only parameters a driver is
allowed to adjust on behalf of the client. Typically the
driver just adjusts the frag_size due to some hw limitaition
and then recalculates the dma_buffer size.

Do I need call the dma_interrupt() function after each completed frag or
after the all completed frags ?

You need to call dma_interrupt when each fragment has been
processed by the hw. This is how io-audio knows it can reuse
the fragment buffer.

Mike Gorchak <mike@malva.ua.remove.this.for.no.spam> wrote:

  1. The docs nothing says about PCI Bus Master auto enabling. Hugh Brown and
    Igor believes in that ado_pci_device function when internally call the
    pci_attach_device function uses the undocumented (for now) PCI_MASTER_ENABLE
    flag. Is that correct ?

This bit is indeed turned on the ado_pci_device as:

if ((pci->handle = pci_attach_device (NULL, PCI_SEARCH_VENDEV |
PCI_MASTER_ENABLE | PCI_INIT_ALL, index = pci_idx, &inf)) == NULL)


  1. ado_mixer_element_muxX() function set is not well documented (I mean
    control callback for this element, callback’s function args is not
    documented at all).

This callback in similar to the other element callbacks with
respect to most of the arguements, the “set” tells you to
set (write) / read the elements state and “inelements” is an
array of elements references. So in the example below for a
cs4218 codec 2 elements route to a stereo mux.

static int32_t
abc_input_mux_control (MIXER_CONTEXT_T * abc, ado_mixer_delement_t * element, uint8_t set,
ado_mixer_delement_t ** inelements, void *instance_data)
{
uint32_t i;
uint32_t data;
uint32_t tmp;
uint32_t val;
int32_t altered = 0;

data = (abc->cs4218_ctrl >> 16) & 0x3;
if (set)
{
for (i = 0, val = 0; i < 2; i++)
{
tmp = 0;
if (inelements == abc->input_l1)
tmp = 0;
else if (inelements == abc->input_l2)
tmp = 1;
val |= tmp << i;
}
altered = val != data;
if (altered)
{
abc->cs4218_ctrl = (abc->cs4218_ctrl & ~(0x3 << 16)) | (val << 16);
cs4218_ctrl_write (abc);
}
}
else
{
for (i = 0; i < 2; i++)
{
tmp = (data >> i) & 0x1;
if (tmp == 0)
inelements = abc->input_l1;
else if (tmp == 1)
inelements = abc->input_l2;
}
}
return (altered);
}

3) I can’t build full capture group. ado_mixer_capture_group_create function
uses cap_elem and mux_in_elem as last two args. This args is not documented
at all. The docs says ‘if the cap_elem is multiplexer’, but I trying to
create all elements, but only multiplexer type is usefull in this case. So
what does mean the word ‘if’ ? I need the good example of creating full
capture group when cap_elem and mux_in_elem is not NULL. I spent too many
hours to understand this mux’es, the result is always unsuccessfull, I
always get errors from ado_mixer_capture_group_create function or io-audio
is core dumped or input switch element doesn’t occurs in photon mixer. This
is for my CMI8738 audio driver, this audio doesn’t have AC’97 codec, so I
need manually create all mixer elements. ALSA architecture has more clear
interface for this things.

The capture element may not be a Mux we may support other
elements at some point, but for now if the element that
enables capture for this group is a mux, then the
mux_in_elem is need for io-audio to call the control
function above.

if (!error && (abc->input_l1 = ado_mixer_element_io (abc->mixer, SND_MIXER_MIC_IN,
SND_MIXER_ETYPE_INPUT, 0, 2, stereo_voices)) == NULL)
error++;
if (!error && (abc->input_l2 = ado_mixer_element_io (abc->mixer, SND_MIXER_LINE_IN,
SND_MIXER_ETYPE_INPUT, 0, 2, stereo_voices)) == NULL)
error++;

if (!error && (input_mux = ado_mixer_element_mux1 (mixer, SND_MIXER_ELEMENT_INPUT_MUX,
0, 2, abc_input_mux_control, NULL, NULL)) == NULL)



if (!error && (input_l1_grp = ado_mixer_capture_group_create (mixer, SND_MIXER_MIC_IN,
SND_MIXER_CHN_MASK_STEREO, NULL, NULL, input_mux, abc->input_l1)) == NULL)
error++;
if (!error && (input_l2_grp = ado_mixer_capture_group_create (mixer, SND_MIXER_LINE_IN,
SND_MIXER_CHN_MASK_STEREO, NULL, NULL, input_mux, abc->input_l2)) == NULL)
error++;


But as a side note I thought the CMI8738 used a SB16 legacy
mixer that doesn’t use Multiplexers but rather accumulators.
That is multiple input sources can be selected at the same
time. You may want to look at the ess1938 mixer source as it also
used accumulators rather then multiplexers.

Hello, audio_support!

as> But as a side note I thought the CMI8738 used a SB16 legacy
as> mixer that doesn’t use Multiplexers but rather accumulators.
as> That is multiple input sources can be selected at the same
as> time. You may want to look at the ess1938 mixer source as it also
as> used accumulators rather then multiplexers.

Big thanks for great answer !!! BTW CMI8738 uses not only SB16 legacy mixer,
it uses some internal switches for AUX-like input also. Thanks one more !

With best regards, Mike Gorchak.