Update of /cvsroot/alsa/alsa-kernel/Documentation/DocBook
In directory sc8-pr-cvs1:/tmp/cvs-serv5736
Modified Files:
writing-an-alsa-driver.tmpl
Log Message:
- added the description of pcm runtime.
- added the section how to put the new driver into alsa tree.
Index: writing-an-alsa-driver.tmpl
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/Documentation/DocBook/writing-an-alsa-driver.tmpl,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- writing-an-alsa-driver.tmpl 19 Mar 2003 16:14:29 -0000 1.7
+++ writing-an-alsa-driver.tmpl 26 Mar 2003 15:17:52 -0000 1.8
@@ -18,8 +18,8 @@
</affiliation>
</author>
- <date>Dec. 27, 2002</date>
- <edition>0.2 (reborn at Christmas)</edition>
+ <date>Mar. 26, 2003</date>
+ <edition>0.3</edition>
<abstract>
<para>
@@ -30,7 +30,7 @@
<legalnotice>
<para>
- Copyright (c) 2002 Takashi Iwai <email>[EMAIL PROTECTED]</email>
+ Copyright (c) 2002, 2003 Takashi Iwai <email>[EMAIL PROTECTED]</email>
</para>
<para>
@@ -1425,11 +1425,11 @@
<section id="pci-resource-resource-allocation">
<title>Resource Allocation</title>
<para>
- The allocation of ports and irqs are done via standard kernel
+ 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
- allocate (pseudo-)DMA for PCI like 0.5.x.
+ 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>
@@ -1461,7 +1461,7 @@
since irq 0 is valid. The port address and its resource pointer
can be initialized as null by
<function>snd_magic_kcalloc()</function> automatically, so you
- don't have to take care of it.
+ don't have to take care of resetting them.
</para>
<para>
@@ -2227,79 +2227,157 @@
</para>
</section>
- <section id="pcm-interface-operators">
- <title>Operators</title>
- <para>
- OK, now let me explain the detail of each pcm callback
- (<parameter>ops</parameter>). In general, every callback must
- return 0 if successful, or a negative number with the error
- number such as <constant>-EINVAL</constant> at any
- error.
- </para>
-
- <para>
- The callback function takes at least the argument with
- <type>snd_pcm_substream_t</type> pointer. For retrieving the
- chip record from the given substream instance, you can use the
- following macro.
-
- <informalexample>
- <programlisting>
-<![CDATA[
- #define chip_t mychip_t
-
- int xxx() {
- mychip_t *chip = snd_pcm_substream_chip(substream);
- ....
- }
-]]>
- </programlisting>
- </informalexample>
- </para>
-
- <para>
- It's expanded with a magic-cast, so the cast-error is
- automatically checked. You should define <type>chip_t</type> at
- the beginning of the code, since this will be referred in many
- places of pcm and control interfaces.
- </para>
+ <section id="pcm-interface-runtime">
+ <title>Runtime Pointer - The Chest of PCM Information</title>
+ <para>
+ When the PCM substream is opened, a PCM runtime instance is
+ allocated and assigned to the substream. This pointer is
+ accessible via <constant>substream->runtime</constant>.
+ This runtime pointer holds the various information; it holds
+ the copy of hw_params and sw_params configurations, the buffer
+ pointers, mmap records, spinlocks, etc. Almost everyhing you
+ need for controlling the PCM can be found there.
+ </para>
- <section id="pcm-interface-operators-open-callback">
- <title>open callback</title>
- <para>
+ <para>
+ The definition of runtime instance is found in
+ <filename><sound/pcm.h></filename>. Here is the
+ copy from the file.
<informalexample>
<programlisting>
<![CDATA[
- static int snd_xxx_open(snd_pcm_substream_t *subs);
+struct _snd_pcm_runtime {
+ /* -- Status -- */
+ snd_pcm_substream_t *trigger_master;
+ snd_timestamp_t trigger_tstamp; /* trigger timestamp */
+ int overrange;
+ snd_pcm_uframes_t avail_max;
+ snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
+ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/
+
+ /* -- HW params -- */
+ snd_pcm_access_t access; /* access mode */
+ snd_pcm_format_t format; /* SNDRV_PCM_FORMAT_* */
+ snd_pcm_subformat_t subformat; /* subformat */
+ unsigned int rate; /* rate in Hz */
+ unsigned int channels; /* channels */
+ snd_pcm_uframes_t period_size; /* period size */
+ unsigned int periods; /* periods */
+ snd_pcm_uframes_t buffer_size; /* buffer size */
+ unsigned int tick_time; /* tick time */
+ snd_pcm_uframes_t min_align; /* Min alignment for the format */
+ size_t byte_align;
+ unsigned int frame_bits;
+ unsigned int sample_bits;
+ unsigned int info;
+ unsigned int rate_num;
+ unsigned int rate_den;
+
+ /* -- SW params -- */
+ int tstamp_timespec; /* use timeval (0) or timespec (1) */
+ snd_pcm_tstamp_t tstamp_mode; /* mmap timestamp is updated */
+ unsigned int period_step;
+ unsigned int sleep_min; /* min ticks to sleep */
+ snd_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */
+ snd_pcm_uframes_t start_threshold;
+ snd_pcm_uframes_t stop_threshold;
+ snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
+ noise is nearest than this */
+ snd_pcm_uframes_t silence_size; /* Silence filling size */
+ snd_pcm_uframes_t boundary; /* pointers wrap point */
+
+ snd_pcm_uframes_t silenced_start;
+ snd_pcm_uframes_t silenced_size;
+
+ snd_pcm_sync_id_t sync; /* hardware synchronization ID */
+
+ /* -- mmap -- */
+ volatile snd_pcm_mmap_status_t *status;
+ volatile snd_pcm_mmap_control_t *control;
+ atomic_t mmap_count;
+
+ /* -- locking / scheduling -- */
+ spinlock_t lock;
+ wait_queue_head_t sleep;
+ struct timer_list tick_timer;
+ struct fasync_struct *fasync;
+
+ /* -- private section -- */
+ void *private_data;
+ void (*private_free)(snd_pcm_runtime_t *runtime);
+
+ /* -- hardware description -- */
+ snd_pcm_hardware_t hw;
+ snd_pcm_hw_constraints_t hw_constraints;
+
+ /* -- interrupt callbacks -- */
+ void (*transfer_ack_begin)(snd_pcm_substream_t *substream);
+ void (*transfer_ack_end)(snd_pcm_substream_t *substream);
+
+ /* -- timer -- */
+ unsigned int timer_resolution; /* timer resolution */
+
+ /* -- DMA -- */
+ unsigned char *dma_area; /* DMA area */
+ dma_addr_t dma_addr; /* physical bus address (not accessible from
main CPU) */
+ size_t dma_bytes; /* size of DMA area */
+ void *dma_private; /* private DMA data for the memory allocator */
+
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+ /* -- OSS things -- */
+ snd_pcm_oss_runtime_t oss;
+#endif
+};
]]>
</programlisting>
</informalexample>
+ </para>
- This is called when a pcm substream is opened.
- </para>
+ <para>
+ For the operators (callbacks) of each sound driver, most of
+ these records are supposed to be read-only. Only the PCM
+ middle-layer changes / updates these info. The excpetions are
+ the hardware description (hw), interrupt callbacks
+ (transfer_ack_xxx), DMA buffer information, and the private
+ data. Besides, if you use the standard buffer allocation
+ method via <function>snd_pcm_lib_malloc_pages()</function>,
+ you don't need to set the DMA buffer information by yourself.
+ </para>
- <para>
- At least, here you have to initialize the runtime hardware
- record. Typically, this is done by like this:
+ <para>
+ In the sections below, important records are explained.
+ </para>
+ <section id="pcm-interface-runtime-hw">
+ <title>Hardware Description</title>
+ <para>
+ The hardware descriptor (<type>snd_pcm_hardware_t</type>)
+ contains the definitions of the fundamental hardware
+ configuration. Above all, you'll need to define this in
+ <link linkend="pcm-interface-operators-open-callback"><citetitle>
+ the open callback</citetitle></link>.
+ Note that the runtime instance holds the copy of the
+ descriptor, not the pointer to the existing descriptor. That
+ is, in the open callback, you can modify the copied descriptor
+ (<constant>runtime->hw</constant>) as you need. For example, if the maximum
+ number of channels is 1 only on some chip models, you can
+ still use the same hardware descriptor and change the
+ channels_max later:
<informalexample>
<programlisting>
<![CDATA[
- static int snd_xxx_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;
- return 0;
- }
+ ...
+ runtime->hw = snd_mychip_playback_hw; // common definition
+ if (chip->model == VERY_OLD_ONE)
+ runtime->hw.channels_max = 1;
]]>
</programlisting>
</informalexample>
+ </para>
- where <parameter>snd_mychip_playback_hw</parameter> is the
- pre-defined hardware record.
-
+ <para>
+ Typically, you'll have a hardware descriptor like below:
<informalexample>
<programlisting>
<![CDATA[
@@ -2326,11 +2404,8 @@
</para>
<para>
- The similar struct exists on ALSA 0.5.x driver, so you can
- guess the values if you already wrote a driver.
- </para>
-
- <para>
+ <itemizedlist>
+ <listitem><para>
The <structfield>info</structfield> field contains the type and
capabilities of this pcm. The bit flags are defined in
<filename><sound/asound.h></filename> as
@@ -2366,6 +2441,17 @@
must handle the corresponding commands.
</para>
+ <para>
+ When the PCM substreams can be synchronized (typically,
+ synchorinized start/stop of a playback and a capture streams),
+ you can give <constant>SNDRV_PCM_INFO_SYNC_START</constant>,
+ too. In this case, you'll need to check the linked-list of
+ PCM substreams in the trigger callback. This will be
+ described in the later section.
+ </para>
+ </listitem>
+
+ <listitem>
<para>
<structfield>formats</structfield> field contains the bit-flags
of supported formats (<constant>SNDRV_PCM_FMTBIT_XXX</constant>).
@@ -2373,38 +2459,181 @@
bits. In the example above, the signed 16bit little-endian
format is specified.
</para>
+ </listitem>
+ <listitem>
<para>
<structfield>rates</structfield> field contains the bit-flags of
supported rates (<constant>SNDRV_PCM_RATE_XXX</constant>).
When the chip supports continuous rates, pass
<constant>CONTINUOUS</constant> bit additionally.
- The pre-defined rate bits are only for typical rates. If your
- chip supports unconventional rates, you need to add
- <constant>KNOT</constant> bit and set up the
+ The pre-defined rate bits are provided only for typical
+ rates. If your chip supports unconventional rates, you need to add
+ <constant>KNOT</constant> bit and set up the hardware
constraint manually (explained later).
</para>
+ </listitem>
- <para>
- There have been many changes of terminology between
- ALSA 0.5.x and 0.9.x.
- On the ALSA 0.9.x world, <quote>period</quote> means what is
- known as <quote>fragment</quote> in the OSS. It's the least
- size of (a part of) the buffer to generate an interrupt.
+ <listitem>
+ <para>
+ <structfield>rate_min</structfield> and
+ <structfield>rate_max</structfield> define the minimal and
+ maximal sample rate. This should correspond somehow to
+ <structfield>rates</structfield> bits.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <structfield>channel_min</structfield> and
+ <structfield>channel_max</structfield>
+ define, as you might already expected, the minimal and maximal
+ number of channels.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <structfield>buffer_bytes_max</structfield> defines the
+ maximal buffer size in bytes. There is no
+ <structfield>buffer_bytes_min</structfield> field, since
+ it can be calculated from the minimal period size and the
+ minimal number of periods.
+ Meanwhile, <structfield>period_bytes_min</structfield> and
+ define the minimal and maximal size of the period in bytes.
+ <structfield>periods_max</structfield> and
+ <structfield>periods_min</structfield> define the maximal and
+ minimal number of periods in the buffer.
</para>
- <para>
- Now, taking the new terminology into account, the other fields
- are self-explanatory (I hope). Please note that here, both
- min/max buffer and period sizes are specified in bytes.
+ <para>
+ The <quote>period</quote> is a term, that corresponds to
+ fragment in the OSS world. The period defines the size at
+ which the PCM interrupt is generated. This size strongly
+ depends on the hardware.
+ Generally, the smaller period size will give you more
+ interrupts, that is, more controls.
+ In the case of capture, this size defines the input latency.
+ On the other hand, the whole buffer size defines the
+ output latency for the playback direction.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ There is also a field <structfield>fifo_size</structfield>.
+ This specifies the size of the hardware FIFO, but it's not
+ used currently in the driver nor in the alsa-lib. So, you
+ can ignore this field.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </section>
+
+ <section id="pcm-interface-runtime-config">
+ <title>PCM Configurations</title>
+ <para>
+ Ok, let's go back again to the PCM runtime records.
+ The most frequently referred records in the runtime instance are
+ the PCM configurations.
+ The PCM configurations are stored on runtime instance
+ after the application sends <type>hw_params</type> data via
+ alsa-lib. There are many fields copied from hw_params and
+ sw_params structs. For example,
+ <structfield>format</structfield> holds the format type
+ chosen by the application. This field contains the enum value
+ <constant>SNDRV_PCM_FORMAT_XXX</constant>.
+ </para>
+
+ <para>
+ One thing to be noted is that the configured buffer and period
+ sizes are stored in <quote>frames</quote> in the runtime
+ In the ALSA world, 1 frame = channels * samples-size.
+ For conversion between frames and bytes, you can use the
+ helper functions, <function>frames_to_bytes()</function> and
+ <function>bytes_to_frames()</function>.
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+]]>
+ </programlisting>
+ </informalexample>
</para>
- <para>
- Some drivers allocate the private instance for each pcm
- substream. It can be stored in
- <constant>substream->runtime->private_data</constant>.
- Since it's a void pointer, you
- should use magic-kmalloc and magic-cast for such an object.
+ <para>
+ Also, many software parameters (sw_params) are
+ stored in frames, too. Please check the type of the field.
+ <type>snd_pcm_uframes_t</type> is for the frames as unsigned
+ integer while <type>snd_pcm_sframes_t</type> is for the frames
+ as signed integer.
+ </para>
+ </section>
+
+ <section id="pcm-interface-runtime-dma">
+ <title>DMA Buffer Information</title>
+ <para>
+ The DMA buffer is defined by the following four fields,
+ <structfield>dma_area</structfield>,
+ <structfield>dma_addr</structfield>,
+ <structfield>dma_bytes</structfield> and
+ <structfield>dma_private</structfield>.
+ The <structfield>dma_area</structfield> holds the buffer
+ pointer (the logical address). You can call
+ <function>memcpy</function> from/to
+ this pointer. Meanwhile, <structfield>dma_addr</structfield>
+ holds the physical address of the buffer. This field is
+ specified only when the buffer is a linear buffer.
+ <structfield>dma_bytes</structfield> holds the size of buffer
+ in bytes. <structfield>dma_private</structfield> is used for
+ the ALSA DMA allocator.
+ </para>
+
+ <para>
+ If you use a standard ALSA function,
+ <function>snd_pcm_lib_malloc_pages()</function>, for
+ allocating the buffer, these fields are set by the ALSA middle
+ layer, and you should <emphasis>not</emphasis> change them by
+ yourself. You can read them but not write them.
+ On the other hand, if you want to allocate the buffer by
+ yourself, you'll need to manage it in hw_params callback.
+ At least, <structfield>dma_bytes</structfield> is mandatory.
+ <structfield>dma_area</structfield> is necessary when the
+ buffer is mmapped. If your driver doesn't support mmap, this
+ field is not necessary. <structfield>dma_addr</structfield>
+ is also not mandatory. You can use
+ <structfield>dma_private</structfield> as you like, too.
+ </para>
+ </section>
+
+ <section id="pcm-interface-runtime-status">
+ <title>Running Status</title>
+ <para>
+ The running status can be referred via <constant>runtime->status</constant>.
+ This is the pointer to <type>snd_pcm_mmap_status_t</type>
+ record. For example, you can get the current DMA hardware
+ pointer via <constant>runtime->status->hw_ptr</constant>.
+ </para>
+
+ <para>
+ The DMA application pointer can be referred via
+ <constant>runtime->control</constant>, which points
+ <type>snd_pcm_mmap_control_t</type> record.
+ However, accessing directly to this value is not recommended.
+ </para>
+ </section>
+
+ <section id="pcm-interface-runtime-private">
+ <title>Private Data</title>
+ <para>
+ You can allocate a record for the substream and store it in
+ <constant>runtime->private_data</constant>. Usually, this
+ done in
+ <link linkend="pcm-interface-operators-open-callback"><citetitle>
+ the open callback</citetitle></link>.
+ Since it's a void pointer, you should use magic-kmalloc and
+ magic-cast for such an object.
<informalexample>
<programlisting>
@@ -2423,8 +2652,110 @@
</para>
<para>
- The allocated object must be released in the close callback below.
+ The allocated object must be released in
+ <link linkend="pcm-interface-operators-open-callback"><citetitle>
+ the close callback</citetitle></link>.
</para>
+ </section>
+
+ <section id="pcm-interface-runtime-intr">
+ <title>Interrupt Callbacks</title>
+ <para>
+ The field <structfield>transfer_ack_begin</structfield> and
+ <structfield>transfer_ack_end</structfield> are called at
+ the beginning and the end of
+ <function>snd_pcm_period_elapsed()</function>, respectively.
+ </para>
+ </section>
+
+ </section>
+
+ <section id="pcm-interface-operators">
+ <title>Operators</title>
+ <para>
+ OK, now let me explain the detail of each pcm callback
+ (<parameter>ops</parameter>). In general, every callback must
+ return 0 if successful, or a negative number with the error
+ number such as <constant>-EINVAL</constant> at any
+ error.
+ </para>
+
+ <para>
+ The callback function takes at least the argument with
+ <type>snd_pcm_substream_t</type> pointer. For retrieving the
+ chip record from the given substream instance, you can use the
+ following macro.
+
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ #define chip_t mychip_t
+
+ int xxx() {
+ mychip_t *chip = snd_pcm_substream_chip(substream);
+ ....
+ }
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+
+ <para>
+ It's expanded with a magic-cast, so the cast-error is
+ automatically checked. You should define <type>chip_t</type> at
+ the beginning of the code, since this will be referred in many
+ places of pcm and control interfaces.
+ </para>
+
+ <section id="pcm-interface-operators-open-callback">
+ <title>open callback</title>
+ <para>
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ static int snd_xxx_open(snd_pcm_substream_t *subs);
+]]>
+ </programlisting>
+ </informalexample>
+
+ This is called when a pcm substream is opened.
+ </para>
+
+ <para>
+ At least, here you have to initialize the runtime->hw
+ record. Typically, this is done by like this:
+
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ static int snd_xxx_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;
+ return 0;
+ }
+]]>
+ </programlisting>
+ </informalexample>
+
+ where <parameter>snd_mychip_playback_hw</parameter> is the
+ pre-defined hardware description.
+ </para>
+
+ <para>
+ You can allocate a private data in this callback, as described
+ in <link linkend="pcm-interface-runtime-private"><citetitle>
+ Private Data</citetitle></link> section.
+ </para>
+
+ <para>
+ If the hardware configuration needs more constraints, set the
+ hardware constraints here, too.
+ See <link linkend="pcm-interface-constraints"><citetitle>
+ Constraints</citetitle></link> for more details.
+ </para>
</section>
<section id="pcm-interface-operators-close-callback">
@@ -2622,23 +2953,6 @@
</para>
<para>
- Note that the period and the buffer sizes are stored in
- <quote>frames</quote>. In the ALSA world, 1 frame = channels
- * samples-size. For conversion between frames and bytes, you
- can use the helper functions,
- <function>frames_to_bytes()</function> and
- <function>bytes_to_frames()</function>.
-
- <informalexample>
- <programlisting>
-<![CDATA[
- period_bytes = frames_to_bytes(runtime, runtime->period_size);
-]]>
- </programlisting>
- </informalexample>
- </para>
-
- <para>
Be careful that this callback will be called many times at
each set up, too.
</para>
@@ -5115,6 +5429,217 @@
</para>
</chapter>
+
+<!-- ****************************************************** -->
+<!-- How To Put Your Driver -->
+<!-- ****************************************************** -->
+ <chapter id="how-to-put-your-driver">
+ <title>How To Put Your Driver Into ALSA Tree</title>
+ <section>
+ <title>General</title>
+ <para>
+ So far, you've learned how to write the driver codes.
+ And you might have a question now: how to put my own
+ driver into the ALSA driver tree?
+ Here (finally :) the standard procedure is described briefly.
+ </para>
+
+ <para>
+ Suppose that you'll create a new PCI driver for the card
+ <quote>xyz</quote>. The card module name would be
+ snd-xyz. The new driver is usually put into alsa-driver
+ tree. Then the driver is evaluated, audited and tested
+ by developers and users. After a certain time, the driver
+ will go to alsa-kernel tree and eventually integrated into
+ Linux 2.5 tree.
+ </para>
+
+ <para>
+ In the following sections, the driver code is supposed
+ to be put into alsa-driver tree. The two cases are assumed:
+ a driver consisting of a single source file and one consisting
+ of several source files.
+ </para>
+ </section>
+
+ <section>
+ <title>Driver with A Single Source File</title>
+ <para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Modify alsa-driver/pci/Makefile
+ </para>
+
+ <para>
+ Suppose you have a file xyz.c. Add the following
+ two lines
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ snd-xyz-objs := xyz.o
+ extra-obj-$(CONFIG_SND_XYZ) += snd-xyz.o
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Modify alsa-driver/acore/Makefile
+ </para>
+
+ <para>
+ Here define the dependent modules.
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ obj-$(CONFIG_SND_XYZ) += snd.o ...
+]]>
+ </programlisting>
+ </informalexample>
+
+ If the driver supports PCM, snd-pcm.o,
+ snd-timer.o and snd-page-alloc.o
+ will be needed.
+ </para>
+ <para>
+ For rawmidi, snd-rawmidi.o is needed in addition.
+ The MIDI stuff is also related to the sequencer.
+ You'll need to modify alsa-driver/acore/seq/Makefile.
+ </para>
+
+ <para>
+ For OPL3, snd-hwdep.o is needed, too.
+ It's involved with the sequencer, and as well as rawmidi,
+ you'll need to modify alsa-driver/acore/seq/Makefile
+ and acore/seq/instr/Makefile in addition.
+ Also, a new entry is necessary in
+ alsa-driver/drivers/opl3/Makefile.
+ </para>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ Modify alsa-driver/utils/Modules.dep
+ </para>
+
+ <para>
+ Add the module definition for configure, here.
+ The beginning of the line must be a vertical bar, following
+ the card module name (snd-xyz) and the list of its all
+ dependent modules.
+
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ %dir linux/sound/pci
+ |snd-azt3328 snd-pcm snd-mpu401-uart snd-opl3-lib snd-opl3-synth
+ |snd-xyz snd-pcm ...
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Run cvscompile script to re-generate the configure script and
+ build the whole stuff again.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </section>
+
+ <section>
+ <title>Drivers with Several Source Files</title>
+ <para>
+ Suppose that the driver snd-xyz have several source files.
+ They are located in the new subdirectory,
+ pci/xyz.
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Add a new directory (xyz) to extra-subdir-y list in alsa-driver/pci/Makefile
+
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ extra-subdir-y := pdplus vx222 xyz
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Under the directory xyz, create a Makefile
+
+ <example>
+ <title>Sample Makefile for a driver xyz</title>
+ <programlisting>
+<![CDATA[
+ TOPDIR = ../..
+
+ include $(TOPDIR)/toplevel.config
+ include $(TOPDIR)/Makefile.conf
+
+ TOPDIR = $(MAINSRCDIR)
+
+ snd-xyz-objs := xyz.o abc.o def.o
+
+ obj-$(CONFIG_SND_XYZ) += snd-xyz.o
+
+ include $(TOPDIR)/Rules.make
+]]>
+ </programlisting>
+ </example>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Modify alsa-driver/acore/Makefile
+ </para>
+
+ <para>
+ This procedure is as same as in the last section.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Modify alsa-driver/utils/Modules.dep
+ </para>
+
+ <para>
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ %dir linux/sound/pci/xyz
+ |snd-xyz snd-pcm ...
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Run cvscompile script to re-generate the configure script and
+ build the whole stuff again.
+ </para>
+ </listitem>
+ </orderedlist>
+ </para>
+ </section>
+
+ </chapter>
<!-- ****************************************************** -->
<!-- Useful Functions -->
-------------------------------------------------------
This SF.net email is sponsored by:
The Definitive IT and Networking Event. Be There!
NetWorld+Interop Las Vegas 2003 -- Register today!
http://ads.sourceforge.net/cgi-bin/redirect.pl?keyn0001en
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog