?? writing-an-alsa-driver.tmpl
字號:
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->private_data for the chip-specific data. Note that this data <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>&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> You might have objections against such a typedef, but this typedef is necessary if you use a <quote>magic-cast</quote> (explained <link linkend="card-management-chip-what-advantage"><citetitle>later</citetitle></link>). </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. But you cannot use <quote>magic-cast</quote> for this record pointer, instead. </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>snd_magic_kcalloc()</function>. <informalexample> <programlisting><![CDATA[ snd_card_t *card; mychip_t *chip; card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); ..... chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL);]]> </programlisting> </informalexample> Once when the record is allocated via snd_magic stuff, you can use <quote>magic-cast</quote> for the void pointer. </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> Also, you need to define a magic-value for <type>mychip_t</type>. <informalexample> <programlisting><![CDATA[ #define mychip_t_magic 0xa15a4501]]> </programlisting> </informalexample> (the detail will be described in the <link linkend="card-management-chip-what-advantage"><citetitle> next</citetitle></link> subsection). </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 = snd_magic_cast(mychip_t, device->device_data, return -ENXIO); return snd_mychip_free(chip); }]]> </programlisting> </informalexample> where <function>snd_mychip_free()</function> is the real destructor. </para> </section> <section id="card-management-chip-what-advantage"> <title>Not a magic but a logic</title> <para>Now, you might have a question: What is the advantage of the second method? Obviously, it looks far more complicated.</para> <para> As I wrote many times, the second method allows a <quote>magic-cast</quote> for <type>mychip_t</type>. If you have a void pointer (such as pcm->private_data), the pointer type is unknown at the compile time, and you cannot know even if a wrong pointer type is passed. The compiler would accept it. The magic-cast checks the pointer type at the runtime (and whether it's a null pointer, too). Hence, the cast will be much safer and good for debugging. </para> <para> As you have already seen, allocation with a magic-header can be done via <function>snd_magic_kmalloc()</function> or <function>snd_magic_kcalloc()</function>. <informalexample> <programlisting><![CDATA[ mychip_t *chip; chip = snd_magic_kmalloc(mychip_t, 0, GFP_KERNEL); chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL);]]> </programlisting> </informalexample> The difference of these two functions is whether the area is zero-cleared (<function>kcalloc</function>) or not (<function>kmalloc</function>). </para> <para> The first argument of the allocator is the type of the record. The magic-constant has to be defined for this type beforehand. In this case, we'll need to define <constant>mychip_t_magic</constant>, for example, as already seen, <informalexample> <programlisting><![CDATA[ #define mychip_t_magic 0xa15a4501]]> </programlisting> </informalexample> The value is arbitrary but should be unique. This is usually defined in <filename><include/sndmagic.h></filename> or <filename><include/amagic.h></filename> for alsa-driver tree, but you may define it locally in the code at the early development stage, since changing <filename>sndmagic.h</filename> will lead to the recompilation of the whole driver codes. </para> <para> The second argument is the extra-data length. It is usually zero. The third argument is the flags to be passed to kernel memory allocator, <constant>GFP_XXX</constant>. Normally, <constant>GFP_KERNEL</constant> is passed. </para> <para> For casting a pointer, use <function>snd_magic_cast()</function> macro: <informalexample> <programlisting><![CDATA[ mychip_t *chip = snd_magic_cast(mychip_t, source_pointer, action);]]> </programlisting> </informalexample> where <parameter>source_pointer</parameter> is the pointer to be casted (e.g. pcm->private_data), and <parameter>action</parameter> is the action to do if the cast fails (e.g. return <constant>-EINVAL</constant>). </para> <para> For releasing the magic-allocated data, you need to call <function>snd_magic_kfree()</function> function instead of <function>kfree()</function>. <informalexample> <programlisting><![CDATA[ snd_magic_kfree(chip);]]> </programlisting> </informalexample> </para> <para> If you call <function>kfree()</function> for the magic-allocated value, it will lead to memory leaks. When the ALSA drivers are compiled with <constant>CONFIG_SND_DEBUG_MEMORY</constant> kernel config (or configured with <option>--with-debug=full</option>), the non-matching free will be checked and you'll see warning messages. </para> <para> If you are 100% sure that your code is bug-free, you can compile the driver without <constant>CONFIG_SND_DEBUG_MEMORY</constant> kernel config, so that the magic-allocator and the magic-cast will be replaced to the normal kmalloc and cast. </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>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -