天天看點

UsbStorage驅動開發

前段時間發現有網友在開發驅動的過程中遇到問題,是以今天我整理了一下我在寫驅動中的一點心得。希望大家指導!

    win2k的UsbStorage不需要驅動程式就能運作,但是如果我們的裝置有特殊功能,像前幾天有網友問的那種要顯示自已的标号的。那麼UsbStor.sys就不能滿足我們的需求。當然如果要實作自己的功能,我們也隻需要UsbStor.sys的基礎上修改就行了!

    USB磁盤驅動程式是一個BUS DRIVER,它的主要入口如下:

    NTSTATUS

DriverEntry(

            IN PDRIVER_OBJECT DriverObject,

            IN PUNICODE_STRING pRegistryPath

            )

{

#if    DBG

    DbgPrint("Enter UsbStore DriverEntry!/n");

#endif     

    DriverObject->DriverExtension->AddDevice = UsbStore_AddDevice;

    DriverObject->DriverUnload = UsbStore_Unload;

    DriverObject->DriverStartIo = UsbStore_StartIo;

    DriverObject->MajorFunction[IRP_MJ_CREATE] =  

    DriverObject->MajorFunction[IRP_MJ_CLOSE]  = UsbStore_CreateClose;

    DriverObject->MajorFunction[IRP_MJ_READ]   =

    DriverObject->MajorFunction[IRP_MJ_WRITE]  = UsbStore_ReadWrite;

    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = UsbStore_DeviceIoControl;

    DriverObject->MajorFunction[IRP_MJ_SCSI]   = UsbStore_Scsi;

    DriverObject->MajorFunction[IRP_MJ_PNP]    = UsbStore_Pnp;

    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = UsbStore_SystemControl;

    DriverObject->MajorFunction[IRP_MJ_POWER]  = UsbStore_Power;

    return STATUS_SUCCESS;

}

USB STORAGE DRIVER對裝置的主要操作MajorFunction是IRP_MJ_SCSI,而不是IRP_MJ_READ 以及IRP_MJ_WRITE 。

USB STORAGE DRIVER的上層程式是CLASS DRIVER。CLASS DRIVER對上層的USB磁盤的讀寫等操作轉換成IRP_MJ_SCSI,USB STORAGE DRIVER根據USB CBI規範和BULK ONLY規範将上層DRIVER傳送來的IRP_MJ_SCSI的SRB(SCSI_REQUEST_BLOCK)的相關部分傳遞給裝置。

UsbStore_AddDevice的功能是建立USB STORAGE DRIVER的FDO。

NTSTATUS

UsbStore_AddDevice(

                   IN PDRIVER_OBJECT DriverObject,

                   IN PDEVICE_OBJECT PhysicalDeviceObject

                   )

{

    NTSTATUS status;

    PUSB_DEVICE_EXTENSION pUsb_DeviceExtension;

    PDEVICE_OBJECT USbStore_FileDeviceObject = NULL;

    KEVENT Event;

#if    DBG

    DbgPrint("Enter AddDevice Dispatch!/n");

#endif

    status = IoCreateDevice(

                   DriverObject,

                   sizeof(USB_DEVICE_EXTENSION),

                   NULL,

                   FILE_DEVICE_BUS_EXTENDER,

                   FILE_AUTOGENERATED_DEVICE_NAME ,

                   FALSE,

                   &USbStore_FileDeviceObject

                   );

    if(!NT_SUCCESS(status))

    {

#if DBG

        DbgPrint("IoCreateDevice Failed!/n");

#endif

        return status;

    }

    pUsb_DeviceExtension = (PUSB_DEVICE_EXTENSION)USbStore_FileDeviceObject->DeviceExtension;

    RtlZeroMemory(pUsb_DeviceExtension,sizeof(USB_DEVICE_EXTENSION));

    pUsb_DeviceExtension->DeviceType = USBSTORE_FDO;

    pUsb_DeviceExtension->UsbFileDeviceObject = USbStore_FileDeviceObject;

    pUsb_DeviceExtension->UsbPhysicalDeviceObject = PhysicalDeviceObject;

    pUsb_DeviceExtension->SystemPowerState = PowerSystemWorking;

    pUsb_DeviceExtension->CurrentPowerState = PowerDeviceD0;

    pUsb_DeviceExtension->UsbStore_TopOfStackDeviceObject =  

                            IoAttachDeviceToDeviceStack(

                                                        USbStore_FileDeviceObject,

                                                        PhysicalDeviceObject

                                                        );

    KeInitializeEvent(

                      &Event,

                      SynchronizationEvent,

                      FALSE

                      );

    pUsb_DeviceExtension->Usb_Event = Event;

    UsbStore_GetDriverFlags(USbStore_FileDeviceObject);

    USbStore_FileDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    USbStore_FileDeviceObject->Flags |= DO_DIRECT_IO;

    USbStore_FileDeviceObject->Flags |= DO_POWER_PAGABLE;

    return STATUS_SUCCESS;

}

