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

📄 writing-an-alsa-driver.tmpl

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
  /* chip-specific destructor   * (see "PCI Resource Managements")   */  static int snd_mychip_free(mychip_t *chip)  {          .... // will be implemented later...  }  /* component-destructor   * (see "Management of Cards and Components")   */  static int snd_mychip_dev_free(snd_device_t *device)  {          mychip_t *chip = device->device_data;          return snd_mychip_free(chip);  }  /* chip-specific constructor   * (see "Management of Cards and Components")   */  static int __devinit snd_mychip_create(snd_card_t *card,                                         struct pci_dev *pci,                                         mychip_t **rchip)  {          mychip_t *chip;          int err;          static snd_device_ops_t ops = {                 .dev_free = snd_mychip_dev_free,          };          *rchip = NULL;          // check PCI availability here          // (see "PCI Resource Managements")          ....          /* allocate a chip-specific data with zero filled */          chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);          if (chip == NULL)                  return -ENOMEM;          chip->card = card;          // rest of initialization here; will be implemented          // later, see "PCI Resource Managements"          ....          if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,                                    chip, &ops)) < 0) {                  snd_mychip_free(chip);                  return err;          }          snd_card_set_dev(card, &pci->dev);          *rchip = chip;          return 0;  }  /* constructor -- see "Constructor" sub-section */  static int __devinit snd_mychip_probe(struct pci_dev *pci,                               const struct pci_device_id *pci_id)  {          static int dev;          snd_card_t *card;          mychip_t *chip;          int err;          /* (1) */          if (dev >= SNDRV_CARDS)                  return -ENODEV;          if (!enable[dev]) {                  dev++;                  return -ENOENT;          }          /* (2) */          card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);          if (card == NULL)                  return -ENOMEM;          /* (3) */          if ((err = snd_mychip_create(card, pci, &chip)) < 0) {                  snd_card_free(card);                  return err;          }          /* (4) */          strcpy(card->driver, "My Chip");          strcpy(card->shortname, "My Own Chip 123");          sprintf(card->longname, "%s at 0x%lx irq %i",                  card->shortname, chip->ioport, chip->irq);          /* (5) */          .... // implemented later          /* (6) */          if ((err = snd_card_register(card)) < 0) {                  snd_card_free(card);                  return err;          }          /* (7) */          pci_set_drvdata(pci, card);          dev++;          return 0;  }  /* destructor -- see "Destructor" sub-section */  static void __devexit snd_mychip_remove(struct pci_dev *pci)  {          snd_card_free(pci_get_drvdata(pci));          pci_set_drvdata(pci, NULL);  }]]>          </programlisting>        </example>      </para>    </section>    <section id="basic-flow-constructor">      <title>Constructor</title>      <para>        The real constructor of PCI drivers is probe callback. The      probe callback and other component-constructors which are called      from probe callback should be defined with      <parameter>__devinit</parameter> prefix. You       cannot use <parameter>__init</parameter> prefix for them,      because any PCI device could be a hotplug device.       </para>      <para>        In the probe callback, the following scheme is often used.      </para>      <section id="basic-flow-constructor-device-index">        <title>1) Check and increment the device index.</title>        <para>          <informalexample>            <programlisting><![CDATA[  static int dev;  ....  if (dev >= SNDRV_CARDS)          return -ENODEV;  if (!enable[dev]) {          dev++;          return -ENOENT;  }]]>            </programlisting>          </informalexample>        where enable[dev] is the module option.        </para>        <para>          At each time probe callback is called, check the        availability of the device. If not available, simply increment        the device index and returns. dev will be incremented also        later (<link        linkend="basic-flow-constructor-set-pci"><citetitle>step        7</citetitle></link>).         </para>      </section>      <section id="basic-flow-constructor-create-card">        <title>2) Create a card instance</title>        <para>          <informalexample>            <programlisting><![CDATA[  snd_card_t *card;  ....  card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);]]>            </programlisting>          </informalexample>        </para>        <para>          The detail will be explained in the section          <link linkend="card-management-card-instance"><citetitle>          Management of Cards and Components</citetitle></link>.        </para>      </section>      <section id="basic-flow-constructor-create-main">        <title>3) Create a main component</title>        <para>          In this part, the PCI resources are allocated.          <informalexample>            <programlisting><![CDATA[  mychip_t *chip;  ....  if ((err = snd_mychip_create(card, pci, &chip)) < 0) {          snd_card_free(card);          return err;  }]]>            </programlisting>          </informalexample>          The detail will be explained in the section <link        linkend="pci-resource"><citetitle>PCI Resource        Managements</citetitle></link>.        </para>      </section>      <section id="basic-flow-constructor-main-component">        <title>4) Set the driver ID and name strings.</title>        <para>          <informalexample>            <programlisting><![CDATA[  strcpy(card->driver, "My Chip");  strcpy(card->shortname, "My Own Chip 123");  sprintf(card->longname, "%s at 0x%lx irq %i",          card->shortname, chip->ioport, chip->irq);]]>            </programlisting>          </informalexample>          The driver field holds the minimal ID string of the        chip. This is referred by alsa-lib's configurator, so keep it        simple but unique.           Even the same driver can have different driver IDs to        distinguish the functionality of each chip type.         </para>        <para>          The shortname field is a string shown as more verbose        name. The longname field contains the information which is        shown in <filename>/proc/asound/cards</filename>.         </para>      </section>      <section id="basic-flow-constructor-create-other">        <title>5) Create other components, such as mixer, MIDI, etc.</title>        <para>          Here you define the basic components such as          <link linkend="pcm-interface"><citetitle>PCM</citetitle></link>,          mixer (e.g. <link linkend="api-ac97"><citetitle>AC97</citetitle></link>),          MIDI (e.g. <link linkend="midi-interface"><citetitle>MPU-401</citetitle></link>),          and other interfaces.          Also, if you want a <link linkend="proc-interface"><citetitle>proc        file</citetitle></link>, define it here, too.        </para>      </section>      <section id="basic-flow-constructor-register-card">        <title>6) Register the card instance.</title>        <para>          <informalexample>            <programlisting><![CDATA[  if ((err = snd_card_register(card)) < 0) {          snd_card_free(card);          return err;  }]]>            </programlisting>          </informalexample>        </para>        <para>          Will be explained in the section <link        linkend="card-management-registration"><citetitle>Management        of Cards and Components</citetitle></link>, too.         </para>      </section>      <section id="basic-flow-constructor-set-pci">        <title>7) Set the PCI driver data and return zero.</title>        <para>          <informalexample>            <programlisting><![CDATA[        pci_set_drvdata(pci, card);        dev++;        return 0;]]>            </programlisting>          </informalexample>          In the above, the card record is stored. This pointer is        referred in the remove callback and power-management        callbacks, too.         </para>      </section>    </section>    <section id="basic-flow-destructor">      <title>Destructor</title>      <para>        The destructor, remove callback, simply releases the card      instance. Then the ALSA middle layer will release all the      attached components automatically.       </para>      <para>        It would be typically like the following:        <informalexample>          <programlisting><![CDATA[  static void __devexit snd_mychip_remove(struct pci_dev *pci)  {          snd_card_free(pci_get_drvdata(pci));          pci_set_drvdata(pci, NULL);  }]]>          </programlisting>        </informalexample>        The above code assumes that the card pointer is set to the PCI	driver data.      </para>    </section>    <section id="basic-flow-header-files">      <title>Header Files</title>      <para>        For the above example, at least the following include files      are necessary.         <informalexample>          <programlisting><![CDATA[  #include <sound/driver.h>  #include <linux/init.h>  #include <linux/pci.h>  #include <linux/slab.h>  #include <sound/core.h>  #include <sound/initval.h>]]>          </programlisting>        </informalexample>	where the last one is necessary only when module options are      defined in the source file.  If the codes are split to several      files, the file without module options don't need them.      </para>      <para>        In addition to them, you'll need      <filename>&lt;linux/interrupt.h&gt;</filename> for the interrupt      handling, and <filename>&lt;asm/io.h&gt;</filename> for the i/o      access. If you use <function>mdelay()</function> or      <function>udelay()</function> functions, you'll need to include      <filename>&lt;linux/delay.h&gt;</filename>, too.       </para>      <para>      The ALSA interfaces like PCM or control API are define in other      header files as <filename>&lt;sound/xxx.h&gt;</filename>.      They have to be included after      <filename>&lt;sound/core.h&gt;</filename>.      </para>    </section>  </chapter><!-- ****************************************************** --><!-- Management of Cards and Components  --><!-- ****************************************************** -->  <chapter id="card-management">    <title>Management of Cards and Components</title>    <section id="card-management-card-instance">      <title>Card Instance</title>      <para>      For each soundcard, a <quote>card</quote> record must be allocated.      </para>      <para>      A card record is the headquarters of the soundcard.  It manages      the list of whole devices (components) on the soundcard, such as      PCM, mixers, MIDI, synthesizer, and so on.  Also, the card      record holds the ID and the name strings of the card, manages      the root of proc files, and controls the power-management states      and hotplug disconnections.  The component list on the card      record is used to manage the proper releases of resources at      destruction.       </para>      <para>        As mentioned above, to create a card instance, call      <function>snd_card_new()</function>.        <informalexample>          <programlisting><![CDATA[  snd_card_t *card;  card = snd_card_new(index, id, module, extra_size);]]>          </programlisting>        </informalexample>      </para>      <para>        The function takes four arguments, the card-index number, the        id string, the module pointer (usually        <constant>THIS_MODULE</constant>),        and the size of extra-data space.  The last argument is used to        allocate card-&gt;private_data for the        chip-specific data.  Note that this data

⌨️ 快捷键说明

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