diff --git a/kernel/trunk/docs/events_subsystem.txt b/kernel/trunk/docs/events_subsystem.txt new file mode 100644 index 0000000000..ffd2f83913 --- /dev/null +++ b/kernel/trunk/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 . +--------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/kernel/trunk/docs/usbapi_ru.txt b/kernel/trunk/docs/usbapi_ru.txt new file mode 100644 index 0000000000..cf89079d4e --- /dev/null +++ b/kernel/trunk/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 \ No newline at end of file