Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ДП.docx
Скачиваний:
11
Добавлен:
23.09.2019
Размер:
4.64 Mб
Скачать

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;

}