⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 writing-an-alsa-driver.tmpl

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
      use a slash <quote>/</quote> in this string.       </para>      <para>        And at last, the module entries:        <informalexample>          <programlisting><![CDATA[  static int __init alsa_card_mychip_init(void)  {          return pci_module_init(&driver);  }  static void __exit alsa_card_mychip_exit(void)  {          pci_unregister_driver(&driver);  }  module_init(alsa_card_mychip_init)  module_exit(alsa_card_mychip_exit)]]>          </programlisting>        </informalexample>      </para>      <para>        Note that these module entries are tagged with      <parameter>__init</parameter> and       <parameter>__exit</parameter> prefixes, not      <parameter>__devinit</parameter> nor      <parameter>__devexit</parameter>.      </para>      <para>        Oh, one thing was forgotten. If you have no exported symbols,        you need to declare it on 2.2 or 2.4 kernels (on 2.6 kernels        it's not necessary, though).        <informalexample>          <programlisting><![CDATA[  EXPORT_NO_SYMBOLS;]]>          </programlisting>        </informalexample>        That's all!      </para>    </section>  </chapter><!-- ****************************************************** --><!-- PCM Interface  --><!-- ****************************************************** -->  <chapter id="pcm-interface">    <title>PCM Interface</title>    <section id="pcm-interface-general">      <title>General</title>      <para>        The PCM middle layer of ALSA is quite powerful and it is only      necessary for each driver to implement the low-level functions      to access its hardware.      </para>      <para>        For accessing to the PCM layer, you need to include      <filename>&lt;sound/pcm.h&gt;</filename> above all. In addition,      <filename>&lt;sound/pcm_params.h&gt;</filename> might be needed      if you access to some functions related with hw_param.       </para>      <para>        Each card device can have up to four pcm instances. A pcm      instance corresponds to a pcm device file. The limitation of      number of instances comes only from the available bit size of      the linux's device number. Once when 64bit device number is      used, we'll have more available pcm instances.       </para>      <para>        A pcm instance consists of pcm playback and capture streams,      and each pcm stream consists of one or more pcm substreams. Some      soundcard supports the multiple-playback function. For example,      emu10k1 has a PCM playback of 32 stereo substreams. In this case, at      each open, a free substream is (usually) automatically chosen      and opened. Meanwhile, when only one substream exists and it was      already opened, the succeeding open will result in the blocking      or the error with <constant>EAGAIN</constant> according to the      file open mode. But you don't have to know the detail in your      driver. The PCM middle layer will take all such jobs.       </para>    </section>    <section id="pcm-interface-example">      <title>Full Code Example</title>      <para>      The example code below does not include any hardware access      routines but shows only the skeleton, how to build up the PCM      interfaces.        <example>          <title>PCM Example Code</title>          <programlisting><![CDATA[  #include <sound/pcm.h>  ....  /* hardware definition */  static snd_pcm_hardware_t snd_mychip_playback_hw = {          .info = (SNDRV_PCM_INFO_MMAP |                   SNDRV_PCM_INFO_INTERLEAVED |                   SNDRV_PCM_INFO_BLOCK_TRANSFER |                   SNDRV_PCM_INFO_MMAP_VALID),          .formats =          SNDRV_PCM_FMTBIT_S16_LE,          .rates =            SNDRV_PCM_RATE_8000_48000,          .rate_min =         8000,          .rate_max =         48000,          .channels_min =     2,          .channels_max =     2,          .buffer_bytes_max = 32768,          .period_bytes_min = 4096,          .period_bytes_max = 32768,          .periods_min =      1,          .periods_max =      1024,  };  /* hardware definition */  static snd_pcm_hardware_t snd_mychip_capture_hw = {          .info = (SNDRV_PCM_INFO_MMAP |                   SNDRV_PCM_INFO_INTERLEAVED |                   SNDRV_PCM_INFO_BLOCK_TRANSFER |                   SNDRV_PCM_INFO_MMAP_VALID),          .formats =          SNDRV_PCM_FMTBIT_S16_LE,          .rates =            SNDRV_PCM_RATE_8000_48000,          .rate_min =         8000,          .rate_max =         48000,          .channels_min =     2,          .channels_max =     2,          .buffer_bytes_max = 32768,          .period_bytes_min = 4096,          .period_bytes_max = 32768,          .periods_min =      1,          .periods_max =      1024,  };  /* open callback */  static int snd_mychip_playback_open(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          snd_pcm_runtime_t *runtime = substream->runtime;          runtime->hw = snd_mychip_playback_hw;          // more hardware-initialization will be done here          return 0;  }  /* close callback */  static int snd_mychip_playback_close(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          // the hardware-specific codes will be here          return 0;  }  /* open callback */  static int snd_mychip_capture_open(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          snd_pcm_runtime_t *runtime = substream->runtime;          runtime->hw = snd_mychip_capture_hw;          // more hardware-initialization will be done here          return 0;  }  /* close callback */  static int snd_mychip_capture_close(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          // the hardware-specific codes will be here          return 0;  }  /* hw_params callback */  static int snd_mychip_pcm_hw_params(snd_pcm_substream_t *substream,                               snd_pcm_hw_params_t * hw_params)  {          return snd_pcm_lib_malloc_pages(substream,                                     params_buffer_bytes(hw_params));  }  /* hw_free callback */  static int snd_mychip_pcm_hw_free(snd_pcm_substream_t *substream)  {          return snd_pcm_lib_free_pages(substream);  }  /* prepare callback */  static int snd_mychip_pcm_prepare(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          snd_pcm_runtime_t *runtime = substream->runtime;          /* set up the hardware with the current configuration           * for example...           */          mychip_set_sample_format(chip, runtime->format);          mychip_set_sample_rate(chip, runtime->rate);          mychip_set_channels(chip, runtime->channels);          mychip_set_dma_setup(chip, runtime->dma_area,                               chip->buffer_size,                               chip->period_size);          return 0;  }  /* trigger callback */  static int snd_mychip_pcm_trigger(snd_pcm_substream_t *substream,                                    int cmd)  {          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;          }  }  /* pointer callback */  static snd_pcm_uframes_t  snd_mychip_pcm_pointer(snd_pcm_substream_t *substream)  {          mychip_t *chip = snd_pcm_substream_chip(substream);          unsigned int current_ptr;          /* get the current hardware pointer */          current_ptr = mychip_get_hw_pointer(chip);          return current_ptr;  }  /* operators */  static snd_pcm_ops_t snd_mychip_playback_ops = {          .open =        snd_mychip_playback_open,          .close =       snd_mychip_playback_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,  };  /* operators */  static snd_pcm_ops_t snd_mychip_capture_ops = {          .open =        snd_mychip_capture_open,          .close =       snd_mychip_capture_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,  };  /*   *  definitions of capture are omitted here...   */  /* create a pcm device */  static int __devinit snd_mychip_new_pcm(mychip_t *chip)  {          snd_pcm_t *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;          /* set operators */          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);          /* pre-allocation of buffers */          snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,                                                snd_dma_pci_data(chip->pci),                                                64*1024, 64*1024);          return 0;  }]]>          </programlisting>        </example>      </para>    </section>    <section id="pcm-interface-constructor">      <title>Constructor</title>      <para>        A pcm instance is allocated <function>snd_pcm_new()</function>      function. It would be better to create a constructor for pcm,      namely,         <informalexample>          <programlisting><![CDATA[  static int __devinit snd_mychip_new_pcm(mychip_t *chip)  {          snd_pcm_t *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;  }]]>          </programlisting>        </informalexample>      </para>      <para>        The <function>snd_pcm_new()</function> 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.       </para>      <para>        The third argument (<parameter>index</parameter>, 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,      <parameter>index</parameter> = 1 for the second PCM device.        </para>      <para>        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.      </para>      <para>        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      <type>snd_pcm_substream_t</type> data passed to each callback      as follows:         <informalexample>          <programlisting><![CDATA[  snd_pcm_substream_t *substream;  int index = substream->number;]]>          </programlisting>        </informalexample>      </para>      <para>        After the pcm is created, you need to set operators for each        pcm stream.         <informalexample>          <programlisting><![CDATA[  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);]]>          </programlisting>        </informalexample>      </para>      <para>        The operators are defined typically like this:        <informalexample>          <programlisting><![CDATA[  static snd_pcm_ops_t 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,  };]]>          </programlisting>        </informalexample>        Each of callbacks is explained in the subsection  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -