diff options
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 125 |
1 files changed, 77 insertions, 48 deletions
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 74d3a35b59bc..9ec634c398d9 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
@@ -18,8 +18,8 @@ | |||
18 | </affiliation> | 18 | </affiliation> |
19 | </author> | 19 | </author> |
20 | 20 | ||
21 | <date>November 17, 2005</date> | 21 | <date>July 26, 2007</date> |
22 | <edition>0.3.6</edition> | 22 | <edition>0.3.6.1</edition> |
23 | 23 | ||
24 | <abstract> | 24 | <abstract> |
25 | <para> | 25 | <para> |
@@ -405,8 +405,9 @@ | |||
405 | /* definition of the chip-specific record */ | 405 | /* definition of the chip-specific record */ |
406 | struct mychip { | 406 | struct mychip { |
407 | struct snd_card *card; | 407 | struct snd_card *card; |
408 | // rest of implementation will be in the section | 408 | /* rest of implementation will be in the section |
409 | // "PCI Resource Managements" | 409 | * "PCI Resource Managements" |
410 | */ | ||
410 | }; | 411 | }; |
411 | 412 | ||
412 | /* chip-specific destructor | 413 | /* chip-specific destructor |
@@ -414,7 +415,7 @@ | |||
414 | */ | 415 | */ |
415 | static int snd_mychip_free(struct mychip *chip) | 416 | static int snd_mychip_free(struct mychip *chip) |
416 | { | 417 | { |
417 | .... // will be implemented later... | 418 | .... /* will be implemented later... */ |
418 | } | 419 | } |
419 | 420 | ||
420 | /* component-destructor | 421 | /* component-destructor |
@@ -440,8 +441,9 @@ | |||
440 | 441 | ||
441 | *rchip = NULL; | 442 | *rchip = NULL; |
442 | 443 | ||
443 | // check PCI availability here | 444 | /* check PCI availability here |
444 | // (see "PCI Resource Managements") | 445 | * (see "PCI Resource Managements") |
446 | */ | ||
445 | .... | 447 | .... |
446 | 448 | ||
447 | /* allocate a chip-specific data with zero filled */ | 449 | /* allocate a chip-specific data with zero filled */ |
@@ -451,12 +453,13 @@ | |||
451 | 453 | ||
452 | chip->card = card; | 454 | chip->card = card; |
453 | 455 | ||
454 | // rest of initialization here; will be implemented | 456 | /* rest of initialization here; will be implemented |
455 | // later, see "PCI Resource Managements" | 457 | * later, see "PCI Resource Managements" |
458 | */ | ||
456 | .... | 459 | .... |
457 | 460 | ||
458 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | 461 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
459 | chip, &ops)) < 0) { | 462 | if (err < 0) { |
460 | snd_mychip_free(chip); | 463 | snd_mychip_free(chip); |
461 | return err; | 464 | return err; |
462 | } | 465 | } |
@@ -490,7 +493,8 @@ | |||
490 | return -ENOMEM; | 493 | return -ENOMEM; |
491 | 494 | ||
492 | /* (3) */ | 495 | /* (3) */ |
493 | if ((err = snd_mychip_create(card, pci, &chip)) < 0) { | 496 | err = snd_mychip_create(card, pci, &chip); |
497 | if (err < 0) { | ||
494 | snd_card_free(card); | 498 | snd_card_free(card); |
495 | return err; | 499 | return err; |
496 | } | 500 | } |
@@ -502,10 +506,11 @@ | |||
502 | card->shortname, chip->ioport, chip->irq); | 506 | card->shortname, chip->ioport, chip->irq); |
503 | 507 | ||
504 | /* (5) */ | 508 | /* (5) */ |
505 | .... // implemented later | 509 | .... /* implemented later */ |
506 | 510 | ||
507 | /* (6) */ | 511 | /* (6) */ |
508 | if ((err = snd_card_register(card)) < 0) { | 512 | err = snd_card_register(card); |
513 | if (err < 0) { | ||
509 | snd_card_free(card); | 514 | snd_card_free(card); |
510 | return err; | 515 | return err; |
511 | } | 516 | } |
@@ -605,7 +610,8 @@ | |||
605 | <![CDATA[ | 610 | <![CDATA[ |
606 | struct mychip *chip; | 611 | struct mychip *chip; |
607 | .... | 612 | .... |
608 | if ((err = snd_mychip_create(card, pci, &chip)) < 0) { | 613 | err = snd_mychip_create(card, pci, &chip); |
614 | if (err < 0) { | ||
609 | snd_card_free(card); | 615 | snd_card_free(card); |
610 | return err; | 616 | return err; |
611 | } | 617 | } |
@@ -666,7 +672,8 @@ | |||
666 | <informalexample> | 672 | <informalexample> |
667 | <programlisting> | 673 | <programlisting> |
668 | <![CDATA[ | 674 | <![CDATA[ |
669 | if ((err = snd_card_register(card)) < 0) { | 675 | err = snd_card_register(card); |
676 | if (err < 0) { | ||
670 | snd_card_free(card); | 677 | snd_card_free(card); |
671 | return err; | 678 | return err; |
672 | } | 679 | } |
@@ -1091,7 +1098,7 @@ | |||
1091 | static int snd_mychip_free(struct mychip *chip) | 1098 | static int snd_mychip_free(struct mychip *chip) |
1092 | { | 1099 | { |
1093 | /* disable hardware here if any */ | 1100 | /* disable hardware here if any */ |
1094 | .... // (not implemented in this document) | 1101 | .... /* (not implemented in this document) */ |
1095 | 1102 | ||
1096 | /* release the irq */ | 1103 | /* release the irq */ |
1097 | if (chip->irq >= 0) | 1104 | if (chip->irq >= 0) |
@@ -1119,7 +1126,8 @@ | |||
1119 | *rchip = NULL; | 1126 | *rchip = NULL; |
1120 | 1127 | ||
1121 | /* initialize the PCI entry */ | 1128 | /* initialize the PCI entry */ |
1122 | if ((err = pci_enable_device(pci)) < 0) | 1129 | err = pci_enable_device(pci); |
1130 | if (err < 0) | ||
1123 | return err; | 1131 | return err; |
1124 | /* check PCI availability (28bit DMA) */ | 1132 | /* check PCI availability (28bit DMA) */ |
1125 | if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || | 1133 | if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || |
@@ -1141,7 +1149,8 @@ | |||
1141 | chip->irq = -1; | 1149 | chip->irq = -1; |
1142 | 1150 | ||
1143 | /* (1) PCI resource allocation */ | 1151 | /* (1) PCI resource allocation */ |
1144 | if ((err = pci_request_regions(pci, "My Chip")) < 0) { | 1152 | err = pci_request_regions(pci, "My Chip"); |
1153 | if (err < 0) { | ||
1145 | kfree(chip); | 1154 | kfree(chip); |
1146 | pci_disable_device(pci); | 1155 | pci_disable_device(pci); |
1147 | return err; | 1156 | return err; |
@@ -1156,10 +1165,10 @@ | |||
1156 | chip->irq = pci->irq; | 1165 | chip->irq = pci->irq; |
1157 | 1166 | ||
1158 | /* (2) initialization of the chip hardware */ | 1167 | /* (2) initialization of the chip hardware */ |
1159 | .... // (not implemented in this document) | 1168 | .... /* (not implemented in this document) */ |
1160 | 1169 | ||
1161 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | 1170 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
1162 | chip, &ops)) < 0) { | 1171 | if (err < 0) { |
1163 | snd_mychip_free(chip); | 1172 | snd_mychip_free(chip); |
1164 | return err; | 1173 | return err; |
1165 | } | 1174 | } |
@@ -1233,7 +1242,8 @@ | |||
1233 | <informalexample> | 1242 | <informalexample> |
1234 | <programlisting> | 1243 | <programlisting> |
1235 | <![CDATA[ | 1244 | <![CDATA[ |
1236 | if ((err = pci_enable_device(pci)) < 0) | 1245 | err = pci_enable_device(pci); |
1246 | if (err < 0) | ||
1237 | return err; | 1247 | return err; |
1238 | if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || | 1248 | if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || |
1239 | pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { | 1249 | pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { |
@@ -1294,7 +1304,8 @@ | |||
1294 | <informalexample> | 1304 | <informalexample> |
1295 | <programlisting> | 1305 | <programlisting> |
1296 | <![CDATA[ | 1306 | <![CDATA[ |
1297 | if ((err = pci_request_regions(pci, "My Chip")) < 0) { | 1307 | err = pci_request_regions(pci, "My Chip"); |
1308 | if (err < 0) { | ||
1298 | kfree(chip); | 1309 | kfree(chip); |
1299 | pci_disable_device(pci); | 1310 | pci_disable_device(pci); |
1300 | return err; | 1311 | return err; |
@@ -1773,7 +1784,8 @@ | |||
1773 | struct snd_pcm_runtime *runtime = substream->runtime; | 1784 | struct snd_pcm_runtime *runtime = substream->runtime; |
1774 | 1785 | ||
1775 | runtime->hw = snd_mychip_playback_hw; | 1786 | runtime->hw = snd_mychip_playback_hw; |
1776 | // more hardware-initialization will be done here | 1787 | /* more hardware-initialization will be done here */ |
1788 | .... | ||
1777 | return 0; | 1789 | return 0; |
1778 | } | 1790 | } |
1779 | 1791 | ||
@@ -1781,7 +1793,8 @@ | |||
1781 | static int snd_mychip_playback_close(struct snd_pcm_substream *substream) | 1793 | static int snd_mychip_playback_close(struct snd_pcm_substream *substream) |
1782 | { | 1794 | { |
1783 | struct mychip *chip = snd_pcm_substream_chip(substream); | 1795 | struct mychip *chip = snd_pcm_substream_chip(substream); |
1784 | // the hardware-specific codes will be here | 1796 | /* the hardware-specific codes will be here */ |
1797 | .... | ||
1785 | return 0; | 1798 | return 0; |
1786 | 1799 | ||
1787 | } | 1800 | } |
@@ -1793,7 +1806,8 @@ | |||
1793 | struct snd_pcm_runtime *runtime = substream->runtime; | 1806 | struct snd_pcm_runtime *runtime = substream->runtime; |
1794 | 1807 | ||
1795 | runtime->hw = snd_mychip_capture_hw; | 1808 | runtime->hw = snd_mychip_capture_hw; |
1796 | // more hardware-initialization will be done here | 1809 | /* more hardware-initialization will be done here */ |
1810 | .... | ||
1797 | return 0; | 1811 | return 0; |
1798 | } | 1812 | } |
1799 | 1813 | ||
@@ -1801,7 +1815,8 @@ | |||
1801 | static int snd_mychip_capture_close(struct snd_pcm_substream *substream) | 1815 | static int snd_mychip_capture_close(struct snd_pcm_substream *substream) |
1802 | { | 1816 | { |
1803 | struct mychip *chip = snd_pcm_substream_chip(substream); | 1817 | struct mychip *chip = snd_pcm_substream_chip(substream); |
1804 | // the hardware-specific codes will be here | 1818 | /* the hardware-specific codes will be here */ |
1819 | .... | ||
1805 | return 0; | 1820 | return 0; |
1806 | 1821 | ||
1807 | } | 1822 | } |
@@ -1844,10 +1859,12 @@ | |||
1844 | { | 1859 | { |
1845 | switch (cmd) { | 1860 | switch (cmd) { |
1846 | case SNDRV_PCM_TRIGGER_START: | 1861 | case SNDRV_PCM_TRIGGER_START: |
1847 | // do something to start the PCM engine | 1862 | /* do something to start the PCM engine */ |
1863 | .... | ||
1848 | break; | 1864 | break; |
1849 | case SNDRV_PCM_TRIGGER_STOP: | 1865 | case SNDRV_PCM_TRIGGER_STOP: |
1850 | // do something to stop the PCM engine | 1866 | /* do something to stop the PCM engine */ |
1867 | .... | ||
1851 | break; | 1868 | break; |
1852 | default: | 1869 | default: |
1853 | return -EINVAL; | 1870 | return -EINVAL; |
@@ -1900,8 +1917,8 @@ | |||
1900 | struct snd_pcm *pcm; | 1917 | struct snd_pcm *pcm; |
1901 | int err; | 1918 | int err; |
1902 | 1919 | ||
1903 | if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, | 1920 | err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); |
1904 | &pcm)) < 0) | 1921 | if (err < 0) |
1905 | return err; | 1922 | return err; |
1906 | pcm->private_data = chip; | 1923 | pcm->private_data = chip; |
1907 | strcpy(pcm->name, "My Chip"); | 1924 | strcpy(pcm->name, "My Chip"); |
@@ -1939,8 +1956,8 @@ | |||
1939 | struct snd_pcm *pcm; | 1956 | struct snd_pcm *pcm; |
1940 | int err; | 1957 | int err; |
1941 | 1958 | ||
1942 | if ((err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, | 1959 | err = snd_pcm_new(chip->card, "My Chip", 0, 1, 1, &pcm); |
1943 | &pcm)) < 0) | 1960 | if (err < 0) |
1944 | return err; | 1961 | return err; |
1945 | pcm->private_data = chip; | 1962 | pcm->private_data = chip; |
1946 | strcpy(pcm->name, "My Chip"); | 1963 | strcpy(pcm->name, "My Chip"); |
@@ -2097,7 +2114,7 @@ | |||
2097 | struct mychip *chip = snd_pcm_chip(pcm); | 2114 | struct mychip *chip = snd_pcm_chip(pcm); |
2098 | /* free your own data */ | 2115 | /* free your own data */ |
2099 | kfree(chip->my_private_pcm_data); | 2116 | kfree(chip->my_private_pcm_data); |
2100 | // do what you like else | 2117 | /* do what you like else */ |
2101 | .... | 2118 | .... |
2102 | } | 2119 | } |
2103 | 2120 | ||
@@ -2884,10 +2901,10 @@ struct _snd_pcm_runtime { | |||
2884 | <![CDATA[ | 2901 | <![CDATA[ |
2885 | switch (cmd) { | 2902 | switch (cmd) { |
2886 | case SNDRV_PCM_TRIGGER_START: | 2903 | case SNDRV_PCM_TRIGGER_START: |
2887 | // do something to start the PCM engine | 2904 | /* do something to start the PCM engine */ |
2888 | break; | 2905 | break; |
2889 | case SNDRV_PCM_TRIGGER_STOP: | 2906 | case SNDRV_PCM_TRIGGER_STOP: |
2890 | // do something to stop the PCM engine | 2907 | /* do something to stop the PCM engine */ |
2891 | break; | 2908 | break; |
2892 | default: | 2909 | default: |
2893 | return -EINVAL; | 2910 | return -EINVAL; |
@@ -3071,7 +3088,7 @@ struct _snd_pcm_runtime { | |||
3071 | spin_unlock(&chip->lock); | 3088 | spin_unlock(&chip->lock); |
3072 | snd_pcm_period_elapsed(chip->substream); | 3089 | snd_pcm_period_elapsed(chip->substream); |
3073 | spin_lock(&chip->lock); | 3090 | spin_lock(&chip->lock); |
3074 | // acknowledge the interrupt if necessary | 3091 | /* acknowledge the interrupt if necessary */ |
3075 | } | 3092 | } |
3076 | .... | 3093 | .... |
3077 | spin_unlock(&chip->lock); | 3094 | spin_unlock(&chip->lock); |
@@ -3134,7 +3151,7 @@ struct _snd_pcm_runtime { | |||
3134 | snd_pcm_period_elapsed(substream); | 3151 | snd_pcm_period_elapsed(substream); |
3135 | spin_lock(&chip->lock); | 3152 | spin_lock(&chip->lock); |
3136 | } | 3153 | } |
3137 | // acknowledge the interrupt if necessary | 3154 | /* acknowledge the interrupt if necessary */ |
3138 | } | 3155 | } |
3139 | .... | 3156 | .... |
3140 | spin_unlock(&chip->lock); | 3157 | spin_unlock(&chip->lock); |
@@ -3604,7 +3621,7 @@ struct _snd_pcm_runtime { | |||
3604 | <title>Example of info callback</title> | 3621 | <title>Example of info callback</title> |
3605 | <programlisting> | 3622 | <programlisting> |
3606 | <![CDATA[ | 3623 | <![CDATA[ |
3607 | static int snd_myctl_info(struct snd_kcontrol *kcontrol, | 3624 | static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol, |
3608 | struct snd_ctl_elem_info *uinfo) | 3625 | struct snd_ctl_elem_info *uinfo) |
3609 | { | 3626 | { |
3610 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 3627 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
@@ -3639,7 +3656,7 @@ struct _snd_pcm_runtime { | |||
3639 | <informalexample> | 3656 | <informalexample> |
3640 | <programlisting> | 3657 | <programlisting> |
3641 | <![CDATA[ | 3658 | <![CDATA[ |
3642 | static int snd_myctl_info(struct snd_kcontrol *kcontrol, | 3659 | static int snd_myctl_enum_info(struct snd_kcontrol *kcontrol, |
3643 | struct snd_ctl_elem_info *uinfo) | 3660 | struct snd_ctl_elem_info *uinfo) |
3644 | { | 3661 | { |
3645 | static char *texts[4] = { | 3662 | static char *texts[4] = { |
@@ -3658,6 +3675,16 @@ struct _snd_pcm_runtime { | |||
3658 | </programlisting> | 3675 | </programlisting> |
3659 | </informalexample> | 3676 | </informalexample> |
3660 | </para> | 3677 | </para> |
3678 | |||
3679 | <para> | ||
3680 | Some common info callbacks are prepared for easy use: | ||
3681 | <function>snd_ctl_boolean_mono_info()</function> and | ||
3682 | <function>snd_ctl_boolean_stereo_info()</function>. | ||
3683 | Obviously, the former is an info callback for a mono channel | ||
3684 | boolean item, just like <function>snd_myctl_mono_info</function> | ||
3685 | above, and the latter is for a stereo channel boolean item. | ||
3686 | </para> | ||
3687 | |||
3661 | </section> | 3688 | </section> |
3662 | 3689 | ||
3663 | <section id="control-interface-callbacks-get"> | 3690 | <section id="control-interface-callbacks-get"> |
@@ -3794,7 +3821,8 @@ struct _snd_pcm_runtime { | |||
3794 | <informalexample> | 3821 | <informalexample> |
3795 | <programlisting> | 3822 | <programlisting> |
3796 | <![CDATA[ | 3823 | <![CDATA[ |
3797 | if ((err = snd_ctl_add(card, snd_ctl_new1(&my_control, chip))) < 0) | 3824 | err = snd_ctl_add(card, snd_ctl_new1(&my_control, chip)); |
3825 | if (err < 0) | ||
3798 | return err; | 3826 | return err; |
3799 | ]]> | 3827 | ]]> |
3800 | </programlisting> | 3828 | </programlisting> |
@@ -3880,7 +3908,7 @@ struct _snd_pcm_runtime { | |||
3880 | { | 3908 | { |
3881 | struct mychip *chip = ac97->private_data; | 3909 | struct mychip *chip = ac97->private_data; |
3882 | .... | 3910 | .... |
3883 | // read a register value here from the codec | 3911 | /* read a register value here from the codec */ |
3884 | return the_register_value; | 3912 | return the_register_value; |
3885 | } | 3913 | } |
3886 | 3914 | ||
@@ -3889,7 +3917,7 @@ struct _snd_pcm_runtime { | |||
3889 | { | 3917 | { |
3890 | struct mychip *chip = ac97->private_data; | 3918 | struct mychip *chip = ac97->private_data; |
3891 | .... | 3919 | .... |
3892 | // write the given register value to the codec | 3920 | /* write the given register value to the codec */ |
3893 | } | 3921 | } |
3894 | 3922 | ||
3895 | static int snd_mychip_ac97(struct mychip *chip) | 3923 | static int snd_mychip_ac97(struct mychip *chip) |
@@ -3902,7 +3930,8 @@ struct _snd_pcm_runtime { | |||
3902 | .read = snd_mychip_ac97_read, | 3930 | .read = snd_mychip_ac97_read, |
3903 | }; | 3931 | }; |
3904 | 3932 | ||
3905 | if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0) | 3933 | err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus); |
3934 | if (err < 0) | ||
3906 | return err; | 3935 | return err; |
3907 | memset(&ac97, 0, sizeof(ac97)); | 3936 | memset(&ac97, 0, sizeof(ac97)); |
3908 | ac97.private_data = chip; | 3937 | ac97.private_data = chip; |
@@ -4447,10 +4476,10 @@ struct _snd_pcm_runtime { | |||
4447 | <informalexample> | 4476 | <informalexample> |
4448 | <programlisting> | 4477 | <programlisting> |
4449 | <![CDATA[ | 4478 | <![CDATA[ |
4450 | struct list_head *list; | ||
4451 | struct snd_rawmidi_substream *substream; | 4479 | struct snd_rawmidi_substream *substream; |
4452 | list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | 4480 | list_for_each_entry(substream, |
4453 | substream = list_entry(list, struct snd_rawmidi_substream, list); | 4481 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, |
4482 | list { | ||
4454 | sprintf(substream->name, "My MIDI Port %d", substream->number + 1); | 4483 | sprintf(substream->name, "My MIDI Port %d", substream->number + 1); |
4455 | } | 4484 | } |
4456 | /* same for SNDRV_RAWMIDI_STREAM_INPUT */ | 4485 | /* same for SNDRV_RAWMIDI_STREAM_INPUT */ |