reactos/drivers/usb/usbstor/pdo.c

1377 lines
32 KiB
C

/*
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbstor/pdo.c
* PURPOSE: USB block storage device driver.
* PROGRAMMERS:
* James Tabor
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbstor.h"
#define NDEBUG
#include <debug.h>
LPCSTR
USBSTOR_GetDeviceType(
IN PUFI_INQUIRY_RESPONSE InquiryData,
IN UCHAR IsFloppy)
{
//
// check if device type is zero
//
if (InquiryData->DeviceType == 0)
{
if (IsFloppy)
{
//
// floppy device
//
return "SFloppy";
}
//
// direct access device
//
return "Disk";
}
//
// FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
//
switch (InquiryData->DeviceType)
{
case 1:
{
//
// sequential device, i.e magnetic tape
//
return "Sequential";
}
case 4:
{
//
// write once device
//
return "Worm";
}
case 5:
{
//
// CDROM device
//
return "CdRom";
}
case 7:
{
//
// optical memory device
//
return "Optical";
}
case 8:
{
//
// medium change device
//
return "Changer";
}
default:
{
//
// other device
//
return "Other";
}
}
}
LPCSTR
USBSTOR_GetGenericType(
IN PUFI_INQUIRY_RESPONSE InquiryData,
IN UCHAR IsFloppy)
{
//
// check if device type is zero
//
if (InquiryData->DeviceType == 0)
{
if (IsFloppy)
{
//
// floppy device
//
return "GenSFloppy";
}
//
// direct access device
//
return "GenDisk";
}
//
// FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
//
switch (InquiryData->DeviceType)
{
case 1:
{
//
// sequential device, i.e magnetic tape
//
return "GenSequential";
}
case 4:
{
//
// write once device
//
return "GenWorm";
}
case 5:
{
//
// CDROM device
//
return "GenCdRom";
}
case 7:
{
//
// optical memory device
//
return "GenOptical";
}
case 8:
{
//
// medium change device
//
return "GenChanger";
}
default:
{
//
// other device
//
return "UsbstorOther";
}
}
}
ULONG
CopyField(
IN PUCHAR Name,
IN PCHAR Buffer,
IN ULONG MaxLength)
{
ULONG Index;
for(Index = 0; Index < MaxLength; Index++)
{
if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',')
{
//
// convert to underscore
//
Buffer[Index] = '_';
}
else
{
//
// just copy character
//
Buffer[Index] = Name[Index];
}
}
return MaxLength;
}
NTSTATUS
USBSTOR_PdoHandleQueryDeviceText(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
//PPDO_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IoStack;
LPWSTR Buffer;
static WCHAR DeviceText[] = L"USB Mass Storage Device";
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
{
DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
//
// allocate item
//
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
if (!Buffer)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// copy buffer
//
wcscpy(Buffer, DeviceText);
//
// save result
//
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
else
{
DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
//
// allocate item
//
Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
if (!Buffer)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// copy buffer
//
wcscpy(Buffer, DeviceText);
//
// save result
//
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
}
NTSTATUS
USBSTOR_PdoHandleQueryDeviceId(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
CHAR Buffer[100];
LPCSTR DeviceType;
ULONG Offset = 0;
PUFI_INQUIRY_RESPONSE InquiryData;
ANSI_STRING AnsiString;
UNICODE_STRING DeviceId;
//
// get device extension
//
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(DeviceExtension->InquiryData);
//
// get inquiry data
//
InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData;
//
// get device type
//
DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy);
//
// zero buffer
//
RtlZeroMemory(Buffer, sizeof(Buffer));
//
// lets create device string
//
Offset = sprintf(&Buffer[Offset], "USBSTOR\\");
Offset += sprintf(&Buffer[Offset], DeviceType);
Offset += sprintf(&Buffer[Offset], "&Ven_");
Offset += CopyField(InquiryData->Vendor, &Buffer[Offset], 8);
Offset += sprintf(&Buffer[Offset], "&Prod_");
Offset += CopyField(InquiryData->Product, &Buffer[Offset], 16);
Offset += sprintf(&Buffer[Offset], "&Rev_");
Offset += CopyField(InquiryData->Revision, &Buffer[Offset], 4);
//
// now initialize ansi string
//
RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
//
// allocate DeviceId string
//
DeviceId.Length = 0;
DeviceId.MaximumLength = (strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR);
DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
if (!DeviceId.Buffer)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// convert to unicode
//
Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
if (NT_SUCCESS(Status))
{
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
}
DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
//
// done
//
return Status;
}
VOID
USBSTOR_ConvertToUnicodeString(
IN CHAR * Buffer,
IN ULONG ResultBufferLength,
IN ULONG ResultBufferOffset,
OUT LPWSTR ResultBuffer,
OUT PULONG NewResultBufferOffset)
{
UNICODE_STRING DeviceString;
ANSI_STRING AnsiString;
NTSTATUS Status;
ASSERT(ResultBufferLength);
ASSERT(ResultBufferLength > ResultBufferOffset);
DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
//
// construct destination string
//
DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
DeviceString.Length = 0;
DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
//
// initialize source string
//
RtlInitAnsiString(&AnsiString, Buffer);
//
// convert to unicode
//
Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
ASSERT(Status == STATUS_SUCCESS);
//
// subtract consumed bytes
//
ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
//
// store new offset
//
*NewResultBufferOffset = ResultBufferOffset;
}
NTSTATUS
USBSTOR_PdoHandleQueryHardwareId(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
LPCSTR GenericType, DeviceType;
LPWSTR Buffer;
CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length;
ULONG Offset, TotalLength, Length;
PUFI_INQUIRY_RESPONSE InquiryData;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(FDODeviceExtension->DeviceDescriptor);
//
// get inquiry data
//
InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
//
// get device type and generic type
//
DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy);
GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy);
ASSERT(GenericType);
//
// generate id 1
// USBSTOR\SCSIType_Vendor(8)_Product(16)_Revision(4)
//
RtlZeroMemory(Id1, sizeof(Id1));
Offset = 0;
Offset = sprintf(&Id1[Offset], "USBSTOR\\");
Offset += sprintf(&Id1[Offset], DeviceType);
Offset += CopyField(InquiryData->Vendor, &Id1[Offset], 8);
Offset += CopyField(InquiryData->Product, &Id1[Offset], 16);
Offset += CopyField(InquiryData->Revision, &Id1[Offset], 4);
Id1Length = strlen(Id1) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
//
// generate id 2
// USBSTOR\SCSIType_VENDOR(8)_Product(16)
//
RtlZeroMemory(Id2, sizeof(Id2));
Offset = 0;
Offset = sprintf(&Id2[Offset], "USBSTOR\\");
Offset += sprintf(&Id2[Offset], DeviceType);
Offset += CopyField(InquiryData->Vendor, &Id2[Offset], 8);
Offset += CopyField(InquiryData->Product, &Id2[Offset], 16);
Id2Length = strlen(Id2) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
//
// generate id 3
// USBSTOR\SCSIType_VENDOR(8)
//
RtlZeroMemory(Id3, sizeof(Id3));
Offset = 0;
Offset = sprintf(&Id3[Offset], "USBSTOR\\");
Offset += sprintf(&Id3[Offset], DeviceType);
Offset += CopyField(InquiryData->Vendor, &Id3[Offset], 8);
Id3Length = strlen(Id3) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
//
// generate id 4
// USBSTOR\SCSIType_VENDOR(8)_Product(16)_Revision(1)
//
RtlZeroMemory(Id4, sizeof(Id4));
Offset = 0;
Offset = sprintf(&Id4[Offset], "USBSTOR\\");
Offset += sprintf(&Id4[Offset], DeviceType);
Offset += CopyField(InquiryData->Vendor, &Id4[Offset], 8);
Offset += CopyField(InquiryData->Product, &Id4[Offset], 16);
Offset += CopyField(InquiryData->Revision, &Id4[Offset], 1);
Id4Length = strlen(Id4) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
//
// generate id 5
// USBSTOR\SCSIType
//
RtlZeroMemory(Id5, sizeof(Id5));
Offset = 0;
Offset = sprintf(&Id5[Offset], "USBSTOR\\");
Offset += sprintf(&Id5[Offset], GenericType);
Id5Length = strlen(Id5) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
//
// generate id 6
// SCSIType
//
RtlZeroMemory(Id6, sizeof(Id6));
Offset = 0;
Offset = sprintf(&Id6[Offset], GenericType);
Id6Length = strlen(Id6) + 1;
DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
//
// compute total length
//
TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
//
// allocate buffer
//
Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR));
if (!Buffer)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// reset offset
//
Offset = 0;
Length = TotalLength;
USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
//
// sanity check
//
ASSERT(Offset + 1 == Length);
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_PdoHandleQueryCompatibleId(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
CHAR Buffer[100];
ULONG Length, Offset;
LPWSTR InstanceId;
LPCSTR DeviceType;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(FDODeviceExtension->DeviceDescriptor);
//
// get target device type
//
DeviceType = USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy);
//
// zero memory
//
RtlZeroMemory(Buffer, sizeof(Buffer));
//
// format instance id
//
Length = sprintf(Buffer, "USBSTOR\\%s", DeviceType) + 1;
Length += sprintf(&Buffer[Length], "USBSTOR\\%s", "RAW") + 2;
//
// allocate instance id
//
InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
if (!InstanceId)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId);
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
//
// completed successfully
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_PdoHandleQueryInstanceId(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
WCHAR Buffer[100];
ULONG Length;
LPWSTR InstanceId;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// format instance id
//
if (FDODeviceExtension->SerialNumber)
{
//
// using serial number from device
//
swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
}
else
{
//
// use instance count and LUN
//
swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
}
//
// calculate length
//
Length = wcslen(Buffer) + 1;
//
// allocate instance id
//
InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
if (!InstanceId)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// copy instance id
//
wcscpy(InstanceId, Buffer);
DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
//
// completed successfully
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_PdoHandleDeviceRelations(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PDEVICE_RELATIONS DeviceRelations;
PIO_STACK_LOCATION IoStack;
DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// check if relation type is BusRelations
//
if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
{
//
// PDO handles only target device relation
//
return Irp->IoStatus.Status;
}
//
// allocate device relations
//
DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
if (!DeviceRelations)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize device relations
//
DeviceRelations->Count = 1;
DeviceRelations->Objects[0] = DeviceObject;
ObReferenceObject(DeviceObject);
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
//
// completed successfully
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_PdoHandlePnp(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PPDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
PDEVICE_CAPABILITIES Caps;
ULONG bDelete;
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// get device extension
//
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(DeviceExtension->Common.IsFDO == FALSE);
switch(IoStack->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_DEVICE_TEXT:
{
Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_ID:
{
if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
{
//
// handle query device id
//
Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
break;
}
else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
{
//
// handle instance id
//
Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
break;
}
else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
{
//
// handle instance id
//
Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
break;
}
else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
{
//
// handle instance id
//
Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
break;
}
DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
Status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Information = 0;
break;
}
case IRP_MN_REMOVE_DEVICE:
{
DPRINT("IRP_MN_REMOVE_DEVICE\n");
if(*DeviceExtension->PDODeviceObject != NULL)
{
//
// clear entry in FDO pdo list
//
*DeviceExtension->PDODeviceObject = NULL;
bDelete = TRUE;
}
else
{
//
// device object already marked for deletion
//
bDelete = FALSE;
}
/* Complete the IRP */
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
if (bDelete)
{
/* Delete the device object */
IoDeleteDevice(DeviceObject);
}
return STATUS_SUCCESS;
}
case IRP_MN_QUERY_CAPABILITIES:
{
//
// just forward irp to lower device
//
Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
ASSERT(Status == STATUS_SUCCESS);
if (NT_SUCCESS(Status))
{
//
// check if no unique id
//
Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
Caps->UniqueID = FALSE; // no unique id is supported
Caps->Removable = TRUE; //FIXME
}
break;
}
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
{
#if 0
//
// if we're not claimed it's ok
//
if (DeviceExtension->Claimed)
#else
if (TRUE)
#endif
{
Status = STATUS_UNSUCCESSFUL;
DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
}
else
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_START_DEVICE:
{
//
// no-op for PDO
//
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_SURPRISE_REMOVAL:
{
Status = STATUS_SUCCESS;
break;
}
default:
{
//
// do nothing
//
Status = Irp->IoStatus.Status;
}
}
//
// complete request
//
if (Status != STATUS_PENDING)
{
//
// store result
//
Irp->IoStatus.Status = Status;
//
// complete request
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
//
// done processing
//
return Status;
}
NTSTATUS
NTAPI
USBSTOR_CompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Ctx)
{
PKEVENT Event = (PKEVENT)Ctx;
//
// signal event
//
KeSetEvent(Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
USBSTOR_AllocateIrp(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG DataTransferLength,
IN UCHAR OpCode,
IN PKEVENT Event,
OUT PSCSI_REQUEST_BLOCK *OutRequest,
OUT PIRP *OutIrp)
{
PIRP Irp;
PIO_STACK_LOCATION IoStack;
PSCSI_REQUEST_BLOCK Request;
PCDB pCDB;
//
// allocate irp
//
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// get next stack location
//
IoStack = IoGetNextIrpStackLocation(Irp);
//
// create scsi block
//
Request = ExAllocatePoolWithTag(NonPagedPool,
sizeof(SCSI_REQUEST_BLOCK),
USB_STOR_TAG);
if (!Request)
{
//
// no memory
//
IoFreeIrp(Irp);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// init request
//
RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK));
//
// allocate data transfer block
//
Request->DataBuffer = ExAllocatePoolWithTag(NonPagedPool,
DataTransferLength,
USB_STOR_TAG);
if (!Request->DataBuffer)
{
//
// no memory
//
IoFreeIrp(Irp);
ExFreePoolWithTag(Request, USB_STOR_TAG);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// allocate MDL
//
Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL);
if (!Irp->MdlAddress)
{
//
// no memory
//
IoFreeIrp(Irp);
ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
ExFreePoolWithTag(Request, USB_STOR_TAG);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// non paged pool
//
MmBuildMdlForNonPagedPool(Irp->MdlAddress);
//
// init scsi block
//
Request->DataTransferLength = DataTransferLength;
Request->Function = SRB_FUNCTION_EXECUTE_SCSI;
Request->SrbFlags = SRB_FLAGS_DATA_IN;
RtlZeroMemory(Request->DataBuffer, DataTransferLength);
//
// get SCSI command data block
//
pCDB = (PCDB)Request->Cdb;
//
// set op code
//
pCDB->AsByte[0] = OpCode;
//
// store result
//
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IoStack->Parameters.Others.Argument1 = Request;
IoStack->DeviceObject = DeviceObject;
//
// init event
//
KeInitializeEvent(Event, NotificationEvent, FALSE);
//
// lets setup a completion routine
//
IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE);
//
// output result
//
*OutIrp = Irp;
*OutRequest = Request;
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_SendIrp(
IN PDEVICE_OBJECT PDODeviceObject,
IN ULONG DataTransferLength,
IN UCHAR OpCode,
OUT PVOID *OutData)
{
NTSTATUS Status;
PIRP Irp;
KEVENT Event;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PSCSI_REQUEST_BLOCK Request;
//
// let's allocate an irp
//
Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp);
if (!NT_SUCCESS(Status))
{
//
// failed
//
DPRINT1("[USBSTOR] Failed to build irp\n");
return Status;
}
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
//
// send irp
//
ASSERT(Irp);
ASSERT(PDODeviceExtension->LowerDeviceObject);
Status = IoCallDriver(PDODeviceExtension->Self, Irp);
if (Status == STATUS_PENDING)
{
//
// wait for completion
//
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
if (NT_SUCCESS(Status))
{
//
// store result
//
*OutData = Request->DataBuffer;
}
else
{
//
// free the data
//
ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
*OutData = NULL;
}
//
// free resources
//
ExFreePoolWithTag(Request, USB_STOR_TAG);
IoFreeMdl(Irp->MdlAddress);
IoFreeIrp(Irp);
return Status;
}
NTSTATUS
USBSTOR_SendInquiryIrp(
IN PDEVICE_OBJECT PDODeviceObject)
{
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PUFI_INQUIRY_RESPONSE Response;
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
//
// send request
//
Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
if (!NT_SUCCESS(Status))
{
//
// command failed
//
DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
return Status;
}
DPRINT1("Response %p\n", Response);
DPRINT1("DeviceType %x\n", Response->DeviceType);
DPRINT1("RMB %x\n", Response->RMB);
DPRINT1("Version %x\n", Response->Version);
DPRINT1("Format %x\n", Response->Format);
DPRINT1("Length %x\n", Response->Length);
DPRINT1("Reserved %p\n", Response->Reserved);
DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
//
// store result
//
PDODeviceExtension->InquiryData = (PVOID)Response;
return Status;
}
NTSTATUS
USBSTOR_SendFormatCapacityIrp(
IN PDEVICE_OBJECT PDODeviceObject)
{
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PUCHAR Response;
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
//
// send request
//
Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
if (!NT_SUCCESS(Status))
{
//
// command failed
//
return Status;
}
//
// check if its a floppy
//
PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
//
// free response
//
ExFreePoolWithTag(Response, USB_STOR_TAG);
return Status;
}
NTSTATUS
USBSTOR_CreatePDO(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR LUN)
{
PDEVICE_OBJECT PDO;
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PUFI_INQUIRY_RESPONSE Response;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
//
// get device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// create child device object
//
Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
if (!NT_SUCCESS(Status))
{
//
// failed to create device
//
return Status;
}
//
// patch the stack size
//
PDO->StackSize = DeviceObject->StackSize;
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
//
// initialize device extension
//
RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
PDODeviceExtension->Common.IsFDO = FALSE;
PDODeviceExtension->LowerDeviceObject = DeviceObject;
PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
PDODeviceExtension->Self = PDO;
PDODeviceExtension->LUN = LUN;
//
// set device flags
//
PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
//
// device is initialized
//
PDO->Flags &= ~DO_DEVICE_INITIALIZING;
//
// output device object
//
FDODeviceExtension->ChildPDO[LUN] = PDO;
//
// send inquiry command by irp
//
Status = USBSTOR_SendInquiryIrp(PDO);
ASSERT(Status == STATUS_SUCCESS);
//
// check response data
//
Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
ASSERT(Response);
if (Response->DeviceType == 0)
{
//
// check if it is a floppy
//
Status = USBSTOR_SendFormatCapacityIrp(PDO);
//
// display result
//
DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
//
// failing command is non critical
//
Status = STATUS_SUCCESS;
}
//
// done
//
return Status;
}