linux alsa驱动
// struct snd_card *card; struct snd_pcm *pcm; err = snd_card_new(&g_audio->gadget->dev, -1, NULL, THIS_MODULE, 0, &card); err = snd_pcm_new(uac->card, pcm_name, 0, p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm); if (err < 0) goto snd_fail; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); snd_fail: snd_card_free(card); // read|write: struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; /* Pack USB load in ALSA ring buffer */ pending = runtime->dma_bytes - hw_ptr; case read: memcpy(runtime->dma_area + hw_ptr, req->buf, pending); memcpy(runtime->dma_area, req->buf + pending, req->actual - pending); case write: memcpy(req->buf, runtime->dma_area + hw_ptr, pending); memcpy(req->buf + pending, runtime->dma_area, req->actual - pending); if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual) snd_pcm_period_elapsed(substream); machine: snd_soc_card_set_drvdata(&priv->snd_card, priv); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); codec: snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); platform: ret = devm_snd_soc_register_component(&pdev->dev, &rockchip_i2s_component, soc_dai, 1); ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) { dev_err(&pdev->dev, "Could not register PCM\n"); return ret; }
一勤天下无难事。