upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / Documentation / sound / alsa / DocBook / writing-an-alsa-driver.tmpl
index d08c20d..e789475 100644 (file)
@@ -18,8 +18,8 @@
       </affiliation>
      </author>
 
-     <date>July 11, 2004</date>
-     <edition>0.3.3</edition>
+     <date>March 6, 2005</date>
+     <edition>0.3.4</edition>
 
     <abstract>
       <para>
       </para>
 
       <para>
-        One is the the trees provided as a tarball or via cvs from the
+        One is the trees provided as a tarball or via cvs from the
       ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
-      tree. To synchronize both, the ALSA driver tree is split to
+      tree. To synchronize both, the ALSA driver tree is split into
       two different trees: alsa-kernel and alsa-driver. The former
       contains purely the source codes for the Linux 2.6 (or later)
       tree. This tree is designed only for compilation on 2.6 or
   #include <sound/core.h>
   #include <sound/initval.h>
 
-  // module parameters (see "Module Parameters")
+  /* module parameters (see "Module Parameters") */
   static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
   static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
   static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
-  // definition of the chip-specific record
+  /* definition of the chip-specific record */
   typedef struct snd_mychip mychip_t;
   struct snd_mychip {
           snd_card_t *card;
           // "PCI Resource Managements"
   };
 
-  // chip-specific destructor
-  // (see "PCI Resource Managements")
+  /* chip-specific destructor
+   * (see "PCI Resource Managements")
+   */
   static int snd_mychip_free(mychip_t *chip)
   {
-          // will be implemented later...
+          .... // will be implemented later...
   }
 
-  // component-destructor
-  // (see "Management of Cards and Components")
+  /* 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")
+  /* 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)
 
           // check PCI availability here
           // (see "PCI Resource Managements")
+          ....
 
-          // allocate a chip-specific data with zero filled
+          /* allocate a chip-specific data with zero filled */
           chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
           if (chip == NULL)
                   return -ENOMEM;
 
           // 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
+  /* constructor -- see "Constructor" sub-section */
   static int __devinit snd_mychip_probe(struct pci_dev *pci,
                                const struct pci_device_id *pci_id)
   {
           mychip_t *chip;
           int err;
 
-          // (1)
+          /* (1) */
           if (dev >= SNDRV_CARDS)
                   return -ENODEV;
           if (!enable[dev]) {
                   return -ENOENT;
           }
 
-          // (2)
+          /* (2) */
           card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
           if (card == NULL)
                   return -ENOMEM;
 
-          // (3)
+          /* (3) */
           if ((err = snd_mychip_create(card, pci, &chip)) < 0) {
                   snd_card_free(card);
                   return err;
           }
 
-          // (4)
+          /* (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
+          /* (5) */
+          .... // implemented later
 
-          // (6)
+          /* (6) */
           if ((err = snd_card_register(card)) < 0) {
                   snd_card_free(card);
                   return err;
           }
 
-          // (7)
+          /* (7) */
           pci_set_drvdata(pci, card);
           dev++;
           return 0;
   }
 
