1 | Содержание | 3

Управление вводом-выводом: железо с точки зрения ядра.

Устройства бывают разные. Бывают стандартные устройства, которые понимает система. Система самостоятельно работает с таймером, мышью, клавиатурой, видеокартой, аудио, системным динамиком, сетевыми картами, CD/DVD, жёсткими дисками, не давая приложениям доступа к этим устройствам напрямую.

Для получения данных мыши есть специальная сисфункция 37 (подфункции 0,1,2,7 - получить информацию о разных аспектах происходящего с мышью) и специальное событие - при любом дёргании мыши система извещает всех подряд, что с мышью что-то произошло (по умолчанию поток не реагирует на события мыши, а должен явно установить маску учитываемых событий, разрешающую событие мыши). Приложение может управлять формой курсора мыши (сисфункция 37, подфункции 4,5,6) для своего окна (когда курсор проходит над окном потока, он принимает заданную форму; физически хэндл курсора для окна хранится в структуре для потока, но логически это скорее атрибут окна, поэтому я его не указал в предыдущем посте). Приложение может управлять настройками движения мыши, может переместить курсор в нужную позицию, может симулировать нужное состояние клавиш мыши - всё это функцией 18.19 (есть ещё хронологически более старая функция 18.15: поместить курсор в центр экрана). Кроме того, приложение может определить некоторое количество кнопок (кнопки реализованы в ядре). Кнопка - прямоугольная область в окне (ядро обычно рисует их самостоятельно, но приложение может попросить ядро не делать этого), которой приписан (приложением) некоторый идентификатор; при нажатии на кнопку мышью ядро посылает потоку-владельцу окна событие о нажатии кнопки.

Внутренне в системе происходит следующее. Есть поддержка COM-мышей и обычных PS/2, и то, и другое вынесено в драйвера (commouse.obj, ps2mouse.obj соответственно). Ядро экспортирует для драйверов функцию SetMouseData (это имя для драйверов; реализована в [hid/mousedrv.inc, set_mouse_data]; драйвер мыши при поступлении очередного события вызывает эту функцию с нужными аргументами, сообщая ядру, что именно произошло с мышью. Ядро преобразует данные о движении мыши в перемещения курсора в соответствии с настройками (18.19), обновляет свои переменные (из которых впоследствии берёт информацию для 37) и устанавливает флаг активности мыши [mouse_active]; когда главный цикл системы получит управление, он проверит этот флаг и известит все приложения, что что-то произошло с мышью. Работа идёт по схеме (мышь) <-> (драйвер) <-> (ядро) <-> (приложения); PS/2-драйвер предоставляет определённые API приложению напрямую (версия драйвера и тип мыши), но их никто не использует.

Работа с клавиатурой. Здесь полезны комментарии к функции 2 из документации. У приложения есть два режима получения данных о нажатых клавиш: ASCII и сканкоды, переключение - функция 66. Судьба нажатой клавиши зависит от следующих вещей: Обработчик клавиатуры [hid/keyboard.inc, irq1] обновляет состояние клавиатуры (Alt/Shift/Ctrl/*Lock) для клавиш-модификаторов (и переключает огоньки на клаве при нажатии *Lock); проверяет, не нажато ли Ctrl+Alt+Del, и если да, то устанавливает соответствующий флаг, который будет проверен главным циклом системы, когда тот получит управление (что приведёт к запуску приложения /sys/cpu); сканирует список установленных горячих комбинаций и, если такая комбинация зарегистрирована, посылает событие клавиатуры зарегистрированному приложению (пример: @panel регистрирует нажатие на клавишу Win для вызова меню и комбинации типа Alt+F4, Alt+Tab, Alt+Shift+Tab и Ctrl+Shift - полный список есть в hot_keys.htm, API здесь - та же функция 66), а если нет, то кладёт её в буфер нажатых клавиш для активного окна (есть такой системный массив на 120 байт), что активирует событие клавиатуры для потока-владельца активного окна. Как именно кладёт, зависит от режима: в сканкодном просто кладёт сканкод, полученный от клавиатуры, а в ASCII-режиме клавиши-модификаторы и события об отпускании клавиш просто игнорирует, а нормальные клавиши транслирует в ASCII-коды с помощью таблиц преобразования. Таблицы для каждого языка свои, переключение языка заключается в установке правильной таблицы (это делает приложение @panel), API - 21.2, 26.2. Клавишам F1-F12 тоже соответствуют определённые коды, которые совпадают с нормальными клавишами (например, F1='2',F5='6'), и в результате приложения, работающие в этом режиме (например, sysxtree, eolite, mtdbg), не могут отличить кнопку F5 и цифру 6.

На уровне системы: поддержка клавиатуры зашита в ядре (уже упоминавшийся обработчик irq1 из hid/keyboard.inc). Схема обработки:
(клавиатура) <-> (ядро) <-> (приложения).

Работа с видеокартой - это, собственно, GUI, на тему которого можно говорить отдельно довольно долго. Ограничиваясь работой с железом:
здесь схема работы в типичном случае выглядит так:
    (видеокарта) <-> (ядро) <-> (приложения),
             \        /
             (драйвер)
    
в менее типичных случаях приложения могут обращаться напрямую к драйверу и/или framebuffer'у видеокарты.

Поддержка аудио есть для SB-совместимых карт и для AC97-кодеков на определённом железе, здесь ядро уже не принимает прямого участия, а приложение общается напрямую с соответствующим драйвером (infinity.obj, в свою очередь опирающийся на драйвер sound.obj/sis.obj, какой именно, зависит от железа). Драйвер предоставляет соответствующие API.

Системным динамиком приложение может попищать с помощью функции 55.55, но только если это разрешено в настройках (с точки зрения пользователя: есть иконка в "трее" - правой части @panel, включающей этот режим, по умолчанию писк запрещён; если включить, можно понаслаждаться писком при открытии меню и запуска программ по иконкам и через трей). Данные для функции 55.55 - это ноты в определённом формате (описанном в документации), ядро пересчитывает их в нужную последовательность частот с задержками и на основании результатов вычислений пишет нужные значения в третий канал таймера - порты 42h/43h (и 61h для включения/выключения динамика), код в [sound/playnote.inc, playNote].

Системным таймером управляет исключительно ядро. При загрузке система программирует таймер на срабатывание 100 раз в секунду. Обработчик прерывания от таймера, [core/sched.inc, irq0], делает следующее: Работа с сетевыми картами зашита в ядро (папка network, работа с железом сидит в network/eth_drv/drivers). API для работы с сетью - сисфункции 52 и 53, но работа с сетью - это отдельный разговор.

CD/DVD бывают с данными и музыкальные. Музыкальные CD при определённых условиях может проигрывать сам привод, для поддержки этого есть сисфункция 24 (подфункции 1,2,3), поддержка зашита в ядро [blkdev/cdrom.inc, sys_cd_audio]. Чтение данных с CD/DVD, равно как и работа с жёсткими дисками и дискетами, относится скорее к области файловой системы ("железная" часть, впрочем, как и всё остальное, зашита в ядро: blkdev/cd_drv.inc для работы с CD/DVD, blkdev/flp_drv.inc для работы с дискетами, blkdev/hd_drv.inc для работы с жёсткими дисками (собственными силами обрабатывает ATA, обращается к BIOS для поддержки BIOS-дисков через V86 из core/v86.inc).

1 | Содержание | 3

Pterox' DocPack R6. Last Edition: 29.05.2010. История выпусков