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

📄 writing-an-alsa-driver.tmpl

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
        <emphasis>is</emphasis> allocated by        <function>snd_card_new()</function>.      </para>    </section>    <section id="card-management-component">      <title>Components</title>      <para>        After the card is created, you can attach the components      (devices) to the card instance. On ALSA driver, a component is      represented as a <type>snd_device_t</type> object.      A component can be a PCM instance, a control interface, a raw      MIDI interface, etc.  Each of such instances has one component      entry.      </para>      <para>        A component can be created via        <function>snd_device_new()</function> function.         <informalexample>          <programlisting><![CDATA[  snd_device_new(card, SNDRV_DEV_XXX, chip, &ops);]]>          </programlisting>        </informalexample>      </para>      <para>        This takes the card pointer, the device-level      (<constant>SNDRV_DEV_XXX</constant>), the data pointer, and the      callback pointers (<parameter>&amp;ops</parameter>). The      device-level defines the type of components and the order of      registration and de-registration.  For most of components, the      device-level is already defined.  For a user-defined component,      you can use <constant>SNDRV_DEV_LOWLEVEL</constant>.      </para>      <para>      This function itself doesn't allocate the data space. The data      must be allocated manually beforehand, and its pointer is passed      as the argument. This pointer is used as the identifier      (<parameter>chip</parameter> in the above example) for the      instance.       </para>      <para>        Each ALSA pre-defined component such as ac97 or pcm calls      <function>snd_device_new()</function> inside its      constructor. The destructor for each component is defined in the      callback pointers.  Hence, you don't need to take care of      calling a destructor for such a component.      </para>      <para>        If you would like to create your own component, you need to      set the destructor function to dev_free callback in      <parameter>ops</parameter>, so that it can be released      automatically via <function>snd_card_free()</function>. The      example will be shown later as an implementation of a      chip-specific data.       </para>    </section>    <section id="card-management-chip-specific">      <title>Chip-Specific Data</title>      <para>      The chip-specific information, e.g. the i/o port address, its      resource pointer, or the irq number, is stored in the      chip-specific record.      Usually, the chip-specific record is typedef'ed as      <type>xxx_t</type> like the following:        <informalexample>          <programlisting><![CDATA[  typedef struct snd_mychip mychip_t;  struct snd_mychip {          ....  };]]>          </programlisting>        </informalexample>      </para>      <para>        In general, there are two ways to allocate the chip record.      </para>      <section id="card-management-chip-specific-snd-card-new">        <title>1. Allocating via <function>snd_card_new()</function>.</title>        <para>          As mentioned above, you can pass the extra-data-length to the 4th argument of <function>snd_card_new()</function>, i.e.          <informalexample>            <programlisting><![CDATA[  card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(mychip_t));]]>            </programlisting>          </informalexample>          whether <type>mychip_t</type> is the type of the chip record.        </para>        <para>          In return, the allocated record can be accessed as          <informalexample>            <programlisting><![CDATA[  mychip_t *chip = (mychip_t *)card->private_data;]]>            </programlisting>          </informalexample>          With this method, you don't have to allocate twice.          The record is released together with the card instance.        </para>      </section>      <section id="card-management-chip-specific-allocate-extra">        <title>2. Allocating an extra device.</title>        <para>          After allocating a card instance via          <function>snd_card_new()</function> (with          <constant>NULL</constant> on the 4th arg), call          <function>kcalloc()</function>.           <informalexample>            <programlisting><![CDATA[  snd_card_t *card;  mychip_t *chip;  card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);  .....  chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);]]>            </programlisting>          </informalexample>        </para>        <para>          The chip record should have the field to hold the card          pointer at least,           <informalexample>            <programlisting><![CDATA[  struct snd_mychip {          snd_card_t *card;          ....  };]]>            </programlisting>          </informalexample>        </para>        <para>          Then, set the card pointer in the returned chip instance.          <informalexample>            <programlisting><![CDATA[  chip->card = card;]]>            </programlisting>          </informalexample>        </para>        <para>          Next, initialize the fields, and register this chip          record as a low-level device with a specified          <parameter>ops</parameter>,           <informalexample>            <programlisting><![CDATA[  static snd_device_ops_t ops = {          .dev_free =        snd_mychip_dev_free,  };  ....  snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);]]>            </programlisting>          </informalexample>          <function>snd_mychip_dev_free()</function> is the        device-destructor function, which will call the real        destructor.         </para>        <para>          <informalexample>            <programlisting><![CDATA[  static int snd_mychip_dev_free(snd_device_t *device)  {          mychip_t *chip = device->device_data;          return snd_mychip_free(chip);  }]]>            </programlisting>          </informalexample>          where <function>snd_mychip_free()</function> is the real destructor.        </para>      </section>    </section>    <section id="card-management-registration">      <title>Registration and Release</title>      <para>        After all components are assigned, register the card instance      by calling <function>snd_card_register()</function>. The access      to the device files are enabled at this point. That is, before      <function>snd_card_register()</function> is called, the      components are safely inaccessible from external side. If this      call fails, exit the probe function after releasing the card via      <function>snd_card_free()</function>.       </para>      <para>        For releasing the card instance, you can call simply      <function>snd_card_free()</function>. As already mentioned, all      components are released automatically by this call.       </para>      <para>        As further notes, the destructors (both      <function>snd_mychip_dev_free</function> and      <function>snd_mychip_free</function>) cannot be defined with      <parameter>__devexit</parameter> prefix, because they may be      called from the constructor, too, at the false path.       </para>      <para>      For a device which allows hotplugging, you can use      <function>snd_card_free_in_thread</function>.  This one will      postpone the destruction and wait in a kernel-thread until all      devices are closed.      </para>    </section>  </chapter><!-- ****************************************************** --><!-- PCI Resource Managements  --><!-- ****************************************************** -->  <chapter id="pci-resource">    <title>PCI Resource Managements</title>    <section id="pci-resource-example">      <title>Full Code Example</title>      <para>        In this section, we'll finish the chip-specific constructor,      destructor and PCI entries. The example code is shown first,      below.         <example>          <title>PCI Resource Managements Example</title>          <programlisting><![CDATA[  struct snd_mychip {          snd_card_t *card;          struct pci_dev *pci;          unsigned long port;          int irq;  };  static int snd_mychip_free(mychip_t *chip)  {          /* disable hardware here if any */          .... // (not implemented in this document)          /* release the irq */          if (chip->irq >= 0)                  free_irq(chip->irq, (void *)chip);          /* release the i/o ports */          pci_release_regions(chip->pci);          /* disable the PCI entry */          pci_disable_device(chip->pci);          /* release the data */          kfree(chip);          return 0;  }  /* chip-specific constructor */  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;          /* initialize the PCI entry */          if ((err = pci_enable_device(pci)) < 0)                  return err;          /* check PCI availability (28bit DMA) */          if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||              pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {                  printk(KERN_ERR "error to set 28bit mask DMA\n");                  pci_disable_device(pci);                  return -ENXIO;          }          chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);          if (chip == NULL) {                  pci_disable_device(pci);                  return -ENOMEM;          }          /* initialize the stuff */          chip->card = card;          chip->pci = pci;          chip->irq = -1;          /* (1) PCI resource allocation */          if ((err = pci_request_regions(pci, "My Chip")) < 0) {                  kfree(chip);                  pci_disable_device(pci);                  return err;          }          chip->port = pci_resource_start(pci, 0);          if (request_irq(pci->irq, snd_mychip_interrupt,                          SA_INTERRUPT|SA_SHIRQ, "My Chip",                          (void *)chip)) {                  printk(KERN_ERR "cannot grab irq %d\n", pci->irq);                  snd_mychip_free(chip);                  return -EBUSY;          }          chip->irq = pci->irq;          /* (2) initialization of the chip hardware */          .... //   (not implemented in this document)          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;  }          /* PCI IDs */  static struct pci_device_id snd_mychip_ids[] = {          { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },          ....          { 0, }  };  MODULE_DEVICE_TABLE(pci, snd_mychip_ids);  /* pci_driver definition */  static struct pci_driver driver = {          .name = "My Own Chip",          .id_table = snd_mychip_ids,          .probe = snd_mychip_probe,          .remove = __devexit_p(snd_mychip_remove),  };  /* initialization of the module */  static int __init alsa_card_mychip_init(void)  {          return pci_module_init(&driver);  }  /* clean up the module */  static void __exit alsa_card_mychip_exit(void)  {          pci_unregister_driver(&driver);  }  module_init(alsa_card_mychip_init)  module_exit(alsa_card_mychip_exit)  EXPORT_NO_SYMBOLS; /* for old kernels only */]]>          </programlisting>        </example>      </para>    </section>    <section id="pci-resource-some-haftas">      <title>Some Hafta's</title>      <para>        The allocation of PCI resources is done in the      <function>probe()</function> function, and usually an extra      <function>xxx_create()</function> function is written for this      purpose.       </para>      <para>        In the case of PCI devices, you have to call at first      <function>pci_enable_device()</function> function before      allocating resources. Also, you need to set the proper PCI DMA      mask to limit the accessed i/o range. In some cases, you might

⌨️ 快捷键说明

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