diff options
author | Jaroslav Kysela <perex@suse.cz> | 2004-05-17 15:37:11 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2004-05-17 15:37:11 +0200 |
commit | f2f6bd5c8eb6f35e3075d2211d566c71cf826b70 (patch) | |
tree | f719dfd49f189677fcd619c2028f9ad2f5fb6d95 /Documentation | |
parent | bd7b6c43e2e61a6380c1a1b99229d108c16c1f3a (diff) | |
parent | 1c4b231784c979c38d0912417b0b63c48eb7f727 (diff) | |
download | history-f2f6bd5c8eb6f35e3075d2211d566c71cf826b70.tar.gz |
Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5
into suse.cz:/home/perex/bk/linux-sound/linux-sound
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 218 | ||||
-rw-r--r-- | Documentation/sound/alsa/Procfile.txt | 6 |
2 files changed, 53 insertions, 171 deletions
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 63a46fd2b52737..ac30faad22adb3 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -511,7 +511,7 @@ } // (7) - pci_set_drvdata(pci, chip); + pci_set_drvdata(pci, card); dev++; return 0; } @@ -519,10 +519,7 @@ // destructor -- see "Destructor" sub-section static void __devexit snd_mychip_remove(struct pci_dev *pci) { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(pci), return); - if (chip) - snd_card_free(chip->card); + snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } ]]> @@ -691,21 +688,16 @@ <informalexample> <programlisting> <![CDATA[ - pci_set_drvdata(pci, chip); + pci_set_drvdata(pci, card); dev++; return 0; ]]> </programlisting> </informalexample> - In the above, the chip record is stored. This pointer is + In the above, the card record is stored. This pointer is referred in the remove callback and power-management callbacks, too. - If the card doesn't support the suspend/resume, you can store - the card pointer instead of the chip pointer, so that - <function>snd_card_free</function> can be called directly - without cast in the remove callback. But anyway, be sure - which pointer is used. </para> </section> </section> @@ -726,21 +718,15 @@ <![CDATA[ static void __devexit snd_mychip_remove(struct pci_dev *pci) { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(pci), return); - if (chip) - snd_card_free(chip->card); + snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } ]]> </programlisting> </informalexample> - The above code assumes that the chip is allocated - with snd_magic stuff and - has the field to hold the card pointer (see <link - linkend="card-management"><citetitle>the next - section</citetitle></link>). + The above code assumes that the card pointer is set to the PCI + driver data. </para> </section> @@ -1355,16 +1341,7 @@ // initialization of the module static int __init alsa_card_mychip_init(void) { - int err; - - if ((err = pci_module_init(&driver)) < 0) { - #ifdef MODULE - printk(KERN_ERR "My chip soundcard not found " - "or device busy\n"); - #endif - return err; - } - return 0; + return pci_module_init(&driver); } // clean up the module @@ -1781,16 +1758,7 @@ <![CDATA[ static int __init alsa_card_mychip_init(void) { - int err; - - if ((err = pci_module_init(&driver)) < 0) { - #ifdef MODULE - printk(KERN_ERR "My chip soundcard not found" - " or device busy\n"); - #endif - return err; - } - return 0; + return pci_module_init(&driver); } static void __exit alsa_card_mychip_exit(void) @@ -5254,47 +5222,23 @@ struct _snd_pcm_runtime { </para> <para> - Basic jobs of suspend/resume are done in - <structfield>suspend</structfield> and - <structfield>resume</structfield> callbacks of - <structname>pci_driver</structname> struct. Unfortunately, the - API of these callbacks was changed at the middle time of Linux - 2.4.x, if you want to keep the support for older kernels, you - have to write two different callbacks. The example below is the - skeleton callbacks which just call the real suspend and resume - functions. + ALSA provides the common power-management layer. Each card driver + needs to have only low-level suspend and resume callbacks. <informalexample> <programlisting> <![CDATA[ - #ifndef PCI_OLD_SUSPEND - static int snd_my_suspend(struct pci_dev *dev, u32 state) + #ifdef CONFIG_PM + static int snd_my_suspend(snd_card_t *card, unsigned int state) { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(dev), return -ENXIO); - mychip_suspend(chip); + .... // do things for suspsend return 0; } - static int snd_my_resume(struct pci_dev *dev) + static int snd_my_resume(snd_card_t *card, unsigned int state) { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(dev), return -ENXIO); - mychip_resume(chip); + .... // do things for suspsend return 0; } - #else - static void snd_my_suspend(struct pci_dev *dev) - { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(dev), return); - mychip_suspend(chip); - } - static void snd_mychip_resume(struct pci_dev *dev) - { - mychip_t *chip = snd_magic_cast(mychip_t, - pci_get_drvdata(dev), return); - mychip_resume(chip); - } #endif ]]> </programlisting> @@ -5302,17 +5246,10 @@ struct _snd_pcm_runtime { </para> <para> - For keeping the readability of 2.6 source code, it's recommended to - separate the above ifdef condition as the patch file in alsa-driver - directory. - See <filename>alsa-driver/pci/ali5451.c</filename> for example. - </para> - - <para> The scheme of the real suspend job is as following. <orderedlist> - <listitem><para>Check whether the power-state is already D3hot. If yes, skip the job.</para></listitem> + <listitem><para>Retrieve the chip data from pm_private_data field.</para></listitem> <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> @@ -5326,12 +5263,11 @@ struct _snd_pcm_runtime { <informalexample> <programlisting> <![CDATA[ - static void mychip_suspend(mychip_t *chip) + static int mychip_suspend(snd_card_t *card, unsigned int state) { - snd_card_t *card = chip->card; // (1) - if (card->power_state == SNDRV_CTL_POWER_D3hot) - return; + mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data, + return -ENXIO); // (2) snd_pcm_suspend_all(chip->pcm); // (3) @@ -5340,6 +5276,7 @@ struct _snd_pcm_runtime { snd_mychip_stop_hardware(chip); // (5) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + return 0; } ]]> </programlisting> @@ -5350,8 +5287,7 @@ struct _snd_pcm_runtime { The scheme of the real resume job is as following. <orderedlist> - <listitem><para>Check whether the power-state is already D0. - If yes, skip the job.</para></listitem> + <listitem><para>Retrieve the chip data from pm_private_data field.</para></listitem> <listitem><para>Enable the pci device again by calling <function>pci_enable_device()</function>.</para></listitem> <listitem><para>Re-initialize the chip.</para></listitem> @@ -5372,10 +5308,9 @@ struct _snd_pcm_runtime { <![CDATA[ static void mychip_resume(mychip_t *chip) { - snd_card_t *card = chip->card; // (1) - if (card->power_state == SNDRV_CTL_POWER_D0) - return; + mychip_t *chip = snd_magic_cast(mychip_t, card->pm_private_data, + return -ENXIO); // (2) pci_enable_device(chip->pci); // (3) @@ -5388,38 +5323,6 @@ struct _snd_pcm_runtime { snd_mychip_restart_chip(chip); // (7) snd_power_change_state(card, SNDRV_CTL_POWER_D0); - } -]]> - </programlisting> - </informalexample> - </para> - - <para> - In addition to the callbacks above, you should define a callback - for the changes via the ALSA control interface. It's defined - like below: - - <informalexample> - <programlisting> -<![CDATA[ - static int snd_mychip_set_power_state(snd_card_t *card, - unsigned int power_state) - { - mychip_t *chip = snd_magic_cast(mychip_t, - card->power_state_private_data, return -ENXIO); - switch (power_state) { - case SNDRV_CTL_POWER_D0: - case SNDRV_CTL_POWER_D1: - case SNDRV_CTL_POWER_D2: - mychip_resume(chip); - break; - case SNDRV_CTL_POWER_D3hot: - case SNDRV_CTL_POWER_D3cold: - mychip_suspend(chip); - break; - default: - return -EINVAL; - } return 0; } ]]> @@ -5439,41 +5342,42 @@ struct _snd_pcm_runtime { { .... snd_card_t *card; + mychip_t *chip; .... - #ifdef CONFIG_PM - card->set_power_state = snd_mychip_set_power_state; - card->power_state_private_data = chip; - #endif + snd_card_set_pm_callback(card, snd_my_suspend, snd_my_resume, chip); .... } ]]> </programlisting> </informalexample> + + Here you don't have to put ifdef CONFIG_PM around, since it's already + checked in the header and expanded to empty if not needed. </para> <para> If you need a space for saving the registers, you'll need to - allocate the buffer for it here, too, since you cannot call - <function>kmalloc()</function> with - <constant>GFP_KERNEL</constant> flag or - <function>vmalloc()</function> in the suspend callback. + allocate the buffer for it here, too, since it would be fatal + if you cannot allocate a memory in the suspend phase. The allocated buffer should be released in the corresponding destructor. </para> <para> And next, set suspend/resume callbacks to the pci_driver, + This can be done by passing a macro SND_PCI_PM_CALLBACKS + in the pci_driver struct. This macro is expanded to the correct + (global) callbacks if CONFIG_PM is set. <informalexample> <programlisting> <![CDATA[ static struct pci_driver driver = { .name = "My Chip", - .... - #ifdef CONFIG_PM - .suspend = snd_mychip_suspend, - .resume = snd_mychip_resume, - #endif + .id_table = snd_my_ids, + .probe = snd_my_probe, + .remove = __devexit_p(snd_my_remove), + SND_PCI_PM_CALLBACKS }; ]]> </programlisting> @@ -5521,7 +5425,8 @@ struct _snd_pcm_runtime { <para> The module parameters must be declared with the standard - <function>MODULE_PARM()</function> and + <function>module_param()()</function>, + <function>module_param_array()()</function> and <function>MODULE_PARM_DESC()</function> macros. The ALSA provides an additional macro, <function>MODULE_PARM_SYNTAX()</function>, for describing its syntax. The strings will be written to @@ -5545,18 +5450,22 @@ struct _snd_pcm_runtime { <![CDATA[ #define CARD_NAME "My Chip" - MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); + static int boot_devs; + module_param_array(index, int, boot_devs, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); - MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); + module_param_array(id, charp, boot_devs, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); - MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); + module_param_array(enable, bool, boot_devs, 0444); MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); ]]> </programlisting> </informalexample> + + Here boot_devs is passed but simply ignored since we don't care + the number of parsed parameters. </para> <para> @@ -5577,39 +5486,6 @@ struct _snd_pcm_runtime { </informalexample> </para> - <para> - For building the driver into kernel, you should define the - <function>setup()</function> function in addition, too. - ALSA provides <function>get_id()</function> function to retrieve - a string argument from the kernel boot parameters. - - <informalexample> - <programlisting> -<![CDATA[ - #ifndef MODULE - - /* format is: snd-mychip=enable,index,id */ - - static int __init alsa_card_mychip_setup(char *str) - { - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= SNDRV_CARDS) - return 0; - (void)(get_option(&str,&enable[nr_dev]) == 2 && - get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); - nr_dev++; - return 1; - } - - __setup("snd-mychip=", alsa_card_mychip_setup); - - #endif /* ifndef MODULE */ -]]> - </programlisting> - </informalexample> - </para> </chapter> diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index d686ea3c39eb59..25c5d648aef6c2 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -131,6 +131,12 @@ card*/codec97#*/ac97#?-? card*/codec97#0/ac97#?-?+regs Shows the AC97 register dump. Useful for debugging. + When CONFIG_SND_DEBUG is enabled, you can write to this file for + changing an AC97 register directly. Pass two hex numbers. + For example, + + # echo 02 9f1f > /proc/asound/card0/codec97#0/ac97#0-0+regs + Sequencer Information --------------------- |