//UsbStore_GetDriverFlags

NTSTATUS

UsbStore_GetDriverFlags(

                        IN PDEVICE_OBJECT UsbFdo

                        )

{

    PUSB_DEVICE_EXTENSION pUsb_DeviceExtension;

    NTSTATUS status;

    HANDLE RegHandle;

    RTL_QUERY_REGISTRY_TABLE RegTable;

    ULONG Value = 0;

    RtlZeroMemory(&RegTable,sizeof(RTL_QUERY_REGISTRY_TABLE));

    pUsb_DeviceExtension = UsbFdo->DeviceExtension;

    status = IoOpenDeviceRegistryKey(

                                     pUsb_DeviceExtension->UsbPhysicalDeviceObject,

                                     PLUGPLAY_REGKEY_DRIVER,

                                     STANDARD_RIGHTS_ALL,

                                     &RegHandle

                                     );

    if(NT_SUCCESS(status))

    {

        RegTable.Flags = RTL_QUERY_REGISTRY_DIRECT;

        RegTable.Name = L"DriverFlags";

        RegTable.EntryContext = &Value;

        RegTable.DefaultType = REG_DWORD;

        RegTable.DefaultData = &Value;

        RegTable.DefaultLength = sizeof(ULONG);

        status = RtlQueryRegistryValues(

                                        RTL_REGISTRY_HANDLE,

                                        RegHandle,

                                        &RegTable,

                                        NULL,

                                        NULL

                                        );

        if(!NT_SUCCESS(status))

        {

#if DBG

            DbgPrint("RtlQueryRegistryValues Failed!/n");

#endif

            return status;

        }

        ZwClose(RegHandle);  

    }

    if(Value>=4)

        Value =0;

    pUsb_DeviceExtension->DriverFlags = Value;     

    return status;

}

在這段代碼中,

status = IoCreateDevice(

                   DriverObject,

                   sizeof(USB_DEVICE_EXTENSION),

                   NULL,

                   FILE_DEVICE_BUS_EXTENDER,

                   FILE_AUTOGENERATED_DEVICE_NAME ,

                   FALSE,

                   &USbStore_FileDeviceObject

                   );

負責建立一個USB STORAGE DRIVER的FDO,請各位注意,裝置的類型(DEVICE TYPE)是FILE_DEVICE_BUS_EXTENDER。

取系統資料庫的一段代碼,主要負責是取出DRIVER FLAGS,它用于标記裝置是滿足CBI規範還是BULK ONLY規範。

UsbStore_ReadWrite這一函數不做任何實際有用的讀寫操作。

NTSTATUS UsbStore_ReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )

{

#if DBG

DbgPrint("Enter ReadWrite Dispatch!/n");

#endif

Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;

 Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return STATUS_INVALID_PARAMETER;

}

