Hi Pierre,
On 9/25/2024 7:43 AM, Pierre-Louis Bossart wrote:
>> + int snd_soc_usb_setup_offload_jack(struct snd_soc_component *component,
>> + struct snd_soc_jack *jack)
>> +..
>> +
>> + - ``component``: ASoC component to add the jack
>> + - ``jack``: jack component to populate
>> +
>> +**snd_soc_usb_setup_offload_jack()** is a helper to add a sound jack control to
>> +the platform sound card. This will allow for consistent naming to be used on
>> +designs that support USB audio offloading.
>> +
>> +Returns 0 on success, negative otherwise.
>> +
>> +.. code-block:: rst
>> +
>> + int snd_soc_usb_disable_offload_jack(struct snd_soc_component *component)
>> +..
>> +
>> + - ``component``: ASoC component to disable the jack
>> +
>> +**snd_soc_usb_disable_offload_jack()** is a helper to disable a sound jack control
>> +on the platform sound card.
> is disable_offload_jack() the companion operation to setup_offload_jack()?
>
> it's not clear to me if there's any relationship between the two.
I guess there is a relation in that one creates the jack and the other will disable it when needed. Might need to have a respective enable API, because I believe there are some situations during PM suspend where a jack may want to be disabled and re-enabled on PM resume.
>> +
>> +Returns 0 on success, negative otherwise.
>> +
>> +.. code-block:: rst
>> +
>> + int snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm,
>> + int direction, long *route)
>> +..
>> +
>> + - ``dev``: USB device to look up offload path mapping
>> + - ``card``: USB sound card index
>> + - ``pcm``: USB sound PCM device index
>> + - ``direction``: direction to fetch offload routing information
>> + - ``route``: mapping of sound card and pcm indexes for the offload path. This is
>> + an array of two integers that will carry the card and pcm device indexes
>> + in that specific order. This can be used as the array for the kcontrol
>> + output.
>> +
>> +**snd_soc_usb_update_offload_route()** calls a registered callback to the USB BE DAI
>> +link to fetch the information about the mapped ASoC devices for executing USB audio
>> +offload for the device. ``route`` may be a pointer to a kcontrol value output array,
>> +which carries values when the kcontrol is read.
>> +
>> +Returns 0 on success, negative otherwise.
> please clarify what happens if there is no offloaded device for a
> specific USB card. from [2] below it looks like the intended behavior
> for a device without offload capabilities would be to return 0 but the
> mapping would use the -1 magic value to state there is no offload?
>
That is the idea... If we return -1,-1 that is an invalid card/pcm device index, so it would signify that offloading is not available for a USB device.
>> +**snd_soc_usb_free_port()** frees a SOC USB device.
>> +
>> +.. code-block:: rst
>> +
>> + void snd_soc_usb_add_port(struct snd_soc_usb *usb);
>> +..
>> +
>> + - ``usb``: SOC USB device to add
>> +
>> +**snd_soc_usb_add_port()** add an allocated SOC USB device to the SOC USB framework.
>> +Once added, this device can be referenced by further operations.
>> +
>> +.. code-block:: rst
>> +
>> + void snd_soc_usb_remove_port(struct snd_soc_usb *usb);
>> +..
>> +
>> + - ``usb``: SOC USB device to remove
>> +
>> +**snd_soc_usb_remove_port()** removes a SOC USB device from the SOC USB framework.
>> +After removing a device, any SOC USB operations would not be able to reference the
>> +device removed.
> I don't think the last sentence is correct, below [1] you show an
> example where the free_port() routine is required...
>
The remove will remove it from the available list of SOC USB ports. The free will just make sure the memory allocated for the SOC USB port is freed.
>> +
>> + static void q6usb_component_remove(struct snd_soc_component *component)
>> + {
>> + ...
> [1]
>
>> + 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 links can pass along vendor specific information as part of the
>> +call to allocate the SOC USB device. This will allow any BE DAI link
>> +parameters or settings to be accessed by the USB offload driver that
>> +resides in USB SND.
>> +
>> +USB Audio Device Connection Flow
>> +--------------------------------
>> +USB devices can be hotplugged into the USB ports at any point in time.
>> +The BE DAI link should be aware of the current state of the physical USB
>> +port, i.e. if there are any USB devices with audio interface(s) connected.
>> +connection_status_cb() can be used to notify the BE DAI link of any change.
>> +
>> +This is called whenever there is a USB SND interface bind or remove event,
>> +using snd_soc_usb_connect() or snd_soc_usb_disconnect():
>> +
>> +.. code-block:: rst
>> +
>> + 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);
>> + ...
>> + }
>> +..
>> +
>> +In order to account for conditions where driver or device existence is
>> +not guaranteed, USB SND exposes snd_usb_rediscover_devices() to resend the
>> +connect events for any identified USB audio interfaces. Consider the
>> +the following situation:
>> +
>> + **usb_audio_probe()**
>> + | --> USB audio streams allocated and saved to usb_chip[]
>> + | --> Propagate connect event to USB offload driver in USB SND
>> + | --> **snd_soc_usb_connect()** exits as USB BE DAI link is not ready
>> +
>> + BE DAI link component probe
>> + | --> DAI link is probed and SOC USB port is allocated
>> + | --> The USB audio device connect event is missed
>> +
>> +To ensure connection events are not missed, **snd_usb_rediscover_devices()**
>> +is executed when the SOC USB device is registered. Now, when the BE DAI
>> +link component probe occurs, the following highlights the sequence:
>> +
>> + BE DAI link component probe
>> + | --> DAI link is probed and SOC USB port is allocated
>> + | --> SOC USB device added, and **snd_usb_rediscover_devices()** runs
>> +
>> + **snd_usb_rediscover_devices()**
>> + | --> Traverses through usb_chip[] and for non-NULL entries issue
>> + | **connection_status_cb()**
>> +
>> +In the case where the USB offload driver is unbound, while USB SND is ready,
>> +the **snd_usb_rediscover_devices()** is called during module init. This allows
>> +for the offloading path to also be enabled with the following flow:
>> +
>> + **usb_audio_probe()**
>> + | --> USB audio streams allocated and saved to usb_chip[]
>> + | --> Propagate connect event to USB offload driver in USB SND
>> + | --> USB offload driver **NOT** ready!
>> +
>> + BE DAI link component probe
>> + | --> DAI link is probed and SOC USB port is allocated
>> + | --> No USB connect event due to missing USB offload driver
>> +
>> + USB offload driver probe
>> + | --> **qc_usb_audio_offload_init()**
>> + | --> Calls **snd_usb_rediscover_devices()** to notify of devices
>> +
>> +USB Offload Related Kcontrols
>> +=============================
>> +Details
>> +-------
>> +A set of kcontrols can be utilized by applications to help select the proper sound
>> +devices to enable USB audio offloading. SOC USB exposes the get_offload_dev()
>> +callback that designs can use to ensure that the proper indices are returned to the
>> +application.
>> +
>> +Implementation
>> +--------------
>> +
>> +**Example:**
>> +
>> + **Sound Cards**:
>> +
>> + ::
>> +
>> + 0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
>> + SM8250-MTP-WCD9380-WSA8810-VA-DMIC
>> + 1 [Seri ]: USB-Audio - Plantronics Blackwire 3225 Seri
>> + Plantronics Plantronics Blackwire
>> + 3225 Seri at usb-xhci-hcd.1.auto-1.1,
>> + full sp
>> + 2 [C320M ]: USB-Audio - Plantronics C320-M
>> + Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed
>> +
>> + **USB Sound Card** - card#1:
>> +
>> + ::
>> +
>> + USB Offload Playback Route PCM#0 -1, -1 (range -1->255)
>> +
>> + **USB Sound Card** - card#2:
>> +
>> + ::
>> +
>> + USB Offload Playback Route PCM#0 0, 1 (range -1->255)
>> +
>> +The above example shows a scenario where the system has one ASoC platform card
>> +(card#0) and two USB sound devices connected (card#1 and card#2). When reading
>> +the available kcontrols for each USB audio device, the following kcontrol lists
>> +the mapped offload path for the specific device:
>> +
>> + ``USB Offload Playback Route#*``
>> +
>> +The kcontrol is indexed, because a USB audio device could potentially have
>> +several PCM devices. The above kcontrols are defined as:
>> +
>> + - ``USB Offload Playback Route PCM`` **(R)**: Returns the ASoC platform sound
>> + card and PCM device index. The output **"0, 1"** (card index, PCM device index)
>> + signifies that there is an available offload path for the USB SND device
>> + through card#0 - PCM device#1. If **"-1, -1"** is seen, then no offload path is
>> + available for the USB SND device.
> [2]
>
> maybe I got this wrong but you may want to clarify that the kcontrol is
> always created, but the values indicate if the offload support is real
> or not?
Sure, I will explicitly mention that the kcontrol always exists, and if the path is not available, then this would show -1, -1
>
>> +
>> +USB Offload Playback Route Kcontrol
>> +-----------------------------------
>> +In order to allow for vendor specific implementations on audio offloading device
>> +selection, the SOC USB layer exposes the following:
>> +
>> +.. code-block:: rst
>> +
>> + int (*update_offload_route_info)(struct snd_soc_component *component,
>> + int card, int pcm, long *route);
>> +..
>> +
>> +These are specific for the **USB Offload Playback Route PCM#** kcontrol.
>> +
>> +When users issue get calls to the kcontrol, the registered SOC USB callbacks will
>> +execute the registered function calls to the DPCM BE DAI link.
>> +
>> +**Callback Registration:**
>> +
>> +.. code-block:: rst
>> +
>> + static int q6usb_component_probe(struct snd_soc_component *component)
>> + {
>> + ...
>> + usb = snd_soc_usb_allocate_port(component, 1, &data->priv);
>> + if (IS_ERR(usb))
>> + return -ENOMEM;
>> +
>> + usb->connection_status_cb = q6usb_alsa_connection_cb;
>> + usb->update_offload_route_info = q6usb_get_offload_dev;
>> +
>> + ret = snd_soc_usb_add_port(usb);
>> +..
>> +
>> +Existing USB Sound Kcontrol
>> +---------------------------
>> +With the introduction of USB offload support, the above USB offload kcontrol
>> +can be added to the pre existing list of kcontrols identified by the USB sound
> is this 'can be added' or 'will be added'? The latter seems more correct
> to me, I don't see anything optional or conditional in the description
> and the example below.
Will be added sounds better. Will change that.
Thanks
Wesley Cheng
>> +framework. These kcontrols are still the main controls that are used to
>> +modify characteristics pertaining to the USB audio device.
>> +
>> + ::
>> +
>> + Number of controls: 9
>> + ctl type num name value
>> + 0 INT 2 Capture Channel Map 0, 0 (range 0->36)
>> + 1 INT 2 Playback Channel Map 0, 0 (range 0->36)
>> + 2 BOOL 1 Headset Capture Switch On
>> + 3 INT 1 Headset Capture Volume 10 (range 0->13)
>> + 4 BOOL 1 Sidetone Playback Switch On
>> + 5 INT 1 Sidetone Playback Volume 4096 (range 0->8192)
>> + 6 BOOL 1 Headset Playback Switch On
>> + 7 INT 2 Headset Playback Volume 20, 20 (range 0->24)
>> + 8 INT 2 USB Offload Playback Route PCM#0 -1, -1 (range -1->255)
>> +
>> +Since USB audio device controls are handled over the USB control endpoint, use the
>> +existing mechanisms present in the USB mixer to set parameters, such as volume.
[Index of Archives]
[Pulseaudio]
[Linux Audio Users]
[ALSA Devel]
[Fedora Desktop]
[Fedora SELinux]
[Big List of Linux Books]
[Yosemite News]
[KDE Users]