Драйвер клавиатуры, реализующий функции музыкального синтезатора на клавиатуре для Windows NT 5

Архитектура Windows NT 5. Приоритеты выполнения программного кода. Описание формата MIDI-данных. Установка драйвера в системе. Выбор средств разработки программного обеспечения. Обработка запросов драйверной модели WDM. Использование библиотеки DirectKS.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 24.06.2009
Размер файла 498,8 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Факультет информатики и систем управления

Кафедра ПО ЭВМ и информационные технологии

РАСЧЕТНО-ПОЯСНИТЕЛЬНАЯ ЗАПИСКА

к курсовой работе на тему:

Драйвер клавиатуры, реализующий функции музыкального синтезатора на клавиатуре для Windows NT 5

Содержание

1. Введение

2. Конструкторский раздел

2.1 Постановка задачи

2.2 Архитектура Windows NT 5

2.3 Драйверная модель WDM

2.3.1 Функции загрузки/выгрузки драйвера

2.3.2 Функции обработки запросов/прерываний

2.4 Приоритеты выполнения программного кода

2.5 Стек клавиатуры

2.6 Kernel Streaming

2.7 Описание формата MIDI-данных

2.8 Выбор структуры программного обеспечения

2.8.1 Драйвер-фильтр

2.8.2 Получение доступа к аудиоустройству

2.8.3 Взаимодействие компонент программного обеспечения

2.9 Алгоритм работы драйвера-фильтра

2.9.1 Функции загрузки/выгрузки драйвера

2.9.2 Функции обработки пакетов IRP

2.9.3 Функции работы с аудио-устройством

2.9.4 Схема хранения музыкальных параметров клавиш

2.9.5 Разделение задачи на потоки

3. Технологический раздел

3.1 Выбор средств разработки программного обеспечения

3.2 Установка драйвера в системе

3.3 Сборка программного обеспечения

3.4 Использование библиотеки DirectKS

3.5 Отправление запросов из приложения в драйвер

3.6 Описание интерфейса пользователя

3.7 Тестирование программного обеспечения

4. Заключение

5. Список литературы

6. Приложения

6.1 Функции установки драйвера в системе

6.2 Изменения в библиотеке DirectKS

1. Введение

В современных вычислительных системах важнейшую роль играет подсистема ввода/вывода. Известно, что примерно 80% инструкций программы связаны с этой подсистемой. В связи с этим в настоящее время возрастает актуальность разработки программных систем, осуществляющих взаимодействие с периферийными устройствами посредством подсистемы ввода/вывода.

Данное программное обеспечение позволяет организовать настраиваемое звуковое сопровождение нажатий клавиш на клавиатуре. Существует множество вариантов его применения, среди которых можно выделить следующие:

Упрощение работы с компьютером людям со слабым зрением.

Создание MIDI-синтезатора на клавиатуре.

Создание системы звуковой сигнализации.

В стандартную поставку ОС Microsoft Windows XP Professional входят компоненты, обеспечивающие специальные возможности операционной системы для пользователей с различными отклонениями в здоровье. Среди этих компонент следует отметить:

«Экранную клавиатуру», с помощью которой, в частности, можно озвучить выбор клавиш мышью.

Возможность озвучивания нажатий клавиш Num, Caps и Scroll Lock.

Характерной особенностью вышеперечисленных компонент является подача сигнала одной частоты независимо от нажатой клавиши и невозможность настройки параметров звучания. В этой связи представляется целесообразной разработка нового программного обеспечения, позволяющего организовать звуковое сопровождение клавиатуры в более полном объеме, в частности, настраивать выборочное озвучивание клавиш.

2. Конструкторский раздел

2.1 Постановка задачи

В соответствии с заданием на курсовую работу необходимо разработать программное обеспечение для решения следующих задач:

Вывод музыкальных нот с заданными параметрами при нажатии клавиш.

Возможность настройки пользователем параметров звучания клавиш.

Программное обеспечение состоит из двух взаимодействующих частей:

Драйвер-фильтр, реализующий первую задачу.

Программа настройки, реализующая вторую задачу.

Требования к программному обеспечению:

Драйвер-фильтр должен отслеживать нажатия всех клавиш клавиатуры PS/2 и генерировать музыкальные ноты с соответствующими клавише параметрами.

Программа настройки должна позволять пользователю редактировать параметры звучания клавиш, предоставляя удобный интерфейс.

В качестве устройства для вывода музыкальных нот используется синтезатор MIDI, встроенный в звуковую карту Sound Blaster.

Приоритетным критерием при разработке продукта является производительность для драйвера-фильтра и удобство пользователя для программы настройки.

Программное обеспечение ориентировано на работу в ОС Windows NT 5. Функционирование программного обеспечения не должно влиять на работу других драйверов системы.

2.2 Архитектура Windows NT 5

Архитектура Windows NT 5 соответствует классическим представлениям о проектировании операционных систем. Наиболее распространены реализации данной ОС для платформы Intel x86 в одно- или многопроцессорных конфигурациях, однако существуют также версии для DEC Alpha и MIPS. Windows NT 5 использует защищённый режим центрального процессора, реализует механизмы виртуальной памяти и многозадачности.

Исполняемый код в Windows NT 5 имеет два уровня привилегий: код пользовательского режима и код режима ядра. Уровень привилегий накладывает определённые ограничения: в пользовательском режиме не могут выполняться привилегированные инструкции процессора, не разрешено обращение к защищённым страницам памяти. Эти ограничения накладываются для обеспечения безопасности работы системы. Пользовательское приложение не должно иметь возможность в результате ошибки или преднамеренно вносить изменения в критические таблицы операционной системы или в память других приложений. В частности, такие ограничения запрещают пользовательскому приложению напрямую управлять внешними устройствами, потому что каждое из них является разделяемым ресурсом.

В Windows NT 5 обеспечение обмена данными и управление доступом к внешнему устройству как к разделяемому ресурсу возлагается на его драйвер. Ввод и вывод в драйверах осуществляется посредством IRP-пакетов (Input/Output Request Packet). Запросы на ввод/вывод, посылаемые приложениями или другими драйверами, обрабатываются драйвером, после чего запрашивающей программе в том же пакете посылается статус завершения операции. Общий принцип взаимодействия проиллюстрирован на рис. 2.1.

Рис.2.1. Архитектура ввода/вывода Windows NT 5

Управление внешним устройством в общем случае сводится к заполнению его регистров необходимыми данными. Монопольный доступ драйвера к этим регистрам гарантируется операционной системой. Очевидно, что при данных обстоятельствах требуется, чтобы драйвер устройства выполнялся в режиме ядра.

Обобщённая классификация драйверов Windows NT 5 может быть представлена следующим образом:

Драйверы режима ядра:

Унаследованные драйверы

Драйверы файловой системы

Видеодрайверы

Драйверы PnP (Plug And Play):

Драйверы WDM

Драйверы пользовательского режима:

Драйверы виртуальных устройств

2.3 Драйверная модель WDM

