OK, now let me explain the detail of each pcm callback
(ops). In general, every callback must
return 0 if successful, or a negative number with the error
number such as -EINVAL at any
error.
The callback function takes at least the argument with
snd_pcm_substream pointer. For retrieving the
chip record from the given substream instance, you can use the
following macro.
substream->private_data,
which is a copy of pcm->private_data.
You can override the former if you need to assign different data
records per PCM substream. For example, cmi8330 driver assigns
different private_data for playback and capture directions,
because it uses two different codecs (SB- and AD-compatible) for
different directions.
This is called when a pcm substream is opened.
At least, here you have to initialize the runtime->hw record. Typically, this is done by like this:
static int snd_xxx_open(struct snd_pcm_substream *substream)
{
struct mychip *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw = snd_mychip_playback_hw;
return 0;
}
snd_mychip_playback_hw is the
pre-defined hardware description.
You can allocate a private data in this callback, as described in Private Data section.
If the hardware configuration needs more constraints, set the hardware constraints here, too. See Constraints for more details.
Obviously, this is called when a pcm substream is closed.
Any private instance for a pcm substream allocated in the open callback will be released here.
This is used for any special action to pcm ioctls. But
usually you can pass a generic ioctl callback,
snd_pcm_lib_ioctl.
static int snd_xxx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params);
hw_free callbacks exist
only on ALSA 0.9.x.
This is called when the hardware parameter
(hw_params) is set
up by the application,
that is, once when the buffer size, the period size, the
format, etc. are defined for the pcm substream.
Many hardware set-up should be done in this callback, including the allocation of buffers.
Parameters to be initialized are retrieved by
params_xxx() macros. For allocating a
buffer, you can call a helper function,
snd_pcm_lib_malloc_pages() is available
only when the DMA buffers have been pre-allocated.
See the section Buffer Types for more details.
Note that this and prepare callbacks
may be called multiple times per initialization.
For example, the OSS emulation may
call these callbacks at each change via its ioctl.
Thus, you need to take care not to allocate the same buffers many times, which will lead to memory leak! Calling the helper function above many times is OK. It will release the previous buffer automatically when it was already allocated.
Another note is that this callback is non-atomic
(schedulable). This is important, because the
trigger callback
is atomic (non-schedulable). That is, mutex or any
schedule-related functions are not available in
trigger callback.
Please see the subsection
Atomicity for details.
This is called to release the resources allocated via
hw_params. For example, releasing the
buffer via
snd_pcm_lib_malloc_pages() is done by
calling the following:
This function is always called before the close callback is called. Also, the callback may be called multiple times, too. Keep track whether the resource was already released.
This callback is called when the pcm is
"prepared". You can set the format type, sample
rate, etc. here. The difference from
hw_params is that the
prepare callback will be called at each
time
snd_pcm_prepare() is called, i.e. when
recovered after underruns, etc.
Note that this callback became non-atomic since the recent version. You can use schedule-related functions safely in this callback now.
In this and the following callbacks, you can refer to the values via the runtime record, substream->runtime. For example, to get the current rate, format or channels, access to runtime->rate, runtime->format or runtime->channels, respectively. The physical address of the allocated buffer is set to runtime->dma_area. The buffer and period sizes are in runtime->buffer_size and runtime->period_size, respectively.
Be careful that this callback will be called many times at each set up, too.
This is called when the pcm is started, stopped or paused.
Which action is specified in the second argument,
SNDRV_PCM_TRIGGER_XXX in
<sound/pcm.h>. At least,
START and STOP
commands must be defined in this callback.
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
// do something to start the PCM engine
break;
case SNDRV_PCM_TRIGGER_STOP:
// do something to stop the PCM engine
break;
default:
return -EINVAL;
}
When the pcm supports the pause operation (given in info
field of the hardware table), PAUSE_PUSE
and PAUSE_RELEASE commands must be
handled here, too. The former is the command to pause the pcm,
and the latter to restart the pcm again.
When the pcm supports the suspend/resume operation,
regardless of full or partial suspend/resume support,
SUSPEND and RESUME
commands must be handled, too.
These commands are issued when the power-management status is
changed. Obviously, the SUSPEND and
RESUME
do suspend and resume of the pcm substream, and usually, they
are identical with STOP and
START commands, respectively.
See Power Management section for details.
As mentioned, this callback is atomic. You cannot call the function going to sleep. The trigger callback should be as minimal as possible, just really triggering the DMA. The other stuff should be initialized hw_params and prepare callbacks properly beforehand.
This callback is called when the PCM middle layer inquires the current hardware position on the buffer. The position must be returned in frames (which was in bytes on ALSA 0.5.x), ranged from 0 to buffer_size - 1.
This is called usually from the buffer-update routine in the
pcm middle layer, which is invoked when
snd_pcm_period_elapsed() is called in the
interrupt routine. Then the pcm middle layer updates the
position and calculates the available space, and wakes up the
sleeping poll threads, etc.
This callback is also atomic.
These callbacks are not mandatory, and can be omitted in most cases. These callbacks are used when the hardware buffer cannot be on the normal memory space. Some chips have their own buffer on the hardware which is not mappable. In such a case, you have to transfer the data manually from the memory buffer to the hardware buffer. Or, if the buffer is non-contiguous on both physical and virtual memory spaces, these callbacks must be defined, too.
If these two callbacks are defined, copy and set-silence operations are done by them. The detailed will be described in the later section Buffer and Memory Management.
This callback is also not mandatory. This callback is called when the appl_ptr is updated in read or write operations. Some drivers like emu10k1-fx and cs46xx need to track the current appl_ptr for the internal buffer, and this callback is useful only for such a purpose.
This callback is atomic.
This callback is also not mandatory. This callback is used mainly for the non-contiguous buffer. The mmap calls this callback to get the page address. Some examples will be explained in the later section Buffer and Memory Management, too.