USB core
USB Core — это подсистема ядра Linux, созданная для поддержки USB-устройств и контроллеров шины USB. Цель её создания — абстрагирование от аппаратной реализации стандарта USB (либо аппаратно-зависимых функций) путём определения набора структур данных, макросов и функций.
История развития
[править | править код]Поддержка USB в ядро Linux была добавлена вскоре после появления ветки ядра 2.2 и незадолго до начала работ в линейке 2.3. Разработки из линейки 2.3 регулярно переносились в линейку 2.2, добавляя тем самым новые возможности, как например, поддержку «горячего подключения», новые драйверы, оптимизацию работы. Линейка ядра 2.5 унаследовала все эти улучшения, причём к ним добавилась поддержка работы с USB 2.0 и, как следствие, более высокая производительность, более устойчивая работа между устройствами, упрощение прикладного интерфейса (делать ошибки в коде стало труднее), а также ведение внутренней документации.
Поскольку возможность запуска Linux со временем появилась и на многих медиаустройствах, то в ходе своей эволюции поддержка USB в Linux разделилась на две части. С одной стороны, Linux может запускаться с подключаемых к устройству USB-устройств (например, флэш-накопители), с другой стороны, на основном компьютере, к которому подключают USB-устройства, также может работать Linux. Используемые при этом драйверы USB сильно различаются, поэтому чтобы их различать для драйверов устройств было введено соответствующее название англ. gadget drivers[1].
Принцип работы
[править | править код]Внутри ядра драйверы основной ОС обращаются к прикладным интерфейсам USB Core. Существует два типа публичных прикладных интерфейса USB Core, нацеленных на два различных уровня драйвера USB: драйверы общего назначения, доступные через фреймворки драйвера, как, например, блочное, символьное или сетевое устройства, и драйверы, являющиеся частью ядра, участвующие в управлении шиной USB. Такие драйверы ядра включают в себя драйвер хаба, управляющего деревом USB-устройств, а также несколько различных типов драйверов хост-контроллера (англ. host controller driver, сокр. HCD), который контролирует отдельные шины.
Метод определения оптимального способа работы драйверов с USB-устройством довольно сложный:
- USB поддерживает 4 способа передачи данных (control, bulk, interrupt и isochronous). Два типа из них (control и bulk) используют всю доступную пропускную способность, тогда как остальные два (interrupt и isochronous) должны обеспечивать заданную пропускную способность.
- Модель описания устройства включает в себя одну или более «конфигураций» для каждого устройства, причём активной в любой момент времени может быть только одна из них. Устройства стандарта «high speed» должны поддерживать и конфигурации для работы со стандартом «full speed», а также возможна поддержка конфигураций и для других стандартов/скоростей.
- Конфигурации имеют один или более «интерфейсов», каждый из которых может содержать различные параметры/настройки. Такие интерфейсы могут соответствовать стандарту USB, а могут быть специфичными лишь для определенного производителя/устройства. И именно к интерфейсам и привязаны драйверы USB-устройств, а не к устройству непосредственно.
- Интерфейсы имеют одну или более «конечных точек» (endpoints), каждая из которых поддерживает один тип и направление передачи данных (например, «bulk out» или «interrupt in»). Полная конфигурация может иметь до шестнадцати конечных точек в каждом направлении.
- Передача данных по USB осуществляется пакетами, причём каждая точка имеет запись о максимальном размере пакета.
- Прикладной интерфейс USB в Linux поддерживает синхронные вызовы для передачи сообщений типа control и bulk. Также поддерживаются асинхронные вызовы для всех видов передачи данных путём использования специальных структур запроса, называемых «блоками запроса USB» (англ. USB Request Blocks, сокр. URBs).
Единственные драйверы хостовой ОС, которые реально обращаются к устройству (регистры чтения/записи, обработка сигналов прерываний и т. д.), это драйверы хост-контроллера. В теории все драйверы хост-контроллера поддерживают схожий функционал за счет использования единого прикладного интерфейса. На практике же это начало поддерживаться лишь в версии ядра 2.5, но при этом есть различия в обработке ошибок[2].
Список стандартных прикладных интерфейсов
[править | править код]Ниже перечислены стандартные прикладные интерфейсы программирования (API), входящие в состав USB Core[3].
Название | Функции |
---|---|
usb_init_urb | Инициализирует URB для их последующего использования драйвером USB |
usb_alloc_urb | Создает новый URB для его последующего использования драйвером USB |
usb_free_urb | Освобождает память, занимаемую URB, по окончании работы всех пользователей с ним |
usb_get_urb | Увеличивает счетчик ссылок на URB |
usb_submit_urb | Посылает запрос асинхронной передачи к конечному устройству |
usb_unlink_urb | Прерывает/отменяет запрос передачи к конечному устройству |
usb_kill_urb | Отменяет запрос передачи и ожидает его завершения |
usb_control_msg | Создает сообщение управления URB, отсылает его и ожидает выполнения |
usb_bulk_msg | Создает общее сообщение URB, отсылает его и ожидает выполнения |
usb_sg_init | Инициализирует запрос ввода-вывода общего типа или прерывания на базе распределённого списка |
usb_sg_wait | Синхронно выполняет запрос разделения/объединения |
usb_sg_cancel | Останавливает разделение/объединение ввода-вывода, начатого по команде usb_sg_wait |
usb_get_descriptor | Отправляет обобщённый запрос получения дескриптора (GET_DESCRIPTOR) |
usb_string | Возвращает строковый дескриптор в формате ISO 8859-1 |
usb_get_status | Отправляет вызов GET_STATUS |
usb_clear_halt | Сообщает устройству о сбросе состояния ожидания для конечного устройства |
usb_set_interface | Делает активными альтернативный набор настроек |
usb_reset_configuration | Программная перезагрузка устройства |
usb_register_dev | Регистрирует USB-устройство и запрашивает младший номер |
usb_deregister_dev | Разрегистрирует динамический младший номер USB-устройства |
usb_match_id | Находит первый совпавший usb_device_id для устройства или интерфейса |
usb_register_driver | Регистрирует USB-драйвер |
usb_deregister | Разрегистрирует USB-драйвер |
usb_ifnum_to_if | Получает объект интерфейса для данного номера интерфейса |
usb_altnum_to_altsetting | Получает структуру альтернативных настроек для данного номера интерфейса |
usb_driver_claim_interface | Привязывает драйвер к интерфейсу |
usb_driver_release_interface | Отвязывает драйвер от интерфейса |
usb_find_interface | Находит указатель usb_interface для драйвера и устройства |
usb_get_dev | Увеличивает счетчик ссылок структуры USB-устройства |
usb_put_dev | Освобождает используемую структуру USB-устройства |
usb_get_intf | Увеличивает счетчик ссылок структуры интерфейса USB |
usb_put_intf | Освобождает используемую структуру интерфейса USB |
usb_lock_device_for_reset | Корректно накладывает блокировку на устройство для последующей перезагрузки |
usb_find_device | Находит требуемое USB-устройство в системе |
usb_get_current_frame_number | Возвращает номер текущего кадра шины |
usb_buffer_alloc | Выделяет DMA-совместимый буфер для размещения URB_NO_xxx_DMA_MAP |
usb_buffer_free | Освобождает память, выделенную при помощи usb_buffer_alloc |
usb_buffer_map | Создает DMA-привязки к URB |
usb_buffer_dmasync | Синхронизирует просмотр буферов DMA и центрального процессора |
usb_buffer_unmap | Разрушает DMA-привязки к URB |
usb_buffer_map_sg | Создает распределённые DMA-привязки к конечным точкам |
usb_buffer_dmasync_sg | Синхронизирует просмотр распределённых буферов DMA и центрального процессора |
usb_buffer_unmap_sg | Разрушает распределённые DMA-привязки |
usb_hub_tt_clear_buffer | Сбрасывает режим control/bulk в высокоскоростном хабе |
usb_root_hub_lost_power | Вызывается HCD в случае потери корневым хабом питания по Vbus-шине |
usb_reset_device | Выполняет перезагрузку порта USB для переинициализации устройства |
Модели USB API
[править | править код]Существуют две основные модели ввода-вывода в USB API. Наиболее простая модель является асинхронной: драйверы отправляют запрос в виде URB, а затем обратный вызов URB на следующем шаге завершает операцию. Все типы передачи USB поддерживают данную модель, однако существуют специальные модели для управляющих URB (которые всегда имеют собственные настройки и статусы, но не всегда обладают возможностью продвижения данных (англ. data stage) и изохронных URB (которые допускают передачу больших пакетов и включают в себя генерацию отчетов по каждому некорректному пакету). Такие модели строятся на основе поддержки синхронного API, в котором драйвер вызывает подпрограмму, которая размещает в памяти один или более URB, отправляет их и ждет их завершения. Также существуют синхронные обертки для однобуферных управляющих и массовых передач (которые неудобны для применения в некоторых сценариях драйверного отключения), а также для потоковой передачи на основе распределённых списков (потоком или с прерываниями).
Драйверам USB требуется наличие буферов, которые могут быть использованы для прямого доступа к памяти (DMA), хотя им не обязательно самостоятельно выполнять привязку DMA. Существуют API, применяемые при выделении DMA-буферов, поскольку они смогут предотвратить использование некорректных буферов на некоторых системах. В некоторых случаях драйверы могут использовать 64-битный режим DMA для устранения прочих видов буферных ограничений[3].
Примечания
[править | править код]- ↑ Introduction to USB on Linux Архивировано 18 мая 2009 года. (англ.)
- ↑ USB Host-Side API Model Архивировано 19 мая 2009 года. (англ.)
- ↑ 1 2 USB Core APIs Архивировано 1 мая 2010 года. (англ.)
Ссылки
[править | править код]- Официальный сайт (англ.)
- The Linux USB Subsystem (англ.)
В статье не хватает ссылок на источники (см. рекомендации по поиску). |