Windows Driver Model (WDM) -- это стандартная спецификация Microsoft для разработчиков драйверов устройств. Она поддерживается в операционных системах Windows 98/Me/2000/XP. Компания Microsoft требует, чтобы все новые драйверы под эти операционные системы создавались по этой спецификации. Для этого от них требуется чёткое следование структуре WDM, поддержка Plug and Play и управления электропитанием.

Драйверная модель WDM построена на организации и манипулировании слоями объектов физических устройств (PDO, Physical Device Object) и объектов функциональных устройств (FDO, Functional Device Object).

Объект PDO создается для каждого физически идентифицируемого элемента аппаратуры, подключенного к шине данных, и подразумевает ответственность за низкоуровневый контроль, достаточно общий для набора функций реализуемых этим аппаратным элементом. Объект PDO - это особая структура данных, создаваемая системой для взаимодействия программного и аппаратного обеспечения.

Объекты FDO подразумевает единицу логической функциональности устройства.

Объектам FDO устройств разрешается окружать себя Объектами Фильтрами (FiDO, Filter Device objects) как показано на рис. 2.2. Соответственно, каждому FiDO объекту сопоставлен драйвер, который выполняет определенную работу. Объекты фильтры подразделяются на фильтры нижнего уровня и фильтры верхнего уровня. И тех и других может существовать произвольное количество. Они модифицируют процесс обработки запросов ввода/вывода. Объекты FDO и FiDO отличаются только в смысловом отношении. FDO объект и его драйвер считаются главными. Они обычно обеспечивают управление устройством, а объекты FiDO являются вспомогательными.

Рис. 2.2. Стек устройств

Все объекты FDO и FiDO позиционируют себя в стеке устройств. Порядок объектов в стеке определяет порядок обработки запросов ввода-вывода. Если необходимо перехватить и обработать запрос, непосредственно идущий от пользователя, то нужно устанавливать верхний фильтр. Если же нужно отслеживать обращение к портам ввода вывода, обрабатывать прерывания, то нужен нижний фильтр. Данная модель позволяет драйверу устанавливать callback процедуры. Когда запрос начинает обрабатываться, то он обрабатывается последовательно всеми драйверами стека устройства ( исключая ситуацию, когда какой-либо драйвер сам завершит обработку запроса ). После этого диспетчер ввода-вывода передает запрос callback процедуре каждого драйвера стека. Сначала запрос передается callback процедуре последнего драйвера который в стеке, потом процедуре предпоследнего драйвера и т.д. Callback процедуры нужны для того, чтобы обработать прочитанную из устройства информацию. Если фильтр обрабатывает запросы на чтение, то когда этот запрос поступит в драйвер информация еще не будет считана. Поэтому драйверу необходимо установить callback функцию. При ее вызове запрос уже будет содержать считанные данные.

Драйвер имеет следующие точки входа:

DriverEntry

DriverUnload

AddDevice

Функции для обработки пакетов IRP

ISR

2.3.1 Функции загрузки/выгрузки драйвера

WDM-драйверы отличаются от унаследованных драйверов тем, что должны содержать дополнительные точки входа для поддержки PnP. Приведем список точек входа и кратко охарактеризуем их назначение.

NTSTATUS DriverEntry(

IN PDRIVER_OBJECT DriverObject, // указатель на объект драйвера

IN PUNICODE_STRING RegistryPath) // путь к подразделу регистра,

// относящегося к драйверу

Эта функция выполняется при загрузке драйвера операционной системой. В WDM-драйверах на DriverEntry возложены обязанности по регистрации всех остальных точек входа драйвера.

NTSTATUS AddDevice(

IN PDRIVER_OBJECT DriverObject, // указатель на объект драйвера

IN PDEVICE_OBJECT PhysicalDeviceObject) // указатель на родительский PDO

В поддерживающих PnP драйверах через эту точку входа менеджер PnP посылает драйверу уведомление об обнаружении устройства, за которое должен отвечать драйвер. Функция AddDevice должна создать объект устройства с помощью вызова IoCreateDevice и при необходимости присоединить его к стеку устройств вызовом IoAttachDeviceToDeviceStack.

NTSTATUS DriverUnload(

IN PDRIVER_OBJECT DriverObject) // указатель на объект драйвера

Вызывается при выгрузке драйвера. В этой функции должны осво-бождаться все затребованные драйвером ресурсы. Драйверы WDM-модели выполняют эти действия в обработчике запросов IRP_MJ_PNP с субкодом IRP_MN_REMOVE_DEVICE, то есть при удалении устройства из системы.

2.3.2 Функции обработки запросов/прерываний

Следует выделить отдельный класс точек входа драйвера, которые предназначены для обработки IRP-пакетов с различными кодами операций. Эти точки входа регистрируются при загрузке драйвера в функции DriverEntry. Регистрация производится путем заполнения элементов массива MajorFunction адресами диспетчеризуемых функций. Индексом в этом массиве являются коды IRP_MJ_XXX, то есть описанные числами типы пакетов IRP. Диспетчер ввода/вывода, ориентируясь на заполнение этого массива, вызывает нужные функции драйвера.

Поскольку для драйвера важны только адреса рабочих процедур, то все рабочие процедуры могут иметь совершенно произвольные имена.

Стандартный прототип таких функций обработки:

NTSTATUS IRPControl(

IN PDEVICE_OBJECT DeviceObject, // указатель на объект устройства

IN PIRP Irp) // указатель на пакет IRP

Функции обработки пакетов IRP

Функции, адреса которых записаны в массиве MajorFunctions, вызываются диспетчером ввода/вывода для обработки соответствующих запросов от клиентского драйвера (пользовательских приложений или модулей уровня ядра). Эти запросы оформляются в виде специальных структур - IRP пакетов.

При любом запросе Диспетчер формирует IRP. Память для структуры IRP выделяется в нестраничной памяти. В IRP записывается код операции ввода вывода. Пакет IRP состоит из заголовка (рис. 2.3), который имеет постоянный размер и стека IRP (рис. 2.4). Стек имеет переменную длину.

Заголовок IRP пакета:

Поле IoStatus типа IO_STATUS_BLOCK содержит два подполя

Status - значение, которое устанавливает драйвер после обработки пакета.

В Information - чаще всего число переданных или полученных байт.

Поле AssociatedIrp.SystemBuffer типа void* содержит указатель на системный буфер для случая если устройство поддерживает буферизованный ввод/вывод.

Поле MdlAddress типа PMDL содержит указатель на MDL список, если устройство поддерживает прямой ввод вывод.

Поле UserBuffer типа void* содержит адрес пользовательского буфера для ввода/вывода.

Поле Cancel типа BOOLEAN - это индикатор того, что пакет IRP должен быть аннулирован.

Рис. 2.3. Заголовок IRP-пакета

Стек IRP пакета

Основное значение ячеек стека IRP пакета состоит в том, чтобы хранить функциональный код и параметры запроса на ввод/вывод. Для запроса, который адресован драйверу самого нижнего уровня, соответствующий IRP пакет имеет только одну ячейку стека. Для запроса, который послан драйверу верхнего уровня, Диспетчер ввода/вывода создает пакет IRP с несколькими стековыми ячейками - по одной для каждого FDO.

Каждая ячейка стека IRP содержит:

MajorFunction типа UCHAR - это код, описывающий назначение операции

MinorFunction типа UCHAR - это код, описывающий суб-код операции

DeviceObject типа PDEVICE_OBJECT - это указатель на объект устройства, которому был адресован данный запрос IRP

FileObject типа PFILE_OBJECT - файловый объект для данного запроса

Диспетчер ввода/вывода использует поле MajorFunction для того, чтобы извлечь из массива MajorFunction нужную для обработки запроса процедуру.

Рис. 2.4 Стек IRP-пакета

Функция обработки пакетов IRP_MJ_DEVICE_CONTROL

Эта функция позволяет обрабатывать расширенные запросы от клиентов пользовательского режима. Такой запрос может быть сформирован посредством вызова функции DeviceIoControl. Каждый IOCTL запрос имеет свой код. Этот код передается как параметр функции DeviceIoControl. Код IOCTL - это 32-битное число.

Запросы IOCTL служат чаще всего для обмена данными между драйвером и приложением. Для передачи данных в Windows предусмотрены 4 способа:

METHOD_BUFFERED

Входной пользовательский буфер копируется в системный, а по окончании обработки системный копируется в в выходной пользовательский буфер.

METHOD_IN_DIRECT и METHOD_OUT_DIRECT

Необходимые страницы пользовательского буфера загружаются с диска в оперативную память и блокируются. Используются MDL-списки для доступа к буферу пользователя.

METHOD_NEITHER

При данном методе передачи не производится проверка доступности памяти, не выделяются промежуточные буфера и не создаются MDL. В пакете IRP передаются виртуальные адреса буферов в пространстве памяти инициатора запроса ввода/вывода.

Функция обработки пакетов IRP_MJ_READ

Данная функция должна обрабатывать запросы на чтение информации из устройства.

Функция обработки пакетов IRP_MJ_PNP

Данная функция должна обрабатывать запросы от менеджера PnP.

Функция обработки пакетов IRP_MJ_POWER

Данная функция должна обрабатывать запросы от менеджера питания.

ISR

Данная точка входа вызовется когда произойдет прерывание, на которое зарегистрирована эта ISR функция. Вызов может произойти в любом контексте: как ядра, так и пользовательского процесса. Здесь драйвер может либо дожидаться следующего прерывания либо запросить отложенный вызов процедуры DPC (Deferred Procedure Call).

2.4 Приоритеты выполнения программного кода

Прерывание требует обработки, поэтому выполнение текущего кода прекращается и управление передается обработчику прерывания. Существуют как аппаратные, так и программные прерывания. Прерывания обслуживаются в соответствии с их приоритетом. Windows NT 5 использует схему приоритетов прерываний, известную под названием «уровни запросов прерываний» (interrupt request levels, IRQL). Всего существует 32 уровня, с 0 (passive), имеющего самый низкий приоритет, по 31 (high), имеющего соответственно самый высокий. Причем, прерывания с IRQL=0 (PASSIVE_LEVEL, уровень нормального исполнения потоков) по IRQL=2 (DISPATCH_LEVEL, планирование потоков и выполнение отложенных процедур) являются программными, а прерывания с IRQL=3 (device 1) по IRQL=31 (HIGH_LEVEL, проверка компьютера и шинные ошибки) являются аппаратными. В любой конкретный момент времени каждая инструкция выполняется на одном определенном уровне IRQL. Прерывание с уровнем IRQL=0, строго говоря, прерыванием не является, так как оно не может прервать работу никакого кода (для этого этот код должен выполняться на еще более низком уровне прерывания, а такого уровня нет).

Потоки, работающие на уровне PASSIVE_LEVEL, попадают под управление планировщика заданий (scheduler). Приоритеты, которые различает планировщик заданий для потоков с уровнем PASSIVE_LEVEL, принимают значения от 0 до 31 (MAXIMUM_PRIORITY) и называются приоритетами планирования. Различают Real-Time и Normal приоритеты планирования. Первые продолжают свою работу до тех пор, пока не появится поток с большим приоритетом, так что потоки низких приоритетов должны дожидаться, пока текущий поток Real-Time не завершит работу естественным путем. Потоки с приоритетами Normal планируются по другим правилам. Для работы им выделяется определенный квант процессорного времени, после чего управление передается другим потокам такого же приоритета. Время от времени планировщик может повышать приоритет отложенного потока в пределах диапазона Normal, в результате чего все программные потоки среди потоков этой группы, даже имеющие самые низкие приоритеты, рано или поздно получают управление.

2.5 Стек клавиатуры

Физическую связь клавиатуры с шиной осуществляет микроконтроллер клавиатуры Intel 8042. На современных компьютерах он интегрирован в чипсет материнской платы. Этот контроллер может работать в двух режимах: AT-совместимом и PS/2-совместимом. Почти все клавиатуры уже давно являются PS/2-совместимыми. В PS/2-совместимом режиме микроконтроллер клавиатуры также связывает с шиной и PS/2-совместимую мышь. Данным микроконтроллером управляет функциональный драйвер i8042prt. Драйвер i8042prt создает два безымянных объекта «устройство» и подключает один к стеку клавиатуры, а другой к стеку мыши. Поверх драйвера i8042prt, точнее, поверх его устройств, располагаются именованные объекты «устройство» драйверов Kbdclass и Mouclass. Драйверы Kbdclass и Mouclass являются так называемыми драйверами класса и реализуют общую функциональность для всех типов клавиатур и мышей, т.е. для всего класса этих устройств. Оба эти драйвера устанавливаются как высокоуровневые драйверы.

Стек клавиатуры обрабатывает несколько типов запросов. В данной курсовой работе необходимо рассмотреть только IRP типа IRP_MJ_READ, которые несут с собой коды клавиш. Генератором этих IRP является поток необработанного ввода RawInputThread системного процесса csrcc.exe. Этот поток открывает объект «устройство» драйвера класса клавиатуры для эксклюзивного использования и направляет ему IRP типа IRP_MJ_READ. Получив IRP, драйвер Kbdclass отмечает его как ожидающий завершения (pending), ставит в очередь и возвращает STATUS_PENDING. Потоку необработанного ввода придется ждать завершения IRP. Подключаясь к стеку, драйвер Kbdclass регистрирует у драйвера i8042prt процедуру обратного вызова KeyboardClassServiceCallback, направляя ему IRP IOCTL_INTERNAL_KEYBOARD_CONNECT. Драйвер i8042prt тоже регистрирует у системы свою процедуру обработки прерывания (ISR) I8042KeyboardInterruptService, вызовом функции IoConnectInterrupt. Когда будет нажата или отпущена клавиша, контроллер клавиатуры выработает аппаратное прерывание. Его обработчик вызовет I8042KeyboardInterruptService, которая прочитает из внутренней очереди контроллера клавиатуры необходимые данные. Т.к. обработка аппаратного прерывания происходит на повышенном IRQL, ISR делает только самую неотложную работу и ставит в очередь вызов отложенной процедуры I8042KeyboardIsrDpc (DPC). DPC работает при IRQL = DISPATCH_LEVEL. Когда IRQL понизится до DISPATCH_LEVEL, система вызовет процедуру I8042KeyboardIsrDpc, которая вызовет зарегистрированную драйвером Kbdclass процедуру обратного вызова KeyboardClassServiceCallback (также выполняется на IRQL = DISPATCH_LEVEL). KeyboardClassServiceCallback извлечет из своей очереди ожидающий завершения IRP, заполнит структуру KEYBOARD_INPUT_DATA, несущую всю необходимую информацию о нажатиях/отпусканиях клавиш, и завершит IRP. Поток необработанного ввода пробуждается, обрабатывает полученную информацию и вновь посылает IRP типа IRP_MJ_READ драйверу класса, который опять ставится в очередь до следующего нажатия/отпускания клавиши. Таким образом, у стека клавиатуры всегда есть, по крайней мере, один, ожидающий завершения IRP, и находится он в очереди драйвера Kbdclass. Стек клавиатуры представлен на рис.2.5.

Рис. 2.5. Стек клавиатуры

2.6 Kernel Streaming

Kernel streaming (KS) - это совокупность функций Windows NT 5, которые обрабатывают в режиме ядра потоковые данные, такие как аудио и видео-данные. WDM аудио-драйвер предоставляет системе свои музыкальные функции, как набор фильтров KS. Объект KS фильтра может расширить функции аудиоадаптера, если требуется дополнительная цифровая обработка аудио-потоков, которые идут через этот фильтр. Например, фильтр может преобразовывать форматы потоков, синтезировать или смешивать потоки.

Фильтр может содержать несколько пинов. Пин является точкой входа или выхода, через которую аудио-поток входит или покидает фильтр. У каждого пина есть определённый формат данных, и данные только этого формата могут проходить через пин.

Пины могут быть подсоединены к пинам других фильтров, что позволяет создавать графы фильтров. Для того чтобы быть частью графа аудио-фильтров, фильтр должен содержать не менее одного пина.

KS-фильтр - это объект ядра и к нему можно получить доступ используя HANDLE. Обращение к объекту пина производится также с использованием HANDLE. Данные входят во входные пины, проходят соответствующую обработку в узлах фильтра и выходят из выходящих пинов, как показано на рис. 2.6.

Рис.2.6. Схема аудио-фильтра

2.7 Описание формата MIDI-данных

Формат МИДИ - Musical Instrument Digital Interface. Существует 16 миди каналов (0..15). На каждом из них в одно и то же время может находиться один инструмент.

Всего существует 128 разных инструментов (0..127). Каждый инструмент занимает определенную позицию в общей структуре тембровой схемы - таблица 2.1. Каждый инструмент имеет 128 нот (0..127).

Простейшая MIDI-команда состоит из 3 байт, которые отправляются MIDI-устройству.

MIDI-команды, которые используются в данной курсовой работе:

Утановить инструмент Instrument в канале Channel

InstrumentByte[0] = 0xC0 | Channel;

InstrumentByte[1] = Instrument;

InstrumentByte[2] = 0;

Воспроизвести ноту Note в канале Channel на максимальной громкости

NoteOnByte[0] = 0x90 | Channel;

NoteOnByte[1] = Note;

NoteOnByte[2] = 0x7F;

Выключить воспроизведение ноты Note в канале Channel

NoteOffByte[0] = 0x80 | Channel;

NoteOffByte[1] = Note;

NoteOffByte[2] = 0x00;

Таблица 2.1 Инструменты MIDI

Acoustic Grand Piano

Bright acoustic piano

Electric grand piano

Honky-tonk piano

Electric piano 1

Electric piano 2

Harpsichord

Clavi

Celesta

Glockenspiel

Music box

Vibraphone

Marimba

Xylophone

Tubular bells

Dulcimer

Drawbar organ

Percussive organ

Rock organ

Church organ

Reed organ

Accordian

Harmonica

Tango accordian

Acoustic guitar (nylon)

Acoustic guitar (steel)

Jazz guitar

Clean electric guitar

Muted electric guitar

Overdrive guitar

Distortion guitar

Guitar harmonics

Accoustic bass

Fingered bass

Picked bass

Fretless bass

Slap bass 1

Slap bass 2

Synth bass 1

Synth bass 2

Violin

Viola

Cello

Contrabass

Tremolo strings

Pizzicato strings

Orchestral harp

Timpani

String ensemble 1

String ensemble 2

Synth. strings 1

Synth strings 2

Choir ahh

Choir oohh

Synth voice

Orchestral hit

Trumpet

Trombone

Tuba

Muted trumpet

French horn

Brass section

Synth brass 1

Synth brass 2

Soprano sax

Alto sax

Tenor sax

Baritone sax

Oboe

English horn

Bassoon

Clarinet

Piccolo

Flute

Recorder

Pan flute

Blown bottle

Shakuhachi

Whistle

Ocarina

Square wave

Sawtooth wave

Caliope

Chiff

Charang

Voice

Fifth's

Bass & lead

New age

Warm

Polysynth

Choir

Bowed

Metallic

Halo

Sweep

FX rain

FX soundtrack

FX crystal

FX atmosphere

FX brightness

FX goblins

FX echo drops

FX star theme

Sitar

Banjo

Shamisen

Koto

Kalimba

Bagpipe

Fiddle

Shanai

Tinkle bell

Agogo

Steel drums

Woodblock

Taiko drum

Melodic tom

Synth drum

Reverse cymbal

Guit.fret noise

Breath noise

Seashore

Bird tweet

Telephone ring

Helicopter

Applause

Gunshot

2.8 Выбор структуры программного обеспечения

Реализация проекта требует предварительного изучения уже существующих технологий, тщательного отбора методов, удовлетворяющих всем накладываемым заданием условиям. В соответствии с заданием на курсовую работу, необходимо разработать программное обеспечение, позволяющее воспроизводить музыкальные ноты с заданными параметрами при нажатии клавиш. Необходимо выбрать тип и структуру драйвера, который будет получать информацию о нажатых клавишах. Также необходимо выбрать способ доступа к аудиоустройству, способному воспроизводить MIDI-ноты.

2.8.1 Драйвер-фильтр

Из анализа архитектуры Windows XP следует, что для доступа к информации, содержащей коды нажатых или отпущенных клавиш необходимо написать драйвер. Драйвер может получить доступ к кодам нажатых или отпущенных клавиш двумя способами. Либо перехватывая IRP пакеты от других драйверов, либо самостоятельно обрабатывая прерывания от клавиатуры. Предпочтительнее выбрать драйвер-фильтр верхнего уровня, поскольку информация, возвращаемая драйвером клавиатуры, хорошо документирована и описана в литературе. Разрабатываемый драйвер должен быть WDM-драйвером.

Разрабатываемый драйвер-фильтр устанавливается над фильтром Kbdclass. Так как IRP типа IRP_MJ_READ является фактически запросом на чтение данных, то когда он идет вниз по стеку, его буфер пуст. Прочитанные данные буфер будет содержать после завершения IRP. Чтобы эти данные увидеть, фильтр должен установить в свой блок стека IRP процедуру завершения. Место драйвера-фильтра в стеке клавиатуры представлено на рис.2.7.

Рис.2.7. Место драйвера-фильтра в стеке клавиатуры

2.8.2 Получение доступа к аудиоустройству

Для того чтобы воспроизводить звук, используя Kernel Streaming, необходимо:

Перебрать все аудио-фильтры категории KSCATEGORY_AUDIO.

Для фильтра перебрать все входные пины с требуемым форматом данных.

Выбрать подходящий пин и инициализировать объект пина.

Установить состояние пина в KSSTATE_RUN, отправив IRP-пакет.

Отправить пину музыкальные команды IRP-пакетом.

Интерфейс для работы с функциями Kernel Streaming в режиме ядра описан не полностью. Разработчики MS Windows рекомендуют воспроизводить звук только из режима пользователя, используя API Windows Multimedia, библиотеки DirectMusic или DirectSound.

Существует описание интерфейса для работы с фильтрами и пинами в режиме пользователя. Данная функциональность предоставляется библиотекой DirectKS от фирмы Microsoft. Исходные тексты этой библиотеки открыты. В исходном варианте этой библиотеки был реализован доступ к устройствам, воспроизводящим WAVE-данные. Эта библиотека используется в данном проекте, и в неё внесены изменения. Реализован доступ к устройствам, воспроизводящим MIDI-ноты.

В данном проекте поиск нужного пина и инициализация его объекта производится в режиме пользователя с использованием библиотеки DirectKS. Далее объект пина передаётся в драйвер режима ядра. Драйвер отправляет музыкальные команды аудиоустройству, отправляя IRP-пакеты пину.

2.8.3 Взаимодействие компонент программного обеспечения

В рамках данного курсового проекта реализован драйвер-фильтр и программа, которая управляет работой драйвера. Используется открытая библиотека DirectKS. На рис. 2.8 представлена схема взаимодействия компонент проекта, а также процессов и драйверов операционной системы, которые участвуют в работе этих компонент.

Рис.2.8. Схема взаимодействия компонент разрабатываемого проекта

2.9 Алгоритм работы драйвера-фильтра

Поскольку разрабатываемый драйвер-фильтр является WDM-драйвером, то должен иметь следующие точки входа: DriverEntry, DriverUnload, AddDevice, функции для обработки пакетов IRP. Функции для обработки прерываний в данной работе не регистрируются, поскольку драйвер не работает с прерываниями.

2.9.1 Функции загрузки/выгрузки драйвера

DiverEntry

Заполнение массива MajorFunctions.

Регистрируется процедура обработки пакета на чтение, процедура обработки IOCTL-запросов, процедуры обработки запросов от менеджера PnP и менеджера питания. Остальные элементы массива заполняются адресом функции __MyFilterDispatchGeneral, которая пропускает пакеты ниже по стеку.

Регистрация процедуры AddDevice. В данной работе она называется MyFilterAddDevice.

Регистрация процедуры DriverUnload, называющейся MyFilterUnload.

AddDevice

В данной работе функция __MyFilterAddDevice создает одно функциональное устройство с именем \Device\kbd_filter. Происходит резервирование места для хранения адреса устройства, расположенного ниже в стеке драйверов. Это сделано для того, чтобы при разрушении стека драйверов передать запрос PnP на демонтаж нижестоящему драйверу. Созданное устройство подключается к стеку драйверов клавиатуры. Это делается с помощью функции IoAttachDeviceToDeviceStack. Это стандартная функция Windows, она принимает PDO и указатель на структуру подключаемого FDO. FDO занимает место в стеке драйверов сразу после объекта, находящегося в вершине стека. Теперь подключаемый FDO становится вершиной стека. Очередность загрузки драйверов описана в реестре Windows.

Для того чтобы пользовательское приложение смогло обратиться к драйверу для FDO должно быть зарегистрировано DOS имя. Используя это имя, приложение сможет послать драйверу IOCTL-запрос. Для регистрации такого имени создается строка-юникод со значением \DosDevices\kbd_filter и применяется функция IoCreateSymbolicLink. Ее параметрами является только что созданная строка и имя FDO, которое обслуживает наш драйвер. Теперь \DosDevices\kbd_filter - это DOS имя созданного FDO устройства.

В этой функции происходит также инициализация других объектов, используемых в работе драйвера-фильтра:

PinInit() - инициализация модуля, который работает с пином.

KeyMidiInit() - инициализация таблицы, в которой хранится информация о музыкальных параметрах клавиш.

Создание системного потока PlayThread, который отправляет музыкальные команды аудиоустройству.

Создание двух очередей, используемых в работе двух потоков.

Создание объектов синхронизации потоков .

DriverUnload

Поскольку данный фильтр является PnP драйвером, то на процедуру DriverUnload ничего не возложено.

2.9.2 Функции обработки пакетов IRP

Разрабатываемый драйвер-фильтр осуществляет обработку следующих пакетов IRP:

IRP_MJ_DEVICE_CONTROL

IRP_MJ_READ

IRP_MJ_PNP

IRP_MJ_POWER

Остальные IRP пакеты пропускаются ниже по стеку драйверов.

Функция обработки пакетов IRP_MJ_DEVICE_CONTROL

В данной работе пользовательское приложение должно иметь возможность посылать IOCTL-запросы драйверу. Приложение должно иметь возможность отправить драйверу объект открытого музыкального пина и музыкальные параметры клавиши.

Для этого в теле драйвера определены две 32-битные константы:

#define IOCTL_SHARE_PIN \

CTL_CODE(FILE_DEVICE_KEYBOARD, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)

По этому коду в драйвер передаётся 4 байта, которые являются HANDLE объекта пина, открытого в пользовательской программе.

#define IOCTL_MIDI_NOTE \

CTL_CODE(FILE_DEVICE_KEYBOARD, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)

По этому коду в драйвер передаётся 7 байт, которые можно описать структурой:

typedef struct _KEY_MIDI_INFO

{UCHAR ScanCode; // Скан-код клавиши, генерируемый клавиатурой

UCHAR Flag; // Флаг клавиши, генерируемый клавиатурой

UCHAR Position; // Позиция на клавиатуре (всего 104 клавиши)

UCHAR Channel; // Музыкальный канал

UCHAR Instrument; // Музыкальный инструмент

UCHAR Note; // Музыкальная нота

UCHAR Used; // Для клавиши используется нота или нет

} KEY_MIDI_INFO, * PKEY_MIDI_INFO;

Это коды IOCTL-запросов, которые не используются драйверами стека клавиатуры. Поэтому в данном проекте они могут быть использованы безо всяких опасений.

Применяется способ передачи данных METHOD_BUFFERED. Т.к. передаётся буфер в 4 или 7 байт, то его размер не повредит системному пулу, и копироваться пользовательский буфер в системный будет очень быстро. Нет необходимости применять более сложные методы METHOD_IN_DIRECT или METHOD_NEITHER, которые используются при передаче больших объемов данных.

Функция обработки пакетов IRP_MJ_READ

Данная функция осуществляет обработку пакетов на чтение. IRP-пакет сначала попадает в разрабатываемый драйвер. Вызовется зарегистрированная в DriverEntry функция __MyFilterDispatchRead. К моменту вызова __MyFilterDispatchRead, буфер не содержит кодов считанных клавиш. Для того чтобы получить доступ к ним __MyFilterDispatchRead должна установить CallBack процедуру __MyFilterReadComplete. Она получит управление, когда буфер IRP-пакета будет содержать информацию о нажатых клавишах. Пакет будет подниматься вверх по стеку драйверов и вызывать CallBack функции на каждом уровне стека. CallBack процедура устанавливается с помощью функции IoSetCompletionRoutine.

MyFilterReadComplete получает буфер нажатых клавиш, как массив структур KEYBOARD_INPUT_DATA, функция выполняется на IRQL <= DISPATCH_LEVEL.

Далее в MyFilterDispatchRead происходит копирование текущей ячейки IRP-пакета в следующую ячейку. Таким образом происходит передача неизмененных параметров в Kbdclass.

Функция обработки пакетов IRP_MJ_PNP

Драйвер-фильтр должен обрабатывать только запросы IRP_MN_REMOVE_DEVICE и IRP_MN_SURPRISE_REMOVAL. При этом функция посылает данный пакет менеджера PnP нижестоящему в стеке устройству. В обработчиках этих запросов происходит освобождение памяти, которая выделялась для модуля работы с пином, для таблицы музыкальных нот, происходит завершение работы музыкального потока, освобождение очередей и объектов синхронизации, используемых в драйвере.

В обработчике IRP_MN_REMOVE_DEVICE дополнительно происходит:

отключение устройства от стека драйверов вызовом функции IoDetachDevice,

удаление устройства FDO вызовом функции IoDeleteDevice,

удаление символьной ссылки вызовом IoDeleteSymbolicLink.

Остальные пакеты пропускаются ниже по стеку.

Функция обработки пакетов IRP_MJ_POWER

Т.к. разрабатываемый драйвер является фильтром, задача которого - получить информацию о нажатых клавишах, то в нём не производится никаких действий, связанных с изменением питания. Поэтому эти IRP-пакеты пропускаются ниже по стеку.

Обработка остальных пактов IRP

Остальные IRP-пакеты, которые не обрабатываются в данном фильтре, пропускаются ниже по стеку. Функции данного драйвера-фильтра не в праве самостоятельно обрабатывать эти запросы, так как это могут запросы, адресованные нижестоящим драйверам. Примером одного из таких запросов является IOCTL-запрос, адресованный драйверу i8042prt и предназначенный для перепрограммирования котроллера клавиатуры и для зажжения лампочек на клавиатуре.

В данной работе за пропускание пакетов вниз отвечает процедура __MyFilterDispatchGeneral. Она передает IRP пакет нижестоящему драйверу с помощью функции IoCallDriver. При этом нижестоящий драйвер должен считывать текущую ячейку IRP пакета. Это достигается за счет использования функции IoSkipCurrentIrpStackLocation.

2.9.3 Функции работы с аудио-устройством

В модуле midi_pin реализованы все функции, которые обеспечивают работу с музыкальным пином на уровне ядра. В работе с музыкальным пином используются запросы на установку состояния пина и отправление пакетов с музыкальными данными.

NTSTATUS PinInit()

В этой функции происходит инициализация полей заголовка IRP-пакета и MIDI-данных, которые используются во время отправления музыкальных команд в пин. Далее в функциях PinMidiNoteOn и PinMidiNoteOff используется инициализированный заголовок.

Инициализация заголовка IRP-пакета происходит следующим образом:

typedef __declspec(align(16)) struct _MIDI_DATA

{KSMUSICFORMAT InstrumentFormat; // include <ksmedia.h>

union

{UCHAR InstrumentByte[4];

UCHAR NoteOffByte[4];};

KSMUSICFORMAT NoteFormat;

UCHAR NoteOnByte[4];

} MIDI_DATA, * PMIDI_DATA;

MIDI_DATA PinMidiData;

KSSTREAM_HEADER PinWriteHeader; // include <ks.h>

RtlZeroMemory(&PinWriteHeader, sizeof(PinWriteHeader));

// 12 байт

PinMidiData.InstrumentFormat.TimeDeltaMs = 0;

PinMidiData.InstrumentFormat.ByteCount = 3;

PinMidiData.InstrumentByte[0] = 0x00;

PinMidiData.InstrumentByte[1] = 0x00;

PinMidiData.InstrumentByte[2] = 0x00;

PinMidiData.InstrumentByte[3] = 0x00;

// ещё 12 байт

PinMidiData.NoteFormat.TimeDeltaMs = 0;

PinMidiData.NoteFormat.ByteCount = 3;

PinMidiData.NoteOnByte[0] = 0x00;

PinMidiData.NoteOnByte[1] = 0x00;

PinMidiData.NoteOnByte[2] = 0x00;

PinMidiData.NoteOnByte[3] = 0x00;

PinWriteHeader.Size = sizeof(PinWriteHeader);

PinWriteHeader.TypeSpecificFlags = 0;

PinWriteHeader.PresentationTime.Time = 0;

PinWriteHeader.PresentationTime.Numerator = 1;

PinWriteHeader.PresentationTime.Denominator = 1;

PinWriteHeader.Duration = 0;

PinWriteHeader.FrameExtent = 24; // всего 24 байта

PinWriteHeader.DataUsed = 24; // всего 24 байта

PinWriteHeader.Data = &PinMidiData;

NTSTATUS PinOpenStream(IN HANDLE UserPin)

Когда через запрос IOCTL_SHARE_PIN драйвер получает объект открытого пина, то необходимо вызвать эту функцию. В ней происходит вызов функции ObReferenceObjectByHandle для того, чтобы получить указатель на объект пина в режиме ядра и увеличить число ссылок на объект. Это делается для того, чтобы объект пина не был удалён из таблицы объектов ОС после заверешения работы пользовательского приложения, в котором был создан объект пина. Также здесь происходит установка флага, что пин открыт для драйвера.

UserPin - HANDLE того пина, который содержится в буфере IRP-пакета.

NTSTATUS PinIsOpenedStream()

Возвращает STATUS_SUCCESS если пин открыт.

NTSTATUS PinFree()

Здесь происходит вызов функции ObDereferenceObject, которая уменьшает число ссылок на объект пина.

NTSTATUS PinSetState(IN KSSTATE State)

Устанавливает состояние пина в State (KSSTATE_RUN, KSSTATE_PAUSE или KSSTATE_STOP). Перед тем, как воспроизводить ноты, необходимо установить состояние пина в KSSTATE_RUN. Функция работает только при IRQL = PASSIVE_LEVEL.

NTSTATUS PinWriteData(IN KSSTREAM_HEADER * Pheader)

Отправляет заголовок в открытый пин посредством IOCTL_KS_WRITE_STREAM.

Функция работает только при IRQL = PASSIVE_LEVEL.

NTSTATUS PinMidiNoteOn(IN UCHAR Channel,

IN UCHAR Instrument, IN UCHAR Note)

Если пин открыт, то отправляет команду на воспроизведение ноты Note с использованием инструмента Instrument в канале Channel.

Модификация инициализированного заголовка:

PinMidiData.InstrumentByte[0] = 0xC0 | Channel;

PinMidiData.InstrumentByte[1] = Instrument;

PinMidiData.NoteOnByte[0] = 0x90 | Channel;

PinMidiData.NoteOnByte[1] = Note;

PinMidiData.NoteOnByte[2] = 0x7F;

// 24 байта отправляем, т.к. в одном

PinWriteHeader.FrameExtent = 24; // пакете 2 команды: устанавливаем

PinWriteHeader.DataUsed = 24; // инструмент и отправляем ноту

PinWriteData(&PinWriteHeader);

Функция работает только при IRQL = PASSIVE_LEVEL.

NTSTATUS PinMidiNoteOff(IN UCHAR Channel, IN UCHAR Note)

Выключает ноту Note в канале Channel.

Модификация инициализированного заголовка:

PinMidiData.NoteOffByte[0] = 0x80 | Channel;

PinMidiData.NoteOffByte[1] = Note;

PinWriteHeader.FrameExtent = 12; // 12 байт шлём, т.к. в одном пакете

PinWriteHeader.DataUsed = 12; // 1 команда: выключаем ноту

PinWriteData(&PinWriteHeader);

Функция работает только при IRQL = PASSIVE_LEVEL.

2.9.4 Схема хранения музыкальных параметров клавиш

Во время нажатия клавиши клавиатура генерирует скан-код и флаг (эта информация находится в структуре KEYBOARD_INPUT_DATA).

Нужно организовать такую схему хранения музыкальных данных клавиш, чтобы во время получения скан-кода и флага клавиши возможно было быстро найти её музыкальные параметры.

Для нескольких клавиш может быть сгенерирован один и тот же скан-код, например для левого и правого Shift. Их возможно различить только по флагу. Не более чем трём клавишам может сооответствовать один скан-код. Поэтому скан-код нельзя использовать как индекс массива, в котором хранятся музыкальные данные только для одной клавиши - эти музыкальные данные будут использоваться для нескольких клавиш с одинаковым скан-кодом.

Тогда следует для каждой пары (скан-код, флаг) создать новый скан-код клавиши такой, чтобы для каждой клавиши существовал единственный скан-код. Позиция - пусть так называется новый скан-код.

Схема реализована в модуле keys.

Схема такова:

typedef struct _KEY_SCANS_TABLE

{UCHAR Usage;

UCHAR ScanMake;

UCHAR ScanE0;

UCHAR ScanE1;

} KEY_SCANS_TABLE, * PKEY_SCANS_TABLE;

typedef struct _KEY_MIDI_TABLE

{UCHAR Used;

UCHAR Channel;

UCHAR Instrument;

UCHAR Note;

} KEY_MIDI_TABLE, * PKEY_MIDI_TABLE;

Создаётся массив структур KEY_SCANS_TABLE, где индекс массива - реальный скан-код, генерируемый клавиатурой, а в полях ScanMake, ScanE0, ScanE1 хранится позиция клавиши, соответствующая тому или иному значению флага клавиши, генерируемого клавиатурой. В поле Usage число единичных бит равно числу установленных клавиш, соответствующих одному скан-коду.

Создаётся массив структур KEY_MIDI_TABLE, где индекс массива - позиция клавиши, в полях структуры содержится музыкальная информация о клавише:

Used - используется в схеме или нет. Если используется: нажата или отпущена.

Channel - канал, в котором звучит нота. Существует 16 каналов - 0..15.

Instrument - инструмент ноты. Существует 128 инструментов - 0..127.

Note - нота. Существует 128 нот для каждого инструмента - 0..127.

Когда клавиатура во время нажатия клавиши генерирует скан-код и флаг, то по первой таблице с использованием скан-кода в качестве индекса массива быстро находится ячейка с тремя возможными позициями. По значению флага ценой максимум трёх сравнений находится нужная позиция. С использованием позиции в качестве индекса второй таблицы быстро находятся музыкальные данные, соответствующие нажатой клавише.

На обычной клавиатуре находится 104 клавиши. Поэтому в данной курсовой работе используется 104 позиции (0..103).

Функции установки и выборки музыкальной информации

NTSTATUS KeyMidiInit()

Выделяет память для двух таблиц и заполняет их нулями.

NTSTATUS KeyMidiFree()

Освобождает память, выделенную для таблиц.

NTSTATUS KeyMidiSetNote(IN UCHAR ScanCode, IN UCHAR Flag,

IN UCHAR Position,

IN UCHAR Channel, IN UCHAR Instrument,

IN UCHAR Note, IN UCHAR Used)

Устанавливает в первой таблице для скан-кода и флага позицию. Для позиции во второй таблице устанавливает музыкальные параметры.

NTSTATUS KeyMidiGetPosition(IN UCHAR ScanCode, IN UCHAR Flag,

OUT PUCHAR Position)

По скан-коду и флагу, сгенерированным клавиатурой, получает позицию, используя первую таблицу.

NTSTATUS KeyMidiGetNote(IN UCHAR Position, PUCHAR Channel,

OUT PUCHAR Instrument, OUT PUCHAR Note,

OUT PUCHAR Used)

Используя позицию клавиши, получает музыкальные данные из второй таблицы.

NTSTATUS KeyMidiSetUsed(IN UCHAR Position, IN UCHAR Used)

Используя позицию клавиши, устанавливает состояние клавиши KEY_RELEASED (отпущена) или KEY_PRESSED (нажата).

2.9.5 Разделение задачи на потоки

Функция MyFilterReadComplete, которая получает буфер нажатых клавиш как массив структур KEYBOARD_INPUT_DATA, выполняется на IRQL <= DISPATCH_LEVEL.

Функция PinMidiNoteOn работает только при IRQL = PASSIVE_LEVEL.

Это значит, что функцию PinMidiNoteOn нельзя вызывать внутри функции MyFilterReadComplete.

В драйвере создан системный поток PlayThread, который отправляет музыкальные команды аудиоустройству. В основном потоке драйвера функция MyFilterReadComplete заполняет очередь нажатых клавиш. Далее эта функция сигнализирует о событии, что можно начинать воспроизведение нот. По этому событию пробуждается поток PlayThread. Возникает проблема работы двух потоков с разделяемым ресусрсом - очередью. Поэтому используется 2 очереди.

Принцип синхронизации потоков

Функция MyFilterReadComplete:

(поток 1, выполняется на IRQL <= DISPATCH_LEVEL)

if(PlayCompleted)

{Подсоединить Очередь Б к Очереди А

Опустошить Очередь Б

for(все нажатые или отпущенные клавиши)

{Добавить в Очередь А позицию клавиши}

Установить Событие PlayEvent в состояние «Сигнал»}

else

{for(все нажатые или отпущенные клавиши)

{Добавить в Очередь Б позицию клавиши}}

Функция PlayThread:

(поток 2, выполняется на IRQL = PASSIVE_LEVEL)

Ждать пока Событие PlayEvent не перейдёт в состояние «Сигнал»

Установить Событие PlayEvent в состояние «Нет сигнала»

// Устанавливает значение 0 переменной PlayCompleted

// Обеспечивает монопольный доступ к этой переменной аппаратными средствами

InterlockedExchange(&PlayCompleted, 0);

PinSetState(KSSTATE_RUN);

while(Очередь А не пуста)

{Извлечь из Очереди А информацию о нажатой клавиши

if(состояние на клавиатуре = нажата и

музыкальное состояние = отпущена)

{Воспроизвести ноту

Музыкальное состояние = нажата}

else if(состояние на клавиатуре = отпущена и

музыкальное состояние = нажата)

{Выключить ноту

Музыкальное состояние = отпущена}}

PinSetState(KSSTATE_PAUSE);

PinSetState(KSSTATE_STOP);

InterlockedExchange(&PlayCompleted, 1);

Т.к. первый поток выполняется на более высоком IRQL, то он может прервать выполнение второго потока в любой момент. Например, это может произойти до того, как второй поток завершит обработку Очереди А. В этом случае первый поток заполняет Очередь Б. Как только второй поток закончит свою предыдущую операцию и установит флаг PlayCompleted, то первый поток подсоединит Очередь Б к Очереди А, добавит новые элементы к Очереди А и сигнализирует второму потоку о том, что можно начать новую музыкальную обработку. Второй поток получит управление не сразу, а как только первый поток, работающий на более высоком уровне IRQL, полностью завершит свою работу.

Функция InterlockedExchange обеспечивает монопольный доступ к переменной того потока, который их вызвал. Все остальные потоки, которые используют эту переменную в это же время, будут ждать пока до конца не отработает InterlockedExchange. Использование этой функции возможно на любом уровне IRQL, т.к. она реализована аппаратно.

Данный механизм обеспечивает работу первого потока без ожидания второго. Т.е. происходит быстрая обработка возвращаемого из стека IRP-пакета с нажатыми клавишами. По сигналам из первого потока второй поток производит музыкальную обработку.

3. Технологический раздел

3.1 Выбор средств разработки программного обеспечения

Из двух языков, используемых для программирования драйверов, С и ассемблера, выбор следует остановить на С ввиду того, что это язык высокого уровня, т.е. этот язык обеспечивает уровень абстракции выше, чем ассемблер, что безусловно большой плюс. Кроме того, этот язык используется фирмой Microsoft в наиболее распространенном пакете для разработки драйверов MS DDK. Еще одним плюсом С является то, что вместе с пакетом DDK поставляется специальный компилятор для С, предназначенный для компиляции драйверов.

Ориентированный на язык С, набор DDK включает в себя справочники, все необходимые библиотеки и заголовочные файлы. Поэтому была использована технология структурного программирования. В данной работе применяется DDK для Windows Server 2003.

Для редактирования исходных текстов применяется среда Microsoft Visual Studio .NET и входящий в неё компилятор Microsoft Visual C++.

При сборке исполняемого (с расширением .sys) файла используется утилита build, входящая в состав DDK.

При разработке управляющего приложения используется среда Microsoft Visual Studio .NET с визуальным редактором форм.

В проекте используется библиотека DirectKS, которая является примером получения доступа к фильтрам Kernel Streaming в режиме пользователя. В библиотеку внесены изменения. Использование библиотеки описано ниже.

Операционной системой, в которой работает драйвер, является Windows NT 5, т.е. Windows 2000, Windows XP, Windows Server 2003.

Т.к. драйвер работает с аудиоустройством напрямую, то на компьютере должна быть установлена такая звуковая карта, которая поддерживает запросы и формат данных, которые ей отправляет драйвер. Звуковые карты, начиная с Creative Sound Blaster Live поддерживают запросы, используемые в данном курсовом проекте.

3.2 Установка драйвера в системе

Для установки драйвера необходимо вызвать функции драйвера в определенный момент загрузки системы. Это необходимо для того, чтобы драйвер занял нужное место в стеке драйверов. Операционная система Windows осуществляет загрузку драйверов в порядке, прописанном в системном реестре.


Подобные документы

  • Архитектура ввода/вывода Windows NT. Внутренняя организация шины USB. Сущностная характеристика драйверной модели WDM. Точки входа разрабатываемого драйвера, размещение кода в памяти, установка драйвера в системе. Реализация кода драйвера на языке C.

    курсовая работа [1,2 M], добавлен 27.09.2014

  • Разработка и практическая апробация действия драйвер-фильтра клавиатуры для операционной системы Windows, переопределяющего значение любых клавиш и отключающего клавиши клавиатуры. Составление программы для установки и управления данным драйвером.

    курсовая работа [226,8 K], добавлен 18.06.2009

  • Разработка программного обеспечения для упрощения буквенно-цифрового ввода при невозможности использовать функционал стандартной буквенной клавиатуры. Классификация и установка драйверов. Выбор языка и среды программирования. Пользовательский интерфейс.

    курсовая работа [183,0 K], добавлен 12.03.2013

  • Описание принципа работы драйвера. Установка и регистрация драйвера. Назначение и возможности утилиты TestTerminals.exe. Использование редактора форм. Создание форм с помощью редактора задач. Последовательность выполнения операций и обработок данных.

    курсовая работа [843,6 K], добавлен 09.11.2011

  • Методика исследования и анализа средств аудита системы Windows с целью обнаружения несанкционированного доступа программного обеспечения к ресурсам вычислительных машин. Анализ угрозы информационной безопасности. Алгоритм работы программного средства.

    дипломная работа [2,9 M], добавлен 28.06.2011

  • Управление задачами и процессами, запускаемыми под управлением Microsoft Windows. Учетные записи пользователей Windows. Установка оборудования и программного обеспечения. Изменение параметров и удаление учетной записи. Проверка дисков на наличие ошибок.

    реферат [2,7 M], добавлен 23.05.2012

  • Основные характеристики графики в операционной системе Windows, реализация объектно-ориентированной идеологии. Специфика и этапы разработки программного продукта, описывающего графический объект, на 32-битном ассемблере с использованием API-функции.

    курсовая работа [82,3 K], добавлен 18.05.2014

  • Общий календарный план выполнения этапов проекта программного обеспечения. Последовательность разработки согласно классической каскадной модели. Изображение хода работ по спиральной модели согласно Боему. Технические требования на продукт, WBS-структура.

    лабораторная работа [614,1 K], добавлен 17.01.2014

  • Многослойная архитектура драйверов. Организация внутреннего хранения данных диска. Выбор и обоснование языка и среды программирования. Обработка расширенных запросов. Процедуры установки драйвера виртуального диска. Блокировка выгрузки устройства.

    курсовая работа [159,1 K], добавлен 23.06.2009

  • Классификация служебных программных средств. Файловая структура операционных систем. Основы графического интерфейса пользователя Windows XX. Анализ алгоритмов решения задач. Описание процесса разработки программного обеспечения и результатов работы.

    курсовая работа [2,4 M], добавлен 14.11.2016

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.