UsbStore_Scsi将上層DRIVER的IRP_MJ_SCSI的請求排隊,

NTSTATUS UsbStore_Scsi(IN PDEVICE_OBJECT UsbStorePdo, IN PIRP Irp)

{

PUSBSTORE_DEVICE_EXTENSION pUsbStoreDeviceExtension = UsbStorePdo->DeviceExtension;

PIO_STACK_LOCATION irpStackLocation = IoGetCurrentIrpStackLocation(Irp);

PSCSI_REQUEST_BLOCK Srb = irpStackLocation->Parameters.Scsi.Srb;

NTSTATUS status;

KIRQL Irql;

 if(pUsbStoreDeviceExtension->DeviceType == USBSTORE_PDO)

{

 if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI)

{

if(Srb->DataTransferLength <=0x10000)

{

Srb->SrbStatus = SRB_STATUS_PENDING;

IoMarkIrpPending(Irp);

IoStartPacket(UsbStorePdo, Irp, &Srb->QueueSortKey, (PDRIVER_CANCEL)UsbStore_CancelRoutine);

status = STATUS_PENDING;

}

else

{

status = STATUS_INVALID_PARAMETER;

}

}

else if(Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)

{

KeAcquireSpinLock(&pUsbStoreDeviceExtension->SpinLock, &Irql);

if(pUsbStoreDeviceExtension->DeviceFlags&0x01)

{

status = STATUS_END_OF_FILE;

Srb->SrbStatus = SRB_STATUS_BUSY;

}

else

{

pUsbStoreDeviceExtension->DeviceFlags|=0x01;

Srb->DataBuffer = UsbStorePdo;

Srb->SrbStatus = SRB_STATUS_SUCCESS;

}

KeReleaseSpinLock(&pUsbStoreDeviceExtension->SpinLock, Irql);

}

else if(Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)

{

KeAcquireSpinLock(&pUsbStoreDeviceExtension->SpinLock,&Irql);

pUsbStoreDeviceExtension->DeviceFlags &= 0xFFFFFFFE;

KeReleaseSpinLock(&pUsbStoreDeviceExtension->SpinLock, Irql);

Srb->SrbStatus = SRB_STATUS_SUCCESS;

status = STATUS_SUCCESS;

}

else if(Srb->Function == SRB_FUNCTION_FLUSH)

{

Srb->SrbStatus = SRB_STATUS_SUCCESS;

status = STATUS_SUCCESS;

}

else

{

status = STATUS_NOT_SUPPORTED;

}

}

else

{

status = STATUS_NOT_SUPPORTED;

}

if(status != STATUS_PENDING)

{

Irp->IoStatus.Status = STATUS_SUCCESS;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

}

return status;

}

而UsbStore_StartIo函數将排隊的IRP通過CBI規範或者BULK ONLY規範發送給裝置,

VOID UsbStore_StartIo( IN PDEVICE_OBJECT UsbStorePdo, IN PIRP Irp )

