- •Введение 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.4 Процедура передачи запроса usbd
Для непосредственного выполнения запросов к устройству, т.е. передачи URB – блоков USBD-классовому драйверу, необходимо выполнить следующие действия:
выделить блок нестраничной памяти (non paged memory) с помощью вызова ExAllocatePool;
сформировать запрос с помощью одной из функций формирования запросов:
UsbBuildGetDescriptorRequest;
UsbBuildSelectConfigurationRequest;
UsbBuildInterruptOrBulkTransferRequest;
передать запрос USBD с помощью функции CallUSBD (нижеприведенный листинг);
обработать результат запроса;
освободить память.
В случае асинхронного вызова два последних действия переносятся в функцию, вызываемую при завершении выполнения операции.
NTSTATUS CallUSBD (
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb
)
// Отправляет блок URB USBD-классовому драйверу в качестве параметра в
// IRP со следующими значениями полей:
// Irp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
// Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
ISOUSB_KdPrint( DBGLVL_MAXIMUM,("enter IsoUsb_CallUSBD\n"));
deviceExtension = DeviceObject->DeviceExtension;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
deviceExtension->TopOfStackDeviceObject,
NULL, // Входной буфер нам не нужен
0, // Длина входного буфера здесь не имеет значения
NULL, // Выходной буфер – не нужен
0, // Длина выходного буфера здесь не имеет значения
TRUE,
&event,
&ioStatus); // Передаем блок статуса ввода/вывода;
// Устанавливается когда запрос выполнен нижестоящим драйвером
// Осуществляем вызов классового драйвера для выполнения операции
// Если возвращаемое значение STATUS_PENDING, то ждем выполнения операции
nextStack = IoGetNextIrpStackLocation(irp);
// Отправляем URB-блок
nextStack->Parameters.Others.Argument1 = Urb;
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if (ntStatus == STATUS_PENDING) {
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
} else {
ioStatus.Status = ntStatus;
}
Urb->UrbHeader.Status, status, ioStatus.Status));
// Возвращаем статус операции
ntStatus = ioStatus.Status;
return ntStatus;
}
2.4.5 Обработчики usbCreate и usbClose
Обработчики USBCreate и USBClose, в общем случае, могут не выполнять никаких специальных действий за исключением управления счетчиком копий драйвера. Однако, процедура USBCreate еще важна потому, что является «точкой входа» для пользовательской функции Win32 API CreateFile, позволяющей открывать манипулятор устройства и, соответственно, работать с ним.
NTSTATUS USBCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
// Обработчик для IRP IRP_MJ_CREATE.
// Точка входа для пользовательской функции CreateFile().
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
ULONG i, ix;
NTSTATUS actStat;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION PipeInfo;
PISOUSB_PIPEINFO ourPipeInfo = NULL;
deviceExtension = DeviceObject->DeviceExtension;
interface = deviceExtension->UsbInterface;
// Увеличиваем кол-во обрабатываемых в данный момент IRP
IncrementIoCount(DeviceObject);
Вызов CanAcceptIoRequests проверяет, можем ли мы выполнить новый запрос ввода/вывода. Не можем в следующих случаях:
Устройство физически удалено;
Устройство не включено;
Устройство находится в "приостановленном" состоянии;
Выполняется запрос на удаление устройства.
do
{
if ( ! CanAcceptIoRequests( DeviceObject ) ) {
ntStatus = STATUS_DELETE_PENDING;
break;
}
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
fileObject->FsContext = NULL;
if ( 0 == fileObject->FileName.Length )
break;
// Вызов PipeWithName() возвращает PUSBD_PIPE_INFORMATION, т.е. структуру с информацией о канале USB, иначе NULL
ourPipeInfo = PipeWithName( DeviceObject, &fileObject->FileName );
if ( !ourPipeInfo ) {
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
for (i=0; i<interface->NumberOfPipes; i++)
{
PipeInfo = &interface->Pipes[i]; // PUSBD_PIPE_INFORMATION
if ( ourPipeInfo == &deviceExtension->PipeInfo[i] )
{
// Найдено совпадение
fileObject->FsContext = PipeInfo;
// Устанавливаем флаг ОТКРЫТО
ourPipeInfo->fPipeOpened = TRUE;
ntStatus = STATUS_SUCCESS;
// Увеличиваем счетчик конечных точек
deviceExtension->OpenPipeCount++;
// Вызов SelfSuspendOrActivate() пытается включить устройство,
// если оно находится в состоянии энергопотребления отличном от D0
actStat = SelfSuspendOrActivate( DeviceObject, FALSE );
break;
}
}
break;
}
while( FALSE );
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
DeviceObject->OpenHandles += 1;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
// Обработали IO-запрос - уменьшаем счетчик запросов ввода/вывода
DecrementIoCount(DeviceObject);
return ntStatus;
}
Обработчик USBClose обрабатывает IRP_MJ_CLOSE. Фактически является точкой входа для пользовательской функции Win32 API CloseHandle(). Данный обработчик осуществляет закрытие манипулятора конечной точки USB-устройства.
NTSTATUS USBClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS ntStatus;
NTSTATUS actStat;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PISOUSB_PIPEINFO pipeInfo = NULL;
IncrementIoCount(DeviceObject);
deviceExtension = DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
if (fileObject->FsContext) {
// Закрываем манипулятор канала
pipeHandle = fileObject->FsContext;
// Вызов PipeWithName() возвращает PUSBD_PIPE_INFORMATION, т.е. структуру
// с информацией о канале, иначе NULL
pipeInfo = PipeWithName( DeviceObject, &fileObject->FileName );
if ( NULL != pipeInfo )
{
if ( pipeInfo->fPipeOpened ) { // Если манипулятор открыт,
// уменьшаем кол-во открытых (используемых)
// каналов
deviceExtension->OpenPipeCount--;
pipeInfo->fPipeOpened = FALSE;
}
else {
// Иначе, если канал уже открыт
ASSERT( deviceExtension->DeviceRemoved );
// Ситуация маловероятна, но возможна, поэтому ограничимся макросом ASSERT
}
}
}
DecrementIoCount(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
ntStatus = Irp->IoStatus.Status;
if( DeviceObject->OpenHandles > 0 ) {
DeviceObject->OpenHandles -= 1;
}
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
return ntStatus;
}