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零拷贝
相关推荐
ZHANG13HAO2 小时前
Android 13 系统源码定制的保活方案,
android
2501_9462309810 小时前
Cordova&OpenHarmony通知中心实现
android·javascript
csj5011 小时前
安卓基础之《(9)—中级控件(3)文本输入》
android
Elastic 中国社区官方博客13 小时前
Elasticsearch:在 X-mas 吃一些更健康的东西
android·大数据·数据库·人工智能·elasticsearch·搜索引擎·全文检索
2501_9462309814 小时前
Cordova&OpenHarmony提醒管理系统实现
android·javascript
shaominjin12315 小时前
Jetpack Compose 实践入门:从环境搭建到待办列表实现
android
冬奇Lab17 小时前
稳定性性能系列之二——ANR机制深度解析:从触发到上报
android·性能优化·debug
江上清风山间明月17 小时前
Android BIND_NOTIFICATION_LISTENER_SERVICE 权限详解
android·notification·service·bind·listener
Lei活在当下18 小时前
【日常知识积累】Kotlin let 函数、inline 函数以及 DSL
android·kotlin·编程语言