Основы USB устройства

Предыдущая  Содержание  Следующая V*D*V

USB-устройство представляет собой очень сложную вещь, как описано в официальной документации USB (доступной на http://www.usb.org). К счастью, ядро Linux предоставляет подсистему, называемую ядром USB, чтобы справляться с большинством сложностей. В этой главе описывается взаимодействие между драйвером и USB ядром. Рисунок 13-2 показывает, как USB-устройства состоят из конфигураций, интерфейсов и оконечных точек и как USB драйверы связаны с интерфейсами USB, а не всего устройства USB.

 

Рисунок 13-2. Обзор USB устройства

Рисунок 13-2. Обзор USB устройства

Оконечные точки

Самый основной формой USB взаимодействия является то, что называется endpoint (оконечная точка). Оконечная точка USB может переносить данные только в одном направлении, либо со стороны хост-компьютера на устройство (называемая оконечной точкой OUT) или  от устройства на хост-компьютер (называемая оконечной точкой IN). Оконечные точки можно рассматривать как однонаправленные трубы.

 

Оконечная точка USB может быть одной из четырёх типов, которые описывают, каким образом передаются данные:

 

CONTROL (Управляющая)

Управляющие оконечные точки используются для обеспечения доступа к различным частям устройства USB. Они широко используются для настройки устройства, получения информации об устройстве, посылке команд в устройство, или получения статусных сообщений устройства. Эти оконечные точки, как правило, малы по размеру. Каждое устройство имеет управляющую оконечную точку, называемую "endpoint 0", которая используется ядром USB для настройки устройства во время подключения. Эти передачи гарантируются протоколом USB, чтобы всегда иметь достаточную зарезервированную пропускную способность шины для их передачи на устройство.

INTERRUPT (Прерывание)

Оконечные точки прерывания передают небольшие объёмы данных с фиксированной частотой каждый раз, когда USB хост запрашивает устройство для передачи данных. Эти оконечные точки являются основным транспортным методом для USB клавиатур и мышей. Они также часто используются для передачи данных на USB устройства для управления устройством, но обычно не используются для передачи больших объёмов данных. Эти передачи гарантируются протоколом USB, чтобы всегда иметь достаточную зарезервированную пропускную способность для их передачи.

BULK (Поточная)

Поточные оконечные точки передают большие объёмы данных. Эти оконечные точки, как правило, значительно больше (они могут содержать больше символов за один раз), чем оконечные точки прерывания. Они являются обычными для устройств, которые должны передавать любые данные, которые должны пройти через шину, без потери данных. Этим передачам протокол USB не гарантирует выполнения в определённые сроки. Если на шине нет достаточного места, чтобы отправить целый пакет BULK, он распадается на несколько передач в или из устройства. Эти оконечные точки общеприняты на принтерах, устройствах хранения и сетевых устройствах.

ISOCHRONOUS (Изохронная)

Изохронные оконечные точки также передают большие объёмы данных, но этим данным не всегда гарантирована доставка. Эти оконечные точки используются в устройствах, которые могут обрабатывать потери данных, и больше полагаются на сохранение постоянного потока поступающих данных. При сборе данных в реальном времени, таком, как аудио- и видео-устройства, почти всегда используются такие оконечные точки.

 

Управляющие и поточные оконечные точки используются для асинхронной передачи данных, когда драйвер решает их использовать. Оконечные точки прерывания и изохронные точки являются периодическими. Это означает, что эти оконечные точки созданы для передачи данных непрерывно за фиксированное время, что приводит к тому, что их пропускная способность защищена ядром USB.

 

Оконечные точки USB описаны в ядро структурой struct usb_host_endpoint. Эта структура содержит реальную информацию оконечной точки в другой структуре, названной struct usb_endpoint_descriptor. Последняя структура содержит все специфичные USB данные точно в том формате, который указало само устройство. Полями этой структуры, с которыми имеют дело драйверы, являются:

 

bEndpointAddress

Это адрес USB этой данной оконечной точки. Также в это 8-ми разрядное значение включено направление оконечной точки. В это поле могут быть помещены битовые маски USB_DIR_OUT и USB_DIR_IN, чтобы определить, куда направлены данные этой оконечной точки, в устройство или в хост.

 

bmAttributes

Это тип оконечной точки. В этом значении должна присутствовать битовая маска USB_ENDPOINT_XFERTYPE_MASK, чтобы определить, является ли конечная точка типом USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK или типом USB_ENDPOINT_XFER_INT. Эти макросы определяют изохронные, поточные и оконечные точки прерывания, соответственно.

 

wMaxPacketSize

Это максимальный размер в байтах, который эта оконечная точка может обработать за раз. Заметим, что возможно для драйвера отправить объём данных в оконечной точке, превышающий это значение, но во время фактической передачи на устройство эти данные будут разделены на куски по wMaxPacketSize. Для высокоскоростных устройств это поле может быть использовано для поддержки режима высокой пропускной способности для оконечной точки с помощью нескольких дополнительных битов в верхней части значения. Для более подробной информации о том, как это делается, смотрите спецификацию USB .

 

bInterval

Если эта оконечная точка имеет тип прерывания, это значение является установкой интервала для оконечной точки, то есть времени между запросами прерывания для оконечной точки. Это значение представляется в миллисекундах.

 

Поля этой структуры не имеют "традиционной" для ядра Linux схемы именования. Это происходит потому, что эти поля напрямую соотносятся с именами полей в спецификации USB. Программисты ядра USB посчитали, что было более важно использовать специфицированные имена, чтобы избежать путаницы при чтении спецификации, чем иметь имена переменных, которые выглядят знакомо для программистов Linux.

Интерфейсы

Оконечные точки USB завёрнуты в интерфейсы. USB интерфейсы обрабатывают только один тип логического USB соединения, такого как мышь, клавиатура или аудио поток. Некоторые USB устройства имеют несколько интерфейсов, таких как USB динамик, который может состоять из двух интерфейсов: USB клавиатура для кнопок и USB аудио поток. Поскольку USB интерфейс представляет собой основную функциональность, каждый драйвер USB управляет интерфейсом; так что в случае динамика, Linux необходимы два разных драйвера для одного аппаратного устройства.

 

USB интерфейсы могут иметь дополнительные параметры настройки, которые представляют собой разные наборы параметров интерфейса. Первоначальное состояние интерфейса находится в первой настройке под номером 0. Другие параметры могут быть использованы, чтобы управлять отдельными оконечными точками по-разному, например, резервировать разные размеры полосы пропускания USB устройства. Каждое устройство с изохронной оконечной точкой использует дополнительные параметры на том же самом интерфейсе.

 

USB интерфейсы описаны в ядре структурой struct usb_interface. Эта структура является тем, что ядро USB передаёт в USB драйверы и тем, за чьё управление затем отвечает драйвер USB. Важными полями в этой структуре являются:

 

struct usb_host_interface *altsetting

Массив интерфейсных структур, содержащий все дополнительные настройки, которые могут быть выбраны для этого интерфейса. Каждая структура struct usb_host_interface состоит из набора конфигураций оконечной точки, определённой структурой struct usb_host_endpoint, описанной выше. Заметим, что эти интерфейсные структуры не имеют какого-то определённого порядка.

 

unsigned num_altsetting

Количество дополнительных параметров, на которые указывает указатель altsetting.

 

struct usb_host_interface *cur_altsetting

Указатель на массив altsetting, обозначающий активные в настоящее время настройки для этого интерфейса.

 

int minor

Если драйвер USB, связанный с этим интерфейсом, использует старший номер USB, эта переменная содержит младший номер, присвоенный интерфейсу USB ядром. Это справедливо только после успешного вызова usb_register_dev (описываемого далее в этой главе).

 

В структуре struct usb_interface есть и другие поля, но USB драйверам знания о них не требуются.

Конфигурации

Сами USB интерфейсы завёрнуты в конфигурации. USB устройство может иметь множество конфигураций и может переключаться между ними с целью изменения состояния устройства. Например, некоторые устройства, которые позволяют загружать в них программное обеспечение, для решения этой задачи содержат несколько конфигураций. В один момент времени может быть разрешена только одна конфигурация. Linux не очень хорошо обрабатывает множественную конфигурацию USB устройства, но, к счастью, они встречаются редко.

 

Linux описывает USB конфигурации структурой struct usb_host_config и устройства USB в целом структурой struct usb_device. Драйверам устройств USB обычно даже не требуется читать или записывать какие-то значения в эти структуры, поэтому подробности их здесь не описываются. Любопытный читатель может найти их описания в файле include/linux/usb.h в дереве исходных текстов ядра.

 

Драйверу USB устройства обычно требуется преобразовать данные из заданной структуры struct usb_interface в структуру struct usb_device, которая необходима ядру USB для широкого круга функциональных вызовов. Для этого предоставляется функция interface_to_usbdev. Надеемся, что в будущем все USB вызовы, которым в настоящее время требуется struct usb_device будут преобразованы для приёма параметра struct usb_interface и не будут требовать от драйверов выполнения преобразования.

 

Так что подводя итоги, USB устройства являются довольно сложными и состоят из множества разных логических единиц. Отношения между этими частями можно описать просто следующим образом:

 

Устройство обычно имеют одну или более конфигураций.

Конфигурации часто имеют один или несколько интерфейсов.

Интерфейсы обычно имеет один или несколько наборов параметров.

Интерфейсы имеют ноль или более оконечных точек.

Предыдущая  Содержание  Следующая