-  // destructor -- see "Destructor" sub-section
+  /* destructor -- see "Destructor" sub-section */
   static void __devexit snd_mychip_remove(struct pci_dev *pci)
   {
           snd_card_free(pci_get_drvdata(pci));
           </programlisting>
         </informalexample>
 
-       where the last twos are necessary only when module options are
+       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>
 
       <para>
-      The ALSA interfaces like PCM or control API are define in other
+      The ALSA interfaces like PCM or control API are defined 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>.
 
   static int snd_mychip_free(mychip_t *chip)
   {
-          // disable hardware here if any
-          // (not implemented in this document)
+          /* disable hardware here if any */
+          .... // (not implemented in this document)
 
-          // release the irq
+          /* release the irq */
           if (chip->irq >= 0)
                   free_irq(chip->irq, (void *)chip);
-          // release the i/o ports
+          /* release the i/o ports & memory */
           pci_release_regions(chip->pci);
-          // release the data
+          /* disable the PCI entry */
+          pci_disable_device(chip->pci);
+          /* release the data */
           kfree(chip);
           return 0;
   }
 
-  // chip-specific constructor
+  /* chip-specific constructor */
   static int __devinit snd_mychip_create(snd_card_t *card,
                                          struct pci_dev *pci,
                                          mychip_t **rchip)
 
           *rchip = NULL;
 
-          // check PCI availability (28bit DMA)
+          /* 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)
+          if (chip == NULL) {
+                  pci_disable_device(pci);
                   return -ENOMEM;
+          }
 
-          // initialize the stuff
+          /* initialize the stuff */
           chip->card = card;
           chip->pci = pci;
           chip->irq = -1;
 
-          // (1) PCI resource allocation
+          /* (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);
           }
           chip->irq = pci->irq;
 
-          // (2) initialization of the chip hardware
-          //     (not implemented in this document)
+          /* (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
+  /* 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, },
   };
   MODULE_DEVICE_TABLE(pci, snd_mychip_ids);
 
-  // pci_driver definition
+  /* pci_driver definition */
   static struct pci_driver driver = {
           .name = "My Own Chip",
           .id_table = snd_mychip_ids,
           .remove = __devexit_p(snd_mychip_remove),
   };
 
-  // initialization of the module
+  /* initialization of the module */
   static int __init alsa_card_mychip_init(void)
   {
           return pci_module_init(&driver);
   }
 
-  // clean up the module
+  /* clean up the module */
   static void __exit alsa_card_mychip_exit(void)
   {
           pci_unregister_driver(&driver);
   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;
   }
   
 <![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);
       </para>
 
       <para>
+        <!-- obsolete -->
         It will reserve the i/o port region of 8 bytes of the given
       PCI device. The returned value, chip-&gt;res_port, is allocated
       via <function>kmalloc()</function> by
       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.
 
       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
+      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.
           </programlisting>
         </informalexample>
 
-        and the allocation would be (assuming its size is 512 bytes):
+        and the allocation would be like below:
 
         <informalexample>
           <programlisting>
 
     </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>
           mychip_t *chip = snd_pcm_substream_chip(substream);
           snd_pcm_runtime_t *runtime = substream->runtime;
 
-          // set up the hardware with the current configuration
-          // for example...
+          /* set up the hardware with the current configuration
+           * for example...
+           */
           mychip_set_sample_format(chip, runtime->format);
           mychip_set_sample_rate(chip, runtime->rate);
           mychip_set_channels(chip, runtime->channels);
           mychip_t *chip = snd_pcm_substream_chip(substream);
           unsigned int current_ptr;
 
-          // get the current hardware pointer
+          /* get the current hardware pointer */
           current_ptr = mychip_get_hw_pointer(chip);
           return current_ptr;
   }
           snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           &snd_mychip_capture_ops);
           /* pre-allocation of buffers */
+          /* NOTE: this may fail */
           snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                 snd_dma_pci_data(chip->pci),
                                                 64*1024, 64*1024);
     <section id="pcm-interface-constructor">
       <title>Constructor</title>
       <para>
