*参照元 [#i2602357] #backlinks *説明 [#e067dd67] FIXME: なにをするもの? -card, pcm, pcm_substream の関係について。 card0 -+- PCM0 -+- substream0 | | | +- substream1 | +- PCM1 --- substream0 | ... card1 --- PCM0 --- substream0 ... -procfs を見ると上記の関係性がわかりやすいかも。 パスは /proc/asound/card*/pcm*/sub* にある。 ** SoC driver の ops 呼び出し順 [#x82da16c] - DAI: snd_soc_dai_driver の ops (snd_soc_dai_ops 型) - PCM: snd_soc_platform_driver の ops (snd_pcm_ops 型) - SOC: snd_soc_dai_link の ops (snd_soc_ops 型) - LNK: snd_soc_dai_link の ops (snd_soc_ops 型) | soc_ops/pcm_ops | 1st | 2nd | 3rd | | startup/open | DAI | PCM | SOC | | hw_params | SOC | DAI | PCM | | prepare | SOC | PCM | DAI | | trigger | PCM | DAI | SOC | | hw_free | SOC | PCM | DAI | | shutdown/close | DAI | SOC | PCM | | startup/open | DAI | PCM | LNK | | hw_params | LNK | DAI | PCM | | prepare | LNK | PCM | DAI | | trigger | PCM | DAI | LNK | | hw_free | LNK | PCM | DAI | | shutdown/close | DAI | LNK | PCM | **参考: private_data について [#ccc0dfe8] ALSA のコールバック API に渡ってくる構造体から、 ドライバの独自データを獲る方法について。 ALSA SoC Layer を使う場合とそうでない場合が大きく違っていて、 難しすぎだろこれ…。 ALSA SoC Layer を使わない場合 -platform_bus を使っているとして、probe 時に snd_card_register() を呼ぶ前に、 snd_card を作成する際に使用した snd_pcm の void *private_data に直接書けば良いはずです。 -取得の経路 snd_pcm_substream --(snd_pcm_substream_chip)--> ドライバ独自データ --[[linux-4.4.1/snd_card]] --[[linux-4.4.1/snd_pcm]] --[[linux-4.4.1/snd_pcm_substream]] --[[linux-4.4.1/snd_pcm_substream_chip()]] ALSA SoC Layer を使っていて、CPU/CODEC DAI の場合 -platform_bus を使っているとして、probe 時に snd_soc_register_component() を呼ぶ前に、 platform_set_drvdata() で pdev->dev->driver_data に書けば良いはずです。 -取得の経路 snd_pcm_substream --(snd_pcm_substream_chip)--> snd_soc_pcm_runtime --(cpu_dai メンバ/codec_dai メンバ)--> ※SoC のドライバなら cpu_dai で、 CODEC のドライバなら codec_dai を使うはず snd_soc_dai --(snd_soc_dai_get_drvdata)--> ドライバ独自データ --[[linux-4.4.1/snd_pcm_substream]] --[[linux-4.4.1/snd_soc_pcm_runtime]] --[[linux-4.4.1/snd_soc_dai]] --[[linux-4.4.1/snd_pcm_substream_chip()]] --[[linux-4.4.1/snd_soc_dai_get_drvdata()]] ALSA SoC Layer を使っていて、Card の場合 -おそらく platform_bus を使っているとして、probe 時に snd_soc_register_card() を呼ぶ前に、 snd_soc_card_set_drvdata() を使って、card->drvdata に保存すべきでしょう。 -DAI と違って platform_set_drvdata() で pdev->dev->driver_data に書くのは NG です。 platform_device の struct device *dev と、snd_soc_card の sturct device *dev は、 同じ device を指していて、snd_soc_register_card() が card->dev->driver_data を上書きするため、 設定が消えてしまうからです。 -取得の経路 platform_device --(platform_get_drvdata)--> snd_soc_card --(snd_soc_card_get_drvdata)--> ドライバ独自データ --[[linux-4.4.1/platform_device]] --[[linux-4.4.1/snd_soc_card]] --[[linux-4.4.1/platform_get_drvdata()]] --[[linux-4.4.1/platform_set_drvdata()]] --[[linux-4.4.1/snd_soc_card_get_drvdata()]] --[[linux-4.4.1/snd_soc_card_set_drvdata()]] **関連モジュール [#m8242ada] -ALSA SoC Layer --DAPM(Dynamic Audio Power Management) --- --DAI(Digital Audio Interfaces) ---AC97, I2S, PCM の 3つをサポート。 必要そうなものメモ。 - -[[linux-4.4.1/snd_soc_platform_driver]] --[[linux-4.4.1/snd_pcm_ops]] -[[linux-4.4.1/snd_soc_register_platform()]] 包含関係 - snd_soc_platform_driver - snd_pcm_ops - -[[linux-4.4.1/snd_soc_component_driver]] -[[linux-4.4.1/snd_soc_dai_driver]] --[[linux-4.4.1/snd_soc_dai_ops]] --[[linux-4.4.1/snd_soc_pcm_stream]] -[[linux-4.4.1/snd_soc_register_component()]] 包含関係 - snd_soc_component_driver - snd_soc_dai_driver - snd_soc_dai_ops - snd_soc_pcm_stream - -[[linux-4.4.1/snd_soc_card]] --[[linux-4.4.1/snd_soc_dai_link]] ---[[linux-4.4.1/snd_soc_dpcm_trigger]] ---[[linux-4.4.1/snd_soc_ops]] ---[[linux-4.4.1/snd_soc_compr_ops]] --[[linux-4.4.1/snd_soc_codec_conf]] --[[linux-4.4.1/snd_soc_kcontrol_new]] --[[linux-4.4.1/snd_soc_dapm_widget]] --[[linux-4.4.1/snd_soc_dapm_route]] -[[linux-4.4.1/snd_soc_register_card()]] 包含関係 - snd_soc_card - snd_soc_dai_link - snd_soc_dpcm_trigger - snd_soc_ops - snd_soc_compr_ops - snd_soc_codec_conf - snd_soc_kcontrol_new - snd_soc_dapm_widget - snd_soc_dapm_route ** 例 [#na2337a3] platform_bus を使う場合、 struct hoge_device { struct snd_soc_card card; }; static int hoge_probe(struct platform_device *pdev) { struct hoge_device *d; struct device *dev = &pdev->dev; ... d = devm_kzalloc(dev, sizeof(struct hoge_device)); ... snd_soc_register_platform(dev, &hoge_snd_soc_platform_driver); ... snd_soc_register_component(dev, &hoge_snd_soc_component_driver, hoge_snd_soc_dai_drivers, ARRAY_SIZE(hoge_snd_soc_dai_drivers)); ... //FIXME: 他の手立てがありそう d->card.dev = dev; snd_soc_card_set_drvdata(&d->card, d); snd_soc_register_card(&d->card); ... return 0; } -ドライバの固有情報の保存場所について --pdev->dev と d->card.dev が同じ device を指しているため、platform_set_drvdata() で pdev->dev->driver_data に書くのは NG です。 --snd_soc_register_card() が card->dev->driver_data を上書きするため、消えてしまいます。 --おそらく snd_soc_card_set_drvdata() を使って、card->drvdata に保存すべきでしょう。 --[[linux-4.4.1/platform_get_drvdata()]] --[[linux-4.4.1/platform_set_drvdata()]] --[[linux-4.4.1/snd_soc_card_get_drvdata()]] --[[linux-4.4.1/snd_soc_card_set_drvdata()]] static int hoge_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct hoge_device *d = snd_soc_card_get_drvdata(card); struct device *dev = &pdev->dev; ... snd_soc_unregister_card(&d->card); ... snd_soc_unregister_component(dev); ... snd_soc_unregister_platform(dev); ... return 0; } static struct platform_driver hoge_driver = { .driver = { .name = "hoge", }, .probe = hoge_probe, .remove = hoge_remove, }; module_platform_driver(hoge_driver); *コメント [#vd3dc98b]