249 lines
16 KiB
Plaintext
249 lines
16 KiB
Plaintext
|
Когда ядро обнаруживает подключенное устройство 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
|