Драйвер устройства – программный компонент, обеспечивающий согласованное взаимодействие прикладного и системного ПО с аппаратурой через стандартизированный интерфейс. Он инкапсулирует особенности протоколов ввода-вывода, регистров, прерываний, прямого доступа к памяти (DMA), очередей и буферов. В тексте формализованы понятия «устройство», «контроллер», «драйвер», «шина», «регистры», «прерывание», «IOCTL», «диспетчеризация IRP/запросов», «оконные/кольцевые буферы», «синхронизация», «модель памяти», «энергосостояния», «Plug-and-Play (PnP)». Показано, как навыки ЕГЭ (алгоритмизация, конечные автоматы, работу с файлами/строками/битовыми масками, оценку сложности) переносятся на моделирование драйверов. Даны строгие правила корректного проектирования и пять упражнений формата ЕГЭ.
Устройство – физический модуль (датчик, сетевая карта, накопитель).
Контроллер – логика управления устройством (м/схема, IP-ядро), предоставляющая регистры и/или DMA-движок.
Драйвер – программный адаптер между ОС и контроллером.
Шина – среда подключения (PCIe/USB/I²C/SPI и др.) и её протоколы обнаружения/адресации.
Прерывание – асинхронный сигнал от устройства процессору/контроллеру прерываний.
MMIO/PIO – доступ к регистрам через отображение в адресное пространство (Memory-Mapped I/O) или через порты.
IOCTL – управляющий запрос, расширяющий базовые операции чтение/запись.
PnP/PM – Plug-and-Play и управление питанием (состояния устройства/шины).
Граница режимов:
Пользовательский режим – прикладные процессы, системные вызовы, файловые дескрипторы.
Режим ядра – планирование, память, стек драйверов, обработка прерываний, DMA.
Типичный путь запроса:
Приложение вызывает системную функцию (например, read/write/ioctl).
Диспетчер ввода-вывода ОС формирует объект запроса (IRP/URB/transfer).
Запрос проходит по стеку драйверов (фильтры → функциональный драйвер устройства → шина).
Функциональный драйвер переводит запрос в транзакции контроллера: запись в регистры, программирование DMA, ожидание прерывания, копирование данных в буферы.
По завершении драйвер завершает запрос статусом/данными, управление возвращается приложению.
Иерархия (обобщённо): драйвер шины ↔ драйвер класса ↔ драйвер функции ↔ фильтры (верхний/нижний).
Опрос (polling)
ЦП периодически читает регистр состояния.
Плюсы: простота, пригодно для медленных устройств.
Минусы: расход ЦП, задержки.
Сложность: O(k) на «жизненный цикл» запроса, где k – число итераций опроса.
Прерывания (interrupt-driven)
Устройство сигнализирует о готовности/ошибке.
Плюсы: низкая задержка, экономия ЦП.
Минусы: сложность синхронизации, необходимость удерживать обработчик ISR минимальным.
Шаблон: ISR (минимальный) фиксирует причину, планирует deferred handler (DPC/bottom half), который двигает данные и завершает запросы.
DMA (прямой доступ к памяти)
Контроллер сам читает/пишет системную память по описателям.
Плюсы: высокая пропускная способность, минимальная нагрузка на ЦП.
Минусы: настройка таблиц, выравнивание, кэш/барьеры памяти, IOMMU/разрешения.
Кольцевой буфер (ring buffer) – массив фиксированного размера с указателями head/tail, модульная арифметика.
Очереди запросов – на запись (TX) и чтение (RX).
Правила:
Каждое событие изменяет ровно один из указателей; инвариант «не переполнено/не пусто» поддерживается условием (head+1) mod N != tail (для FIFO).
Производитель и потребитель, возможно, в разных контекстах (ISR/поток) – обязательны барьеры памяти.
Для DMA буферы должны быть неперемещаемыми и (при необходимости) кэш-согласованными
Критические секции/спинлоки защищают разделяемые структуры между ISR/DPC/рабочими потоками.
Атомарные операции (инкремент счётчика, CAS) – без зацепок между прерываниями.
Барьеры памяти гарантируют порядок: запись дескриптора → барьер → запись «doorbell» в регистр.
Правило минимизации времени в ISR: ISR только фиксирует событие и будит нижний уровень.
Plug-and-Play, энергосбережение, конфигурация
PnP-события: обнаружение, старт/стоп, удаление. Драйвер обрабатывает ресурсы (IRQ, MMIO, DMA-каналы).
Power Management: D-состояния устройства, переходы спящий/рабочий, сохранение контекста регистров.
Правило «безопасной паузы»: перед усыплением – остановить приём новых запросов, опустошить очереди, сохранить состояние.