-        A pcm instance is allocated <function>snd_pcm_new()</function>
+        A pcm instance is allocated by <function>snd_pcm_new()</function>
       function. It would be better to create a constructor for pcm,
       namely, 
 
   static void mychip_pcm_free(snd_pcm_t *pcm)
   {
           mychip_t *chip = snd_pcm_chip(pcm);
-          // free your own data
+          /* free your own data */
           kfree(chip->my_private_pcm_data);
-          // do what you like else...
+          // do what you like else
+          ....
   }
 
   static int __devinit snd_mychip_new_pcm(mychip_t *chip)
   {
           snd_pcm_t *pcm;
           ....
-          // allocate your own data
+          /* allocate your own data */
           chip->my_private_pcm_data = kmalloc(...);
-          // set the destructor
+          /* set the destructor */
           pcm->private_data = chip;
           pcm->private_free = mychip_pcm_free;
           ....
@@ -2184,7 +2237,8 @@ struct _snd_pcm_runtime {
        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 */
+
+       struct snd_dma_buffer *dma_buffer_p;    /* allocated buffer */
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        /* -- OSS things -- */
@@ -2199,7 +2253,7 @@ struct _snd_pcm_runtime {
        <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
+       middle-layer changes / updates these info.  The exceptions 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
@@ -2231,7 +2285,7 @@ struct _snd_pcm_runtime {
 <![CDATA[
           snd_pcm_runtime_t *runtime = substream->runtime;
           ...
-          runtime->hw = snd_mychip_playback_hw; // common definition
+          runtime->hw = snd_mychip_playback_hw; /* common definition */
           if (chip->model == VERY_OLD_ONE)
                   runtime->hw.channels_max = 1;
 ]]>
@@ -2957,6 +3011,9 @@ struct _snd_pcm_runtime {
        current appl_ptr for the internal buffer, and this callback
        is useful only for such a purpose.
        </para>
+       <para>
+         This callback is atomic.
+       </para>
       </section>
 
       <section id="pcm-interface-operators-page-callback">
@@ -3030,7 +3087,7 @@ struct _snd_pcm_runtime {
           spin_lock(&chip->lock);
           ....
           if (pcm_irq_invoked(chip)) {
-                  // call updater, unlock before it
+                  /* call updater, unlock before it */
                   spin_unlock(&chip->lock);
                   snd_pcm_period_elapsed(chip->substream);
                   spin_lock(&chip->lock);
@@ -3075,24 +3132,25 @@ struct _snd_pcm_runtime {
           ....
           if (pcm_irq_invoked(chip)) {
                   unsigned int last_ptr, size;
-                  // get the current hardware pointer (in frames)
+                  /* get the current hardware pointer (in frames) */
                   last_ptr = get_hw_ptr(chip);
-                  // calculate the processed frames since the
-                  // last update
+                  /* calculate the processed frames since the
+                   * last update
+                   */
                   if (last_ptr < chip->last_ptr)
                           size = runtime->buffer_size + last_ptr 
                                    - chip->last_ptr; 
                   else
                           size = last_ptr - chip->last_ptr;
-                  // remember the last updated point
+                  /* remember the last updated point */
                   chip->last_ptr = last_ptr;
-                  // accumulate the size
+                  /* accumulate the size */
                   chip->size += size;
-                  // over the period boundary?
+                  /* over the period boundary? */
                   if (chip->size >= runtime->period_size) {
-                          // reset the accumulator
+                          /* reset the accumulator */
                           chip->size %= runtime->period_size;
-                          // call updater
+                          /* call updater */
                           spin_unlock(&chip->lock);
                           snd_pcm_period_elapsed(substream);
                           spin_lock(&chip->lock);
@@ -3153,6 +3211,11 @@ struct _snd_pcm_runtime {
       <function>udelay()</function> or <function>mdelay()</function>.
       </para>
 
+      <para>
+      All three atomic callbacks (trigger, pointer, and ack) are
+      called with local interrupts disabled.
+      </para>
+
     </section>
     <section id="pcm-interface-constraints">
       <title>Constraints</title>
@@ -3198,7 +3261,7 @@ struct _snd_pcm_runtime {
 
       <para>
         There are many different constraints.
-        Look in <filename>sound/asound.h</filename> for a complete list.
+        Look in <filename>sound/pcm.h</filename> for a complete list.
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
@@ -3216,7 +3279,7 @@ struct _snd_pcm_runtime {
           snd_mask_t *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
           snd_mask_t fmt;
 
-          snd_mask_any(&fmt);    // Init the struct
+          snd_mask_any(&fmt);    /* Init the struct */
           if (c->min < 2) {
                   fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE;
                   return snd_mask_refine(f, &fmt);
@@ -4014,7 +4077,7 @@ struct _snd_pcm_runtime {
         Both <function>snd_ac97_write()</function> and
         <function>snd_ac97_update()</function> functions are used to
         set a value to the given register
-        (<constant>AC97_XXX</constant>). The different between them is
+        (<constant>AC97_XXX</constant>). The difference between them is
         that <function>snd_ac97_update()</function> doesn't write a
         value if the given value has been already set, while
         <function>snd_ac97_write()</function> always rewrites the
@@ -4100,8 +4163,8 @@ struct _snd_pcm_runtime {
       <title>Proc Files</title>
       <para>
         The ALSA AC97 interface will create a proc file such as
-      <filename>/proc/asound/card0/ac97#0</filename> and
-      <filename>ac97#0regs</filename>. You can refer to these files to
+      <filename>/proc/asound/card0/codec97#0/ac97#0-0</filename> and
+      <filename>ac97#0-0+regs</filename>. You can refer to these files to
       see the current status and registers of the codec. 
       </para>
     </section>
@@ -4148,18 +4211,6 @@ struct _snd_pcm_runtime {
       implementation of mpu401 stuff. For example, emu10k1 has its own
       mpu401 routines. 
       </para>
-
-      <para>
-        In this document, I won't explain the rawmidi interface API,
-      which is the basis of MPU401-UART implementation. 
-      </para>
-
-      <para>
-        For details, please check the source,
-      <filename>core/rawmidi.c</filename>, and examples such as
-      <filename>drivers/mpu401/mpu401_uart.c</filename> or
-      <filename>usb/usbmidi.c</filename>. 
-      </para>
     </section>
 
     <section id="midi-interface-constructor">
@@ -4282,6 +4333,354 @@ struct _snd_pcm_runtime {
   </chapter>
 
 
+<!-- ****************************************************** -->
+<!-- RawMIDI Interface  -->
+<!-- ****************************************************** -->
+  <chapter id="rawmidi-interface">
+    <title>RawMIDI Interface</title>
+
+    <section id="rawmidi-interface-overview">
+      <title>Overview</title>
+
+      <para>
+      The raw MIDI interface is used for hardware MIDI ports that can
+      be accessed as a byte stream.  It is not used for synthesizer
+      chips that do not directly understand MIDI.
+      </para>
+
+      <para>
+      ALSA handles file and buffer management.  All you have to do is
+      to write some code to move data between the buffer and the
+      hardware.
+      </para>
+
+      <para>
+      The rawmidi API is defined in
+      <filename>&lt;sound/rawmidi.h&gt;</filename>.
+      </para>
+    </section>
+
+    <section id="rawmidi-interface-constructor">
+      <title>Constructor</title>
+
+      <para>
+      To create a rawmidi device, call the
+      <function>snd_rawmidi_new</function> function:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_t *rmidi;
+  err = snd_rawmidi_new(chip->card, "MyMIDI", 0, outs, ins, &rmidi);
+  if (err < 0)
+          return err;
+  rmidi->private_data = chip;
+  strcpy(rmidi->name, "My MIDI");
+  rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+                      SNDRV_RAWMIDI_INFO_INPUT |
+                      SNDRV_RAWMIDI_INFO_DUPLEX;
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <para>
+      The first argument is the card pointer, the second argument is
+      the ID string.
+      </para>
+
+      <para>
+      The third argument is the index of this component.  You can
+      create up to 8 rawmidi devices.
+      </para>
+
+      <para>
+      The fourth and fifth arguments are the number of output and
+      input substreams, respectively, of this device.  (A substream is
+      the equivalent of a MIDI port.)
+      </para>
+
+      <para>
+      Set the <structfield>info_flags</structfield> field to specify
+      the capabilities of the device.
+      Set <constant>SNDRV_RAWMIDI_INFO_OUTPUT</constant> if there is
+      at least one output port,
+      <constant>SNDRV_RAWMIDI_INFO_INPUT</constant> if there is at
+      least one input port,
+      and <constant>SNDRV_RAWMIDI_INFO_DUPLEX</constant> if the device
+      can handle output and input at the same time.
+      </para>
+
+      <para>
+      After the rawmidi device is created, you need to set the
+      operators (callbacks) for each substream.  There are helper
+      functions to set the operators for all substream of a device:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mymidi_output_ops);
+  snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mymidi_input_ops);
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <para>
+      The operators are usually defined like this:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static snd_rawmidi_ops_t snd_mymidi_output_ops = {
+          .open =    snd_mymidi_output_open,
+          .close =   snd_mymidi_output_close,
+          .trigger = snd_mymidi_output_trigger,
+  };
+]]>
+          </programlisting>
+        </informalexample>
+      These callbacks are explained in the <link
+      linkend="rawmidi-interface-callbacks"><citetitle>Callbacks</citetitle></link>
+      section.
+      </para>
+
+      <para>
+      If there is more than one substream, you should give each one a
+      unique name:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  struct list_head *list;
+  snd_rawmidi_substream_t *substream;
+  list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
+          substream = list_entry(list, snd_rawmidi_substream_t, list);
+          sprintf(substream->name, "My MIDI Port %d", substream->number + 1);
+  }
+  /* same for SNDRV_RAWMIDI_STREAM_INPUT */
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+    </section>
+
+    <section id="rawmidi-interface-callbacks">
+      <title>Callbacks</title>
+
+      <para>
+      In all callbacks, the private data that you've set for the
+      rawmidi device can be accessed as
+      substream-&gt;rmidi-&gt;private_data.
+      <!-- <code> isn't available before DocBook 4.3 -->
+      </para>
+
+      <para>
+      If there is more than one port, your callbacks can determine the
+      port index from the snd_rawmidi_substream_t data passed to each
+      callback:
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  snd_rawmidi_substream_t *substream;
+  int index = substream->number;
+]]>
+          </programlisting>
+        </informalexample>
+      </para>
+
+      <section id="rawmidi-interface-op-open">
+      <title><function>open</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static int snd_xxx_open(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called when a substream is opened.
+        You can initialize the hardware here, but you should not yet
+        start transmitting/receiving data.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-close">
+      <title><function>close</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static int snd_xxx_close(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        Guess what.
+        </para>
+
+        <para>
+        The <function>open</function> and <function>close</function>
+        callbacks of a rawmidi device are serialized with a mutex,
+        and can sleep.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-trigger-out">
+      <title><function>trigger</function> callback for output
+      substreams</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_output_trigger(snd_rawmidi_substream_t *substream, int up);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called with a nonzero <parameter>up</parameter>
+        parameter when there is some data in the substream buffer that
+        must be transmitted.
+        </para>
+
+        <para>
+        To read data from the buffer, call
+        <function>snd_rawmidi_transmit_peek</function>.  It will
+        return the number of bytes that have been read; this will be
+        less than the number of bytes requested when there is no more
+        data in the buffer.
+        After the data has been transmitted successfully, call
+        <function>snd_rawmidi_transmit_ack</function> to remove the
+        data from the substream buffer:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  unsigned char data;
+  while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) {
+          if (mychip_try_to_transmit(data))
+                  snd_rawmidi_transmit_ack(substream, 1);
+          else
+                  break; /* hardware FIFO full */
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+
+        <para>
+        If you know beforehand that the hardware will accept data, you
+        can use the <function>snd_rawmidi_transmit</function> function
+        which reads some data and removes it from the buffer at once:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  while (mychip_transmit_possible()) {
+          unsigned char data;
+          if (snd_rawmidi_transmit(substream, &data, 1) != 1)
+                  break; /* no more data */
+          mychip_transmit(data);
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+
+        <para>
+        If you know beforehand how many bytes you can accept, you can
+        use a buffer size greater than one with the
+        <function>snd_rawmidi_transmit*</function> functions.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback must not sleep.  If
+        the hardware FIFO is full before the substream buffer has been
+        emptied, you have to continue transmitting data later, either
+        in an interrupt handler, or with a timer if the hardware
+        doesn't have a MIDI transmit interrupt.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback is called with a
+        zero <parameter>up</parameter> parameter when the transmission
+        of data should be aborted.
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-trigger-in">
+      <title><function>trigger</function> callback for input
+      substreams</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_input_trigger(snd_rawmidi_substream_t *substream, int up);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is called with a nonzero <parameter>up</parameter>
+        parameter to enable receiving data, or with a zero
+        <parameter>up</parameter> parameter do disable receiving data.
+        </para>
+
+        <para>
+        The <function>trigger</function> callback must not sleep; the
+        actual reading of data from the device is usually done in an
+        interrupt handler.
+        </para>
+
+        <para>
+        When data reception is enabled, your interrupt handler should
+        call <function>snd_rawmidi_receive</function> for all received
+        data:
+          <informalexample>
+            <programlisting>
+<![CDATA[
+  void snd_mychip_midi_interrupt(...)
+  {
+          while (mychip_midi_available()) {
+                  unsigned char data;
+                  data = mychip_midi_read();
+                  snd_rawmidi_receive(substream, &data, 1);
+          }
+  }
+]]>
+            </programlisting>
+          </informalexample>
+        </para>
+      </section>
+
+      <section id="rawmidi-interface-op-drain">
+      <title><function>drain</function> callback</title>
+
+        <informalexample>
+          <programlisting>
+<![CDATA[
+  static void snd_xxx_drain(snd_rawmidi_substream_t *substream);
+]]>
+          </programlisting>
+        </informalexample>
+
+        <para>
+        This is only used with output substreams.  This function should wait
+        until all data read from the substream buffer has been transmitted.
+        This ensures that the device can be closed and the driver unloaded
+        without losing data.
+        </para>
+
+        <para>
+        This callback is optional.  If you do not set
+        <structfield>drain</structfield> in the snd_rawmidi_ops_t
+        structure, ALSA will simply wait for 50&nbsp;milliseconds
+        instead.
+        </para>
+      </section>
+    </section>
+
+  </chapter>
+
+
 <!-- ****************************************************** -->
 <!-- Miscellaneous Devices  -->
 <!-- ****************************************************** -->
@@ -4581,7 +4980,7 @@ struct _snd_pcm_runtime {
         where <parameter>size</parameter> is the byte size to be
       pre-allocated and the <parameter>max</parameter> is the maximal
       size to be changed via <filename>prealloc</filename> proc file.
-      The allocator will try to get as the large area as possible
+      The allocator will try to get as large area as possible
       within the given size. 
       </para>
 
@@ -4803,7 +5202,7 @@ struct _snd_pcm_runtime {
         If your hardware supports the page table like emu10k1 or the
       buffer descriptors like via82xx, you can use the scatter-gather
       (SG) DMA. ALSA provides an interface for handling SG-buffers.
-      The API is provided in <filename>&lt;sound/pcm_sgbuf.h&gt;</filename>. 
+      The API is provided in <filename>&lt;sound/pcm.h&gt;</filename>. 
       </para>
 
       <para>
@@ -5107,12 +5506,12 @@ struct _snd_pcm_runtime {
         <programlisting>
 <![CDATA[
   #ifdef CONFIG_PM
-  static int snd_my_suspend(snd_card_t *card, unsigned int state)
+  static int snd_my_suspend(snd_card_t *card, pm_message_t state)
   {
           .... // do things for suspsend
           return 0;
   }
-  static int snd_my_resume(snd_card_t *card, unsigned int state)
+  static int snd_my_resume(snd_card_t *card)
   {
           .... // do things for suspsend
           return 0;
@@ -5131,7 +5530,7 @@ struct _snd_pcm_runtime {
         <listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem>
         <listitem><para>Save the register values if necessary.</para></listitem>
         <listitem><para>Stop the hardware if necessary.</para></listitem>
-        <listitem><para>Set the power-state as D3hot by calling <function>snd_power_change_state()</function>.</para></listitem>
+        <listitem><para>Disable the PCI device by calling <function>pci_disable_device()</function>.</para></listitem>
       </orderedlist>
     </para>
 
@@ -5141,18 +5540,18 @@ struct _snd_pcm_runtime {
       <informalexample>
         <programlisting>
 <![CDATA[
-  static int mychip_suspend(snd_card_t *card, unsigned int state)
+  static int mychip_suspend(snd_card_t *card, pm_message_t state)
   {
-          // (1)
+          /* (1) */
           mychip_t *chip = card->pm_private_data;
-          // (2)
+          /* (2) */
           snd_pcm_suspend_all(chip->pcm);
-          // (3)
+          /* (3) */
           snd_mychip_save_registers(chip);
-          // (4)
+          /* (4) */
           snd_mychip_stop_hardware(chip);
-          // (5)
-          snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+          /* (5) */
+          pci_disable_device(chip->pci);
           return 0;
   }
 ]]>
@@ -5172,8 +5571,6 @@ struct _snd_pcm_runtime {
     <listitem><para>Resume the mixer, e.g. calling
     <function>snd_ac97_resume()</function>.</para></listitem>
     <listitem><para>Restart the hardware (if any).</para></listitem>
-    <listitem><para>Set the power-state as D0 by calling
-    <function>snd_power_change_state()</function>.</para></listitem>
     </orderedlist>
     </para>
 
@@ -5185,20 +5582,18 @@ struct _snd_pcm_runtime {
 <![CDATA[
   static void mychip_resume(mychip_t *chip)
   {
-          // (1)
+          /* (1) */
           mychip_t *chip = card->pm_private_data;
-          // (2)
+          /* (2) */
           pci_enable_device(chip->pci);
-          // (3)
+          /* (3) */
           snd_mychip_reinit_chip(chip);
-          // (4)
+          /* (4) */
           snd_mychip_restore_registers(chip);
-          // (5)
+          /* (5) */
           snd_ac97_resume(chip->ac97);
-          // (6)
+          /* (6) */
           snd_mychip_restart_chip(chip);
-          // (7)
-          snd_power_change_state(card, SNDRV_CTL_POWER_D0);
           return 0;
   }
 ]]>
@@ -5314,19 +5709,15 @@ struct _snd_pcm_runtime {
 <![CDATA[
   #define CARD_NAME "My Chip"
 
-  static int boot_devs;
-  module_param_array(index, int, boot_devs, 0444);
+  module_param_array(index, int, NULL, 0444);
   MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
-  module_param_array(id, charp, boot_devs, 0444);
+  module_param_array(id, charp, NULL, 0444);
   MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
-  module_param_array(enable, bool, boot_devs, 0444);
+  module_param_array(enable, bool, NULL, 0444);
   MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 ]]>
         </programlisting>
       </informalexample>
-
-    Here boot_devs is passed but simply ignored since we don't care
-    the number of parsed parameters.
     </para>
 
     <para>
@@ -5423,7 +5814,10 @@ struct _snd_pcm_runtime {
           depends on SND
           select SND_PCM
           help
-            Say 'Y' or 'M' to include support for Foobar XYZ soundcard.
+            Say Y here to include support for Foobar XYZ soundcard.
+
+            To compile this driver as a module, choose M here: the module
+            will be called snd-xyz.
 ]]>
         </programlisting>
       </informalexample>