/kernel/branches/Kolibri-acpi/docs/events_subsystem.txt |
---|
0,0 → 1,232 |
Дата последней правки 26/07/2013. |
Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра. |
Она не имеет отношения к подсистеме событий пользовательского интерфейса. |
С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку. |
struc EVENT |
{ |
.magic dd ? ; 'EVNT' |
.destroy dd ? ; internal destructor |
.fd dd ? ; next object in list |
.bk dd ? ; prev object in list |
.pid dd ? ; owner id. идентификатор владельца (потока) |
.id dd ? ; event uid. уникальный идентификатор события (просто номерок) |
.state dd ? ; internal flags; см. далее. |
.code dd ? ; старший байт класс события, ; следующий байт приоритет |
; (будет использоваться только внутри ядра, при чтении всегда 0), |
; Чем больше численное значение двойного слова тем важнее событие. |
; два младших байта код события. |
rd 5 ; .data - точная структура этого поля не определена и зависит |
; от поля .code. (Здесь можно передавать какие-то свои данные, |
; при необходимости :) |
.size = $ - .magic |
.codesize = $ - .code |
} |
События реального времени получили класс 0хFF. Пока определёны только: |
EVENT.code= ;(Используется в звуковой подсистеме). |
RT_INP_EMPTY equ 0xFF000001 |
RT_OUT_EMPTY equ 0xFF000002 |
RT_INP_FULL equ 0xFF000003 |
RT_OUT_FULL equ 0xFF000004 |
Флаги поля EVENT.state определены в gui/event.inc. |
EVENT_SIGNALED equ 0x20000000 ;Бит 29 событие активно/неактивно; |
EVENT_WATCHED equ 0x10000000 ;бит 28, поток-владелец ожидает активации события; |
MANUAL_RESET equ 0x40000000 ;бит 30, не деактивировать событие автоматически по получении; |
MANUAL_DESTROY equ 0x80000000 ;бит 31, не возвращать событие в список свободных по получении. |
На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc |
и выглядит так: |
struct APPOBJ ; common object header |
magic dd ? ; |
destroy dd ? ; internal destructor |
fd dd ? ; next object in list |
bk dd ? ; prev object in list |
pid dd ? ; owner id |
ends |
struct EVENT APPOBJ |
id dd ? ;event uid |
state dd ? ;internal flags |
code dd ? |
rd 5 ; .data |
ends |
Код находится в gui/event.inc. |
Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd). |
При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents |
(свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных |
и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие): |
ObjList - список объектов ядра, ассоциированных с этим потоком; |
EventList - список событий ядра для потока. |
Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются |
и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков, |
как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая |
(у события всегда есть поток-владелец), по идентификатору потока. |
Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения |
MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается |
ядром, возвращаясь в список свободных событий после получения. |
Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке |
объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY =1 и MANUAL_RESET = 1 |
остаётся активным после получения и может быть сброшено вызовом ClearEvent. |
Пример (вариант) жизненного цикла события из звуковой подсистемы: |
Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью |
CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага |
EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется |
с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически |
повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью |
ClearEvent. |
Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы. |
Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью. |
Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к |
которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события" |
следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер, |
его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием). |
Функции для работы с событиями экспортитуемые ядром: |
(для драйверов и т.п.; вызываются в режиме ядра) |
CreateEvent |
RaiseEvent |
ClearEvent |
SendEvent |
DestroyEvent |
WaitEvent |
WaitEventTimeout |
GetEvent |
Для пользовательских приложений Ф68.14 (GetEvent с обёрткой) |
--------------------------------------------------------------------------------------------- |
CreateEvent: |
Создаёт новое событие в очереди ObjList текущего потока. |
Устанавливает: |
EVENT.destroy <= внутренний деструктор по умолчанию; |
EVENT.pid <= текущий Process id; |
EVENT.id <= уникальный идентификатор; |
EVENT.state <= ecx - флаги; |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: |
eax - указатель на событие или 0 при ошибке. |
edx - Event.id. |
Портит: eax,ebx,edx,ecx,esi,edi |
--------------------------------------------------------------------------------------------- |
RaiseEvent: |
Активирует уже существующее событие (может принадлежать другому потоку) установкой |
флага EVENT_SIGNALED. Если необходимо, - устанавливает данные EVENT.code. |
Если флаг EVENT_SIGNALED в самом событии уже активен - больше ничего не делает. |
Если EVENT_SIGNALED не установлен в самом событии, то он будет установлен, кроме случая |
{EVENT_WATCHED в edx=1 и EVENT_WATCHED в событии=0}. |
Т.е. при установке EVENT_WATCHED в edx, проверяется, ожидает ли поток-владелец активации |
события. |
Кроме EVENT_SIGNALED в событии никакие другие флаги не модифицируются. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события; |
edx - флаги для операции (формат EVENT.state); |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: ? |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
ClearEvent: |
Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.) |
Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id), |
ничего не делает. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: ? |
Портит: eax,ebx,ecx,edi . |
--------------------------------------------------------------------------------------------- |
SendEvent: |
Создаёт новое событие в списке событий целевого потока. Устанавливает в событии |
флаг EVENT_SIGNALED. |
Принимает: |
EVENT.pid <= eax - pid, идентификатор целевого потока; |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: |
eax - указатель на событие или 0 при ошибке. |
edx - Event.id. уникальный идентификатор. |
Портит: eax,ebx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
DestroyEvent: |
Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id. |
Событие может принадлежать другому потоку. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: |
eax - 0 при ошибке, не 0 при успехе. |
Портит: eax,ebx,ecx . |
--------------------------------------------------------------------------------------------- |
WaitEvent: |
Бесконечно ожидает установки флага EVENT_SIGNALED в конкретном событии, принадлежащем |
вызывающему WaitEvent потоку. Сигнализирующий поток устанавливат этот флаг через |
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. |
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: ? |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
WaitEventTimeout: |
Ожидает с таймаутом установки флага EVENT_SIGNALED в конкретном событии, принадлежащем |
вызывающему WaitEventTimeout потоку. Сигнализирующий поток устанавливат этот флаг через |
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. |
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
ecx - время ожидания в тиках системного таймера. |
Возвращает: |
eax - 0 - таймаут, если событие не активировалось, или |
не 0, если было активировано. |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
GetEvent: |
Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается |
путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) |
по получении копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
edi - указатель на буфер, куда копировать данные. |
Возвращает: |
буфер, содержащий следующую информацию: |
+0: (EVENT.code) dword: идентификатор последующих данных сигнала |
+4: (EVENT.data, поле формально не определено) данные принятого |
сигнала (5*dword), формат которых определяется первым dword-ом. |
Портит: eax,ebx,edx,ecx,esi,edi . |
-------------------------------------------------------------------------------------------- |
Ф 68.14 для приложений: ;это тот же GetEvent, но с обёрткой. |
Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток |
замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) |
копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. |
Принимает: |
eax - 68 - номер функции |
ebx - 14 - номер подфункции |
ecx - указатель на буфер для информации (размер 6*dword) |
Возвращает: |
буфер, на который указывает ecx, содержит следующую информацию: |
+0: (EVENT.code) dword: идентификатор последующих данных сигнала |
+4: (EVENT.data, поле формально не определено) данные принятого |
сигнала (5*dword), формат которых определяется первым dword-ом. |
Портит: |
eax . |
--------------------------------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/docs/sysfuncr.txt |
---|
34,7 → 34,7 |
вызов функции с такими Y игнорируется |
* RR, GG, BB = соответственно красная, зеленая, синяя |
составляющие цвета рабочей области окна |
(игнорируется для стиля Y=2) |
(игнорируется для стиля Y=1) |
* X = DCBA (биты) |
* A = 1 - у окна есть заголовок; для стилей Y=3,4 адрес строки |
заголовка задаётся в edi, для прочих стилей |
47,7 → 47,7 |
игнорируются для стилей Y=1,3: |
* esi = 0xXYRRGGBB - цвет заголовка |
* RR, GG, BB определяют сам цвет |
* Y=0 - обычное окно, Y=1 - неперемещаемое окно |
* Y=0 - обычное окно, Y=1 - неперемещаемое окно (работает для всех стилей окон) |
* X определяет градиент заголовка: X=0 - нет градиента, |
X=8 - обычный градиент, |
для окон типа II X=4 - негативный градиент |
372,6 → 372,7 |
* бит 1 (маска 2): окно минимизировано в панель задач |
* бит 2 (маска 4): окно свёрнуто в заголовок |
* +71 = +0x47: dword: маска событий |
* +75 = +0x4B: byte: режим ввода с клавиатуры(ASCII = 0; SCAN = 1) |
Замечания: |
* Слоты нумеруются с 1. |
* Возвращаемое значение не есть общее число потоков, поскольку |
416,7 → 417,7 |
положение и размеры этого окна полагаются нулями. |
* Координаты клиентской области окна берутся относительно окна. |
* В данный момент используется только часть буфера размером |
71 = 0x47 байта. Тем не менее рекомендуется использовать буфер |
76 = 0x4C байта. Тем не менее рекомендуется использовать буфер |
размером 1 Кб для будущей совместимости, в будущем могут быть |
добавлены некоторые поля. |
1803,7 → 1804,7 |
sysdir_path rb 64 |
Пример: |
dir_name1 db 'KolibriOS',0 |
rb 64-8 |
rb 64-10 |
dir_path1 db 'HD0/1',0 |
rb 64-6 |
Возвращаемое значение: |
2027,6 → 2028,14 |
* eax = 40 - номер функции |
* ebx = маска: бит i соответствует событию i+1 (см. список событий) |
(установленный бит разрешает извещение о событии) |
bit 31: фильтр активности событий мыши |
bit 31 = 0 - неактивное окно всегда получает события от мыши |
bit 31 = 1 - неактивное окно не получает события от мыши |
bit 30: фильтр позиции курсора |
bit 30 = 0 - окно принимает события мыши, если курсор |
за пределами окна |
bit 30 = 1 - окно не принимает события мыши, если курсор |
за пределами окна |
Возвращаемое значение: |
* eax = предыдущее значение маски |
Замечания: |
2420,6 → 2429,70 |
* иначе eax = TID - идентификатор потока |
====================================================================== |
====================== Функция 54, подфункция 0 ====================== |
============== Узнать количество слотов в буфере обмена. ============= |
====================================================================== |
Параметры: |
* eax = 54 - номер функции |
* ebx = 0 - номер подфункции |
Возвращаемое значение: |
* eax = количество слотов в буфере |
* eax = -1 - отсутствует область главного списка |
====================================================================== |
====================== Функция 54, подфункция 1 ====================== |
================== Считать данные из буфера обмена. ================== |
====================================================================== |
Параметры: |
* eax = 54 - номер функции |
* ebx = 1 - номер подфункции |
* eсx = номер слота |
Возвращаемое значение: |
* eax = если успешно - указатель на область памяти с данными |
* eax = 1 - ошибка |
* eax = -1 - отсутствует область главного списка |
====================================================================== |
====================== Функция 54, подфункция 2 ====================== |
================== Записать данные в буфер обмена. =================== |
====================================================================== |
Параметры: |
* eax = 54 - номер функции |
* ebx = 2 - номер подфункции |
* eсx = количество копируемых байт |
* edx = указатель на буфер под копируемые данные |
Возвращаемое значение: |
* eax = 0 - успешно |
* eax = 1 - ошибка |
* eax = -1 - отсутствует область главного списка |
====================================================================== |
====================== Функция 54, подфункция 3 ====================== |
========= Удалить последний слот с данными в буфере обмена =========== |
====================================================================== |
Параметры: |
* eax = 54 - номер функции |
* ebx = 3 - номер подфункции |
Возвращаемое значение: |
* eax = 0 - успешно |
* eax = 1 - ошибка |
* eax = -1 - отсутствует область главного списка |
====================================================================== |
====================== Функция 54, подфункция 4 ====================== |
=================== Аварийный сброс блокировки буфера ================ |
====================================================================== |
Параметры: |
* eax = 54 - номер функции |
* ebx = 4 - номер подфункции |
Возвращаемое значение: |
* eax = 0 - успешно |
* eax = -1 - отсутствует область главного списка или нет блокировки |
Замечания: |
* Используется в исключительных случаях, когда зависшее или убитое |
приложение заблокировало работу с буфером обмена. |
====================================================================== |
====================== Функция 55, подфункция 55 ===================== |
========== Начать проигрывать данные на встроенном спикере. ========== |
====================================================================== |
3495,6 → 3568,32 |
номер сигнала соответствует номеру исключения. |
====================================================================== |
= Функция 68, подфункция 26 - освободить страницы памяти ============ |
====================================================================== |
Параметры: |
* eax = 68 - номер функции |
* ebx = 26 - номер подфункции |
* ecx = указатель на блок памяти выделенный подфункцией 12 |
* edx = смещение от начала блока |
* esi = размер высвобождаемого блока памяти, в байтах |
Примечания: |
* функция освобождает страницы с ecx+edx по ecx+edx+esi |
и устанавливает виртуальную память в зарезервированное состояние. |
====================================================================== |
= Функция 68, подфункция 27 - загрузить файл =================== |
====================================================================== |
Параметры: |
* eax = 68 - номер функции |
* ebx = 27 - номер подфункции |
* ecx = указатель на ASCIIZ-строку с именем файла |
Возвращаемое значение: |
* eax = указатель на загруженный файл или 0 |
* edx = размер загруженного файла или 0 |
Примечания: |
* функция загружает и, при необходимости, распаковывает файл (kunpack) |
====================================================================== |
======================== Функция 69 - отладка. ======================= |
====================================================================== |
Процесс может загрузить другой процесс как отлаживаемый установкой |
/kernel/branches/Kolibri-acpi/docs/sysfuncs.txt |
---|
33,7 → 33,7 |
* other possible values (from 5 up to 15) are reserved, |
function call with such Y is ignored |
* RR, GG, BB = accordingly red, green, blue components of a color |
of the working area of the window (are ignored for style Y=2) |
of the working area of the window (are ignored for style Y=1) |
* X = DCBA (bits) |
* A = 1 - window has caption; for styles Y=3,4 caption string |
must be passed in edi, for other styles use |
46,7 → 46,7 |
of a type I and II, and ignored for styles Y=1,3: |
* esi = 0xXYRRGGBB - color of the header |
* RR, GG, BB define color |
* Y=0 - usual window, Y=1 - unmovable window |
* Y=0 - usual window, Y=1 - unmovable window (works for all window styles) |
* X defines a gradient of header: X=0 - no gradient, |
X=8 - usual gradient, |
for windows of a type II X=4 - negative gradient |
367,6 → 367,7 |
* bit 1 (mask 2): window is minimized to panel |
* bit 2 (mask 4): window is rolled up |
* +71 = +0x47: dword: event mask |
* +75 = +0x4B: byte: keyboard mode(ASCII = 0; SCAN = 1) |
Remarks: |
* Slots are numbered starting from 1. |
* Returned value is not a total number of threads, because there |
411,7 → 412,7 |
of its window are considered to be zero. |
* Coordinates of the client area are relative to the window. |
* At the moment only the part of the buffer by a size |
71 = 0x37 bytes is used. Nevertheless it is recommended to use |
76 = 0x4C bytes is used. Nevertheless it is recommended to use |
1-Kb buffer for the future compatibility, in the future |
some fields can be added. |
1785,7 → 1786,7 |
sysdir_path rb 64 |
For example: |
dir_name1 db 'KolibriOS',0 |
rb 64-8 |
rb 64-10 |
dir_path1 db 'HD0/1',0 |
rb 64-6 |
Returned value: |
2010,7 → 2011,7 |
* eax = 40 - function number |
* ebx = mask: bit i corresponds to event i+1 (see list of events) |
(set bit permits notice on event) |
bit 31: active/inactive filter |
bit 31: mouse active/inactive filter |
bit 31 = 0 - inactive window receive mouse events |
bit 31 = 1 - inactive window does not receive mouse events |
bit 30: cursor position filter |
2411,6 → 2412,70 |
</UL> |
====================================================================== |
==================== Function 54, subfunction 0 ====================== |
============== Get the number of slots in the clipboard. ============= |
====================================================================== |
Parameters: |
* eax = 54 - function number |
* ebx = 0 - subfunction number |
Returned value: |
* eax = slots in the clipboard |
* eax = -1 - main list area not found |
====================================================================== |
==================== Function 54, subfunction 1 ====================== |
================= Read the data from the clipboard. ================== |
====================================================================== |
Parameters: |
* eax = 54 - function number |
* ebx = 1 - subfunction number |
* eсx = slot number |
Returned value: |
* eax = if successful - pointer to a memory with data |
* eax = 1 - error |
* eax = -1 - main list area not found |
====================================================================== |
==================== Function 54, subfunction 2 ====================== |
================= Write the data to the clipboard. =================== |
====================================================================== |
Parameters: |
* eax = 54 - function number |
* ebx = 2 - subfunction number |
* eсx = the number of bytes to be copied |
* edx = a pointer to a buffer for data to be copied |
Returned value: |
* eax = 0 - success |
* eax = 1 - error |
* eax = -1 - main list area not found |
====================================================================== |
===================== Function 54, subfunction 3 ===================== |
================ Delete the last slot in the clipboard =============== |
====================================================================== |
Parameters: |
* eax = 54 - function number |
* ebx = 3 - subfunction number |
Returned value: |
* eax = 0 - success |
* eax = 1 - error |
* eax = -1 - main list area not found |
====================================================================== |
===================== Function 54, subfunction 4 ===================== |
===================== Alarm reset the lock buffer ==================== |
====================================================================== |
Parameters: |
* eax = 54 - function number |
* ebx = 4 - subfunction number |
Returned value: |
* eax = 0 - success |
* eax = -1 - main list area not found or no blocking |
Remarks: |
* Used in exceptional cases, where no responsible or killed |
application blocked the clipboard operations. |
====================================================================== |
Function 55, subfunction 55 - begin to play data on built-in speaker. |
====================================================================== |
Parameters: |
3953,7 → 4018,7 |
* +0: dword: 2 = subfunction number |
* +4: dword: 0 (reserved) |
* +8: dword: 0 (reserved) |
* +12 = +0xC: dword: number of bytes to read |
* +12 = +0xC: dword: number of bytes to write |
* +16 = +0x10: dword: pointer to data |
* +20 = +0x14: ASCIIZ-name of file, the rules of names forming are |
given in the general description |
/kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt |
---|
0,0 → 1,249 |
Когда ядро обнаруживает подключенное устройство 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 |