USB API/ru

From KolibriOS wiki
Jump to navigation Jump to search

USB API

Когда ядро ​​обнаруживает подключенное устройство USB, оно настраивает его согласно USB-протокола - SET_ADDRESS + SET_CONFIGURATION. Всегда устанавливается первая конфигурация. Ядро также читает дескриптор устройства, чтобы показать некоторую информацию, читает и анализирует дескриптор конфигурации. Для каждого интерфейса ядро будет искать класс этого интерфейса и попытается загрузить соответствующий драйвер COFF. В настоящее время соответствие кодов классов и имен драйверов жестко прописано в коде ядра и выглядит следующим образом: 3 = usbhid.obj, 7 = usbprint.obj, 8 = usbstor.obj, 9 = поддерживаются самим ядром, другие = usbother.obj.

Драйвер должен быть стандартным драйвером в формате COFF, экспортирующим процедуру под названием "START" и переменную "version". Загрузчик вызывает процедуру "START" как STDCALL с одним параметром DRV_ENTRY = 1. При завершении работы системы, если инициализация драйвера была успешна, "START" процедуру также вызывает код остановки системы с одним параметром DRV_EXIT = -1.

Драйвер должен зарегистрировать себя в качестве драйвера USB в процедуре "START". Это делается путем вызова экспортируемой ядром функции RegUSBDriver и возврата её результата в качестве результата "START" процедуры.

void* __stdcall RegUSBDriver(
    const char* name,
    void* handler,
    const USBFUNC* usbfunc
);

Параметр 'name' должен совпадать с именем драйвера, например "usbhid" для usbhid.obj.

Параметр 'handler' является необязательным. Если он не NULL, то он должен указывать на стандартный обработчик IOCTL интерфейса, как в обычном (не-USB) драйвере.

Параметр "Usbfunc" представляет собой указатель на следующую структуру:

struc USBFUNC
{
  .strucsize         dd ? ; размер структуры, включая это поле
  .add_device        dd ? ; указатель на AddDevice процедуру в драйвере
                          ; (необходимо)
  .device_disconnect dd ? ; указатель на DeviceDisconnected процедуру в драйвере
                          ; опционально, может быть NULL
; В будущем могут быть добавлены другие функции
}

Драйвер ДОЛЖЕН реализовать функцию:

void* __stdcall AddDevice(
    void* pipe0,
    void* configdescr,
    void* interfacedescr
);

Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки устройства. Он может быть использован в качестве аргумента для USBControlTransferAsync (см. далее).

Параметр 'configdescr' указывает на дескриптор конфигурации и все связанные с ним данные, представленные так, как их возвращает запрос GET_DESCRIPTOR. Полный размер данных содержится в поле Length самого дескриптора. (см. USB2.0 spec.)

Параметр 'interfacedescr' указывает на дескриптор интерфейса инициализируемого в данный момент. Это указатель на данные находящиеся внутри структуры "configdescr". (Помним, что структура INTERFACE_DESCRIPTOR, находится внутри структуры CONFIGURATION_DESCRIPTOR. См. USB2.0 Spec.) Обратите внимание, что одно устройство может реализовывать много интерфейсов и AddDevice может быть вызвана несколько раз с одним "configdescr" но разными "interfacedescr".

Возвращенное значение NULL показывает, что инициализация не была успешной. Любое другое значение означает инициализацию устройства. Ядро не делает попыток как-то интерпретировать это значение. Это может быть, например, указатель на внутренние данные драйвера в памяти, выделенной с помощью Kmalloc или индексом в какой-то своей таблице. (Помните, что Kmalloc() НЕ stdcall-функция! Она портит регистр ebx!)

Драйвер МОЖЕТ реализовать функцию:

void __stdcall DeviceDisconnected(
    void* devicedata
);

Если данная функция реализована, то ядро вызывает её, когда устройство отключено, посылая ей в качестве параметра "devicedata" то, что было возвращено ему функцией "AddDevice" при старте драйвера.

Драйвер может использовать следующие функции экспортируемые ядром:

void* __stdcall USBOpenPipe(
    void* pipe0,
    int endpoint,
    int maxpacketsize,
    int type,
    int interval
);

Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки устройства. Используется для идентификации устройства.

Параметр "endpoint" номер конечной точки USB. Младшие 4 бита, собственно, номер точки, а бит 7 имеет следующее значение: 0 - для OUT точки, 1 - для IN точки. Остальные биты должны быть равны нулю.

Параметр "maxpacketsize" устанавливает максимальный размер пакета для канала.

Параметр "type" устанавливает тип передачи для конечной точки, как это прописано в USB спецификации:

0 = control, 1 = isochronous (сейчас не поддерживается), 2 = bulk, 3 = interrupt.

Параметр "interval" игнорируется для control и bulk передач. Для конечных точек по прерываниям устанавливает периодичность опроса в миллисекундах.

Функция возвращает хэндл канала при успешном его открытии либо NULL при ошибке. Хэндл канала обращается в NULL когда: а) канал будет явно закрыт функцией USBClosePipe (см. ниже); б) была выполнена предоставленная драйвером функция "DeviceDisconnected".

void __stdcall USBClosePipe(
    void* pipe
);

Освобождает все ресурсы, связанные с выбранным каналом. Единственный параметр - указатель на хэндл, который был возвращен функцией USBOpenPipe при открытии канала. Когда устройство отключается, все связанные с ним каналы закрываются ядром; нет необходимости в самостоятельном вызове этой функции.