{

ULONG TempFlags;

PSCSI_REQUEST_BLOCK Srb;

UCHAR DeviceErrorFlags ;

ULONG NeedSenseRequestFlags;

PUSBSTORE_DEVICE_EXTENSION pUsbStoreDeviceExtension = UsbStorePdo->DeviceExtension;

PIO_STACK_LOCATION irpStackLocation;

KIRQL Irql;

 irpStackLocation = IoGetCurrentIrpStackLocation(Irp);

 if(irpStackLocation->MajorFunction == IRP_MJ_POWER)

{

Irp->IoStatus.Status = STATUS_SUCCESS;

PoStartNextPowerIrp(Irp);

IoCompleteRequest(Irp,IO_NO_INCREMENT);

return;

}

else

{

IoAcquireCancelSpinLock(&Irql);

InterlockedExchange((PULONG)&Irp->CancelRoutine,0);

if(Irp->Cancel != 0)

{

KeAcquireSpinLockAtDpcLevel(&pUsbStoreDeviceExtension->SpinLock);

pUsbStoreDeviceExtension->DeviceFlags = pUsbStoreDeviceExtension->DeviceFlags>>3; pUsbStoreDeviceExtension->DeviceFlags = ~pUsbStoreDeviceExtension->DeviceFlags;

pUsbStoreDeviceExtension->DeviceFlags = pUsbStoreDeviceExtension->DeviceFlags&1;

TempFlags = pUsbStoreDeviceExtension->DeviceFlags;

KeReleaseSpinLockFromDpcLevel(&pUsbStoreDeviceExtension->SpinLock);

IoReleaseCancelSpinLock(Irql); Irp->IoStatus.Status = STATUS_CANCELLED;

Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp,IO_NO_INCREMENT);

if(TempFlags==0)

return;

else

IoStartNextPacket(UsbStorePdo, TRUE);

return;

}

else

{

IoReleaseCancelSpinLock(Irql);

DeviceErrorFlags = 0;

NeedSenseRequestFlags = 0;

Srb = irpStackLocation->Parameters.Scsi.Srb;

pUsbStoreDeviceExtension->Srb = Srb;

KeAcquireSpinLockAtDpcLevel(&pUsbStoreDeviceExtension->SpinLock);

if(pUsbStoreDeviceExtension->DeviceFlags&DEVICE_ERROR)

{

DeviceErrorFlags = 1;

}

else

{

pUsbStoreDeviceExtension->SrbTimeOutValue = Srb->TimeOutValue;

if(pUsbStoreDeviceExtension->DeviceFlags&NEED_SENSEREQUEST)

{

NeedSenseRequestFlags = 1;

pUsbStoreDeviceExtension->DeviceFlags&=~NEED_SENSEREQUEST;

}

}

KeReleaseSpinLockFromDpcLevel(&pUsbStoreDeviceExtension->SpinLock);

if(DeviceErrorFlags ==0)

{

UsbStore_FormatSrb(UsbStorePdo,Irp,Srb,1);

if(pUsbStoreDeviceExtension->DriverFlags==1)

{

UsbStore_BulkOnly(UsbStorePdo,Irp);

return;

}

else

{

if(NeedSenseRequestFlags == 0||Srb->Cdb[0] == SCSIOP_REQUEST_SENSE)

{

UsbStore_CBI(UsbStorePdo, Irp);

return;

}

else

{

UsbStore_CBIGetRequestSense(UsbStorePdo,Irp,1);

return;

}

}

}

else

{

Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

IoStartNextPacket(UsbStorePdo, TRUE);

return;

}

}

}

}

UsbStore_DeviceIoControl函數負責處理IRP_MJ_DEVICE_CONTROL,其中IOCONTROLCODE主要有IOCTL_SCSI_PASS_THROUGH,IOCTL_SCSI_PASS_THROUGH_DIRECT,IOCTL_STORAGE_QUERY_PROPERTY。限于篇幅,就不将此函數的代碼列下。 UsbStore_Pnp函數負責處理IRP_MJ_PNP,USB STORAGE DRIVER的FDO IRP_MJ_PNP的IRP_MN_START_DEVICE負責建立USB連接配接,建立USB STORAGE DRIVER的PDO。USB STORAGE DRIVER FDO 的IRP_MN_REMOVE_DEVICE負責清除裝置資源及USB連接配接。 USB STORAGE DRIVER PDO的IRP_MN_QUERY_DEVICE_TEXT 和IRP_MN_QUERY_ID是BUS DRIVER的PNP所必須處理的。

NTSTATUS

UsbStore_Pnp(

             IN PDEVICE_OBJECT DeviceObject,

             IN PIRP Irp

             )

