reactos/drivers/usb/usbstor/fdo.c

366 lines
12 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: USB block storage device driver.
* COPYRIGHT: 2005-2006 James Tabor
* 2011-2012 Michael Martin (michael.martin@reactos.org)
* 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
* 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
#include "usbstor.h"
#define NDEBUG
#include <debug.h>
#if DBG
static
VOID
USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
{
DPRINT("Dumping Device Descriptor %p\n", DeviceDescriptor);
DPRINT("bLength %x\n", DeviceDescriptor->bLength);
DPRINT("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
DPRINT("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
DPRINT("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
DPRINT("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
DPRINT("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
DPRINT("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
DPRINT("idVendor %x\n", DeviceDescriptor->idVendor);
DPRINT("idProduct %x\n", DeviceDescriptor->idProduct);
DPRINT("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
DPRINT("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
DPRINT("iProduct %x\n", DeviceDescriptor->iProduct);
DPRINT("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
DPRINT("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
}
#endif
NTSTATUS
USBSTOR_FdoHandleDeviceRelations(
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
INT32 DeviceCount = 0;
LONG Index;
PDEVICE_RELATIONS DeviceRelations;
PIO_STACK_LOCATION IoStack;
IoStack = IoGetCurrentIrpStackLocation(Irp);
// FDO always only handles bus relations
if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
{
// go through array and count device objects
for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
{
if (DeviceExtension->ChildPDO[Index])
{
DeviceCount++;
}
}
DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount - 1) * sizeof(PDEVICE_OBJECT), USB_STOR_TAG);
if (!DeviceRelations)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
DeviceRelations->Count = 0;
// add device objects
for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
{
if (DeviceExtension->ChildPDO[Index])
{
// store child pdo
DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
// add reference
ObReferenceObject(DeviceExtension->ChildPDO[Index]);
DeviceRelations->Count++;
}
}
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
NTSTATUS
USBSTOR_FdoHandleRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
NTSTATUS Status;
ULONG Index;
DPRINT("Handling FDO removal %p\n", DeviceObject);
// FIXME: wait for devices finished processing
for (Index = 0; Index < USB_MAXCHILDREN; Index++)
{
if (DeviceExtension->ChildPDO[Index] != NULL)
{
DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
}
}
// Freeing everything in DeviceExtension
if (DeviceExtension->DeviceDescriptor)
ExFreePoolWithTag(DeviceExtension->DeviceDescriptor, USB_STOR_TAG);
if (DeviceExtension->ConfigurationDescriptor)
ExFreePoolWithTag(DeviceExtension->ConfigurationDescriptor, USB_STOR_TAG);
if (DeviceExtension->InterfaceInformation)
ExFreePoolWithTag(DeviceExtension->InterfaceInformation, USB_STOR_TAG);
if (DeviceExtension->ResetDeviceWorkItem)
IoFreeWorkItem(DeviceExtension->ResetDeviceWorkItem);
if (DeviceExtension->SerialNumber)
ExFreePoolWithTag(DeviceExtension->SerialNumber, USB_STOR_TAG);
// Send the IRP down the stack
IoSkipCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
// Detach from the device stack
IoDetachDevice(DeviceExtension->LowerDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
}
NTSTATUS
USBSTOR_FdoHandleStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp)
{
PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
NTSTATUS Status;
UCHAR Index = 0;
PIO_WORKITEM WorkItem;
// forward irp to lower device
if (!IoForwardIrpSynchronously(DeviceExtension->LowerDeviceObject, Irp))
{
return STATUS_UNSUCCESSFUL;
}
Status = Irp->IoStatus.Status;
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
return Status;
}
if (!DeviceExtension->ResetDeviceWorkItem)
{
WorkItem = IoAllocateWorkItem(DeviceObject);
DeviceExtension->ResetDeviceWorkItem = WorkItem;
if (!WorkItem)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
// initialize irp queue
USBSTOR_QueueInitialize(DeviceExtension);
// first get device & configuration & string descriptor
Status = USBSTOR_GetDescriptors(DeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
return Status;
}
#if DBG
USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
#endif
// Check that this device uses bulk transfers and is SCSI
InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
if (InterfaceDesc->bInterfaceProtocol != USB_PROTOCOL_BULK)
{
DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
return STATUS_NOT_SUPPORTED;
}
if (InterfaceDesc->bInterfaceSubClass == USB_SUBCLASS_UFI)
{
DPRINT1("USB Floppy devices are not supported\n");
return STATUS_NOT_SUPPORTED;
}
// now select an interface
Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
if (!NT_SUCCESS(Status))
{
// failed to get device descriptor
DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
return Status;
}
// check if we got a bulk in + bulk out endpoint
Status = USBSTOR_GetPipeHandles(DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
return Status;
}
Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
return Status;
}
// now create for each LUN a device object, 1 minimum
do
{
Status = USBSTOR_CreatePDO(DeviceObject, Index);
if (!NT_SUCCESS(Status))
{
DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
return Status;
}
Index++;
DeviceExtension->InstanceCount++;
} while(Index < DeviceExtension->MaxLUN);
#if 0
//
// finally get usb device interface
//
Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
if (!NT_SUCCESS(Status))
{
//
// failed to device interface
//
DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
return Status;
}
#endif
//IoStartTimer(DeviceObject);
DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_FdoHandlePnp(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PFDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
IoStack = IoGetCurrentIrpStackLocation(Irp);
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension->Common.IsFDO);
switch(IoStack->MinorFunction)
{
case IRP_MN_SURPRISE_REMOVAL:
{
DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p Type: %u\n", DeviceObject, IoStack->Parameters.QueryDeviceRelations.Type);
return USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
}
case IRP_MN_STOP_DEVICE:
{
DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
IoStopTimer(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_REMOVE_DEVICE:
{
DPRINT("IRP_MN_REMOVE_DEVICE\n");
return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
}
case IRP_MN_QUERY_CAPABILITIES:
{
// FIXME: set custom capabilities
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
{
if (DeviceExtension->IrpPendingCount != 0 || DeviceExtension->ActiveSrb != NULL)
{
/* We have pending requests */
DPRINT1("Failing removal/stop request due to pending requests present\n");
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* We're all clear */
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
break;
}
case IRP_MN_START_DEVICE:
{
Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
break;
}
default:
{
// forward irp to next device object
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}