473 lines
16 KiB
C
473 lines
16 KiB
C
// usb_storage.c - USB mass-storage BOT/SCSI class binding and disk bridge.
|
|
#include "usb.h"
|
|
|
|
DRIVER_OBJECT gUsbStorageDriver;
|
|
|
|
KSTATUS UsbStorageBulkIn(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
|
|
PHYSICAL_ADDRESS phys, uint32_t length,
|
|
uint32_t* outActual) {
|
|
return XhciBulkTransfer(xhci,
|
|
dev,
|
|
dev->MassBulkInEndpointId,
|
|
dev->MassInRing,
|
|
dev->MassInRingPhys,
|
|
&dev->MassInEnqueue,
|
|
&dev->MassInCycle,
|
|
phys,
|
|
length,
|
|
outActual);
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageBulkOut(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
|
|
PHYSICAL_ADDRESS phys, uint32_t length,
|
|
uint32_t* outActual) {
|
|
return XhciBulkTransfer(xhci,
|
|
dev,
|
|
dev->MassBulkOutEndpointId,
|
|
dev->MassOutRing,
|
|
dev->MassOutRingPhys,
|
|
&dev->MassOutEnqueue,
|
|
&dev->MassOutCycle,
|
|
phys,
|
|
length,
|
|
outActual);
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageBotCommand(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
|
|
const uint8_t* cdb, uint8_t cdbLen,
|
|
void* data, PHYSICAL_ADDRESS dataPhys,
|
|
uint32_t dataLength, bool dataIn) {
|
|
if (!xhci || !dev || !cdb || cdbLen == 0 || cdbLen > 16)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (dataLength && (!data || !dataPhys))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
USB_MASS_CBW* cbw = (USB_MASS_CBW*)dev->DescriptorBuffer;
|
|
memset(cbw, 0, sizeof(*cbw));
|
|
cbw->Signature = USB_MASS_BOT_CBW_SIGNATURE;
|
|
cbw->Tag = ++dev->MassTag;
|
|
cbw->DataTransferLength = dataLength;
|
|
cbw->Flags = dataIn ? USB_DIR_IN : USB_DIR_OUT;
|
|
cbw->Lun = 0;
|
|
cbw->CommandBlockLength = cdbLen;
|
|
memcpy(cbw->CommandBlock, cdb, cdbLen);
|
|
|
|
uint32_t actual = 0;
|
|
KSTATUS st = UsbStorageBulkOut(xhci, dev, dev->DescriptorPhys, sizeof(*cbw), &actual);
|
|
if (!KSUCCESS(st) || actual != sizeof(*cbw))
|
|
return KSUCCESS(st) ? STATUS_DEVICE_ERROR : st;
|
|
|
|
if (dataLength) {
|
|
actual = 0;
|
|
if (dataIn)
|
|
st = UsbStorageBulkIn(xhci, dev, dataPhys, dataLength, &actual);
|
|
else
|
|
st = UsbStorageBulkOut(xhci, dev, dataPhys, dataLength, &actual);
|
|
if (!KSUCCESS(st))
|
|
return st;
|
|
}
|
|
|
|
USB_MASS_CSW* csw = (USB_MASS_CSW*)dev->DescriptorBuffer;
|
|
memset(csw, 0, sizeof(*csw));
|
|
actual = 0;
|
|
st = UsbStorageBulkIn(xhci, dev, dev->DescriptorPhys, sizeof(*csw), &actual);
|
|
if (!KSUCCESS(st) || actual != sizeof(*csw))
|
|
return KSUCCESS(st) ? STATUS_DEVICE_ERROR : st;
|
|
|
|
if (csw->Signature != USB_MASS_BOT_CSW_SIGNATURE || csw->Tag != dev->MassTag) {
|
|
DbgPrint("usb-storage: invalid CSW slot=%u sig=%08x tag=%08x expected=%08x\n",
|
|
dev->SlotId, csw->Signature, csw->Tag, dev->MassTag);
|
|
return STATUS_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 STATUS_DEVICE_ERROR;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
uint32_t UsbBe32(const uint8_t* p) {
|
|
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
|
|
((uint32_t)p[2] << 8) | (uint32_t)p[3];
|
|
}
|
|
|
|
|
|
void UsbStoreBe32(uint8_t* p, uint32_t v) {
|
|
p[0] = (uint8_t)(v >> 24);
|
|
p[1] = (uint8_t)(v >> 16);
|
|
p[2] = (uint8_t)(v >> 8);
|
|
p[3] = (uint8_t)v;
|
|
}
|
|
|
|
|
|
void UsbStoreBe16(uint8_t* p, uint16_t v) {
|
|
p[0] = (uint8_t)(v >> 8);
|
|
p[1] = (uint8_t)v;
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageInquiry(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
uint8_t cdb[6] = { SCSI_INQUIRY, 0, 0, 0, 36, 0 };
|
|
memset(dev->MassBuffer, 0, 36);
|
|
KSTATUS st = UsbStorageBotCommand(xhci, dev, cdb, sizeof(cdb),
|
|
dev->MassBuffer, dev->MassBufferPhys,
|
|
36, true);
|
|
if (!KSUCCESS(st)) return st;
|
|
|
|
char vendor[9];
|
|
char product[17];
|
|
memcpy(vendor, dev->MassBuffer + 8, 8); vendor[8] = 0;
|
|
memcpy(product, dev->MassBuffer + 16, 16); product[16] = 0;
|
|
DbgPrint("usb-storage: INQUIRY slot=%u vendor='%s' product='%s'\n",
|
|
dev->SlotId, vendor, product);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageRequestSense(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
uint8_t rs[6] = { SCSI_REQUEST_SENSE, 0, 0, 0, 18, 0 };
|
|
memset(dev->MassBuffer, 0, 18);
|
|
return UsbStorageBotCommand(xhci, dev, rs, sizeof(rs),
|
|
dev->MassBuffer, dev->MassBufferPhys, 18, true);
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageTestUnitReady(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
uint8_t cdb[6] = { SCSI_TEST_UNIT_READY, 0, 0, 0, 0, 0 };
|
|
|
|
KSTATUS last = STATUS_DEVICE_ERROR;
|
|
for (uint32_t attempt = 0; attempt < 10; attempt++) {
|
|
KSTATUS st = UsbStorageBotCommand(xhci, dev, cdb, sizeof(cdb),
|
|
(void*)0, 0, 0, false);
|
|
if (KSUCCESS(st)) return STATUS_SUCCESS;
|
|
|
|
last = st;
|
|
(void)UsbStorageRequestSense(xhci, dev);
|
|
UsbDelayUs(xhci->Hal, 10000u);
|
|
}
|
|
|
|
return last;
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageReadCapacity(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
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(xhci, dev, cdb, sizeof(cdb),
|
|
dev->MassBuffer, dev->MassBufferPhys,
|
|
8, true);
|
|
if (!KSUCCESS(st)) return st;
|
|
|
|
uint32_t lastLba = UsbBe32(dev->MassBuffer + 0);
|
|
uint32_t blockSize = UsbBe32(dev->MassBuffer + 4);
|
|
if (blockSize == 0)
|
|
return STATUS_DEVICE_ERROR;
|
|
|
|
dev->MassBlockSize = blockSize;
|
|
dev->MassBlockCount = (uint64_t)lastLba + 1ull;
|
|
DbgPrint("usb-storage: capacity slot=%u blocks=%llu block_size=%u (%llu MB)\n",
|
|
dev->SlotId,
|
|
(unsigned long long)dev->MassBlockCount,
|
|
dev->MassBlockSize,
|
|
(unsigned long long)((dev->MassBlockCount * (uint64_t)dev->MassBlockSize) / (1024ull * 1024ull)));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageReadWriteSectors(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev,
|
|
bool write, uint64_t lba,
|
|
uint32_t sectors, void* buffer) {
|
|
if (!xhci || !dev || !buffer || sectors == 0)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (dev->MassBlockSize != USB_STORAGE_SECTOR_SIZE)
|
|
return STATUS_NOT_SUPPORTED;
|
|
if (lba > 0xFFFFFFFFull || sectors > 0xFFFFu)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
uint32_t bytes = sectors * USB_STORAGE_SECTOR_SIZE;
|
|
if (bytes > USB_STORAGE_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
uint8_t cdb[10];
|
|
memset(cdb, 0, sizeof(cdb));
|
|
cdb[0] = write ? SCSI_WRITE_10 : SCSI_READ_10;
|
|
UsbStoreBe32(&cdb[2], (uint32_t)lba);
|
|
UsbStoreBe16(&cdb[7], (uint16_t)sectors);
|
|
|
|
if (write)
|
|
memcpy(dev->MassBuffer, buffer, bytes);
|
|
|
|
KSTATUS st = UsbStorageBotCommand(xhci, dev, cdb, sizeof(cdb),
|
|
dev->MassBuffer, dev->MassBufferPhys,
|
|
bytes, !write);
|
|
if (!KSUCCESS(st)) return st;
|
|
|
|
if (!write)
|
|
memcpy(buffer, dev->MassBuffer, bytes);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
void UsbStorageAcquireIo(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
while (_InterlockedCompareExchange(&dev->MassIoBusy, 1, 0) != 0) {
|
|
UsbDelayUs(xhci->Hal, 10);
|
|
}
|
|
}
|
|
|
|
|
|
void UsbStorageReleaseIo(XHCI_DEVICE* dev) {
|
|
_InterlockedExchange(&dev->MassIoBusy, 0);
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageDispatchReadWrite(DEVICE_OBJECT* device, IRP* irp) {
|
|
if (!device || !irp || !device->DeviceExtension)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
XHCI_DEVICE* dev = (XHCI_DEVICE*)device->DeviceExtension;
|
|
if (!dev->MassActive || dev->MassBlockSize != USB_STORAGE_SECTOR_SIZE) {
|
|
IoCompleteRequest(irp, STATUS_DEVICE_ERROR, 0);
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
uint8_t* buffer = (uint8_t*)irp->Buffer;
|
|
uint64_t lba = irp->Lba;
|
|
uint32_t remaining = irp->SectorCount;
|
|
uint32_t done = 0;
|
|
bool write = (irp->Flags & IRP_FLAG_WRITE) != 0;
|
|
uint32_t maxSectors = USB_STORAGE_MAX_BYTES / USB_STORAGE_SECTOR_SIZE;
|
|
|
|
KSTATUS st = STATUS_SUCCESS;
|
|
UsbStorageAcquireIo(&gXhci, dev);
|
|
while (remaining) {
|
|
uint32_t chunk = remaining;
|
|
if (chunk > maxSectors) chunk = maxSectors;
|
|
st = UsbStorageReadWriteSectors(&gXhci, dev, write, lba, chunk,
|
|
buffer + (done * USB_STORAGE_SECTOR_SIZE));
|
|
if (!KSUCCESS(st))
|
|
break;
|
|
lba += chunk;
|
|
done += chunk;
|
|
remaining -= chunk;
|
|
}
|
|
UsbStorageReleaseIo(dev);
|
|
|
|
IoCompleteRequest(irp, st, KSUCCESS(st) ? (size_t)done * USB_STORAGE_SECTOR_SIZE : 0);
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
KSTATUS XhciAllocateMassStorageMemory(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
if (dev->MassInRing && dev->MassOutRing && dev->MassBuffer)
|
|
return STATUS_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)
|
|
return STATUS_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);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
KSTATUS XhciConfigureMassStorageEndpoints(XHCI_CONTROLLER* xhci, XHCI_DEVICE* dev) {
|
|
if (!dev->MassCandidate)
|
|
return STATUS_SUCCESS;
|
|
|
|
KSTATUS st = XhciAllocateMassStorageMemory(xhci, dev);
|
|
if (!KSUCCESS(st)) return st;
|
|
|
|
uint8_t inDci = dev->MassBulkInEndpointId;
|
|
uint8_t outDci = dev->MassBulkOutEndpointId;
|
|
if (inDci < 2 || inDci > 31 || outDci < 2 || outDci > 31)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
memset(dev->InputContext, 0, PAGE_SIZE);
|
|
uint32_t* icc = XhciInputControlContext(xhci, dev);
|
|
uint32_t* slot = XhciInputSlotContext(xhci, dev);
|
|
uint32_t* epIn = XhciInputEndpointContext(xhci, dev, inDci);
|
|
uint32_t* epOut = XhciInputEndpointContext(xhci, dev, outDci);
|
|
|
|
icc[0] = 0;
|
|
icc[1] = (1u << 0) | (1u << inDci) | (1u << outDci);
|
|
|
|
uint8_t maxDci = inDci > outDci ? inDci : outDci;
|
|
slot[0] = XHCI_CONTEXT_ENTRIES(maxDci) | XHCI_SLOT_SPEED(dev->Speed);
|
|
slot[1] = XHCI_SLOT_ROOT_PORT(dev->Port);
|
|
slot[2] = 0;
|
|
slot[3] = 0;
|
|
|
|
uint16_t inMaxPacket = dev->MassBulkInMaxPacket & 0x07FFu;
|
|
uint16_t outMaxPacket = dev->MassBulkOutMaxPacket & 0x07FFu;
|
|
if (inMaxPacket == 0) inMaxPacket = 512;
|
|
if (outMaxPacket == 0) outMaxPacket = 512;
|
|
|
|
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[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[4] = outMaxPacket;
|
|
|
|
XHCI_COMMAND_RESULT result;
|
|
memset(&result, 0, sizeof(result));
|
|
st = XhciSubmitCommand(
|
|
xhci,
|
|
dev->InputContextPhys,
|
|
0,
|
|
(XHCI_TRB_TYPE_CONFIGURE_ENDPOINT << XHCI_TRB_TYPE_SHIFT) |
|
|
((uint32_t)dev->SlotId << 24),
|
|
&result);
|
|
if (!KSUCCESS(st)) {
|
|
DbgPrint("usb-storage: Configure Endpoint failed slot=%u in=%u out=%u st=0x%x cc=%u\n",
|
|
dev->SlotId, inDci, outDci, st, result.CompletionCode);
|
|
return st;
|
|
}
|
|
|
|
UsbTrace("usb-storage: bulk endpoints configured slot=%u if=%u in=%02x/dci=%u out=%02x/dci=%u\n",
|
|
dev->SlotId,
|
|
dev->MassInterface,
|
|
dev->MassBulkInAddress,
|
|
inDci,
|
|
dev->MassBulkOutAddress,
|
|
outDci);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
uint8_t UsbFindFreeDiskIndex(void) {
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
if (!IoDiskDevicePresent(i))
|
|
return i;
|
|
}
|
|
return 0xFFu;
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageRegisterDisk(XHCI_DEVICE* dev) {
|
|
if (!dev || dev->MassBlockSize != USB_STORAGE_SECTOR_SIZE || dev->MassBlockCount == 0)
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
DEVICE_OBJECT* disk = (DEVICE_OBJECT*)0;
|
|
KSTATUS st = IoCreateDevice(&gUsbStorageDriver, 0, &disk);
|
|
if (!KSUCCESS(st)) return st;
|
|
|
|
disk->DeviceExtension = dev;
|
|
disk->SectorCount = dev->MassBlockCount;
|
|
disk->AlignmentRequirement = USB_STORAGE_SECTOR_SIZE;
|
|
disk->Flags |= DEVICE_OBJECT_REMOVABLE;
|
|
|
|
uint8_t index = UsbFindFreeDiskIndex();
|
|
if (index == 0xFFu) {
|
|
IoDeleteDevice(disk);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
st = IoRegisterDiskDevice(index, disk);
|
|
if (!KSUCCESS(st)) {
|
|
IoDeleteDevice(disk);
|
|
return st;
|
|
}
|
|
|
|
dev->MassDeviceObject = disk;
|
|
DbgPrint("usb-storage: registered disk %u slot=%u sectors=%llu\n",
|
|
index, dev->SlotId, (unsigned long long)dev->MassBlockCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
bool UsbStorageMatch(const IO_PUBLISHED_DEVICE* pub, void* context) {
|
|
(void)context;
|
|
if (!pub || pub->BusType != IoBusUsb)
|
|
return false;
|
|
if (pub->u.Usb.InterfaceClass != USB_CLASS_MASS_STORAGE)
|
|
return false;
|
|
if (pub->u.Usb.InterfaceSubclass != USB_MASS_SUBCLASS_SCSI)
|
|
return false;
|
|
if (pub->u.Usb.InterfaceProtocol != USB_MASS_PROTOCOL_BOT)
|
|
return false;
|
|
|
|
return UsbFindEndpoint(pub, USB_ENDPOINT_TYPE_BULK, true) &&
|
|
UsbFindEndpoint(pub, USB_ENDPOINT_TYPE_BULK, false);
|
|
}
|
|
|
|
|
|
KSTATUS UsbStorageBind(IO_PUBLISHED_DEVICE* pub, void* context) {
|
|
(void)context;
|
|
if (!pub || !pub->BusContext || !pub->DeviceContext)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
XHCI_CONTROLLER* xhci = (XHCI_CONTROLLER*)pub->BusContext;
|
|
XHCI_DEVICE* dev = (XHCI_DEVICE*)pub->DeviceContext;
|
|
if (dev->MassActive || dev->MassCandidate)
|
|
return STATUS_ALREADY_EXISTS;
|
|
|
|
const IO_PUBLISHED_USB_ENDPOINT* bulkIn = UsbFindEndpoint(pub, USB_ENDPOINT_TYPE_BULK, true);
|
|
const IO_PUBLISHED_USB_ENDPOINT* bulkOut = UsbFindEndpoint(pub, USB_ENDPOINT_TYPE_BULK, false);
|
|
if (!bulkIn || !bulkOut)
|
|
return STATUS_NOT_FOUND;
|
|
|
|
dev->MassCandidate = true;
|
|
dev->MassInterface = pub->u.Usb.InterfaceNumber;
|
|
dev->MassBulkInAddress = bulkIn->Address;
|
|
dev->MassBulkOutAddress = bulkOut->Address;
|
|
dev->MassBulkInEndpointId = XhciEndpointIdFromAddress(bulkIn->Address);
|
|
dev->MassBulkOutEndpointId = XhciEndpointIdFromAddress(bulkOut->Address);
|
|
dev->MassBulkInMaxPacket = bulkIn->MaxPacketSize;
|
|
dev->MassBulkOutMaxPacket = bulkOut->MaxPacketSize;
|
|
|
|
KSTATUS st = XhciConfigureMassStorageEndpoints(xhci, dev);
|
|
if (!KSUCCESS(st)) goto fail;
|
|
|
|
st = UsbStorageInquiry(xhci, dev);
|
|
if (!KSUCCESS(st)) goto fail;
|
|
|
|
st = UsbStorageTestUnitReady(xhci, dev);
|
|
if (!KSUCCESS(st)) {
|
|
DbgPrint("usb-storage: TEST UNIT READY failed slot=%u st=0x%x\n", dev->SlotId, st);
|
|
goto fail;
|
|
}
|
|
|
|
st = UsbStorageReadCapacity(xhci, dev);
|
|
if (!KSUCCESS(st)) goto fail;
|
|
if (dev->MassBlockSize != USB_STORAGE_SECTOR_SIZE) {
|
|
DbgPrint("usb-storage: unsupported block size slot=%u block_size=%u\n",
|
|
dev->SlotId, dev->MassBlockSize);
|
|
st = STATUS_NOT_SUPPORTED;
|
|
goto fail;
|
|
}
|
|
|
|
dev->MassActive = true;
|
|
st = UsbStorageRegisterDisk(dev);
|
|
if (!KSUCCESS(st)) goto fail;
|
|
|
|
DbgPrint("usb-storage: bound slot=%u if=%u\n", dev->SlotId, dev->MassInterface);
|
|
return STATUS_SUCCESS;
|
|
|
|
fail:
|
|
dev->MassCandidate = false;
|
|
dev->MassActive = false;
|
|
DbgPrint("usb-storage: bind failed slot=%u if=%u st=0x%x\n",
|
|
dev->SlotId, pub->u.Usb.InterfaceNumber, st);
|
|
return st;
|
|
}
|
|
|