{

    NTSTATUS status = STATUS_SUCCESS;

    PUSB_DEVICE_EXTENSION pUsbDeviceExtension;

    PIO_STACK_LOCATION irpStackLocation;

    irpStackLocation = IoGetCurrentIrpStackLocation(Irp);

    pUsbDeviceExtension = DeviceObject->DeviceExtension;

    if(pUsbDeviceExtension->DeviceType == USBSTORE_FDO)

    {

        switch(irpStackLocation->MinorFunction)

        {

        case IRP_MN_STOP_DEVICE:

            status = UsbStore_UsbFdoStopDevice(DeviceObject,Irp);

            break;

        case IRP_MN_START_DEVICE:

            status = UsbStore_UsbFdoStartDevice(DeviceObject,Irp);

            break;

        case IRP_MN_QUERY_REMOVE_DEVICE:

        case IRP_MN_QUERY_STOP_DEVICE:

            status = UsbStore_UsbFdoQueryRemoveDevice(DeviceObject,Irp);

            break;

        case IRP_MN_REMOVE_DEVICE:

            status = UsbStore_UsbFdoRemoveDevice(DeviceObject,Irp);

            break;

        case IRP_MN_CANCEL_REMOVE_DEVICE:

        case IRP_MN_CANCEL_STOP_DEVICE:

            status = UsbStore_UsbFdoCancelRemoveDevice(DeviceObject,Irp);

            break;

        case IRP_MN_QUERY_DEVICE_RELATIONS:

            status = UsbStore_UsbFdoQueryDeviceRelations(DeviceObject,Irp);

            break;

        case IRP_MN_SURPRISE_REMOVAL:

            Irp->IoStatus.Status = STATUS_SUCCESS;

        default:

            IoSkipCurrentIrpStackLocation(Irp);

            status = IoCallDriver(pUsbDeviceExtension->UsbStore_TopOfStackDeviceObject,Irp);

            return status;

        }

    }

    else

    {

        switch(irpStackLocation->MinorFunction)

        {

        case IRP_MN_QUERY_CAPABILITIES:

            status = UsbStore_StorePdoQueryCapabilities(DeviceObject,Irp);

            return status;

        case IRP_MN_START_DEVICE:

            status = UsbStore_StorePdoStartDevice(DeviceObject,Irp);

            return status;

        case IRP_MN_REMOVE_DEVICE:

            status = UsbStore_StoreRemoveDevice(DeviceObject,Irp);

            return status;

        case IRP_MN_QUERY_DEVICE_RELATIONS:

            status = UsbStore_StoreQueryDeviceRelations(DeviceObject,Irp);

            return status;

        case IRP_MN_QUERY_DEVICE_TEXT:

            status = UsbStore_StoreQueryDeviceText(DeviceObject,Irp);

            return status;

        case IRP_MN_QUERY_ID:

            status = UsbStore_StoreQueryID(DeviceObject,Irp);

            return status;

        default:

            Irp->IoStatus.Status = STATUS_SUCCESS;

            IoCompleteRequest(Irp,IO_NO_INCREMENT);

            return status;

        }

    }

    return status;

}

本文以BULK ONLY為例來說明USB STORAGE DRIVER的傳輸過程。

VOID                    

UsbStore_BulkOnly(IN PDEVICE_OBJECT UsbStorePdo,  

                  IN PIRP Irp)