Файловый интерфейс: open/close/read/write.
IOCTL: управляющие команды (настройка скорости, режимов, таймаутов). Формат – структура с полями и битовыми масками.
Событийная модель: неблокирующее чтение, ожидание по объекту синхронизации, промежуточные буферы ядра.
Инварианты корректности:
Реестры конфигурируются только в допустимых комбинациях битов.
Очереди никогда не переполняются/не читаются из пустых.
Каждый запрос имеет путь завершения (успех/ошибка/отмена).
Ошибки устройства → перевод в безопасное состояние, логирование, ограниченные повторные попытки (backoff).
Типовые ошибки и защита:
Гонки ISR↔поток → использовать спинлок/барьеры.
«Забытый» маппинг DMA → кэш-инвалидация/очистка.
Неконтролируемые IOCTL → проверка размеров/прав доступа/выравнивания.
«Зависшее» устройство → watchdog/сброс контроллера.
Состояния: Detached → Enumerated → ResourcesReady → Started → Running ↔ Suspended → Stopping → Removed.
Переходы порождаются событиями PnP/PM/ошибок/команд IOCTL.
Плюс для ЕГЭ: умение строить таблицы переходов/диаграммы, проверять достижимость и детерминизм – это те же навыки, что и в задачах на автоматы/логические схемы.
Алгоритмизация: драйвер – композиция процедур с чёткими пред- и постусловиями.
Конечные автоматы: обработка прерываний и PnP/PM – классические автоматы с событиями.
Битовые операции: конфигурация регистров через маски (AND/OR/XOR, сдвиги).
Обработка данных/файлов: кольцевые буферы и очереди – задачи на массивы/индексы/инварианты.
Оценка сложности: сравнение polling vs interrupt (время/операции), расчёт пропускной способности и размера буфера.
Трассировка программ: пошаговый разбор «ISR→DPC→завершение запроса».
Инициализация и старт
on DeviceStart():
mapMMIO()
setupIRQ()
initQueues()
programDMA(descriptors)
enableInterrupts()
state := Running
Обработчик прерывания (ISR) и нижний уровень
on ISR():
cause := read(REG_STATUS)
if cause & RX_READY:
ack(REG_STATUS, RX_READY)
schedule(DPC_RX)
if cause & TX_DONE:
ack(REG_STATUS, TX_DONE)
schedule(DPC_TX)
return handled
on DPC_RX():
while hasCompletedDMA(RX):
pkt := takeFromRxRing()
copyToUserOrKernelBuffer(pkt)
completeOneReadRequest()
on DPC_TX():
while hasSpace(TX):
req := dequeueWriteRequest()
fillDescriptor(req)
ringDoorbell(TX)
IOCTL c масками
on IOCTL_SET_MODE(arg):
// arg: битовая маска [bit0=enable, bit1=loopback, bit2..=speed]
if invalid(arg): return ERROR
reg := read(REG_CTRL)
reg := (reg & ~MASK_MODE) | (arg & MASK_MODE)
write(REG_CTRL, reg)
return OK
Минимум логики в ISR, максимум – в DPC/потоках.
Доказуемые инварианты для очередей/буферов, атомарные обновления указателей.
Барьеры памяти при взаимодействии с устройством (doorbell после описателей).
Чёткие контракты API (форматы IOCTL, проверка границ, статусов).
Отказоустойчивость и восстановление (watchdog, сброс, backoff).
PnP/PM-согласованность (остановка приёма, слив очередей, сохранение контекста перед сном).
Безопасность (валидация входа, права доступа, избегание переполнений).
Упражнение 1. Трассировка прерываний
Условие. По очереди событий: RX_READY, TX_DONE, RX_READY и кодам ISR/DPC, укажите порядок вызовов ISR/DPC_RX/DPC_TX и моменты завершения запросов чтения/записи.
Критерии. Понимание «верхняя/нижняя половина», учёт подтверждения статуса, корректная последовательность завершений.
Подсказки. Каждое событие в ISR планирует соответствующий DPC; DPC может полностью опустошать очередь.
Упражнение 2. Битовые маски регистра
Условие. Регистр CTRL (8 бит): b0=EN, b1=LOOP, b2..b3=SPEED(00=10Мб/с, 01=100, 10=1000, 11=резерв), b4=INT_EN, b5..b7=0.
Установите EN=1, INT_EN=1, SPEED=1000, LOOP=0.
Запишите формулу для изменения только полей SPEED и INT_EN, не затронув остальных.
Критерии. Правильные маски/сдвиги, отсутствие изменения других битов.
Подсказки. reg = (reg & ~MASK_SPEED) | (2<<2); reg |= (1<<4); reg |= (1<<0); reg &= ~(1<<1).
Упражнение 3. Размер кольцевого буфера
Условие. Поток пакетов со скоростью R пак/с, среднее время обработки пакета на нижнем уровне T сек. Чтобы вероятность переполнения была пренебрежима при всплесках до k пакетов сверх среднего за Δ секунд, предложите формулу минимального N – размера кольцевого буфера.
Критерии. Учёт «рабочего запаса»: N≥⌈R⋅T⌉+k. При пакетизации по DMA партиями – прибавьте максимум незавершённых дескрипторов.
Подсказки. Интерпретация как система «производитель–потребитель».
Упражнение 4. Автомат PnP/PM
Условие. Постройте минимальный конечный автомат состояний Detached, Enumerated, Started, Running, Suspended, Removed с переходами по событиям: found, resources_ok, start, suspend, resume, stop, remove. Укажите недопустимые переходы.
Критерии. Детерминизм, отсутствие висячих состояний, корректные циклы Running↔Suspended.
Подсказки. Removed – поглощающее; из Detached только found.
Упражнение 5. Анализ сложности polling vs interrupt

Работа драйвера устройства – это строго организованная обработка событий ввода-вывода, где алгоритмы, инварианты и модели данных столь же важны, как знание интерфейсов ОС. Формализация через конечные автоматы, очереди, буферы, прерывания и DMA делает поведение доказуемым и эффективным. Для ЕГЭ полученные навыки напрямую применимы: построение автоматов, работа с битовыми масками и массивами, оценка сложности, трассировка программ и корректная обработка ошибок. Осваивая эти принципы, ученик не только лучше решает экзаменационные задачи повышенной сложности, но и получает фундамент для системного программирования.