add a realtime scheduler class and priority-inheritance mutexes with timeouts and abandonment, add an HDA audio driver and a SYS_AUDIO_* syscall family, flesh out kernel32 with Win32 threads, events, mutexes, critical sections, and condition variables, add SYS_RESUME_THREAD for suspended thread creation, add KeInitializeMemoryTypes to reprogram MTRRs and install a canonical PAT for WB/WC/UC control, rework the display pipeline with a pitched present path and console output flush, bring back disk.vhd with mtools since vvfat fucking sucks, harden AHCI with serialized cache flush, USB mass storage with SCSI sense-data decoding, and xHCI with cleaner DMA teardown, fix the last stray for(;;) in HalStopProcessor to while(true), pile on smoke tests for audio, win32 sync primitives, and thread suspend, implement AHCI timeout, kill readahead since it was desperetaly trying to murder me, fix doom sound x2.

This commit is contained in:
maksw committed 2026-08-11 18:38:36 +02:00
1 parent 8b254f84f4
commit 4add6789ba
177 files changed
+22565 -3070

No files matched your search

+261 -50
View File
@@ -56,10 +56,10 @@ static const USB_ENDPOINT_DESCRIPTOR* UsbStorageFindBulkEndpoint(const USB_PDO_E
static KSTATUS UsbStorageSubmitBulk(USB_STORAGE_EXTENSION* storage,
bool dataIn,
PHYSICAL_ADDRESS phys,
uint64_t deviceAddress,
uint32_t length,
uint32_t* outActual) {
if (!storage || !storage->LowerDevice || !storage->Device || !phys || length == 0)
if (!storage || !storage->LowerDevice || !storage->Device || !deviceAddress || length == 0)
return NTLSTATUS_INVALID_PARAMETER;
USB_PIPE* pipe = dataIn ? storage->BulkInPipe : storage->BulkOutPipe;
@@ -73,7 +73,7 @@ static KSTATUS UsbStorageSubmitBulk(USB_STORAGE_EXTENSION* storage,
urb.Device = storage->Device;
urb.Pipe = pipe;
urb.Buffer = (void*)0;
urb.BufferPhys = phys;
urb.BufferDeviceAddress = deviceAddress;
urb.Length = length;
KSTATUS st = UsbSubmitUrbSync(storage->LowerDevice, &urb);
@@ -83,29 +83,42 @@ static KSTATUS UsbStorageSubmitBulk(USB_STORAGE_EXTENSION* storage,
}
KSTATUS UsbStorageBulkIn(USB_STORAGE_EXTENSION* storage,
PHYSICAL_ADDRESS phys,
uint64_t deviceAddress,
uint32_t length,
uint32_t* outActual) {
return UsbStorageSubmitBulk(storage, true, phys, length, outActual);
return UsbStorageSubmitBulk(storage, true, deviceAddress, length, outActual);
}
KSTATUS UsbStorageBulkOut(USB_STORAGE_EXTENSION* storage,
PHYSICAL_ADDRESS phys,
uint64_t deviceAddress,
uint32_t length,
uint32_t* outActual) {
return UsbStorageSubmitBulk(storage, false, phys, length, outActual);
return UsbStorageSubmitBulk(storage, false, deviceAddress, length, outActual);
}
KSTATUS UsbStorageBotCommand(USB_STORAGE_EXTENSION* storage,
const uint8_t* cdb,
uint8_t cdbLen,
void* data,
PHYSICAL_ADDRESS dataPhys,
uint32_t dataLength,
bool dataIn) {
typedef struct USB_STORAGE_SENSE_DATA {
bool Valid;
uint8_t ResponseCode;
uint8_t Key;
uint8_t Asc;
uint8_t Ascq;
} USB_STORAGE_SENSE_DATA;
// Executes one BOT command without issuing follow-up commands.
static KSTATUS UsbStorageBotCommandRaw(USB_STORAGE_EXTENSION* storage,
const uint8_t* cdb,
uint8_t cdbLen,
void* data,
uint64_t dataDeviceAddress,
uint32_t dataLength,
bool dataIn,
uint8_t* outCswStatus,
uint32_t* outResidue) {
if (outCswStatus) *outCswStatus = 0xFFu;
if (outResidue) *outResidue = 0;
if (!storage || !storage->XhciDevice || !cdb || cdbLen == 0 || cdbLen > 16)
return NTLSTATUS_INVALID_PARAMETER;
if (dataLength && (!data || !dataPhys))
if (dataLength && (!data || !dataDeviceAddress))
return NTLSTATUS_INVALID_PARAMETER;
XHCI_DEVICE* dev = storage->XhciDevice;
@@ -120,14 +133,14 @@ KSTATUS UsbStorageBotCommand(USB_STORAGE_EXTENSION* storage,
memcpy(cbw->CommandBlock, cdb, cdbLen);
uint32_t actual = 0;
KSTATUS st = UsbStorageBulkOut(storage, dev->DescriptorPhys, sizeof(*cbw), &actual);
KSTATUS st = UsbStorageBulkOut(storage, dev->DescriptorDeviceAddress, sizeof(*cbw), &actual);
if (!KSUCCESS(st) || actual != sizeof(*cbw))
return KSUCCESS(st) ? NTLSTATUS_DEVICE_ERROR : st;
if (dataLength) {
actual = 0;
st = dataIn ? UsbStorageBulkIn(storage, dataPhys, dataLength, &actual)
: UsbStorageBulkOut(storage, dataPhys, dataLength, &actual);
st = dataIn ? UsbStorageBulkIn(storage, dataDeviceAddress, dataLength, &actual)
: UsbStorageBulkOut(storage, dataDeviceAddress, dataLength, &actual);
if (!KSUCCESS(st))
return st;
}
@@ -135,7 +148,7 @@ KSTATUS UsbStorageBotCommand(USB_STORAGE_EXTENSION* storage,
USB_MASS_CSW* csw = (USB_MASS_CSW*)dev->DescriptorBuffer;
memset(csw, 0, sizeof(*csw));
actual = 0;
st = UsbStorageBulkIn(storage, dev->DescriptorPhys, sizeof(*csw), &actual);
st = UsbStorageBulkIn(storage, dev->DescriptorDeviceAddress, sizeof(*csw), &actual);
if (!KSUCCESS(st) || actual != sizeof(*csw))
return KSUCCESS(st) ? NTLSTATUS_DEVICE_ERROR : st;
@@ -144,15 +157,136 @@ KSTATUS UsbStorageBotCommand(USB_STORAGE_EXTENSION* storage,
dev->SlotId, csw->Signature, csw->Tag, storage->Tag);
return NTLSTATUS_DEVICE_ERROR;
}
if (csw->Status != USB_MASS_BOT_CSW_PASSED) {
DbgPrint("usb-storage: command %02x failed slot=%u csw_status=%u residue=%u\n",
cdb[0], dev->SlotId, csw->Status, csw->DataResidue);
return NTLSTATUS_DEVICE_ERROR;
if (outCswStatus) *outCswStatus = csw->Status;
if (outResidue) *outResidue = csw->DataResidue;
return csw->Status == USB_MASS_BOT_CSW_PASSED
? NTLSTATUS_SUCCESS
: NTLSTATUS_DEVICE_ERROR;
}
// Returns a readable SCSI sense-key name.
static const char* UsbStorageSenseKeyName(uint8_t key) {
switch (key) {
case 0x00u: return "NO SENSE";
case 0x01u: return "RECOVERED ERROR";
case 0x02u: return "NOT READY";
case 0x03u: return "MEDIUM ERROR";
case 0x04u: return "HARDWARE ERROR";
case 0x05u: return "ILLEGAL REQUEST";
case 0x06u: return "UNIT ATTENTION";
case 0x07u: return "DATA PROTECT";
case 0x08u: return "BLANK CHECK";
case 0x0Bu: return "ABORTED COMMAND";
case 0x0Eu: return "MISCOMPARE";
default: return "UNKNOWN";
}
}
// Decodes fixed or descriptor-format REQUEST SENSE data.
static void UsbStorageDecodeSense(const uint8_t* bytes,
uint32_t length,
USB_STORAGE_SENSE_DATA* sense) {
if (!sense) return;
memset(sense, 0, sizeof(*sense));
if (!bytes || length == 0) return;
sense->ResponseCode = bytes[0] & 0x7Fu;
if ((sense->ResponseCode == 0x70u || sense->ResponseCode == 0x71u) && length >= 14u) {
sense->Key = bytes[2] & 0x0Fu;
sense->Asc = bytes[12];
sense->Ascq = bytes[13];
sense->Valid = true;
return;
}
if ((sense->ResponseCode == 0x72u || sense->ResponseCode == 0x73u) && length >= 4u) {
sense->Key = bytes[1] & 0x0Fu;
sense->Asc = bytes[2];
sense->Ascq = bytes[3];
sense->Valid = true;
}
}
// Fetches and decodes sense data after a command failure.
static KSTATUS UsbStorageFetchSense(USB_STORAGE_EXTENSION* storage,
USB_STORAGE_SENSE_DATA* sense) {
if (!storage || !storage->XhciDevice || !sense)
return NTLSTATUS_INVALID_PARAMETER;
XHCI_DEVICE* dev = storage->XhciDevice;
uint8_t cdb[6] = { SCSI_REQUEST_SENSE, 0, 0, 0, 18, 0 };
memset(dev->MassBuffer, 0, 18);
uint8_t cswStatus = 0xFFu;
uint32_t residue = 0;
KSTATUS st = UsbStorageBotCommandRaw(storage, cdb, sizeof(cdb),
dev->MassBuffer, dev->MassBufferDeviceAddress,
18, true, &cswStatus, &residue);
if (!KSUCCESS(st)) {
DbgPrint("usb-storage: REQUEST SENSE failed slot=%u st=0x%x csw_status=%u residue=%u\n",
dev->SlotId, st, cswStatus, residue);
memset(sense, 0, sizeof(*sense));
return st;
}
uint32_t returned = residue < 18u ? 18u - residue : 0u;
UsbStorageDecodeSense(dev->MassBuffer, returned, sense);
return NTLSTATUS_SUCCESS;
}
// Executes one BOT command and reports SCSI sense data on command failure.
static KSTATUS UsbStorageExecuteCommand(USB_STORAGE_EXTENSION* storage,
const uint8_t* cdb,
uint8_t cdbLen,
void* data,
uint64_t dataDeviceAddress,
uint32_t dataLength,
bool dataIn,
USB_STORAGE_SENSE_DATA* outSense) {
if (outSense) memset(outSense, 0, sizeof(*outSense));
uint8_t cswStatus = 0xFFu;
uint32_t residue = 0;
KSTATUS st = UsbStorageBotCommandRaw(storage, cdb, cdbLen, data,
dataDeviceAddress, dataLength, dataIn,
&cswStatus, &residue);
if (KSUCCESS(st)) return st;
XHCI_DEVICE* dev = storage ? storage->XhciDevice : (XHCI_DEVICE*)0;
uint32_t slot = dev ? dev->SlotId : 0;
if (cswStatus != USB_MASS_BOT_CSW_FAILED || !cdb || cdb[0] == SCSI_REQUEST_SENSE) {
DbgPrint("usb-storage: command %02x failed slot=%u st=0x%x csw_status=%u residue=%u\n",
cdb ? cdb[0] : 0, slot, st, cswStatus, residue);
return st;
}
USB_STORAGE_SENSE_DATA sense;
KSTATUS senseStatus = UsbStorageFetchSense(storage, &sense);
if (KSUCCESS(senseStatus) && sense.Valid) {
DbgPrint("usb-storage: command %02x failed slot=%u csw_status=%u residue=%u sense=%s key=%02x asc=%02x ascq=%02x\n",
cdb[0], slot, cswStatus, residue,
UsbStorageSenseKeyName(sense.Key), sense.Key, sense.Asc, sense.Ascq);
if (outSense) *outSense = sense;
} else {
DbgPrint("usb-storage: command %02x failed slot=%u csw_status=%u residue=%u sense=unavailable\n",
cdb[0], slot, cswStatus, residue);
}
return st;
}
// Executes one BOT command through the sense-reporting path.
KSTATUS UsbStorageBotCommand(USB_STORAGE_EXTENSION* storage,
const uint8_t* cdb,
uint8_t cdbLen,
void* data,
uint64_t dataDeviceAddress,
uint32_t dataLength,
bool dataIn) {
return UsbStorageExecuteCommand(storage, cdb, cdbLen, data,
dataDeviceAddress, dataLength, dataIn,
(USB_STORAGE_SENSE_DATA*)0);
}
// Implements the be32 operation.
uint32_t UsbBe32(const uint8_t* p) {
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
@@ -182,7 +316,7 @@ KSTATUS UsbStorageInquiry(USB_STORAGE_EXTENSION* storage) {
uint8_t cdb[6] = { SCSI_INQUIRY, 0, 0, 0, 36, 0 };
memset(dev->MassBuffer, 0, 36);
KSTATUS st = UsbStorageBotCommand(storage, cdb, sizeof(cdb),
dev->MassBuffer, dev->MassBufferPhys,
dev->MassBuffer, dev->MassBufferDeviceAddress,
36, true);
if (!KSUCCESS(st)) return st;
@@ -195,18 +329,6 @@ KSTATUS UsbStorageInquiry(USB_STORAGE_EXTENSION* storage) {
return NTLSTATUS_SUCCESS;
}
// Implements the storage Request Sense operation.
KSTATUS UsbStorageRequestSense(USB_STORAGE_EXTENSION* storage) {
if (!storage || !storage->XhciDevice)
return NTLSTATUS_INVALID_PARAMETER;
XHCI_DEVICE* dev = storage->XhciDevice;
uint8_t rs[6] = { SCSI_REQUEST_SENSE, 0, 0, 0, 18, 0 };
memset(dev->MassBuffer, 0, 18);
return UsbStorageBotCommand(storage, rs, sizeof(rs),
dev->MassBuffer, dev->MassBufferPhys, 18, true);
}
// Implements the storage Test Unit Ready operation.
KSTATUS UsbStorageTestUnitReady(USB_STORAGE_EXTENSION* storage) {
if (!storage || !storage->XhciDevice)
@@ -222,7 +344,6 @@ KSTATUS UsbStorageTestUnitReady(USB_STORAGE_EXTENSION* storage) {
if (KSUCCESS(st)) return NTLSTATUS_SUCCESS;
last = st;
(void)UsbStorageRequestSense(storage);
UsbDelayUs(xhci->Ddk, 10000u);
}
@@ -238,7 +359,7 @@ KSTATUS UsbStorageReadCapacity(USB_STORAGE_EXTENSION* storage) {
uint8_t cdb[10] = { SCSI_READ_CAPACITY_10, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
memset(dev->MassBuffer, 0, 8);
KSTATUS st = UsbStorageBotCommand(storage, cdb, sizeof(cdb),
dev->MassBuffer, dev->MassBufferPhys,
dev->MassBuffer, dev->MassBufferDeviceAddress,
8, true);
if (!KSUCCESS(st)) return st;
@@ -288,7 +409,7 @@ KSTATUS UsbStorageReadWriteSectors(USB_STORAGE_EXTENSION* storage,
memcpy(dev->MassBuffer, buffer, bytes);
KSTATUS st = UsbStorageBotCommand(storage, cdb, sizeof(cdb),
dev->MassBuffer, dev->MassBufferPhys,
dev->MassBuffer, dev->MassBufferDeviceAddress,
bytes, !write);
if (!KSUCCESS(st)) return st;
@@ -297,6 +418,48 @@ KSTATUS UsbStorageReadWriteSectors(USB_STORAGE_EXTENSION* storage,
return NTLSTATUS_SUCCESS;
}
// Returns whether sense data means SYNCHRONIZE CACHE is unsupported.
static bool UsbStorageSenseRejectsSynchronizeCache(const USB_STORAGE_SENSE_DATA* sense) {
if (!sense || !sense->Valid || sense->Key != 0x05u)
return false;
return sense->Asc == 0x20u || sense->Asc == 0x24u;
}
// Flushes device write caches through SCSI SYNCHRONIZE CACHE(10).
static KSTATUS UsbStorageSynchronizeCache(USB_STORAGE_EXTENSION* storage) {
if (!storage || !storage->XhciDevice)
return NTLSTATUS_INVALID_PARAMETER;
if (storage->FlushCapability == UsbStorageFlushUnsupported)
return NTLSTATUS_SUCCESS;
uint8_t cdb[10];
memset(cdb, 0, sizeof(cdb));
cdb[0] = SCSI_SYNCHRONIZE_CACHE_10;
for (uint32_t attempt = 0; attempt < 2; attempt++) {
USB_STORAGE_SENSE_DATA sense;
KSTATUS st = UsbStorageExecuteCommand(storage, cdb, sizeof(cdb),
(void*)0, 0, 0, false, &sense);
if (KSUCCESS(st)) {
storage->FlushCapability = UsbStorageFlushSupported;
return NTLSTATUS_SUCCESS;
}
if (UsbStorageSenseRejectsSynchronizeCache(&sense)) {
storage->FlushCapability = UsbStorageFlushUnsupported;
DbgPrint("usb-storage: slot=%u does not support SYNCHRONIZE CACHE; flushes use BOT command-completion semantics only\n",
storage->XhciDevice->SlotId);
return NTLSTATUS_SUCCESS;
}
if (sense.Valid && sense.Key == 0x06u && attempt == 0)
continue;
return st;
}
return NTLSTATUS_DEVICE_ERROR;
}
// Implements the storage Acquire Io operation.
void UsbStorageAcquireIo(USB_STORAGE_EXTENSION* storage) {
if (!storage) return;
@@ -375,24 +538,70 @@ KSTATUS UsbStorageDispatchReadWrite(DEVICE_OBJECT* device, IRP* irp) {
return NTLSTATUS_PENDING;
}
// Flushes one USB mass-storage disk synchronously.
static KSTATUS UsbStorageDispatchFlush(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp)
return NTLSTATUS_INVALID_PARAMETER;
USB_STORAGE_EXTENSION* storage = UsbStorageFromDiskDevice(device);
if (!storage || !storage->RemoveLockReady)
return NTLSTATUS_OBJECT_DEAD;
KSTATUS st = IoAcquireRemoveLock(&storage->RemoveLock, irp);
if (!KSUCCESS(st))
return st;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_FLUSH_BUFFERS) {
IoReleaseRemoveLock(&storage->RemoveLock, irp);
return NTLSTATUS_INVALID_PARAMETER;
}
if (!storage->Started || storage->SurpriseRemoved || storage->Removed) {
IoReleaseRemoveLock(&storage->RemoveLock, irp);
IoCompleteRequest(irp, NTLSTATUS_OBJECT_DEAD, 0);
return NTLSTATUS_PENDING;
}
UsbStorageAcquireIo(storage);
st = UsbStorageSynchronizeCache(storage);
UsbStorageReleaseIo(storage);
IoReleaseRemoveLock(&storage->RemoveLock, irp);
IoCompleteRequest(irp, st, 0);
return NTLSTATUS_PENDING;
}
// Creates mass Storage Memory.
KSTATUS XhciAllocateMassStorageMemory(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
if (dev->MassInRing && dev->MassOutRing && dev->MassBuffer)
return NTLSTATUS_SUCCESS;
dev->MassInRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->MassInRingPhys);
dev->MassOutRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->MassOutRingPhys);
dev->MassBuffer = (uint8_t*)UsbDmaAllocPages(xhci, USB_STORAGE_DMA_PAGES, &dev->MassBufferPhys);
if (!dev->MassInRing || !dev->MassOutRing || !dev->MassBuffer)
dev->MassInRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->MassInRingDeviceAddress, &dev->MassInRingDma);
dev->MassOutRing = (XHCI_TRB*)UsbDmaAllocPages(xhci, 1, &dev->MassOutRingDeviceAddress, &dev->MassOutRingDma);
dev->MassBuffer = (uint8_t*)UsbDmaAllocPages(xhci, USB_STORAGE_DMA_PAGES, &dev->MassBufferDeviceAddress, &dev->MassBufferDma);
if (!dev->MassInRing || !dev->MassOutRing || !dev->MassBuffer) {
if (gUsbDdk && gUsbDdk->Dma) {
gUsbDdk->Dma->FreeCommonBuffer(dev->MassBufferDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassOutRingDma);
gUsbDdk->Dma->FreeCommonBuffer(dev->MassInRingDma);
}
dev->MassBufferDma = (IO_DMA_BUFFER*)0;
dev->MassOutRingDma = (IO_DMA_BUFFER*)0;
dev->MassInRingDma = (IO_DMA_BUFFER*)0;
dev->MassBuffer = (uint8_t*)0;
dev->MassOutRing = (XHCI_TRB*)0;
dev->MassInRing = (XHCI_TRB*)0;
return NTLSTATUS_NO_MEMORY;
}
dev->MassInEnqueue = 0;
dev->MassInCycle = 1;
dev->MassOutEnqueue = 0;
dev->MassOutCycle = 1;
dev->MassTag = 0x1000u + dev->SlotId;
XhciInitialiseTransferRing(dev->MassInRing, dev->MassInRingPhys, XHCI_BULK_RING_TRBS, dev->MassInCycle);
XhciInitialiseTransferRing(dev->MassOutRing, dev->MassOutRingPhys, XHCI_BULK_RING_TRBS, dev->MassOutCycle);
XhciInitialiseTransferRing(dev->MassInRing, dev->MassInRingDeviceAddress, XHCI_BULK_RING_TRBS, dev->MassInCycle);
XhciInitialiseTransferRing(dev->MassOutRing, dev->MassOutRingDeviceAddress, XHCI_BULK_RING_TRBS, dev->MassOutCycle);
return NTLSTATUS_SUCCESS;
}
@@ -431,21 +640,21 @@ KSTATUS XhciConfigureMassStorageEndpoints(XHCI_CONTROLLER* xhci, XHCI_DEVICE* de
epIn[0] = 0;
epIn[1] = XHCI_EP_CERR_3 | XHCI_EP_TYPE_BULK_IN | ((uint32_t)inMaxPacket << 16);
epIn[2] = (uint32_t)(dev->MassInRingPhys | XHCI_EP_DCS);
epIn[3] = (uint32_t)((dev->MassInRingPhys | XHCI_EP_DCS) >> 32);
epIn[2] = (uint32_t)(dev->MassInRingDeviceAddress | XHCI_EP_DCS);
epIn[3] = (uint32_t)((dev->MassInRingDeviceAddress | XHCI_EP_DCS) >> 32);
epIn[4] = inMaxPacket;
epOut[0] = 0;
epOut[1] = XHCI_EP_CERR_3 | XHCI_EP_TYPE_BULK_OUT | ((uint32_t)outMaxPacket << 16);
epOut[2] = (uint32_t)(dev->MassOutRingPhys | XHCI_EP_DCS);
epOut[3] = (uint32_t)((dev->MassOutRingPhys | XHCI_EP_DCS) >> 32);
epOut[2] = (uint32_t)(dev->MassOutRingDeviceAddress | XHCI_EP_DCS);
epOut[3] = (uint32_t)((dev->MassOutRingDeviceAddress | XHCI_EP_DCS) >> 32);
epOut[4] = outMaxPacket;
XHCI_COMMAND_RESULT result;
memset(&result, 0, sizeof(result));
st = XhciSubmitCommand(
xhci,
dev->InputContextPhys,
dev->InputContextDeviceAddress,
0,
(XHCI_TRB_TYPE_CONFIGURE_ENDPOINT << XHCI_TRB_TYPE_SHIFT) |
((uint32_t)dev->SlotId << 24),
@@ -549,6 +758,7 @@ static KSTATUS UsbStorageStartDevice(DEVICE_OBJECT* device, USB_STORAGE_EXTENSIO
storage->BulkInMaxPacket = bulkIn->wMaxPacketSize;
storage->BulkOutMaxPacket = bulkOut->wMaxPacketSize;
storage->Tag = 0x1000u + storage->Device->SlotId;
storage->FlushCapability = UsbStorageFlushUnknown;
xdev->MassCandidate = true;
xdev->MassInterface = storage->InterfaceNumber;
@@ -844,6 +1054,7 @@ KSTATUS UsbInitializeStorageDriver(void) {
gUsbStorageDriver.DriverAddDevice = UsbStorageAddDevice;
gUsbStorageDriver.MajorFunction[IRP_MJ_READ] = UsbStorageDispatchReadWrite;
gUsbStorageDriver.MajorFunction[IRP_MJ_WRITE] = UsbStorageDispatchReadWrite;
gUsbStorageDriver.MajorFunction[IRP_MJ_FLUSH_BUFFERS] = UsbStorageDispatchFlush;
gUsbStorageDriver.MajorFunction[IRP_MJ_PNP] = UsbStorageDispatchPnp;
return IoRegisterDriverObject(&gUsbStorageDriver);
}