ASoC USB 支援

概述

為了利用 ALSA 中現有的 USB 音訊裝置支援,引入了 ASoC USB API,允許子系統交換配置資訊。

一個潛在的用例是支援 USB 音訊解除安裝,這是一種允許音訊子系統中存在替代的、功耗最佳化的路徑來處理透過 USB 匯流排傳輸音訊資料的實現。 這將允許主處理器在更長的持續時間內保持較低的功耗模式。 以下是一個 ASoC 和 ALSA 元件如何連線在一起以實現此目的的設計示例

           USB                   |            ASoC
                                 |  _________________________
                                 | |   ASoC Platform card    |
                                 | |_________________________|
                                 |         |           |
                                 |      ___V____   ____V____
                                 |     |ASoC BE | |ASoC FE  |
                                 |     |DAI LNK | |DAI LNK  |
                                 |     |________| |_________|
                                 |         ^  ^        ^
                                 |         |  |________|
                                 |      ___V____    |
                                 |     |SoC-USB |   |
 ________       ________               |        |   |
|USB SND |<--->|USBSND  |<------------>|________|   |
|(card.c)|     |offld   |<----------                |
|________|     |________|___     | |                |
    ^               ^       |    | |    ____________V_________
    |               |       |    | |   |IPC                   |
 __ V_______________V_____  |    | |   |______________________|
|USB SND (endpoint.c)     | |    | |              ^
|_________________________| |    | |              |
            ^               |    | |   ___________V___________
            |               |    | |->|audio DSP              |
 ___________V_____________  |    |    |_______________________|
|XHCI HCD                 |<-    |
|_________________________|      |

SoC USB 驅動程式

結構體

struct snd_soc_usb

  • list: SND SoC 結構體列表的連結串列頭

  • component: 對 ASoC 元件的引用

  • connection_status_cb: 回撥函式,用於通知連線事件

  • update_offload_route_info: 回撥函式,用於獲取選定的 USB 音效卡/PCM 裝置

  • priv_data: 驅動程式資料

可以使用 ASoC 平臺卡裝置或 USB 裝置 (udev->dev) 引用 snd_soc_usb 結構。 這是由 ASoC BE DAI 連結建立的,USB 音訊實體將能夠使用此結構將資訊傳遞給 ASoC BE DAI 連結。

struct snd_soc_usb_device

  • card_idx: 與 USB 音訊裝置關聯的音效卡索引

  • chip_idx: USB 音訊晶片陣列索引

  • cpcm_idx: 與 USB 音訊裝置關聯的捕獲 pcm 裝置索引

  • ppcm_idx: 與 USB 音訊裝置關聯的回放 pcm 裝置索引

  • num_playback: 回放流的數量

  • num_capture: 捕獲流的數量

  • list: USB 音訊裝置列表的連結串列頭

struct snd_soc_usb_device 由 USB 音訊解除安裝驅動程式建立。 這將攜帶基本引數/限制,這些引數/限制將用於確定此 USB 音訊裝置可能的解除安裝路徑。

函式

int snd_soc_usb_find_supported_format(int card_idx,
                struct snd_pcm_hw_params *params, int direction)
  • card_idx: USB 音訊晶片陣列的索引。

  • params: 來自 USB DPCM BE DAI 連結的請求的 PCM 引數

  • direction: 捕獲或回放

snd_soc_usb_find_supported_format() 確保外部 DSP 請求的音訊配置檔案受 USB 裝置支援。

成功返回 0,失敗返回 -EOPNOTSUPP。

int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev)
  • usbdev: 發現的 usb 裝置

  • sdev: 裝置的功能

snd_soc_usb_connect() 通知 ASoC USB DCPM BE DAI 連結檢測到 USB 音訊裝置。 這可以在 BE DAI 驅動程式中用於跟蹤可用的 USB 音訊裝置。 這旨在由位於 USB SND 中的 USB 解除安裝驅動程式呼叫。

成功返回 0,失敗返回負錯誤程式碼。

int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev)
  • usbdev: 已移除的 usb 裝置

  • sdev: 要釋放的功能

snd_soc_usb_disconnect() 通知 ASoC USB DCPM BE DAI 連結 USB 音訊裝置已移除。 這旨在由位於 USB SND 中的 USB 解除安裝驅動程式呼叫。

void *snd_soc_usb_find_priv_data(struct device *usbdev)
  • usbdev: 用於引用以查詢私有資料的 usb 裝置

snd_soc_usb_find_priv_data() 獲取儲存到 SoC USB 裝置的私有資料。

成功返回指向 priv_data 的指標,失敗返回 NULL。

int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component,
                                struct snd_soc_jack *jack)
  • component: 要新增插孔的 ASoC 元件

  • jack: 要填充的插孔元件

snd_soc_usb_setup_offload_jack() 是一個幫助程式,用於將聲音插孔控制新增到平臺音效卡。 這將允許在支援 USB 音訊解除安裝的設計中使用一致的命名。 此外,這將使插孔能夠通知更改。

成功返回 0,否則返回負數。

int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm,
                                     int direction, enum snd_soc_usb_kctl path,
                                     long *route)
  • dev: 用於查詢解除安裝路徑對映的 USB 裝置

  • card: USB 音效卡索引

  • pcm: USB 音訊 PCM 裝置索引

  • direction: 用於獲取解除安裝路由資訊的方向

  • path: kcontrol 選擇器 - pcm 裝置或卡索引

  • route: 音訊解除安裝路徑的音效卡和 pcm 索引的對映。 這是

    一個包含兩個整數的陣列,將按特定順序攜帶音效卡和 pcm 裝置索引。 這可以用作 kcontrol 輸出的陣列。

