Драйверы устройств, как правило, – наиболее критичная часть программного обеспечения компьютеров. По иронии судьбы, это также и наиболее скрытая часть системы и программного обеспечения. Драйверы устройств системы Windows фирмы Microsoft не являются исключением. Наоборот, если в UNIX можно взять исходники ядра и помотреть, как там пишутся драйвера, то в Windows это вряд ли будет возможным.
Вспомним первые персоналки и MS DOS, бывшую в то время практически единственным выбором для настольного ПК. Несмотря на всю ее просто ту, драйвера, конечно, присутствовали и в ней. Практически все дело ограничивалось накoпителями — дисководами, CD-ROM приводами, винчестерами, да элементарнейшими драйверами клавиатуры и дисплея. Для каждой программы, требующей большего, чем перечисленный набор оборудования, требовалось создавать собственный драйвер. Представьте себе, что вам требуется воспроизвести звук на имеющейся в компьютере звуковой карте. Если вы знаете ее модель и у вас есть хорошая документация, вы, потратив немало времени, напишете прoграмму, которая сделает все желаемое. По крайней мере, так утверждает идеология открытых систем в общем и Linux в частности. А если необходимо поддерживать две модели? Три? Двадцать? И это при учете того, что новая звуковая карта появляется не реже раза в полтора-два месяца? И все они могут быть подключены различными способами и общаться с компьютером через разнообразные шины? Естественный выход — возложить написание кода, специфичного для аппаратуры, на ее создателя. Да и фирма-производитель, наняв высококвалифицированных специалистов, справится с задачей намного эффективнее и быстрее. Во всех современных операционных системах так и поступают. Существуют требования, например, к драйверу звуковой карты, и пользователь устанавливает тот вариант, который соответствует его "железу". А программа-проигрыватель через вызовы системных функций указывает, что именно она хотела бы воспроизвести, не заботясь об особенностях аппаратуры.
Данный труд не является руководством по написанию драйверов устройств под Windows — для этого пришлось бы писать пару толстых книжек. В нем рассматриваются вопросы написания простого драйвера PCI-устройства под Win 98/ME/2000 с использованием архитектуры драйверов WDM и пакета NuMega DriverStudio. В дальнейшем, будем считать, что нашей целью будет драйвер, работающий на компьютере с архитектурой ЦП i386 под управлением вышеупомянутых ОС. Наше гипотетическое устройство — это PCI–карточка, имеющая некоторое количество памяти.
Прилагаемые к руководству исходные тексты драйвера и программ работы с ним были проверены на PCI-карточке XDSP680c.
Руководство изначально писалось как методические указания для курса "Специальные компьютерные системы" специальности "Компьютерные системы и сети" Черниговского государственного технологического университета, но затем было переработано и дополнено. Предполагается, что читатель знаком с основами программирования под Win32 и средой Visual C++.
1. Общие сведения о драйверах устройств в системе Windows.
Естественно, каждая операционная система имеет собственную архитектуру и свои особенности функционирования драйверов. Но практически во всех современных ОС можно выделить следующие особенности, характерные для работы подсистемы ввода-вывода:
• Фактически, пользовательские программы либо системные утилиты не могут напрямую обращаться к аппаратуре, используя порты ввода-вывода, DMA либо подобные низкоуровневые механизмы напрямую. Этот факт следует из самой идеологии защищенного режима современных ОС: все программы пользователя и часть ОС работают в 3-м кольце защиты компьютера (наименее привилегированном). При этом любая команда обращения к порту из данной программы может быть замаскирована и повлечет за собой аппаратное исключение (Exception). Напрямую к аппаратуре может обратится программа, работающая в самом приоритетном, 0-м кольце защиты.
• В настоящее время практически все устройства используют технологию автоматического распределения ресурсов (портов ввода-вывода, запросов на прерывания и т.п.) — Plug and Play (PnP). Когда новое устройство, например, та же звуковая карта, будет добавлена в систему, ей будут выделены те ресурсы, которые в данный момент свободны — незадействованные линии запросов на прерывание (IRQ), свободные адреса портов ввода-вывода. Поэтому драйвер изначально "не знает", какие именно адреса портов и IRQ ему будут выделены — эти данные будут различными для разных компьютеров. При этом задача распределения ресурсов ложится на ОС.
В ОС Windows, как и в большинстве современных ОС, драйвера управляют буквально всем: работой с аппаратурой, поддержкой файловых систем различных типов, сетевых протоколов и т.п. Это дает определенные преимущества и делает систему более гибкой: например, для того, чтобы ОС стала "понимать" другой сетевой протокол, нужно всего лишь установить соответствующий драйвер. 1.1 Система ввода-вывода в Windows.
На данный момент наиболее распространены два семейства ОС Windows: Windows NT, куда относятся Windows NT, 2000, XP, и Windows 9x (Win 95, 98, ME). При этом отмечается тенденция к отмиранию ветки 9х, хотя такие системы будут встречаться еще достаточно долго. Каждая ветка использует свою архитектуру ядра и подсистемы ввода-вывода. Поэтому естественно, написание драйверов для этих систем должно отличаться.