요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
================
ASoC USB support
================
Overview
========
In order to leverage the existing USB sound device support in ALSA, the
ASoC USB APIs are introduced to allow the subsystems to exchange
configuration information.
One potential use case would be to support USB audio offloading, which is
an implementation that allows for an alternate power-optimized path in the audio
subsystem to handle the transfer of audio data over the USB bus. This would
let the main processor to stay in lower power modes for longer duration. The
following is an example design of how the ASoC and ALSA pieces can be connected
together to achieve this:
::
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 driver
==============
Structures
----------
``struct snd_soc_usb``
- ``list``: list head for SND SoC struct list
- ``component``: reference to ASoC component
- ``connection_status_cb``: callback to notify connection events
- ``update_offload_route_info``: callback to fetch selected USB sound card/PCM
device
- ``priv_data``: driver data
The snd_soc_usb structure can be referenced using the ASoC platform card
device, or a USB device (udev->dev). This is created by the ASoC BE DAI
link, and the USB sound entity will be able to pass information to the
ASoC BE DAI link using this structure.
``struct snd_soc_usb_device``
- ``card_idx``: sound card index associated with USB sound device
- ``chip_idx``: USB sound chip array index
- ``cpcm_idx``: capture pcm device indexes associated with the USB sound device
- ``ppcm_idx``: playback pcm device indexes associated with the USB sound device
- ``num_playback``: number of playback streams
- ``num_capture``: number of capture streams
- ``list``: list head for the USB sound device list
The struct snd_soc_usb_device is created by the USB sound offload driver.
This will carry basic parameters/limitations that will be used to
determine the possible offloading paths for this USB audio device.
Functions
---------
.. code-block:: rst
int snd_soc_usb_find_supported_format(int card_idx,
struct snd_pcm_hw_params *params, int direction)
..
- ``card_idx``: the index into the USB sound chip array.
- ``params``: Requested PCM parameters from the USB DPCM BE DAI link
- ``direction``: capture or playback
**snd_soc_usb_find_supported_format()** ensures that the requested audio profile
being requested by the external DSP is supported by the USB device.
Returns 0 on success, and -EOPNOTSUPP on failure.
.. code-block:: rst
int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev)
..
- ``usbdev``: the usb device that was discovered
- ``sdev``: capabilities of the device
**snd_soc_usb_connect()** notifies the ASoC USB DCPM BE DAI link of a USB
audio device detection. This can be utilized in the BE DAI
driver to keep track of available USB audio devices. This is intended
to be called by the USB offload driver residing in USB SND.
Returns 0 on success, negative error code on failure.
.. code-block:: rst
int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev)
..
- ``usbdev``: the usb device that was removed
- ``sdev``: capabilities to free
**snd_soc_usb_disconnect()** notifies the ASoC USB DCPM BE DAI link of a USB
audio device removal. This is intended to be called by the USB offload
driver that resides in USB SND.
.. code-block:: rst
void *snd_soc_usb_find_priv_data(struct device *usbdev)
..
- ``usbdev``: the usb device to reference to find private data
**snd_soc_usb_find_priv_data()** fetches the private data saved to the SoC USB
device.
Returns pointer to priv_data on success, NULL on failure.
.. code-block:: rst
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. Additionally, this will enable the
jack to notify of changes.
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, enum snd_soc_usb_kctl path,
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
- ``path``: kcontrol selector - pcm device or card index
- ``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.
.. code-block:: rst
struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component,
void *data);
..
- ``component``: DPCM BE DAI link component
- ``data``: private data
**snd_soc_usb_allocate_port()** allocates a SoC USB device and populates standard
parameters that is used for further operations.
Returns a pointer to struct soc_usb on success, negative on error.
.. code-block:: rst
void snd_soc_usb_free_port(struct snd_soc_usb *usb);
..
- ``usb``: SoC USB device to free
**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.
How to Register to SoC USB
--------------------------
The ASoC DPCM USB BE DAI link is the entity responsible for allocating and
registering the SoC USB device on the component bind. Likewise, it will
also be responsible for freeing the allocated resources. An example can
be shown below:
.. code-block:: rst
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 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
**PCM Devices**:
::
card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 0: MultiMedia1 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 1: MultiMedia2 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: Seri [Plantronics Blackwire 3225 Seri], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 2: C320M [Plantronics C320-M], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
**USB Sound Card** - card#1:
::
USB Offload Playback Card Route PCM#0 -1 (range -1->32)
USB Offload Playback PCM Route PCM#0 -1 (range -1->255)
**USB Sound Card** - card#2:
::
USB Offload Playback Card Route PCM#0 0 (range -1->32)
USB Offload Playback PCM Route PCM#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 kcontrols lists
the mapped offload card and pcm device indexes for the specific USB device:
``USB Offload Playback Card Route PCM#*``
``USB Offload Playback PCM Route PCM#*``
The kcontrol is indexed, because a USB audio device could potentially have
several PCM devices. The above kcontrols are defined as:
- ``USB Offload Playback Card Route PCM#`` **(R)**: Returns the ASoC platform sound
card index for a mapped offload path. The output **"0"** (card index) signifies
that there is an available offload path for the USB SND device through card#0.
If **"-1"** is seen, then no offload path is available for the USB SND device.
This kcontrol exists for each USB audio device that exists in the system, and
its expected to derive the current status of offload based on the output value
for the kcontrol along with the PCM route kcontrol.
- ``USB Offload Playback PCM Route PCM#`` **(R)**: Returns the ASoC platform sound
PCM device index for a mapped offload path. The output **"1"** (PCM device index)
signifies that there is an available offload path for the USB SND device through
PCM device#0. If **"-1"** is seen, then no offload path is available for the USB\
SND device. This kcontrol exists for each USB audio device that exists in the
system, and its expected to derive the current status of offload based on the
output value for this kcontrol, in addition to the card route kcontrol.
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, int direction,
enum snd_soc_usb_kctl path,
long *route)
..
These are specific for the **USB Offload Playback Card Route PCM#** and **USB
Offload PCM Route PCM#** kcontrols.
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
will be added to the pre existing list of kcontrols identified by the USB sound
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 1 USB Offload Playback Card Route PCM#0 0 (range -1->32)
9 INT 1 USB Offload Playback PCM Route PCM#0 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.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
개요와 USB 오디오 오프로딩 경로
1-48ALSA에 이미 존재하는 USB 사운드 장치 지원을 활용하기 위해 ASoC USB API가 도입되었다. 이 API를 통해 ALSA USB 사운드 하위 시스템과 ASoC 하위 시스템이 구성 정보를 서로 교환할 수 있다.
가능한 사용 사례 중 하나는 USB 오디오 오프로딩이다. 오디오 하위 시스템에 전력 효율을 높인 대체 경로를 마련해 USB 버스의 오디오 데이터 전송을 처리하는 구현이며, 주 프로세서가 더 오랫동안 저전력 모드에 머물 수 있게 한다.
원문의 예제 설계에서는 USB SND의 `card.c`, 오프로딩 드라이버, `endpoint.c`, XHCI HCD가 USB 쪽을 구성한다. ASoC 쪽에는 플랫폼 카드, BE·FE DAI link, SoC-USB 구성 요소, IPC와 audio DSP가 있으며, 양쪽은 USB 사운드 오프로딩 드라이버와 SoC-USB 사이에서 연결된다.
원문 ASCII 아키텍처를 책임 영역별로 정리한다.
ASCII 그림의 데이터·제어 연결을 깨끗한 흐름으로 다시 나타낸다.
USB 데이터 처리를 대체 오디오 경로로 옮겨 주 프로세서의 활성 시간을 줄인다.
================
ASoC USB support
================
Overview
========
In order to leverage the existing USB sound device support in ALSA, the
ASoC USB APIs are introduced to allow the subsystems to exchange
configuration information.
One potential use case would be to support USB audio offloading, which is
an implementation that allows for an alternate power-optimized path in the audio
subsystem to handle the transfer of audio data over the USB bus. This would
let the main processor to stay in lower power modes for longer duration. The
following is an example design of how the ASoC and ALSA pieces can be connected
together to achieve this:
::
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 드라이버 구조체
49-80`struct snd_soc_usb`는 SoC USB 포트와 ASoC 구성 요소의 연결 상태를 나타낸다. `list`는 SND SoC 구조체 목록의 list head이고, `component`는 ASoC component 참조이며, `connection_status_cb`는 연결 이벤트를 알리는 콜백이다. `update_offload_route_info`는 선택된 USB 사운드 카드와 PCM 장치를 가져오는 콜백이고, `priv_data`는 드라이버 전용 데이터다.
ASoC와 USB SND 사이의 포트 상태 및 콜백을 담는다.
`snd_soc_usb` 구조체는 ASoC 플랫폼 카드 장치나 USB 장치인 `udev->dev`를 사용해 참조할 수 있다. ASoC BE DAI link가 이 구조체를 만들며, USB 사운드 엔터티는 이 구조체를 통해 ASoC BE DAI link에 정보를 전달할 수 있다.
`struct snd_soc_usb_device`는 USB 사운드 오프로딩 드라이버가 만드는 장치 능력 설명이다. `card_idx`는 연결된 USB 사운드 장치의 카드 인덱스, `chip_idx`는 USB sound chip 배열 인덱스, `cpcm_idx`와 `ppcm_idx`는 각각 캡처와 재생 PCM 장치 인덱스다. `num_playback`과 `num_capture`는 재생·캡처 스트림 수이며, `list`는 USB 사운드 장치 목록의 list head다.
USB 오디오 장치의 기본 인덱스와 스트림 한계를 전달한다.
이 구조체가 전달하는 기본 매개변수와 제한은 해당 USB 오디오 장치에서 가능한 오프로딩 경로를 결정하는 데 사용된다.
BE DAI link가 포트를 만들고 USB offload driver가 장치 능력을 채운다.
SoC USB driver
==============
Structures
----------
``struct snd_soc_usb``
- ``list``: list head for SND SoC struct list
- ``component``: reference to ASoC component
- ``connection_status_cb``: callback to notify connection events
- ``update_offload_route_info``: callback to fetch selected USB sound card/PCM
device
- ``priv_data``: driver data
The snd_soc_usb structure can be referenced using the ASoC platform card
device, or a USB device (udev->dev). This is created by the ASoC BE DAI
link, and the USB sound entity will be able to pass information to the
ASoC BE DAI link using this structure.
``struct snd_soc_usb_device``
- ``card_idx``: sound card index associated with USB sound device
- ``chip_idx``: USB sound chip array index
- ``cpcm_idx``: capture pcm device indexes associated with the USB sound device
- ``ppcm_idx``: playback pcm device indexes associated with the USB sound device
- ``num_playback``: number of playback streams
- ``num_capture``: number of capture streams
- ``list``: list head for the USB sound device list
The struct snd_soc_usb_device is created by the USB sound offload driver.
This will carry basic parameters/limitations that will be used to
determine the possible offloading paths for this USB audio device.
SoC USB API 함수
81-220`snd_soc_usb_find_supported_format(int card_idx, struct snd_pcm_hw_params *params, int direction)`은 외부 DSP가 요청한 오디오 프로필을 USB 장치가 지원하는지 확인한다. `card_idx`는 USB sound chip 배열 인덱스, `params`는 USB DPCM BE DAI link가 요청한 PCM 매개변수, `direction`은 캡처 또는 재생 방향이다. 성공하면 0, 실패하면 `-EOPNOTSUPP`를 반환한다.
요청 형식과 USB 장치 능력을 대조한다.
`snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev)`는 USB 오디오 장치가 감지되었음을 ASoC USB DCPM BE DAI link에 알린다. `usbdev`는 발견된 USB 장치이고 `sdev`는 그 장치의 능력이다. BE DAI 드라이버는 이를 사용해 사용 가능한 USB 오디오 장치를 추적할 수 있다. USB SND 안의 USB offload driver가 호출하도록 설계되었으며, 성공하면 0, 실패하면 음수 오류 코드를 반환한다.
`snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev)`는 USB 오디오 장치가 제거되었음을 ASoC USB DCPM BE DAI link에 알린다. `usbdev`는 제거된 USB 장치이고 `sdev`는 해제할 장치 능력이다. 이 함수 역시 USB SND에 있는 USB offload driver가 호출한다.
USB offload driver가 감지·제거 이벤트를 ASoC BE DAI link로 전달한다.
`snd_soc_usb_find_priv_data(struct device *usbdev)`는 지정한 USB 장치로 SoC USB 장치를 찾아 그곳에 저장된 private data를 가져온다. `usbdev`가 검색 기준이며, 성공하면 `priv_data` 포인터를, 실패하면 `NULL`을 반환한다.
`snd_soc_usb_setup_offload_jack(struct snd_soc_component *component, struct snd_soc_jack *jack)`은 플랫폼 사운드 카드에 sound jack control을 추가하는 helper다. `component`는 jack을 추가할 ASoC component이고 `jack`은 채울 jack component다. USB 오디오 오프로딩을 지원하는 설계에서 일관된 이름을 사용하게 하며 jack 상태 변경 통지도 가능하게 한다. 성공하면 0, 실패하면 음수를 반환한다.
장치별 상태 조회와 일관된 jack 제어 등록을 제공한다.
`snd_soc_usb_update_offload_route(struct device *dev, int card, int pcm, int direction, enum snd_soc_usb_kctl path, long *route)`는 등록된 USB BE DAI link 콜백을 호출해 특정 USB 장치의 오디오 오프로딩에 매핑된 ASoC 장치 정보를 가져온다. `dev`는 매핑을 찾을 USB 장치, `card`와 `pcm`은 USB 사운드 카드와 PCM 장치 인덱스, `direction`은 조회 방향, `path`는 PCM 장치 또는 카드 인덱스를 선택하는 kcontrol selector다.
`route`는 오프로딩 경로의 사운드 카드와 PCM 인덱스를 그 순서로 담는 정수 두 개짜리 배열이다. kcontrol 출력 배열로 사용할 수 있으며 kcontrol을 읽을 때 값이 채워진다. 함수는 성공하면 0, 실패하면 음수를 반환한다.
USB 장치와 ASoC 오프로딩 경로 사이의 카드·PCM 매핑을 조회한다.
`snd_soc_usb_allocate_port(struct snd_soc_component *component, void *data)`는 SoC USB 장치를 할당하고 이후 연산에 쓰이는 표준 매개변수를 채운다. `component`는 DPCM BE DAI link component이고 `data`는 private data다. 성공하면 `struct soc_usb` 포인터를, 오류 시 음수 오류 값을 반환한다.
`snd_soc_usb_free_port(struct snd_soc_usb *usb)`는 지정한 SoC USB 장치를 해제한다. `snd_soc_usb_add_port(struct snd_soc_usb *usb)`는 할당된 장치를 SOC USB framework에 추가하며, 추가된 뒤에는 다른 연산이 이 장치를 참조할 수 있다.
`snd_soc_usb_remove_port(struct snd_soc_usb *usb)`는 SoC USB 장치를 framework에서 제거한다. 제거 뒤에는 어떤 SOC USB 연산도 해당 장치를 참조할 수 없다.
할당·등록과 제거·해제를 짝으로 수행한다.
원문에 명시된 성공과 실패 반환을 한눈에 정리한다.
Functions
---------
.. code-block:: rst
int snd_soc_usb_find_supported_format(int card_idx,
struct snd_pcm_hw_params *params, int direction)
..
- ``card_idx``: the index into the USB sound chip array.
- ``params``: Requested PCM parameters from the USB DPCM BE DAI link
- ``direction``: capture or playback
**snd_soc_usb_find_supported_format()** ensures that the requested audio profile
being requested by the external DSP is supported by the USB device.
Returns 0 on success, and -EOPNOTSUPP on failure.
.. code-block:: rst
int snd_soc_usb_connect(struct device *usbdev, struct snd_soc_usb_device *sdev)
..
- ``usbdev``: the usb device that was discovered
- ``sdev``: capabilities of the device
**snd_soc_usb_connect()** notifies the ASoC USB DCPM BE DAI link of a USB
audio device detection. This can be utilized in the BE DAI
driver to keep track of available USB audio devices. This is intended
to be called by the USB offload driver residing in USB SND.
Returns 0 on success, negative error code on failure.
.. code-block:: rst
int snd_soc_usb_disconnect(struct device *usbdev, struct snd_soc_usb_device *sdev)
..
- ``usbdev``: the usb device that was removed
- ``sdev``: capabilities to free
**snd_soc_usb_disconnect()** notifies the ASoC USB DCPM BE DAI link of a USB
audio device removal. This is intended to be called by the USB offload
driver that resides in USB SND.
.. code-block:: rst
void *snd_soc_usb_find_priv_data(struct device *usbdev)
..
- ``usbdev``: the usb device to reference to find private data
**snd_soc_usb_find_priv_data()** fetches the private data saved to the SoC USB
device.
Returns pointer to priv_data on success, NULL on failure.
.. code-block:: rst
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. Additionally, this will enable the
jack to notify of changes.
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, enum snd_soc_usb_kctl path,
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
- ``path``: kcontrol selector - pcm device or card index
- ``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.
.. code-block:: rst
struct snd_soc_usb *snd_soc_usb_allocate_port(struct snd_soc_component *component,
void *data);
..
- ``component``: DPCM BE DAI link component
- ``data``: private data
**snd_soc_usb_allocate_port()** allocates a SoC USB device and populates standard
parameters that is used for further operations.
Returns a pointer to struct soc_usb on success, negative on error.
.. code-block:: rst
void snd_soc_usb_free_port(struct snd_soc_usb *usb);
..
- ``usb``: SoC USB device to free
**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.
SoC USB 등록과 해제
221-266ASoC DPCM USB BE DAI link는 component bind 때 SoC USB 장치를 할당하고 등록할 책임이 있다. 같은 link가 할당한 자원을 해제하는 책임도 진다.
예제의 `q6usb_component_probe()`는 `snd_soc_usb_allocate_port()`로 포트를 할당하고 실패 시 `-ENOMEM`을 반환한다. 이어 `connection_status_cb`에 `q6usb_alsa_connection_cb`를 지정하고 `snd_soc_usb_add_port()`로 포트를 등록한다. 등록 실패 시 오류를 기록하고 `free_usb` 정리 경로로 이동한다.
`q6usb_component_remove()`는 `snd_soc_usb_remove_port(data->usb)`로 framework에서 포트를 제거한 뒤 `snd_soc_usb_free_port(data->usb)`로 메모리를 해제한다. `q6usb_dai_component`는 이 probe와 remove callback, 이름 `q6usb-dai-component`를 `struct snd_soc_component_driver`에 연결한다.
BE DAI component가 포트를 만들고 콜백을 채운 뒤 framework에 공개한다.
참조 가능 상태를 먼저 제거한 다음 자원을 해제한다.
BE DAI link는 SoC USB 장치를 할당하는 호출에 vendor-specific 정보를 함께 전달할 수 있다. 그러면 USB SND 내부의 USB offload driver가 BE DAI link의 매개변수나 설정에 접근할 수 있다.
BE DAI link가 bind와 remove에서 수행할 작업을 짝지어 보여 준다.
How to Register to SoC USB
--------------------------
The ASoC DPCM USB BE DAI link is the entity responsible for allocating and
registering the SoC USB device on the component bind. Likewise, it will
also be responsible for freeing the allocated resources. An example can
be shown below:
.. code-block:: rst
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 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 오디오 장치 연결과 재발견 흐름
267-336USB 장치는 언제든 USB 포트에 hotplug될 수 있다. 따라서 BE DAI link는 실제 USB 포트에 오디오 인터페이스를 가진 USB 장치가 연결되어 있는지 현재 상태를 알아야 한다. `connection_status_cb()`는 상태 변화를 BE DAI link에 알리는 데 사용된다.
USB SND 인터페이스 bind 또는 remove 이벤트가 생길 때 `snd_soc_usb_connect()` 또는 `snd_soc_usb_disconnect()`를 호출한다. 예제에서 `qc_usb_audio_offload_probe()`는 발견한 장치와 능력을 connect 함수에 전달하고, `qc_usb_audio_offload_disconnect()`는 제거되는 장치와 `sdev`를 disconnect 함수에 전달한다.
USB SND의 bind·remove 이벤트가 ASoC 포트 상태로 전파된다.
드라이버나 장치가 항상 존재한다고 보장할 수 없는 상황을 처리하기 위해 USB SND는 `snd_usb_rediscover_devices()`를 제공한다. 이 함수는 이미 식별된 모든 USB 오디오 인터페이스의 connect 이벤트를 다시 보낸다.
첫 번째 누락 시나리오에서는 `usb_audio_probe()`가 USB 오디오 스트림을 할당해 `usb_chip[]`에 저장하고 USB SND의 offload driver로 connect 이벤트를 전달하지만, USB BE DAI link가 아직 준비되지 않아 `snd_soc_usb_connect()`가 종료된다. 나중에 BE DAI link component가 probe되어 SoC USB 포트를 할당해도 앞선 connect 이벤트는 이미 놓친 상태다.
장치가 먼저 발견되면 최초 connect 통지를 받을 대상이 아직 없다.
이 누락을 막기 위해 SoC USB 장치를 등록할 때 `snd_usb_rediscover_devices()`를 실행한다. BE DAI link가 probe되고 포트가 할당·추가되면 rediscover 함수가 `usb_chip[]`를 순회하고 `NULL`이 아닌 각 항목에 대해 `connection_status_cb()`를 호출한다.
새로 준비된 BE DAI link에 기존 USB 장치를 다시 통지한다.
USB SND는 준비되어 있지만 USB offload driver가 unbind된 경우에는 module init 중 `snd_usb_rediscover_devices()`가 호출된다. `usb_audio_probe()`가 스트림을 저장하고 이벤트를 전달하려 해도 offload driver가 준비되지 않았고, BE DAI link probe에서도 driver가 없어 connect 이벤트를 받을 수 없다. 이후 USB offload driver가 probe되면 `qc_usb_audio_offload_init()`이 rediscover 함수를 호출해 이미 존재하는 장치를 통지한다.
offload driver가 나중에 준비되어도 기존 USB 장치로 오프로딩 경로를 활성화한다.
장치·BE DAI·offload driver의 초기화 순서가 달라도 상태를 복구한다.
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 오프로딩 kcontrol 개요
337-345응용 프로그램은 여러 kcontrol을 사용해 USB 오디오 오프로딩에 적합한 사운드 장치를 선택할 수 있다. SoC USB는 설계별 구현이 올바른 인덱스를 응용 프로그램에 반환하도록 `get_offload_dev()` 콜백을 노출한다.
응용 프로그램의 조회가 설계별 콜백을 거쳐 실제 ASoC 경로 인덱스로 변환된다.
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.
오프로딩 kcontrol 구현 예제
346-422예제 시스템에는 ASoC 플랫폼 카드 하나와 USB 사운드 장치 두 개가 있다. 카드 0은 `SM8250MTPWCD938`, 카드 1은 `Plantronics Blackwire 3225 Seri`, 카드 2는 `Plantronics C320-M`이다. PCM 목록에는 플랫폼 카드의 `MultiMedia1` 장치 0과 `MultiMedia2` 장치 1, 각 USB 카드의 `USB Audio` 장치 0이 표시된다.
원문 출력에서 오프로딩 매핑에 참여하는 카드와 PCM을 추린다.
USB 사운드 카드 1의 `USB Offload Playback Card Route PCM#0`과 `USB Offload Playback PCM Route PCM#0` 값은 모두 `-1`이므로 사용 가능한 오프로딩 경로가 없다. USB 사운드 카드 2의 같은 값은 각각 `0`과 `1`이므로 ASoC 플랫폼 카드 0과 PCM 인덱스 1에 매핑된다.
각 USB 장치의 card route와 PCM route 값을 함께 해석한다.
각 USB 오디오 장치에서 읽는 `USB Offload Playback Card Route PCM#*`와 `USB Offload Playback PCM Route PCM#*` kcontrol은 특정 USB 장치에 매핑된 offload card와 PCM 장치 인덱스를 제공한다. USB 오디오 장치 하나가 여러 PCM 장치를 가질 수 있으므로 kcontrol 이름의 `#` 부분은 PCM별 인덱스다.
`USB Offload Playback Card Route PCM#` 읽기 전용 제어는 매핑된 오프로딩 경로의 ASoC 플랫폼 사운드 카드 인덱스를 반환한다. 값 `0`은 USB SND 장치가 card 0을 통해 사용할 수 있는 오프로딩 경로가 있음을 뜻하고, `-1`은 경로가 없음을 뜻한다. 시스템의 각 USB 오디오 장치마다 이 제어가 존재하며 PCM route 제어와 함께 읽어 현재 오프로딩 상태를 판단한다.
`USB Offload Playback PCM Route PCM#` 읽기 전용 제어는 매핑된 오프로딩 경로의 ASoC 플랫폼 PCM 장치 인덱스를 반환한다. 원문은 값 `1`이 PCM device 0을 통한 경로를 뜻한다고 설명하며, `-1`은 경로가 없음을 뜻한다. 이 제어도 각 USB 오디오 장치마다 존재하며 card route 제어와 함께 해석한다.
카드와 PCM 값이 모두 유효해야 실행 가능한 오프로딩 경로가 된다.
두 kcontrol에서 공통으로 사용하는 유효성 규칙이다.
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
**PCM Devices**:
::
card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 0: MultiMedia1 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: SM8250MTPWCD938 [SM8250-MTP-WCD9380-WSA8810-VA-D], device 1: MultiMedia2 (*) []
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: Seri [Plantronics Blackwire 3225 Seri], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 2: C320M [Plantronics C320-M], device 0: USB Audio [USB Audio]
Subdevices: 1/1
Subdevice #0: subdevice #0
**USB Sound Card** - card#1:
::
USB Offload Playback Card Route PCM#0 -1 (range -1->32)
USB Offload Playback PCM Route PCM#0 -1 (range -1->255)
**USB Sound Card** - card#2:
::
USB Offload Playback Card Route PCM#0 0 (range -1->32)
USB Offload Playback PCM Route PCM#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 kcontrols lists
the mapped offload card and pcm device indexes for the specific USB device:
``USB Offload Playback Card Route PCM#*``
``USB Offload Playback PCM Route PCM#*``
The kcontrol is indexed, because a USB audio device could potentially have
several PCM devices. The above kcontrols are defined as:
- ``USB Offload Playback Card Route PCM#`` **(R)**: Returns the ASoC platform sound
card index for a mapped offload path. The output **"0"** (card index) signifies
that there is an available offload path for the USB SND device through card#0.
If **"-1"** is seen, then no offload path is available for the USB SND device.
This kcontrol exists for each USB audio device that exists in the system, and
its expected to derive the current status of offload based on the output value
for the kcontrol along with the PCM route kcontrol.
- ``USB Offload Playback PCM Route PCM#`` **(R)**: Returns the ASoC platform sound
PCM device index for a mapped offload path. The output **"1"** (PCM device index)
signifies that there is an available offload path for the USB SND device through
PCM device#0. If **"-1"** is seen, then no offload path is available for the USB\
SND device. This kcontrol exists for each USB audio device that exists in the
system, and its expected to derive the current status of offload based on the
output value for this kcontrol, in addition to the card route kcontrol.
USB Offload Playback Route 콜백
423-458오디오 오프로딩 장치 선택을 vendor-specific 방식으로 구현할 수 있도록 SoC USB 계층은 `update_offload_route_info` 콜백을 노출한다. 콜백은 `component`, USB `card`, USB `pcm`, 스트림 `direction`, 카드 또는 PCM 경로를 고르는 `path`, 결과를 넣을 `route`를 받는다.
이 콜백은 `USB Offload Playback Card Route PCM#`과 `USB Offload PCM Route PCM#` kcontrol 전용이다. 사용자가 kcontrol에 get 요청을 보내면 등록된 SoC USB callback이 DPCM BE DAI link의 등록 함수를 실행한다.
등록 예제에서 `q6usb_component_probe()`는 `snd_soc_usb_allocate_port()`로 포트를 할당한 뒤 `connection_status_cb`에 `q6usb_alsa_connection_cb`를, `update_offload_route_info`에 `q6usb_get_offload_dev`를 지정하고 `snd_soc_usb_add_port()`를 호출한다.
DPCM BE DAI link가 vendor-specific 매핑을 계산하는 데 필요한 입력과 출력이다.
응용 프로그램의 읽기 요청이 BE DAI link의 설계별 함수로 전달된다.
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, int direction,
enum snd_soc_usb_kctl path,
long *route)
..
These are specific for the **USB Offload Playback Card Route PCM#** and **USB
Offload PCM Route PCM#** kcontrols.
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);
..
기존 USB Sound kcontrol과의 공존
459-482USB 오프로딩 지원이 도입되면 앞에서 설명한 USB offload kcontrol이 USB sound framework가 이미 식별한 kcontrol 목록에 추가된다. 기존 제어들은 여전히 음량처럼 USB 오디오 장치의 특성을 바꾸는 주요 수단이다.
예제 목록에는 캡처·재생 채널 맵, 헤드셋 캡처 스위치와 음량, sidetone 재생 스위치와 음량, 헤드셋 재생 스위치와 음량이 있다. 여기에 `USB Offload Playback Card Route PCM#0` 값 0과 `USB Offload Playback PCM Route PCM#0` 값 1이 추가되어 총 목록에 오프로딩 매핑이 함께 표시된다.
원문 예제의 제어를 기능군별로 정리한다.
USB 오디오 장치 제어는 USB control endpoint를 통해 처리되므로 음량 같은 매개변수를 설정할 때는 USB mixer에 이미 존재하는 메커니즘을 사용한다.
장치 특성 변경은 기존 USB mixer 경로를 유지하고 오프로딩 kcontrol은 경로 매핑을 제공한다.
Existing USB Sound Kcontrol
---------------------------
With the introduction of USB offload support, the above USB offload kcontrol
will be added to the pre existing list of kcontrols identified by the USB sound
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 1 USB Offload Playback Card Route PCM#0 0 (range -1->32)
9 INT 1 USB Offload Playback PCM Route PCM#0 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.
요약·해설
usb.rst:1-482ALSA USB SND와 ASoC가 USB 오디오 오프로딩 구성 정보를 교환하는 구조를 설명합니다. `snd_soc_usb`·`snd_soc_usb_device`, 연결·형식·포트·route API, BE DAI 등록과 hotplug 재발견, card/PCM route kcontrol을 원문 코드와 482개 줄 좌표를 보존해 정리합니다. 원문 예제의 route 값 설명에는 PCM 인덱스 표기상 불일치가 있어 번역에서는 문장을 보존하고 표에서는 실제 출력값 1을 그대로 제시합니다.