A pcm instance is allocated by snd_pcm_new()
function. It would be better to create a constructor for pcm,
namely,
static int __devinit snd_mychip_new_pcm(struct mychip *chip)
{
struct snd_pcm *pcm;
int err;
if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1,
&pcm)) < 0)
return err;
pcm->private_data = chip;
strcpy(pcm->name, "My Chip");
chip->pcm = pcm;
....
return 0;
}
The snd_pcm_new() function takes the four
arguments. The first argument is the card pointer to which this
pcm is assigned, and the second is the ID string.
The third argument (index, 0 in the
above) is the index of this new pcm. It begins from zero. When
you will create more than one pcm instances, specify the
different numbers in this argument. For example,
index = 1 for the second PCM device.
The fourth and fifth arguments are the number of substreams for playback and capture, respectively. Here both 1 are given in the above example. When no playback or no capture is available, pass 0 to the corresponding argument.
If a chip supports multiple playbacks or captures, you can
specify more numbers, but they must be handled properly in
open/close, etc. callbacks. When you need to know which
substream you are referring to, then it can be obtained from
struct snd_pcm_substream data passed to each callback
as follows:
After the pcm is created, you need to set operators for each pcm stream.
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_mychip_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_mychip_capture_ops);
The operators are defined typically like this:
static struct snd_pcm_ops snd_mychip_playback_ops = {
.open = snd_mychip_pcm_open,
.close = snd_mychip_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_mychip_pcm_hw_params,
.hw_free = snd_mychip_pcm_hw_free,
.prepare = snd_mychip_pcm_prepare,
.trigger = snd_mychip_pcm_trigger,
.pointer = snd_mychip_pcm_pointer,
};
After setting the operators, most likely you'd like to pre-allocate the buffer. For the pre-allocation, simply call the following:
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
64*1024, 64*1024);
Additionally, you can set some extra information for this pcm
in pcm->info_flags.
The available values are defined as
SNDRV_PCM_INFO_XXX in
<sound/asound.h>, which is used for
the hardware definition (described later). When your soundchip
supports only half-duplex, specify like this: