Constructor

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:

  struct snd_pcm_substream *substream;
  int index = substream->number;
          

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,
  };
          

Each of callbacks is explained in the subsection Operators.

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);
          

It will allocate up to 64kB buffer as default. The details of buffer management will be described in the later section Buffer and Memory Management.

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:

  pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;