📄 writing-an-alsa-driver.tmpl
字号:
need to call <function>pci_set_master()</function> function, too. </para> <para> Suppose the 28bit mask, and the code to be added would be like: <informalexample> <programlisting><![CDATA[ if ((err = pci_enable_device(pci)) < 0) return err; 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; } ]]> </programlisting> </informalexample> </para> </section> <section id="pci-resource-resource-allocation"> <title>Resource Allocation</title> <para> The allocation of I/O ports and irqs are done via standard kernel functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And these resources must be released in the destructor function (see below). Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI like ALSA 0.5.x. </para> <para> Now assume that this PCI device has an I/O port with 8 bytes and an interrupt. Then <type>mychip_t</type> will have the following fields: <informalexample> <programlisting><![CDATA[ struct snd_mychip { snd_card_t *card; unsigned long port; int irq; };]]> </programlisting> </informalexample> </para> <para> For an i/o port (and also a memory region), you need to have the resource pointer for the standard resource management. For an irq, you have to keep only the irq number (integer). But you need to initialize this number as -1 before actual allocation, since irq 0 is valid. The port address and its resource pointer can be initialized as null by <function>kcalloc()</function> automatically, so you don't have to take care of resetting them. </para> <para> The allocation of an i/o port is done like this: <informalexample> <programlisting><![CDATA[ if ((err = pci_request_regions(pci, "My Chip")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->port = pci_resource_start(pci, 0);]]> </programlisting> </informalexample> </para> <para> It will reserve the i/o port region of 8 bytes of the given PCI device. The returned value, chip->res_port, is allocated via <function>kmalloc()</function> by <function>request_region()</function>. The pointer must be released via <function>kfree()</function>, but there is some problem regarding this. This issue will be explained more below. </para> <para> The allocation of an interrupt source is done like this: <informalexample> <programlisting><![CDATA[ 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;]]> </programlisting> </informalexample> where <function>snd_mychip_interrupt()</function> is the interrupt handler defined <link linkend="pcm-interface-interrupt-handler"><citetitle>later</citetitle></link>. Note that chip->irq should be defined only when <function>request_irq()</function> succeeded. </para> <para> On the PCI bus, the interrupts can be shared. Thus, <constant>SA_SHIRQ</constant> is given as the interrupt flag of <function>request_irq()</function>. </para> <para> The last argument of <function>request_irq()</function> is the data pointer passed to the interrupt handler. Usually, the chip-specific record is used for that, but you can use what you like, too. </para> <para> I won't define the detail of the interrupt handler at this point, but at least its appearance can be explained now. The interrupt handler looks usually like the following: <informalexample> <programlisting><![CDATA[ static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, struct pt_regs *regs) { mychip_t *chip = dev_id; .... return IRQ_HANDLED; }]]> </programlisting> </informalexample> </para> <para> Now let's write the corresponding destructor for the resources above. The role of destructor is simple: disable the hardware (if already activated) and release the resources. So far, we have no hardware part, so the disabling is not written here. </para> <para> For releasing the resources, <quote>check-and-release</quote> method is a safer way. For the interrupt, do like this: <informalexample> <programlisting><![CDATA[ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip);]]> </programlisting> </informalexample> Since the irq number can start from 0, you should initialize chip->irq with a negative value (e.g. -1), so that you can check the validity of the irq number as above. </para> <para> When you requested I/O ports or memory regions via <function>pci_request_region()</function> or <function>pci_request_regions()</function> like this example, release the resource(s) using the corresponding function, <function>pci_release_region()</function> or <function>pci_release_regions()</function>. <informalexample> <programlisting><![CDATA[ pci_release_regions(chip->pci);]]> </programlisting> </informalexample> </para> <para> When you requested manually via <function>request_region()</function> or <function>request_mem_region</function>, you can release it via <function>release_resource()</function>. Suppose that you keep the resource pointer returned from <function>request_region()</function> in chip->res_port, the release procedure looks like below: <informalexample> <programlisting><![CDATA[ if (chip->res_port) { release_resource(chip->res_port); kfree_nocheck(chip->res_port); }]]> </programlisting> </informalexample> As you can see, the resource pointer is also to be freed via <function>kfree_nocheck()</function> after <function>release_resource()</function> is called. You cannot use <function>kfree()</function> here, because on ALSA, <function>kfree()</function> may be a wrapper to its own allocator with the memory debugging. Since the resource pointer is allocated externally outside the ALSA, it must be released via the native <function>kfree()</function>. <function>kfree_nocheck()</function> is used for that; it calls the native <function>kfree()</function> without wrapper. </para> <para> Don't forget to call <function>pci_disable_device()</function> before all finished. </para> <para> And finally, release the chip-specific record. <informalexample> <programlisting><![CDATA[ kfree(chip);]]> </programlisting> </informalexample> </para> <para> Again, remember that you cannot set <parameter>__devexit</parameter> prefix for this destructor. </para> <para> We didn't implement the hardware-disabling part in the above. If you need to do this, please note that the destructor may be called even before the initialization of the chip is completed. It would be better to have a flag to skip the hardware-disabling if the hardware was not initialized yet. </para> <para> When the chip-data is assigned to the card using <function>snd_device_new()</function> with <constant>SNDRV_DEV_LOWLELVEL</constant> , its destructor is called at the last. That is, it is assured that all other components like PCMs and controls have been already released. You don't have to call stopping PCMs, etc. explicitly, but just stop the hardware in the low-level. </para> <para> The management of a memory-mapped region is almost as same as the management of an i/o port. You'll need three fields like the following: <informalexample> <programlisting><![CDATA[ struct snd_mychip { .... unsigned long iobase_phys; void __iomem *iobase_virt; };]]> </programlisting> </informalexample> and the allocation would be like below: <informalexample> <programlisting><![CDATA[ if ((err = pci_request_regions(pci, "My Chip")) < 0) { kfree(chip); return err; } chip->iobase_phys = pci_resource_start(pci, 0); chip->iobase_virt = ioremap_nocache(chip->iobase_phys, pci_resource_len(pci, 0));]]> </programlisting> </informalexample> and the corresponding destructor would be: <informalexample> <programlisting><![CDATA[ static int snd_mychip_free(mychip_t *chip) { .... if (chip->iobase_virt) iounmap(chip->iobase_virt); .... pci_release_regions(chip->pci); .... }]]> </programlisting> </informalexample> </para> </section> <section id="pci-resource-device-struct"> <title>Registration of Device Struct</title> <para> At some point, typically after calling <function>snd_device_new()</function>, you need to register the <structname>struct device</structname> of the chip you're handling for udev and co. ALSA provides a macro for compatibility with older kernels. Simply call like the following: <informalexample> <programlisting><![CDATA[ snd_card_set_dev(card, &pci->dev);]]> </programlisting> </informalexample> so that it stores the PCI's device pointer to the card. This will be referred by ALSA core functions later when the devices are registered. </para> <para> In the case of non-PCI, pass the proper device struct pointer of the BUS instead. (In the case of legacy ISA without PnP, you don't have to do anything.) </para> </section> <section id="pci-resource-entries"> <title>PCI Entries</title> <para> So far, so good. Let's finish the rest of missing PCI stuffs. At first, we need a <structname>pci_device_id</structname> table for this chipset. It's a table of PCI vendor/device ID number, and some masks. </para> <para> For example, <informalexample> <programlisting><![CDATA[ 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);]]> </programlisting> </informalexample> </para> <para> The first and second fields of <structname>pci_device_id</structname> struct are the vendor and device IDs. If you have nothing special to filter the matching devices, you can use the rest of fields like above. The last field of <structname>pci_device_id</structname> struct is a private data for this entry. You can specify any value here, for example, to tell the type of different operations per each device IDs. Such an example is found in intel8x0 driver. </para> <para> The last entry of this list is the terminator. You must specify this all-zero entry. </para> <para> Then, prepare the <structname>pci_driver</structname> record: <informalexample> <programlisting><![CDATA[ static struct pci_driver driver = { .name = "My Own Chip", .id_table = snd_mychip_ids, .probe = snd_mychip_probe, .remove = __devexit_p(snd_mychip_remove), };]]> </programlisting> </informalexample> </para> <para> The <structfield>probe</structfield> and <structfield>remove</structfield> functions are what we already defined in the previous sections. The <structfield>remove</structfield> should be defined with <function>__devexit_p()</function> macro, so that it's not defined for built-in (and non-hot-pluggable) case. The <structfield>name</structfield> field is the name string of this device. Note that you must not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -