- •Введение 5
- •1 Исследовательский раздел
- •1.1 Анализ существующих аналогичных систем
- •1.1.1 Обзор архитектуры устройств usb
- •1.2 Обоснование выбора программно-аппаратных средств
- •1.3 Постановка задачи
- •1.4 Развернутое техническое задание
- •1.4.1 Общие сведения
- •2.1.1 Основные дескрипторы usb драйвера
- •2.1.1.1 Дескриптор устройства
- •2.1.1.2 Дескриптор расширения устройства
- •2.1.1.3 Дескриптор конфигурации
- •2.1.1.4 Дескриптор интерфейса
- •2.1.1.5 Дескриптор конечной точки
- •2.2 Разработка функциональной схемы драйвера
- •2.2.1 Драйвер в иерархии wdm
- •2.2.2 Уровни обмена данными usb устройств
- •2.2.3 Архитектура системного драйвера usb
- •2.2.4 Основные рабочие процедуры драйвера
- •2.2.5 Управление перемещаемостью кода в драйвере
- •2.3 Разработка алгоритмического обеспечения
- •2.3.1 Инициализация драйвера
- •2.3.3 Обработка расширенных запросов ioctl
- •2.3.4 Поддержка запросов Plug and Play
- •2.3.5 Управление питанием
- •2.3.5.1 Обработка запросов irp_mj_power
- •2.3.6 Процедура деинициализации драйвера
- •2.4 Разработка программного обеспечения
- •2.4.1 Процедура DriverEntry
- •2.4.2 Процедура DriverUnload
- •2.4.3 Процедура AddDevice
- •2.4.4 Процедура передачи запроса usbd
- •2.4.5 Обработчики usbCreate и usbClose
- •2.4.6 Обработчик ConfigureDevice
- •2.4.7 Обработчики запросов на чтение и запись
- •3 Технологический раздел
- •3.1 Технология разработки драйверов для операционных систем семейства Windows
- •3.1.1 Архитектура Windows Driver Model
- •3.1.2 Выбор типа разрабатываемого драйвера
- •3.1.3 Разработка usb драйвера
- •3.2 Технология отладки драйверов в операционных системах семейства Windows
- •3.2.1 Основные отладочные тесты
- •3.2.2 Основные «проблемы», возникающие при отладке драйвера
- •3.2.2.1 Аппаратные проблемы
- •3.2.2.2 Программные проблемы
- •3.2.3 Основные отладчики и утилиты для проверки драйвера
- •3.2.3.1 Отладчик WinDbg
- •3.2.3.2 Driver Verifier
- •3.2.4 Общие приемы отладки драйвера
- •3.2.4.1 Установка фиксированных точек прерывания
- •3.2.4.2 Промежуточный вывод на экран
- •3.2.4.3 Сохранение отладочного кода в исходном тексте драйвера
- •3.2.4.4 Перехват некорректных условий
- •3.2.4.5 Обнаружение утечек памяти
- •3.2.5 Замечания по отладке драйверов
- •4 Безопасность жизнедеятельности
- •4.1 Анализ эргономических параметров рабочего места пользователя пэвм
- •4.1.1 Общие эргономические аспекты рабочего места
- •4.2 Организация рабочего места пользователя с учётом эргономических требований
- •4.2.1 Организация рабочего стола
- •4.2.2 Рабочее кресло
- •4.2.3 Работа с клавиатурой и мышью
- •4.2.4 Расположение и эргономические характеристики монитора
- •4.2.5 Внутренний объем
- •4.2.6 Рабочая поза пользователя пэвм
- •4.3 Экологическая оценка и переработка узлов компьютерной техники содержащих платину
- •4.3.1 Извлечение платины из отработанных катализаторов
- •4.3.2 Извлечение платины из радиооборудования и сплавов для электрических контактов
- •5 Экономический раздел
- •5.1 Планирование разработки драйвера с построением графика выполнения работ
- •5.1.1 Определение этапов и работ по созданию программного продукта
- •5.1.2 Расчет трудоемкости и продолжительности работ
- •5.1.3 Построение графика выполнения работ
- •5.2 Расчет затрат на разработку
- •5.3 Оценка экономической эффективности проекта
- •1 К исследовательскому разделу
- •2 К специальному разделу
- •3 К технологическому разделу
- •4 К разделу «Безопасность Жизнедеятельности»
- •5 К экономическому разделу
- •Приложение а Установка драйвера с помощью inf-файла
- •Приложение б Графические материалы
2.4.3 Процедура AddDevice
В архитектуре WDM у драйвера имеется специальная функция AddDevice, которую РnР Manager вызывает для каждого устройства. Данная процедура вызывается для создания и инициализации функционального объекта устройства (FDO). Для удобства и большей читабельности данная процедура разбита на три части. Первый вызов – AddDevice, из AddDevice вызывается CreateDeviceObject, а из CreateDeviceObject вызывается CreateSymbolicLink.
В AddDevice DriverObject – указатель на объект драйвера; PhysicalDeviceObject – указатель на объект устройства, созданного драйвером шины.
NTSTATUS AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
USBD_VERSION_INFORMATION versionInformation;
ULONG i;
// Пытаемся создать функциональный объект устройства
ntStatus =
CreateDeviceObject(DriverObject, PhysicalDeviceObject, &deviceObject);
// В случае успеха
if (NT_SUCCESS(ntStatus)) {
deviceExtension = deviceObject->DeviceExtension;
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
// Поддержка прямого (DIRECT IO) ввода/вывода для операций чтения/записи
deviceObject->Flags |= DO_DIRECT_IO;
// Устанавливаем флаг, так как во время запуска устройства вызов
// GetDescriptors() завершится неудачей
deviceObject->Flags |= DO_POWER_PAGABLE;
// Осуществляем инициализацию структуры расширения устройства
// Запоминаем физический объект устройства
deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
// И присоединяем к стеку
deviceExtension->TopOfStackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
// Создаем копию структуры параметров устройства (DEVICE_CAPABILITIES) в
// нашей структуре расширения устройства
QueryCapabilities(PhysicalDeviceObject,
&deviceExtension->DeviceCapabilities);
// Настраиваем параметры энергопотребления
deviceExtension->PowerDownLevel = PowerDeviceUnspecified;
for (i=PowerSystemSleeping1; i<= PowerSystemSleeping3; i++)
{
if ( deviceExtension->DeviceCapabilities.DeviceState[i] < PowerDeviceD3 )
deviceExtension->PowerDownLevel = deviceExtension->DeviceCapabilities.
DeviceState[i];
}
// Сохраняем кол-во обрабатываемых пакетов ввода/вывода в расширении
// устройства. Впоследствии данный счетчик увеличивается для каждого нового // полученного IRP и уменьшается для каждого обработанного или пропущенного // IRP. Счетчик необходим для правильной обработки IRP_MN_REMOVE_DEVICE
IncrementIoCount(deviceObject);
}
USBD_GetUSBDIVersion(&versionInformation);
if( NT_SUCCESS( ntStatus ) )
{
NTSTATUS actStat;
// Повышаем уровень энергопотребления устройства
actStat = SelfSuspendOrActivate( deviceObject, FALSE );
}
return ntStatus;
}
// ========================================================================
// Именно в данной функции создаем FDO
NTSTATUS CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDEVICE_OBJECT *DeviceObject
)
{
NTSTATUS ntStatus;
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_EXTENSION deviceExtension;
USHORT i;
UNICODE_STRING pdoUniCodeName;
WCHAR pdoName[] = L"\\Device\\DACAL_DC_300";
UNICODE_STRING DeviceLinkUniCodeString;
WCHAR DeviceLinkName[] = L"\\DosDevices\\DACAL_DC_300";
RtlInitUnicodeString (&pdoUniCodeName, pdoName); // Создаем UNICODE-имя
ntStatus = CreateSymbolicLink( PhysicalDeviceObject, &deviceLinkUnicodeString );
if (NT_SUCCESS(ntStatus)) {
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
&pdoUniCodeName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
DeviceObject);
if (NT_SUCCESS(ntStatus)) {
deviceExtension = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
}
if (!NT_SUCCESS(ntStatus)) {
return ntStatus;
}
RtlInitUnicodeString (&DeviceLinkUniCodeString, DeviceLinkName);
ntStatus = IoCreateSymbolicLink(&DeviceLinkUniCodeString, &pdoUniCodeName);
// Максимальный размер пересылаемых данных за запрос вводы/
deviceExtension->MaximumTransferSize = ISO_MAX_TRANSFER_SIZE ;
// Копируем имя нашего устройства в структура расширения устройства
RtlCopyMemory(deviceExtension->DeviceLinkNameBuffer,
deviceLinkUnicodeString.Buffer,
deviceLinkUnicodeString.Length);
// Инициализируем события
KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
KeInitializeEvent(&deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
KeInitializeEvent(&deviceExtension->NoPendingIoEvent, NotificationEvent, FALSE);
// Освобождаем строковый буфер
RtlFreeUnicodeString( &deviceLinkUnicodeString );
}
return ntStatus;
}
// ========================================================================
// Данная функция вызывается для создания и инициализации GUID-
// символической ссылки на наше устройство, дабы из пользовательского
// режима можно было работать с манипулятором (handle) устройства
NTSTATUS CreateSymbolicLink(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PUNICODE_STRING deviceLinkUnicodeString
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
// Создаем символическую ссылку
// Вызов IoRegisterDeviceInterface регистрирует интерфейс устройства и,
// таким образом, драйвер будет «доступен» для приложений пользовательского // режима или иных системных компонентов
ntStatus = IoRegisterDeviceInterface(
DeviceObject,
(LPGUID)& GUID_CLASS_DACAL_DC_300,
NULL,
deviceLinkUnicodeString);
if (NT_SUCCESS(ntStatus)) {
// Вызов IoSetDeviceInterfaceState активирует или деактивирует предыдущие
// зарегистрированные интерфейсы устройства. Приложения и системные
// компоненты могут открыть только активированный (доступный) интерфейс
ntStatus = IoSetDeviceInterfaceState(deviceLinkUnicodeString, TRUE);
}
return ntStatus;
}