void* __stdcall USBNormalTransferAsync(
    void* pipe,
    void* buffer,
    int size,
    void* callback,
    void* calldata,
    int flags
);
void* __stdcall USBControlTransferAsync(
    void* pipe,
    void* setup,
    void* buffer,
    int size,
    void* callback,
    void* calldata,
    int flags
);

Первая функция ставит в очередь bulk или interrupt передачу для выбранного канала. Тип и направление передачи фиксированы для bulk и interrupt типов конечных точек, как это было выбрано функцией USBOpenPipe. Вторая функция ставит в очередь control передачу для выбранного канала. Направление этой передачи определяется битом 7 байта 0 пакета "setup" (0 - для OUT, 1 - для IN передачи). Эта функция возвращает управление немедленно. По окончании передачи вызывается функция "callback" заданная как аргумент USB______TransferAsync.

Параметр "pipe" - хэндл, возвращенный функцией USBOpenPipe.

Параметр 'setup' функции USBControlTransferAsync указывает на 8-байтный конфигурационный пакет (см. USB2.0 Spec).

Параметр "buffer" - это указатель на буфер. Для IN передач он будет заполнен принятыми данными. Для OUT передач он должен быть заполнен данными, которые мы хотим передать. Указатель может быть NULL для пустых передач, либо для передач control, если дополнительных данных не требуется.

Параметр "size" - это размер данных для передачи. Он может быть равен 0 для пустых передач, либо для передач control, если дополнительных данных не требуется.

Параметр "callback" - это указатель на функцию, которая будет вызвана по окончании передачи.

Параметр "calldata" будет передан функции "callback" вызываемой по окончании передачи. Например, он может быть NULL или указывать на данные устройства или указывать на данные используемые как дополнительные параметры, передаваемые от вызывающей USB_____TransferAsync функции в callback функцию.

Другие данные, связанные с передачей, могут быть помещены до буфера (по смещению) или после него. Они могут быть использованы из callback-функции, при необходимости.

Параметр "flags" - это битовое поле. Бит 0 игнорируется для OUT передач. Для IN передач он означает, может ли устройство передать меньше данных (бит=1), чем определено в "size" или нет (бит=0). Остальные биты не используются и должны быть равны 0.

Возвращаемое функциями значение равно NULL в случае ошибки и не NULL если передача успешно поставлена в очередь. Если происходит ошибка при передаче, то callback функция будет об этом оповещена.

void __stdcall CallbackFunction(
    void* pipe,
    int status,
    void* buffer,
    int length,
    void* calldata
);

Параметры 'pipe', 'buffer', 'calldata' значат то же, что и для USB_____TransferAsync.

Параметр "length" это счетчик переданных байт. Для control передач он отражает дополнительные 8 байт этапа SETUP. Т.е. 0 означает ошибку на этапе SETUP, а "size"+8 успешную передачу.

Параметр "status" не равен 0 в случае ошибки:

USB_STATUS_OK = 0 ; без ошибок
USB_STATUS_CRC = 1 ; ошибка контрольной суммы
USB_STATUS_BITSTUFF = 2 ; ошибка инверсии битов (bitstuffing)
USB_STATUS_TOGGLE = 3 ; data toggle mismatch
; (Нарушение последовательности DAT0/DAT1)
USB_STATUS_STALL = 4 ; устройство возвратило STALL статус (остановлено)
USB_STATUS_NORESPONSE = 5 ; устройство не отвечает
USB_STATUS_PIDCHECK = 6 ; ошибка в поле PacketID (PID)
USB_STATUS_WRONGPID = 7 ; неожидаемое PacketID (PID) значение
USB_STATUS_OVERRUN = 8 ; слишком много данных от конечной точки
USB_STATUS_UNDERRUN = 9 ; слишком мало данных от конечной точки
USB_STATUS_BUFOVERRUN = 12 ; переполнение внутреннего буфера контроллера
; возможна только для изохронных передач
USB_STATUS_BUFUNDERRUN = 13 ; опустошение внутреннего буфера контроллера
; возможна только для изохронных передач
USB_STATUS_CLOSED = 16 ; канал закрыт либо через ClosePipe, либо в
; результате отключения устройства

Если несколько передач были поставлены в очередь для одного канала, то callback функции для них будут вызываться в порядке постановки передач в очередь. Если канал был закрыт ввиду USBClosePipe или отключения устройства, то callback функции (если очередь передач не пуста) получат USB_STATUS_CLOSED. Вызов DeviceDisconnected() последует после отработки всех оставшихся в очереди callback функций.

void* __stdcall USBGetParam(void* pipe0, int param);

Возвращает указатель на некоторые параметры устройства запомненные ядром при инициализации первой конфигурации. Не передает ничего устройству по шине.

pipe0 - хэндл контрольного канала для нулевой конечной точки устройства.

param - выбор возвращаемого параметра: 0 - возвратить указатель на дескриптор устройства; 1 - возвратить указатель на дескриптор конфигурации; 2 - возвратить режим шины устройства:

USB_SPEED_FS = 0 ; full-speed
USB_SPEED_LS = 1 ; low-speed
USB_SPEED_HS = 2 ; high-speed

Авторы

CleverMouse, UnКайF(перевод на русский)