{

    PUSBSTORE_DEVICE_EXTENSION pUsbStoreDeviceExtension = UsbStorePdo->DeviceExtension;

    PUSB_DEVICE_EXTENSION pUsbDeviceExtension = pUsbStoreDeviceExtension->pUsbDeviceExtension;

    PIO_STACK_LOCATION nextirpst,irpst,irpStackLocation = IoGetCurrentIrpStackLocation(Irp);

    PSCSI_REQUEST_BLOCK Srb = irpStackLocation->Parameters.Scsi.Srb;

    PUCHAR pCdb = &Srb->Cdb[0];

    PBULKONLY_CBW pBulkOnly_Cbw = &pUsbStoreDeviceExtension->BulkOnly_Cbw;

    pUsbStoreDeviceExtension->ResaetpipeTimes = 0;

    pBulkOnly_Cbw->dCbwSignature = BULKONLY_CBWSIG;

    pBulkOnly_Cbw->dCbwTag = (ULONG_PTR)Irp;

    pBulkOnly_Cbw->dCbwDataTransferLength = Srb->DataTransferLength;

    pBulkOnly_Cbw->bmCbwFlags = ((UCHAR)Srb->SrbFlags&0xC0)<<1;

    pBulkOnly_Cbw->bCbwLun = 0;

    pBulkOnly_Cbw->bCbwCBLength = Srb->CdbLength;

    RtlCopyMemory(pBulkOnly_Cbw->CbwCDB,pCdb,sizeof(CDB));

    UsbStore_TransferData(UsbStorePdo,Irp,pUsbDeviceExtension->pBulkOutPipeInfo->PipeHandle,0,0x1F,pBulkOnly_Cbw,NULL,(PIO_COMPLETION_ROUTINE)UsbStore_BulkOnlySendCbwCompleteRoutine,0);

    return;

}

根據BULK ONLY規範定義了一個結構:

typedef struct _BULKONLY_CBW{

    ULONG dCbwSignature;

    ULONG_PTR dCbwTag;

    ULONG dCbwDataTransferLength;

    UCHAR bmCbwFlags;

    UCHAR bCbwLun :4;

    UCHAR Reserved0:4;

    UCHAR bCbwCBLength:5;

    UCHAR Reserved1:3;

    UCHAR CbwCDB[16];

}BULKONLY_CBW, *PBULKONLY_CBW;

注意:這個結構的長度在BULKONLY規範裡是0X1F,而不是SIZEOF(BULKONLY_CBW),此值傳遞給UsbStore_TransferData

UsbStore_TransferData負責USB資料傳輸

VOID

UsbStore_TransferData(

                      IN PDEVICE_OBJECT UsbStorePdo,

                      IN PIRP Irp,

                      IN USBD_PIPE_HANDLE PipeHandle,

                      IN ULONG TransferFlags,

                      IN ULONG DataTransferBufferLength,

                      IN PVOID DataTransferBuffer,

                      IN PMDL DataTransferBufferMDL,

                      IN PIO_COMPLETION_ROUTINE CompleteRoutine,

                      IN PVOID Context

                      )

{

    PUSBSTORE_DEVICE_EXTENSION pUsbStoreDeviceExtension = UsbStorePdo->DeviceExtension;

    PUSB_DEVICE_EXTENSION pUsbDeviceExtension = pUsbStoreDeviceExtension->pUsbDeviceExtension;

    PURB purb = &pUsbStoreDeviceExtension->CurrentUrb;

    PIO_STACK_LOCATION irpStackLocation = IoGetNextIrpStackLocation(Irp);

    KIRQL Irql;

    RtlZeroMemory(purb,sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));

    UsbBuildInterruptOrBulkTransferRequest(

                                           purb,

                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),

                                           PipeHandle,

                                           DataTransferBuffer,

                                           DataTransferBufferMDL,

                                           DataTransferBufferLength,

                                           TransferFlags,

                                           NULL  

                                           );

    irpStackLocation->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

    irpStackLocation->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

    irpStackLocation->Parameters.Others.Argument1 = purb;

    IoSetCompletionRoutine(Irp, CompleteRoutine, Context, TRUE, TRUE, TRUE);

    KeAcquireSpinLock(&pUsbStoreDeviceExtension->SpinLock, &Irql);

    pUsbStoreDeviceExtension->DeviceFlags |= TRANSFER_FINISHED;

    pUsbStoreDeviceExtension->CurrentIrp = Irp;

    KeReleaseSpinLock(&pUsbStoreDeviceExtension->SpinLock, Irql);

    IoCallDriver(pUsbDeviceExtension->UsbStore_TopOfStackDeviceObject, Irp);

}

繼續閱讀