snd_soc_usb_update_offload_route() 呼叫註冊的回撥函式到 USB BE DAI 連結,以獲取有關用於執行裝置的 USB 音訊解除安裝的對映 ASoC 裝置的資訊。 route 可能是指向 kcontrol 值輸出陣列的指標,該陣列在讀取 kcontrol 時攜帶值。

成功返回 0,否則返回負數。

struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component,
                void *data);
  • component: DPCM BE DAI 連結元件

  • data: 私有資料

snd_soc_usb_allocate_port() 分配一個 SoC USB 裝置並填充用於進一步操作的標準引數。

成功返回指向 struct soc_usb 的指標,錯誤返回負數。

void snd_soc_usb_free_port(struct snd_soc_usb *usb);
  • usb: 要釋放的 SoC USB 裝置

snd_soc_usb_free_port() 釋放一個 SoC USB 裝置。

void snd_soc_usb_add_port(struct snd_soc_usb *usb);
  • usb: 要新增的 SoC USB 裝置

snd_soc_usb_add_port() 將分配的 SoC USB 裝置新增到 SOC USB 框架。 新增後,可以透過進一步的操作引用此裝置。

void snd_soc_usb_remove_port(struct snd_soc_usb *usb);
  • usb: 要移除的 SoC USB 裝置

snd_soc_usb_remove_port() 從 SoC USB 框架中移除一個 SoC USB 裝置。 移除裝置後,任何 SOC USB 操作都將無法引用已移除的裝置。

如何註冊到 SoC USB

ASoC DPCM USB BE DAI 連結是在元件繫結時負責分配和註冊 SoC USB 實體的實體。 同樣,它也將負責釋放分配的資源。 下面可以顯示一個示例

static int q6usb_component_probe(struct snd_soc_component *component)
{
        ...
        data->usb = snd_soc_usb_allocate_port(component, 1, &data->priv);
        if (!data->usb)
                return -ENOMEM;

        usb->connection_status_cb = q6usb_alsa_connection_cb;

        ret = snd_soc_usb_add_port(usb);
        if (ret < 0) {
                dev_err(component->dev, "failed to add usb port\n");
                goto free_usb;
        }
        ...
}

static void q6usb_component_remove(struct snd_soc_component *component)
{
        ...
        snd_soc_usb_remove_port(data->usb);
        snd_soc_usb_free_port(data->usb);
}

static const struct snd_soc_component_driver q6usb_dai_component = {
        .probe = q6usb_component_probe,
        .remove = q6usb_component_remove,
        .name = "q6usb-dai-component",
        ...
};

BE DAI 連結可以作為呼叫的一部分傳遞供應商特定資訊以分配 SoC USB 裝置。 這將允許位於 USB SND 中的 USB 解除安裝驅動程式訪問任何 BE DAI 連結引數或設定。

USB 音訊裝置連線流程

USB 裝置可以在任何時間點熱插拔到 USB 埠。 BE DAI 連結應瞭解物理 USB 埠的當前狀態,即,是否有任何連線了音訊介面的 USB 裝置。 connection_status_cb() 可用於通知 BE DAI 連結任何更改。

每當存在 USB SND 介面繫結或移除事件時,都會呼叫此函式,使用 snd_soc_usb_connect() 或 snd_soc_usb_disconnect()

static void qc_usb_audio_offload_probe(struct snd_usb_audio *chip)
{
        ...
        snd_soc_usb_connect(usb_get_usb_backend(udev), sdev);
        ...
}

static void qc_usb_audio_offload_disconnect(struct snd_usb_audio *chip)
{
        ...
        snd_soc_usb_disconnect(usb_get_usb_backend(chip->dev), dev->sdev);
        ...
}

為了考慮到驅動程式或裝置的存在不保證的情況,USB SND 公開了 snd_usb_rediscover_devices() 以重新發送任何已識別的 USB 音訊介面的連線事件。 考慮以下情況

usb_audio_probe()
--> USB 音訊流被分配並儲存到 usb_chip[]
--> 將連線事件傳播到 USB SND 中的 USB 解除安裝驅動程式
--> snd_soc_usb_connect() 退出,因為 USB BE DAI 連結未準備好
BE DAI 連結元件探測
--> 探測 DAI 連結並分配 SoC USB 埠
--> 錯過了 USB 音訊裝置連線事件

為了確保不會錯過連線事件,在註冊 SoC USB 裝置時執行 snd_usb_rediscover_devices()。 現在,當發生 BE DAI 連結元件探測時,以下突出顯示了該序列

BE DAI 連結元件探測
--> 探測 DAI 連結並分配 SoC USB 埠
--> 新增 SoC USB 裝置,並執行 snd_usb_rediscover_devices()
snd_usb_rediscover_devices()
--> 遍歷 usb_chip[],對於非 NULL 條目,發出
connection_status_cb()

如果 USB 解除安裝驅動程式未繫結,而 USB SND 已準備好,則在模組初始化期間呼叫 snd_usb_rediscover_devices()。 這允許透過以下流程啟用解除安裝路徑

usb_audio_probe()
--> USB 音訊流被分配並儲存到 usb_chip[]
--> 將連線事件傳播到 USB SND 中的 USB 解除安裝驅動程式
--> USB 解除安裝驅動程式 準備好!
BE DAI 連結元件探測
--> 探測 DAI 連結並分配 SoC USB 埠
--> 由於缺少 USB 解除安裝驅動程式,因此沒有 USB 連線事件
USB 解除安裝驅動程式探測
--> qc_usb_audio_offload_init()
--> 呼叫 snd_usb_rediscover_devices() 以通知裝置