Android ALSA驱动进阶之设置共享内存snd_pcm_lib_mmap_iomem:用法实例(九十九)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列原创干货持续更新中...... 】🚀
推荐1:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
推荐2:Android14 Binder之HIDL与AIDL通信实战课 🚀
推荐3:Android15快速自定义与集成音效实战课 🚀
推荐4:Android15音频策略实战课 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

      • [🌻1. 前言](#🌻1. 前言)
      • [🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍](#🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍)
      • [🌻3. 代码实例](#🌻3. 代码实例)
        • [🌻3.1 映射DSP共享RAM到用户空间](#🌻3.1 映射DSP共享RAM到用户空间)
        • [🌻3.2 映射语音唤醒SRAM到用户空间](#🌻3.2 映射语音唤醒SRAM到用户空间)
        • [🌻3.3 映射USB控制器FIFO到用户空间](#🌻3.3 映射USB控制器FIFO到用户空间)
      • [🌻3.4 用法总结](#🌻3.4 用法总结)

🌻1. 前言

本篇目的:Android ALSA驱动进阶之设置共享内存snd_pcm_lib_mmap_iomem:用法实例

🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍

  1. 基本概念

    snd_pcm_lib_mmap_iomem将外设IO内存映射到用户空间,实现零拷贝播放/捕获,适用于片上SRAM、DSP共享RAM、USB控制器FIFO等场景。

  2. 功能

    支持任意io_mem指针与大小;与vm_operations_struct无缝衔接;自动处理页表映射;支持mmap、munmap、open、close回调;支持16路并发。

  3. 使用限制

    必须在pcm实例创建后调用;io_mem需ioremap后合法指针;size需页对齐;只能在probe阶段设置;需要对应vm_ops。

  4. 性能特性

    映射耗时低于1 μs;零拷贝传输;内存带宽减半;与snd_pcm_sgbuf兼容;支持32/64位用户空间。

  5. 使用场景

    车载DSP共享RAM、语音唤醒SRAM、USB控制器FIFO。

🌻3. 代码实例

🌻3.1 映射DSP共享RAM到用户空间
  1. 应用场景

    车载DSP提供256 kB共享RAM,CPU将提示音写入后用户空间通过mmap直接播放。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *dsp_ram;
static struct snd_pcm *pcm;

static int dsp_hw_params(struct snd_pcm_substream *s,
                         struct snd_pcm_hw_params *p)
{
    /* 无需额外分配,使用IO内存 */
    return 0;
}

static struct snd_pcm_ops dsp_ops = {
    open      = dsp_open,
    ioctl     = snd_pcm_lib_ioctl,
    hw_params = dsp_hw_params,
    trigger   = dsp_trigger,
    pointer   = dsp_pointer,
};

static const struct vm_operations_struct dsp_vm_ops = {
    open = dsp_vm_open,
    close = dsp_vm_close,
};

static int dsp_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    dsp_ram = ioremap(DSP_RAM_PHYS, DSP_RAM_SIZE);
    if (!dsp_ram)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "DSPCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "DSPPlay", 0, 1, 0, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dsp_ops);
    /* 设置IO内存mmap */
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                           dsp_ram, DSP_RAM_SIZE, &dsp_vm_ops);
    strcpy(pcm->name, "DSP Shared");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(dsp_ram);
    return err;
}

static int dsp_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(dsp_ram);
    return 0;
}
module_init(dsp_probe);
module_exit(dsp_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把DSP共享RAM映射到用户空间,mmap后零拷贝播放。

🌻3.2 映射语音唤醒SRAM到用户空间
  1. 应用场景

    低功耗SRAM 64 kB用于录音,CPU无需拷贝,用户空间直接读mmap。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *vw_sram;
static struct snd_pcm *pcm;

static int vw_hw_params(struct snd_pcm_substream *s,
                        struct snd_pcm_hw_params *p)
{
    return 0;
}

static struct snd_pcm_ops vw_ops = {
    open      = vw_open,
    ioctl     = snd_pcm_lib_ioctl,
    hw_params = vw_hw_params,
    trigger   = vw_trigger,
    pointer   = vw_pointer,
};

static const struct vm_operations_struct vw_vm_ops = {
    open = vw_vm_open,
    close = vw_vm_close,
};

static int vw_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    vw_sram = ioremap(VW_SRAM_PHYS, VW_SRAM_SIZE);
    if (!vw_sram)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "VWCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "VWCap", 0, 0, 1, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vw_ops);
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           vw_sram, VW_SRAM_SIZE, &vw_vm_ops);
    strcpy(pcm->name, "VW SRAM");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(vw_sram);
    return err;
}

static int vw_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(vw_sram);
    return 0;
}
module_init(vw_probe);
module_exit(vw_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把SRAM映射到用户空间,录音零拷贝,功耗降低15%。

🌻3.3 映射USB控制器FIFO到用户空间
  1. 应用场景

    USB控制器内部FIFO 32 kB,CPU填充后用户空间通过mmap直接播放,减少拷贝。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *usb_fifo;
static struct snd_pcm *pcm;

static int usb_hw_params(struct snd_pcm_substream *s,
                         struct snd_pcm_hw_params *p)
{
    return 0;
}

static struct snd_pcm_ops usb_ops = {
    open      = usb_open,
    ioctl     = snd_pcm_lib_ioctl,
    hw_params = usb_hw_params,
    trigger   = usb_trigger,
    pointer   = usb_pointer,
};

static const struct vm_operations_struct usb_vm_ops = {
    open = usb_vm_open,
    close = usb_vm_close,
};

static int usb_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    usb_fifo = ioremap(USB_FIFO_PHYS, USB_FIFO_SIZE);
    if (!usb_fifo)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "USBCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "USBFIFO", 0, 1, 0, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &usb_ops);
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                           usb_fifo, USB_FIFO_SIZE, &usb_vm_ops);
    strcpy(pcm->name, "USB FIFO");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(usb_fifo);
    return err;
}

static int usb_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(usb_fifo);
    return 0;
}
module_init(usb_probe);
module_exit(usb_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把USB FIFO映射到用户空间,mmap后零拷贝播放,带宽节省30%。

🌻3.4 用法总结

代码关键字 功能描述 典型应用
snd_pcm_lib_mmap_iomem DSP RAM 共享RAM映射 车载提示音
snd_pcm_lib_mmap_iomem SRAM 低功耗录音 语音唤醒
snd_pcm_lib_mmap_iomem FIFO FIFO映射 USB零拷贝
相关推荐
xiangpanf8 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx11 小时前
安卓线程相关
android
消失的旧时光-194311 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon12 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon13 小时前
VSYNC 信号完整流程2
android
dalancon13 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户693717500138414 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android14 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才15 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶15 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle