요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. _usb-urb:
USB Request Block (URB)
~~~~~~~~~~~~~~~~~~~~~~~
:Revised: 2000-Dec-05
:Again: 2002-Jul-06
:Again: 2005-Sep-19
:Again: 2017-Mar-29
.. note::
The USB subsystem now has a substantial section at :ref:`usb-hostside-api`
section, generated from the current source code.
This particular documentation file isn't complete and may not be
updated to the last version; don't rely on it except for a quick
overview.
Basic concept or 'What is an URB?'
==================================
The basic idea of the new driver is message passing, the message itself is
called USB Request Block, or URB for short.
- An URB consists of all relevant information to execute any USB transaction
and deliver the data and status back.
- Execution of an URB is inherently an asynchronous operation, i.e. the
:c:func:`usb_submit_urb` call returns immediately after it has successfully
queued the requested action.
- Transfers for one URB can be canceled with :c:func:`usb_unlink_urb`
at any time.
- Each URB has a completion handler, which is called after the action
has been successfully completed or canceled. The URB also contains a
context-pointer for passing information to the completion handler.
- Each endpoint for a device logically supports a queue of requests.
You can fill that queue, so that the USB hardware can still transfer
data to an endpoint while your driver handles completion of another.
This maximizes use of USB bandwidth, and supports seamless streaming
of data to (or from) devices when using periodic transfer modes.
The URB structure
=================
Some of the fields in struct urb are::
struct urb
{
// (IN) device and pipe specify the endpoint queue
struct usb_device *dev; // pointer to associated USB device
unsigned int pipe; // endpoint information
unsigned int transfer_flags; // URB_ISO_ASAP, URB_SHORT_NOT_OK, etc.
// (IN) all urbs need completion routines
void *context; // context for completion routine
usb_complete_t complete; // pointer to completion routine
// (OUT) status after each completion
int status; // returned status
// (IN) buffer used for data transfers
void *transfer_buffer; // associated data buffer
u32 transfer_buffer_length; // data buffer length
int number_of_packets; // size of iso_frame_desc
// (OUT) sometimes only part of CTRL/BULK/INTR transfer_buffer is used
u32 actual_length; // actual data buffer length
// (IN) setup stage for CTRL (pass a struct usb_ctrlrequest)
unsigned char *setup_packet; // setup packet (control only)
// Only for PERIODIC transfers (ISO, INTERRUPT)
// (IN/OUT) start_frame is set unless URB_ISO_ASAP isn't set
int start_frame; // start frame
int interval; // polling interval
// ISO only: packets are only "best effort"; each can have errors
int error_count; // number of errors
struct usb_iso_packet_descriptor iso_frame_desc[0];
};
Your driver must create the "pipe" value using values from the appropriate
endpoint descriptor in an interface that it's claimed.
How to get an URB?
==================
URBs are allocated by calling :c:func:`usb_alloc_urb`::
struct urb *usb_alloc_urb(int isoframes, int mem_flags)
Return value is a pointer to the allocated URB, 0 if allocation failed.
The parameter isoframes specifies the number of isochronous transfer frames
you want to schedule. For CTRL/BULK/INT, use 0. The mem_flags parameter
holds standard memory allocation flags, letting you control (among other
things) whether the underlying code may block or not.
To free an URB, use :c:func:`usb_free_urb`::
void usb_free_urb(struct urb *urb)
You may free an urb that you've submitted, but which hasn't yet been
returned to you in a completion callback. It will automatically be
deallocated when it is no longer in use.
What has to be filled in?
=========================
Depending on the type of transaction, there are some inline functions
defined in ``linux/usb.h`` to simplify the initialization, such as
:c:func:`usb_fill_control_urb`, :c:func:`usb_fill_bulk_urb` and
:c:func:`usb_fill_int_urb`. In general, they need the usb device pointer,
the pipe (usual format from usb.h), the transfer buffer, the desired transfer
length, the completion handler, and its context. Take a look at the some
existing drivers to see how they're used.
Flags:
- For ISO there are two startup behaviors: Specified start_frame or ASAP.
- For ASAP set ``URB_ISO_ASAP`` in transfer_flags.
If short packets should NOT be tolerated, set ``URB_SHORT_NOT_OK`` in
transfer_flags.
How to submit an URB?
=====================
Just call :c:func:`usb_submit_urb`::
int usb_submit_urb(struct urb *urb, int mem_flags)
The ``mem_flags`` parameter, such as ``GFP_ATOMIC``, controls memory
allocation, such as whether the lower levels may block when memory is tight.
It immediately returns, either with status 0 (request queued) or some
error code, usually caused by the following:
- Out of memory (``-ENOMEM``)
- Unplugged device (``-ENODEV``)
- Stalled endpoint (``-EPIPE``)
- Too many queued ISO transfers (``-EAGAIN``)
- Too many requested ISO frames (``-EFBIG``)
- Invalid INT interval (``-EINVAL``)
- More than one packet for INT (``-EINVAL``)
After submission, ``urb->status`` is ``-EINPROGRESS``; however, you should
never look at that value except in your completion callback.
For isochronous endpoints, your completion handlers should (re)submit
URBs to the same endpoint with the ``URB_ISO_ASAP`` flag, using
multi-buffering, to get seamless ISO streaming.
How to cancel an already running URB?
=====================================
There are two ways to cancel an URB you've submitted but which hasn't
been returned to your driver yet. For an asynchronous cancel, call
:c:func:`usb_unlink_urb`::
int usb_unlink_urb(struct urb *urb)
It removes the urb from the internal list and frees all allocated
HW descriptors. The status is changed to reflect unlinking. Note
that the URB will not normally have finished when :c:func:`usb_unlink_urb`
returns; you must still wait for the completion handler to be called.
To cancel an URB synchronously, call :c:func:`usb_kill_urb`::
void usb_kill_urb(struct urb *urb)
It does everything :c:func:`usb_unlink_urb` does, and in addition it waits
until after the URB has been returned and the completion handler
has finished. It also marks the URB as temporarily unusable, so
that if the completion handler or anyone else tries to resubmit it
they will get a ``-EPERM`` error. Thus you can be sure that when
:c:func:`usb_kill_urb` returns, the URB is totally idle.
There is a lifetime issue to consider. An URB may complete at any
time, and the completion handler may free the URB. If this happens
while :c:func:`usb_unlink_urb` or :c:func:`usb_kill_urb` is running, it will
cause a memory-access violation. The driver is responsible for avoiding this,
which often means some sort of lock will be needed to prevent the URB
from being deallocated while it is still in use.
On the other hand, since usb_unlink_urb may end up calling the
completion handler, the handler must not take any lock that is held
when usb_unlink_urb is invoked. The general solution to this problem
is to increment the URB's reference count while holding the lock, then
drop the lock and call usb_unlink_urb or usb_kill_urb, and then
decrement the URB's reference count. You increment the reference
count by calling :c:func`usb_get_urb`::
struct urb *usb_get_urb(struct urb *urb)
(ignore the return value; it is the same as the argument) and
decrement the reference count by calling :c:func:`usb_free_urb`. Of course,
none of this is necessary if there's no danger of the URB being freed
by the completion handler.
What about the completion handler?
==================================
The handler is of the following type::
typedef void (*usb_complete_t)(struct urb *)
I.e., it gets the URB that caused the completion call. In the completion
handler, you should have a look at ``urb->status`` to detect any USB errors.
Since the context parameter is included in the URB, you can pass
information to the completion handler.
Note that even when an error (or unlink) is reported, data may have been
transferred. That's because USB transfers are packetized; it might take
sixteen packets to transfer your 1KByte buffer, and ten of them might
have transferred successfully before the completion was called.
.. warning::
NEVER SLEEP IN A COMPLETION HANDLER.
These are often called in atomic context.
In the current kernel, completion handlers run with local interrupts
disabled, but in the future this will be changed, so don't assume that
local IRQs are always disabled inside completion handlers.
How to do isochronous (ISO) transfers?
======================================
Besides the fields present on a bulk transfer, for ISO, you also
have to set ``urb->interval`` to say how often to make transfers; it's
often one per frame (which is once every microframe for highspeed devices).
The actual interval used will be a power of two that's no bigger than what
you specify. You can use the :c:func:`usb_fill_int_urb` macro to fill
most ISO transfer fields.
For ISO transfers you also have to fill a :c:type:`usb_iso_packet_descriptor`
structure, allocated at the end of the URB by :c:func:`usb_alloc_urb`, for
each packet you want to schedule.
The :c:func:`usb_submit_urb` call modifies ``urb->interval`` to the implemented
interval value that is less than or equal to the requested interval value. If
``URB_ISO_ASAP`` scheduling is used, ``urb->start_frame`` is also updated.
For each entry you have to specify the data offset for this frame (base is
transfer_buffer), and the length you want to write/expect to read.
After completion, actual_length contains the actual transferred length and
status contains the resulting status for the ISO transfer for this frame.
It is allowed to specify a varying length from frame to frame (e.g. for
audio synchronisation/adaptive transfer rates). You can also use the length
0 to omit one or more frames (striping).
For scheduling you can choose your own start frame or ``URB_ISO_ASAP``. As
explained earlier, if you always keep at least one URB queued and your
completion keeps (re)submitting a later URB, you'll get smooth ISO streaming
(if usb bandwidth utilization allows).
If you specify your own start frame, make sure it's several frames in advance
of the current frame. You might want this model if you're synchronizing
ISO data with some other event stream.
How to start interrupt (INT) transfers?
=======================================
Interrupt transfers, like isochronous transfers, are periodic, and happen
in intervals that are powers of two (1, 2, 4 etc) units. Units are frames
for full and low speed devices, and microframes for high speed ones.
You can use the :c:func:`usb_fill_int_urb` macro to fill INT transfer fields.
The :c:func:`usb_submit_urb` call modifies ``urb->interval`` to the implemented
interval value that is less than or equal to the requested interval value.
In Linux 2.6, unlike earlier versions, interrupt URBs are not automagically
restarted when they complete. They end when the completion handler is
called, just like other URBs. If you want an interrupt URB to be restarted,
your completion handler must resubmit it.
s
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
URB 기본 개념과 비동기 queue
1-45이 문서는 여러 차례 개정된 URB 개요이지만 완전하지 않고 최신 version으로 갱신되지 않았을 수 있습니다. 현재 source code에서 생성되는 `usb-hostside-api`가 상세 기준이며, 이 문서는 빠른 개요로만 사용해야 합니다.
USB driver의 기본 model은 message passing이고 그 message를 USB Request Block, 줄여서 URB라고 합니다. URB 하나에는 USB transaction을 실행하고 data와 status를 driver에 돌려주는 데 필요한 정보가 모두 들어 있습니다.
URB 실행은 본질적으로 asynchronous합니다. `usb_submit_urb()`는 요청 동작을 queue에 성공적으로 넣은 직후 반환하며 transfer 완료를 기다리지 않습니다.
제출한 URB는 언제든 `usb_unlink_urb()`로 cancel할 수 있습니다. 동작이 성공적으로 끝나거나 cancel되면 각 URB의 completion handler가 호출되고, URB의 context pointer로 handler에 추가 정보를 전달할 수 있습니다.
Device의 각 endpoint는 논리적으로 request queue를 지원합니다. Driver가 queue를 채워 두면 한 URB의 completion을 처리하는 동안 hardware가 다른 URB를 계속 전송할 수 있어 USB bandwidth 사용률이 높아지고 periodic transfer에서 끊김 없는 streaming이 가능합니다.
Submit은 queueing만 보장하고 실제 transfer 결과는 completion callback으로 전달됩니다.
.. _usb-urb:
USB Request Block (URB)
~~~~~~~~~~~~~~~~~~~~~~~
:Revised: 2000-Dec-05
:Again: 2002-Jul-06
:Again: 2005-Sep-19
:Again: 2017-Mar-29
.. note::
The USB subsystem now has a substantial section at :ref:`usb-hostside-api`
section, generated from the current source code.
This particular documentation file isn't complete and may not be
updated to the last version; don't rely on it except for a quick
overview.
Basic concept or 'What is an URB?'
==================================
The basic idea of the new driver is message passing, the message itself is
called USB Request Block, or URB for short.
- An URB consists of all relevant information to execute any USB transaction
and deliver the data and status back.
- Execution of an URB is inherently an asynchronous operation, i.e. the
:c:func:`usb_submit_urb` call returns immediately after it has successfully
queued the requested action.
- Transfers for one URB can be canceled with :c:func:`usb_unlink_urb`
at any time.
- Each URB has a completion handler, which is called after the action
has been successfully completed or canceled. The URB also contains a
context-pointer for passing information to the completion handler.
- Each endpoint for a device logically supports a queue of requests.
You can fill that queue, so that the USB hardware can still transfer
data to an endpoint while your driver handles completion of another.
This maximizes use of USB bandwidth, and supports seamless streaming
of data to (or from) devices when using periodic transfer modes.
`struct urb` 핵심 field
46-91`struct urb`의 `dev`와 `pipe`는 endpoint queue를 지정합니다. `dev`는 연관된 `struct usb_device`이고 `pipe`에는 endpoint 정보가 들어갑니다. Driver는 자신이 claim한 interface의 올바른 endpoint descriptor로 pipe 값을 만들어야 합니다.
`transfer_flags`에는 `URB_ISO_ASAP`, `URB_SHORT_NOT_OK` 같은 동작 flag가 들어갑니다. 모든 URB에는 completion routine용 `context`와 `complete`가 필요하며, 완료 뒤 `status`에 결과가 기록됩니다.
Data transfer에는 `transfer_buffer`와 `transfer_buffer_length`를 사용합니다. ISO packet descriptor 배열 크기는 `number_of_packets`이며, CTRL·BULK·INTR transfer가 buffer 일부만 사용했다면 `actual_length`가 실제 길이를 알려 줍니다.
Control transfer의 setup stage는 `setup_packet`에 `struct usb_ctrlrequest`를 전달합니다. Periodic ISO·INT transfer는 `start_frame`과 polling `interval`을 사용합니다.
ISO transfer는 packet별 best-effort 결과를 가지므로 `error_count`와 `iso_frame_desc[]`가 필요합니다. 각 packet descriptor가 개별 status와 길이를 보존합니다.
The URB structure
=================
Some of the fields in struct urb are::
struct urb
{
// (IN) device and pipe specify the endpoint queue
struct usb_device *dev; // pointer to associated USB device
unsigned int pipe; // endpoint information
unsigned int transfer_flags; // URB_ISO_ASAP, URB_SHORT_NOT_OK, etc.
// (IN) all urbs need completion routines
void *context; // context for completion routine
usb_complete_t complete; // pointer to completion routine
// (OUT) status after each completion
int status; // returned status
// (IN) buffer used for data transfers
void *transfer_buffer; // associated data buffer
u32 transfer_buffer_length; // data buffer length
int number_of_packets; // size of iso_frame_desc
// (OUT) sometimes only part of CTRL/BULK/INTR transfer_buffer is used
u32 actual_length; // actual data buffer length
// (IN) setup stage for CTRL (pass a struct usb_ctrlrequest)
unsigned char *setup_packet; // setup packet (control only)
// Only for PERIODIC transfers (ISO, INTERRUPT)
// (IN/OUT) start_frame is set unless URB_ISO_ASAP isn't set
int start_frame; // start frame
int interval; // polling interval
// ISO only: packets are only "best effort"; each can have errors
int error_count; // number of errors
struct usb_iso_packet_descriptor iso_frame_desc[0];
};
Your driver must create the "pipe" value using values from the appropriate
endpoint descriptor in an interface that it's claimed.
URB allocation과 reference lifecycle
92-113URB는 `usb_alloc_urb(int isoframes, int mem_flags)`로 할당합니다. 성공하면 URB pointer를 반환하고 allocation에 실패하면 `0`을 반환합니다.
`isoframes`는 schedule할 isochronous transfer frame 수입니다. CTRL, BULK, INT transfer에는 `0`을 사용합니다. `mem_flags`는 표준 memory allocation flag이며 내부 코드가 block할 수 있는지 등을 제어합니다.
URB 해제에는 `usb_free_urb(struct urb *urb)`를 사용합니다. 이미 submit했지만 completion callback으로 아직 반환되지 않은 URB에도 free를 호출할 수 있으며, 실제 object는 더 이상 사용되지 않을 때 자동으로 deallocate됩니다.
할당 reference와 submit 중 사용 reference가 끝난 뒤 object가 최종 해제됩니다.
How to get an URB?
==================
URBs are allocated by calling :c:func:`usb_alloc_urb`::
struct urb *usb_alloc_urb(int isoframes, int mem_flags)
Return value is a pointer to the allocated URB, 0 if allocation failed.
The parameter isoframes specifies the number of isochronous transfer frames
you want to schedule. For CTRL/BULK/INT, use 0. The mem_flags parameter
holds standard memory allocation flags, letting you control (among other
things) whether the underlying code may block or not.
To free an URB, use :c:func:`usb_free_urb`::
void usb_free_urb(struct urb *urb)
You may free an urb that you've submitted, but which hasn't yet been
returned to you in a completion callback. It will automatically be
deallocated when it is no longer in use.
Transfer type별 URB 초기화
114-133Transaction type별 초기화를 단순화하기 위해 `linux/usb.h`는 `usb_fill_control_urb`, `usb_fill_bulk_urb`, `usb_fill_int_urb` inline helper를 제공합니다.
일반적으로 helper에는 USB device pointer, `usb.h` 형식의 pipe, transfer buffer, 요청 길이, completion handler와 context를 전달합니다. 실제 사용 pattern은 기존 driver 구현을 함께 참고해야 합니다.
ISO transfer 시작 방식은 지정한 `start_frame` 또는 가능한 한 빨리 시작하는 ASAP 두 가지입니다. ASAP scheduling에는 `transfer_flags`에 `URB_ISO_ASAP`을 설정합니다.
Short packet을 허용하지 않아야 한다면 `transfer_flags`에 `URB_SHORT_NOT_OK`를 설정합니다.
What has to be filled in?
=========================
Depending on the type of transaction, there are some inline functions
defined in ``linux/usb.h`` to simplify the initialization, such as
:c:func:`usb_fill_control_urb`, :c:func:`usb_fill_bulk_urb` and
:c:func:`usb_fill_int_urb`. In general, they need the usb device pointer,
the pipe (usual format from usb.h), the transfer buffer, the desired transfer
length, the completion handler, and its context. Take a look at the some
existing drivers to see how they're used.
Flags:
- For ISO there are two startup behaviors: Specified start_frame or ASAP.
- For ASAP set ``URB_ISO_ASAP`` in transfer_flags.
If short packets should NOT be tolerated, set ``URB_SHORT_NOT_OK`` in
transfer_flags.
URB submit 결과와 ISO queue 유지
134-162URB 제출은 `usb_submit_urb(struct urb *urb, int mem_flags)`를 호출합니다. `GFP_ATOMIC` 같은 `mem_flags`는 memory가 부족할 때 lower layer가 block할 수 있는지 등 allocation 동작을 결정합니다.
함수는 즉시 반환하며 `0`이면 request가 queue에 들어간 것입니다. 대표 오류는 memory 부족 `-ENOMEM`, device unplug `-ENODEV`, stalled endpoint `-EPIPE`, ISO queue 과다 `-EAGAIN`, ISO frame 요청 과다 `-EFBIG`, 잘못된 INT interval 또는 INT packet 수 `-EINVAL`입니다.
Submit 이후 `urb->status`는 `-EINPROGRESS`가 되지만 completion callback 밖에서는 이 값을 읽어서는 안 됩니다.
Isochronous endpoint에서 끊김 없는 streaming을 얻으려면 completion handler가 multi-buffering을 사용해 같은 endpoint로 `URB_ISO_ASAP` URB를 계속 재제출해야 합니다.
How to submit an URB?
=====================
Just call :c:func:`usb_submit_urb`::
int usb_submit_urb(struct urb *urb, int mem_flags)
The ``mem_flags`` parameter, such as ``GFP_ATOMIC``, controls memory
allocation, such as whether the lower levels may block when memory is tight.
It immediately returns, either with status 0 (request queued) or some
error code, usually caused by the following:
- Out of memory (``-ENOMEM``)
- Unplugged device (``-ENODEV``)
- Stalled endpoint (``-EPIPE``)
- Too many queued ISO transfers (``-EAGAIN``)
- Too many requested ISO frames (``-EFBIG``)
- Invalid INT interval (``-EINVAL``)
- More than one packet for INT (``-EINVAL``)
After submission, ``urb->status`` is ``-EINPROGRESS``; however, you should
never look at that value except in your completion callback.
For isochronous endpoints, your completion handlers should (re)submit
URBs to the same endpoint with the ``URB_ISO_ASAP`` flag, using
multi-buffering, to get seamless ISO streaming.
비동기 unlink, 동기 kill과 lifetime race
163-210아직 driver에 반환되지 않은 URB를 비동기로 cancel하려면 `usb_unlink_urb()`를 호출합니다. 이 함수는 URB를 internal list에서 제거하고 할당된 hardware descriptor를 해제하며 status를 unlink 상태로 바꿉니다.
`usb_unlink_urb()`가 반환될 때 URB가 보통 아직 완전히 끝난 것은 아니므로 completion handler 호출을 계속 기다려야 합니다.
동기 cancel에는 `usb_kill_urb()`를 사용합니다. Unlink와 같은 작업을 수행한 뒤 URB 반환과 completion handler 종료까지 기다립니다. 또한 URB를 잠시 unusable 상태로 표시해 callback 등이 재제출하면 `-EPERM`을 반환하므로, 함수 반환 시 URB가 완전히 idle임을 보장합니다.
URB는 언제든 complete될 수 있고 completion handler가 URB를 free할 수도 있습니다. 이 일이 unlink나 kill 실행 중 발생하면 memory-access violation이 생기므로 driver는 URB가 사용 중인 동안 deallocate되지 않게 lock과 reference를 관리해야 합니다.
반대로 `usb_unlink_urb()`가 completion handler를 호출할 수 있으므로 handler는 unlink 호출 시 이미 잡혀 있는 lock을 획득해서는 안 됩니다. 일반 해법은 lock을 잡은 채 `usb_get_urb()`로 reference를 늘리고, lock을 놓고 unlink 또는 kill을 호출한 뒤 `usb_free_urb()`로 reference를 줄이는 것입니다.
Completion handler가 URB를 free할 위험이 없다면 추가 reference 보호는 필요하지 않습니다. 원문 line 201의 잘못된 Sphinx function markup도 영어 원문에는 그대로 보존되어 있습니다.
Completion이 동시에 URB를 free하는 race와 callback lock inversion을 함께 피합니다.
How to cancel an already running URB?
=====================================
There are two ways to cancel an URB you've submitted but which hasn't
been returned to your driver yet. For an asynchronous cancel, call
:c:func:`usb_unlink_urb`::
int usb_unlink_urb(struct urb *urb)
It removes the urb from the internal list and frees all allocated
HW descriptors. The status is changed to reflect unlinking. Note
that the URB will not normally have finished when :c:func:`usb_unlink_urb`
returns; you must still wait for the completion handler to be called.
To cancel an URB synchronously, call :c:func:`usb_kill_urb`::
void usb_kill_urb(struct urb *urb)
It does everything :c:func:`usb_unlink_urb` does, and in addition it waits
until after the URB has been returned and the completion handler
has finished. It also marks the URB as temporarily unusable, so
that if the completion handler or anyone else tries to resubmit it
they will get a ``-EPERM`` error. Thus you can be sure that when
:c:func:`usb_kill_urb` returns, the URB is totally idle.
There is a lifetime issue to consider. An URB may complete at any
time, and the completion handler may free the URB. If this happens
while :c:func:`usb_unlink_urb` or :c:func:`usb_kill_urb` is running, it will
cause a memory-access violation. The driver is responsible for avoiding this,
which often means some sort of lock will be needed to prevent the URB
from being deallocated while it is still in use.
On the other hand, since usb_unlink_urb may end up calling the
completion handler, the handler must not take any lock that is held
when usb_unlink_urb is invoked. The general solution to this problem
is to increment the URB's reference count while holding the lock, then
drop the lock and call usb_unlink_urb or usb_kill_urb, and then
decrement the URB's reference count. You increment the reference
count by calling :c:func`usb_get_urb`::
struct urb *usb_get_urb(struct urb *urb)
(ignore the return value; it is the same as the argument) and
decrement the reference count by calling :c:func:`usb_free_urb`. Of course,
none of this is necessary if there's no danger of the URB being freed
by the completion handler.
Completion handler 제약과 partial transfer
211-238Completion handler type은 `typedef void (*usb_complete_t)(struct urb *)`이며 완료를 일으킨 URB pointer를 인자로 받습니다.
Handler에서는 `urb->status`를 확인해 USB error를 판별하고 URB에 저장한 `context`로 driver-specific 정보를 전달받습니다.
Error나 unlink가 보고되어도 일부 data가 전송됐을 수 있습니다. USB transfer는 packet 단위이므로 1 KByte buffer가 16 packet이라면 completion 전에 그중 10 packet이 성공했을 수 있습니다. 따라서 status와 함께 actual length도 해석해야 합니다.
Completion handler에서는 절대로 sleep하면 안 됩니다. Callback은 흔히 atomic context에서 호출됩니다.
현재 kernel에서는 local interrupt가 disabled된 상태로 completion handler가 실행되지만 미래에는 바뀔 수 있으므로 handler 내부에서 local IRQ가 항상 disabled라고 가정해서는 안 됩니다.
What about the completion handler?
==================================
The handler is of the following type::
typedef void (*usb_complete_t)(struct urb *)
I.e., it gets the URB that caused the completion call. In the completion
handler, you should have a look at ``urb->status`` to detect any USB errors.
Since the context parameter is included in the URB, you can pass
information to the completion handler.
Note that even when an error (or unlink) is reported, data may have been
transferred. That's because USB transfers are packetized; it might take
sixteen packets to transfer your 1KByte buffer, and ten of them might
have transferred successfully before the completion was called.
.. warning::
NEVER SLEEP IN A COMPLETION HANDLER.
These are often called in atomic context.
In the current kernel, completion handlers run with local interrupts
disabled, but in the future this will be changed, so don't assume that
local IRQs are always disabled inside completion handlers.
Isochronous transfer scheduling
239-274ISO transfer는 bulk field 외에 `urb->interval`을 설정해 transfer 주기를 지정해야 합니다. 보통 frame마다 한 번이며 high-speed device에서는 microframe마다 한 번입니다. 실제 interval은 요청값 이하의 2의 거듭제곱이 됩니다.
`usb_fill_int_urb` macro로 ISO transfer field 대부분을 채울 수 있습니다. Schedule할 각 packet마다 `usb_iso_packet_descriptor`를 작성하며 이 배열 공간은 `usb_alloc_urb()`가 URB 끝에 할당합니다.
`usb_submit_urb()`는 `urb->interval`을 요청값 이하의 실제 구현 interval로 수정합니다. `URB_ISO_ASAP` scheduling을 쓰면 `urb->start_frame`도 갱신합니다.
각 frame entry에는 `transfer_buffer` 기준 data offset과 쓰거나 읽을 길이를 지정합니다. Completion 뒤 packet별 `actual_length`와 `status`에 실제 길이와 결과가 기록됩니다.
Audio synchronization이나 adaptive transfer rate를 위해 frame마다 다른 길이를 지정할 수 있고, 길이 `0`으로 하나 이상의 frame을 생략하는 striping도 가능합니다.
직접 start frame을 정하거나 `URB_ISO_ASAP`을 선택할 수 있습니다. 항상 URB 하나 이상을 queue에 유지하고 completion에서 후속 URB를 재제출하면 bandwidth가 허용하는 한 smooth ISO streaming을 얻습니다.
직접 start frame을 정한다면 current frame보다 여러 frame 앞선 값을 사용해야 합니다. 다른 event stream과 ISO data를 동기화할 때 이 model이 유용합니다.
How to do isochronous (ISO) transfers?
======================================
Besides the fields present on a bulk transfer, for ISO, you also
have to set ``urb->interval`` to say how often to make transfers; it's
often one per frame (which is once every microframe for highspeed devices).
The actual interval used will be a power of two that's no bigger than what
you specify. You can use the :c:func:`usb_fill_int_urb` macro to fill
most ISO transfer fields.
For ISO transfers you also have to fill a :c:type:`usb_iso_packet_descriptor`
structure, allocated at the end of the URB by :c:func:`usb_alloc_urb`, for
each packet you want to schedule.
The :c:func:`usb_submit_urb` call modifies ``urb->interval`` to the implemented
interval value that is less than or equal to the requested interval value. If
``URB_ISO_ASAP`` scheduling is used, ``urb->start_frame`` is also updated.
For each entry you have to specify the data offset for this frame (base is
transfer_buffer), and the length you want to write/expect to read.
After completion, actual_length contains the actual transferred length and
status contains the resulting status for the ISO transfer for this frame.
It is allowed to specify a varying length from frame to frame (e.g. for
audio synchronisation/adaptive transfer rates). You can also use the length
0 to omit one or more frames (striping).
For scheduling you can choose your own start frame or ``URB_ISO_ASAP``. As
explained earlier, if you always keep at least one URB queued and your
completion keeps (re)submitting a later URB, you'll get smooth ISO streaming
(if usb bandwidth utilization allows).
If you specify your own start frame, make sure it's several frames in advance
of the current frame. You might want this model if you're synchronizing
ISO data with some other event stream.
Interrupt transfer의 periodic interval과 재제출
275-290Interrupt transfer는 isochronous transfer처럼 periodic하며 interval은 1, 2, 4처럼 2의 거듭제곱 단위입니다. Full-speed와 low-speed device에서는 frame, high-speed device에서는 microframe이 단위입니다.
`usb_fill_int_urb` macro로 INT transfer field를 채울 수 있습니다. `usb_submit_urb()`는 `urb->interval`을 요청값 이하에서 hardware가 구현하는 실제 interval로 수정합니다.
Linux 2.6부터 interrupt URB는 완료 뒤 자동으로 restart되지 않습니다. 다른 URB처럼 completion handler 호출로 끝나며 계속 사용하려면 handler가 URB를 명시적으로 재제출해야 합니다.
원문 마지막 line 290에는 고립된 문자 `s`가 있으며 source hash와 줄 좌표 보존을 위해 영어 원문 block에 그대로 남겼습니다. 의미 있는 instruction은 아닙니다.
Periodic INT transfer는 매 completion마다 driver가 다음 submit을 명시적으로 이어야 합니다.
How to start interrupt (INT) transfers?
=======================================
Interrupt transfers, like isochronous transfers, are periodic, and happen
in intervals that are powers of two (1, 2, 4 etc) units. Units are frames
for full and low speed devices, and microframes for high speed ones.
You can use the :c:func:`usb_fill_int_urb` macro to fill INT transfer fields.
The :c:func:`usb_submit_urb` call modifies ``urb->interval`` to the implemented
interval value that is less than or equal to the requested interval value.
In Linux 2.6, unlike earlier versions, interrupt URBs are not automagically
restarted when they complete. They end when the completion handler is
called, just like other URBs. If you want an interrupt URB to be restarted,
your completion handler must resubmit it.
s
요약·해설
URB.rst:1-290URB는 endpoint queue에 비동기로 제출되고 completion callback에서 status와 실제 전송량을 회수하는 USB message object입니다. Driver는 transfer type에 맞는 field와 scheduling을 설정하고 cancel 중 callback·free race를 reference와 lock ordering으로 방지해야 합니다.