Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

682 lines
22 KiB

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
io.c
Abstract:
This module handles device ioctl's and read/write to the sdbus driver.
Authors:
Neil Sandlin (neilsa) 1-Jan-2002
Environment:
Kernel mode
Revision History :
--*/
#include "pch.h"
NTSTATUS
SdbusPdoSubmitRequest(
IN PFDO_EXTENSION fdoExtension,
IN PPDO_EXTENSION pdoExtension,
IN PSDBUS_REQUEST_PACKET SdRp,
PSDBUS_WORKPACKET_COMPLETION_ROUTINE CompletionRoutine,
IN PIRP Irp
);
VOID
SdbusPdoInternalIoctlCompletion (
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
);
VOID
SdbusPdoIoctlCompletion (
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
);
NTSTATUS
SdbusFdoDeviceControl(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp
)
/*++
Routine Description:
IOCTL device routine
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the IRP
Return Value:
Status
--*/
{
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
NTSTATUS
SdbusPdoInternalDeviceControl(
IN PDEVICE_OBJECT Pdo,
IN PIRP Irp
)
/*++
Routine Description:
IOCTL device routine
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the IRP
Return Value:
Status
--*/
{
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
PDEVICE_OBJECT fdo = fdoExtension->DeviceObject;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x irp %.08x code %08x DISPATCH\n", Pdo, Irp,
irpSp->Parameters.DeviceIoControl.IoControlCode));
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_SD_SUBMIT_REQUEST: {
PSDBUS_REQUEST_PACKET SdRp = Irp->AssociatedIrp.SystemBuffer;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_REQUEST_PACKET)) {
status = STATUS_INVALID_PARAMETER;
break;
}
//
// Build and queue a work packet to handle this request
//
status = SdbusPdoSubmitRequest(fdoExtension,
pdoExtension,
SdRp,
SdbusPdoInternalIoctlCompletion,
Irp);
break;
}
default:
status = STATUS_INVALID_DEVICE_REQUEST;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x irp %.08x complete %08x\n", Pdo, Irp, status));
break;
}
if (status != STATUS_PENDING) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x ioctl exits %08x\n", Pdo, status));
return status;
}
VOID
SdbusPdoInternalIoctlCompletion (
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
)
{
PIRP irp = WorkPacket->CompletionContext;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %08x irp %08x ioctl complete %08x\n",
WorkPacket->PdoExtension->DeviceObject, irp, status));
if (NT_SUCCESS(status)) {
irp->IoStatus.Information = WorkPacket->Information;
}
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ExFreePool(WorkPacket);
}
NTSTATUS
SdbusPdoSubmitRequest(
IN PFDO_EXTENSION fdoExtension,
IN PPDO_EXTENSION pdoExtension,
IN PSDBUS_REQUEST_PACKET SdRp,
PSDBUS_WORKPACKET_COMPLETION_ROUTINE CompletionRoutine,
IN PIRP Irp
)
{
NTSTATUS status;
PSD_WORK_PACKET workPacket;
switch(SdRp->Function) {
case SDRP_READ_BLOCK:
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_READBLOCK,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.ReadBlock.ByteOffset = SdRp->Parameters.ReadBlock.ByteOffset;
workPacket->Parameters.ReadBlock.Buffer = SdRp->Parameters.ReadBlock.Buffer;
workPacket->Parameters.ReadBlock.Length = SdRp->Parameters.ReadBlock.Length;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_WRITE_BLOCK:
if ((*(fdoExtension->FunctionBlock->IsWriteProtected))(fdoExtension)) {
status = STATUS_MEDIA_WRITE_PROTECTED;
break;
}
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_WRITEBLOCK,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.WriteBlock.ByteOffset = SdRp->Parameters.WriteBlock.ByteOffset;
workPacket->Parameters.WriteBlock.Buffer = SdRp->Parameters.WriteBlock.Buffer;
workPacket->Parameters.WriteBlock.Length = SdRp->Parameters.WriteBlock.Length;
IoMarkIrpPending(Irp);
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_READ_IO:
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_READIO,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.ReadIo.Offset = SdRp->Parameters.ReadIo.Offset;
workPacket->Parameters.ReadIo.Buffer = SdRp->Parameters.ReadIo.Buffer;
workPacket->Parameters.ReadIo.Length = 1;
IoMarkIrpPending(Irp);
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_READ_IO_EXTENDED:
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_READIO_EXTENDED,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.ReadIo.Offset = SdRp->Parameters.ReadIoExtended.Offset;
workPacket->Parameters.ReadIo.Buffer = SdRp->Parameters.ReadIoExtended.Buffer;
workPacket->Parameters.ReadIo.Length = SdRp->Parameters.ReadIoExtended.Length;
IoMarkIrpPending(Irp);
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_WRITE_IO:
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_WRITEIO,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.WriteIo.Offset = SdRp->Parameters.WriteIo.Offset;
workPacket->Parameters.WriteIo.Data = SdRp->Parameters.WriteIo.Data;
workPacket->Parameters.WriteIo.Length = 1;
IoMarkIrpPending(Irp);
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_WRITE_IO_EXTENDED:
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_WRITEIO_EXTENDED,
CompletionRoutine,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.WriteIo.Offset = SdRp->Parameters.WriteIoExtended.Offset;
workPacket->Parameters.WriteIo.Buffer = SdRp->Parameters.WriteIoExtended.Buffer;
workPacket->Parameters.WriteIo.Length = SdRp->Parameters.WriteIoExtended.Length;
IoMarkIrpPending(Irp);
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
case SDRP_ACKNOWLEDGE_INTERRUPT:
ASSERT((pdoExtension->Flags & SDBUS_PDO_CALLBACK_IN_SERVICE) != 0);
pdoExtension->Flags &= ~SDBUS_PDO_CALLBACK_IN_SERVICE;
(*(fdoExtension->FunctionBlock->AcknowledgeEvent))(fdoExtension, SDBUS_EVENT_CARD_INTERRUPT);
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_PARAMETER;
}
return status;
}
NTSTATUS
SdbusPdoDeviceControl(
IN PDEVICE_OBJECT Pdo,
IN PIRP Irp
)
/*++
Routine Description:
IOCTL device routine
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the IRP
Return Value:
Status
--*/
{
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
PDEVICE_OBJECT fdo = fdoExtension->DeviceObject;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
PSD_WORK_PACKET workPacket;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x irp %.08x code %08x DISPATCH\n", Pdo, Irp,
irpSp->Parameters.DeviceIoControl.IoControlCode));
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_SD_INTERFACE_OPEN: {
PSDBUS_INTERFACE_DATA interfaceData = Irp->AssociatedIrp.SystemBuffer;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_INTERFACE_DATA)) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (interfaceData->DeviceGeneratesInterrupts) {
pdoExtension->Flags |= SDBUS_PDO_GENERATES_IRQ;
//
// ISSUE: this is not multifunction-aware
//
if (interfaceData->CallbackAtDpcLevel) {
//
// reflect ISR at dispatch level
//
pdoExtension->Flags |= SDBUS_PDO_DPC_CALLBACK;
} else {
//
// reflect ISR at passive level
//
KeInitializeEvent(&fdoExtension->CardInterruptEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&fdoExtension->WorkItemExitEvent, SynchronizationEvent, FALSE);
fdoExtension->Flags |= SDBUS_FDO_WORK_ITEM_ACTIVE;
IoQueueWorkItem(fdoExtension->IoWorkItem,
SdbusEventWorkItemProc,
DelayedWorkQueue,
NULL);
}
(*(fdoExtension->FunctionBlock->EnableEvent))(fdoExtension, SDBUS_EVENT_CARD_INTERRUPT);
}
// TO IMPLEMENT: can I validate this address at all?
pdoExtension->CallbackRoutine = interfaceData->CallbackRoutine;
pdoExtension->CallbackRoutineContext = interfaceData->CallbackRoutineContext;
status = STATUS_SUCCESS;
break;
}
case IOCTL_SD_INTERFACE_CLOSE:
//
// ISSUE: this is not multifunction-aware
//
if (fdoExtension->Flags & SDBUS_FDO_WORK_ITEM_ACTIVE) {
fdoExtension->Flags &= ~SDBUS_FDO_WORK_ITEM_ACTIVE;
KeSetEvent(&fdoExtension->WorkItemExitEvent, 0, FALSE);
}
status = STATUS_SUCCESS;
break;
case IOCTL_SD_GET_DEVICE_PARMS: {
PSDBUS_DEVICE_PARAMETERS deviceParameters = Irp->AssociatedIrp.SystemBuffer;
ULONG deviceSize;
ULONGLONG capacity, blockNr, mult, block_len;
PSD_CSD sdCsd;
DebugPrint((SDBUS_DEBUG_IOCTL, "IOCTL_SD_GET_DEVICE_PARMS\n"));
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SDBUS_DEVICE_PARAMETERS)) {
status = STATUS_INVALID_PARAMETER;
break;
}
//ISSUE: NEED TO IMPLEMENT: synchronization
sdCsd = &fdoExtension->CardData->SdCsd;
deviceSize = sdCsd->b.DeviceSizeHigh << 2 | sdCsd->c.DeviceSizeLow;
mult = (1 << (sdCsd->c.DeviceSizeMultiplier+2));
blockNr = (deviceSize+1) * mult;
block_len = (1 << sdCsd->b.MaxReadDataBlockLength);
capacity = blockNr * block_len;
deviceParameters->Capacity = capacity;
deviceParameters->WriteProtected = (*(fdoExtension->FunctionBlock->IsWriteProtected))(fdoExtension);
Irp->IoStatus.Information = sizeof(SDBUS_DEVICE_PARAMETERS);
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x irp %.08x complete %08x\n", Pdo, Irp, status));
break;
}
#if 0
case IOCTL_SD_READ_BLOCK: {
PSDBUS_READ_PARAMETERS readParameters = Irp->AssociatedIrp.SystemBuffer;
DebugPrint((SDBUS_DEBUG_IOCTL, "IOCTL_SD_READ_BLOCK - off %08x len %08x\n",
(ULONG)readParameters->ByteOffset, readParameters->Length));
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_READ_PARAMETERS)) ||
(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG_PTR))) {
status = STATUS_INVALID_PARAMETER;
break;
}
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_READBLOCK,
SdbusPdoIoctlCompletion,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.ReadBlock.ByteOffset = readParameters->ByteOffset;
workPacket->Parameters.ReadBlock.Buffer = readParameters->Buffer;
workPacket->Parameters.ReadBlock.Length = readParameters->Length;
IoMarkIrpPending(Irp);
Irp = NULL;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
}
case IOCTL_SD_WRITE_BLOCK: {
PSDBUS_WRITE_PARAMETERS writeParameters = Irp->AssociatedIrp.SystemBuffer;
DebugPrint((SDBUS_DEBUG_IOCTL, "IOCTL_SD_WRITE_BLOCK - off %08x len %08x\n",
(ULONG)writeParameters->ByteOffset, writeParameters->Length));
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_WRITE_PARAMETERS)) ||
(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG_PTR))) {
status = STATUS_INVALID_PARAMETER;
break;
}
if ((*(fdoExtension->FunctionBlock->IsWriteProtected))(fdoExtension)) {
status = STATUS_MEDIA_WRITE_PROTECTED;
break;
}
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_WRITEBLOCK,
SdbusPdoIoctlCompletion,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.WriteBlock.ByteOffset = writeParameters->ByteOffset;
workPacket->Parameters.WriteBlock.Buffer = writeParameters->Buffer;
workPacket->Parameters.WriteBlock.Length = writeParameters->Length;
IoMarkIrpPending(Irp);
Irp = NULL;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
}
case IOCTL_SD_IO_READ: {
PSDBUS_IO_READ_PARAMETERS readParameters = Irp->AssociatedIrp.SystemBuffer;
WORKPROC_FUNCTION workProcFunction;
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_IO_READ_PARAMETERS)) ||
(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG_PTR))) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (readParameters->CmdType == 52) {
workProcFunction = SDWP_READIO;
} else if (readParameters->CmdType == 53) {
workProcFunction = SDWP_READIO_EXTENDED;
} else {
status = STATUS_INVALID_PARAMETER;
break;
}
status = SdbusBuildWorkPacket(fdoExtension,
workProcFunction,
SdbusPdoIoctlCompletion,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.ReadIo.Offset = readParameters->Offset;
workPacket->Parameters.ReadIo.Buffer = readParameters->Buffer;
workPacket->Parameters.ReadIo.Length = readParameters->Length;
IoMarkIrpPending(Irp);
Irp = NULL;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
}
case IOCTL_SD_IO_WRITE: {
PSDBUS_IO_WRITE_PARAMETERS writeParameters = Irp->AssociatedIrp.SystemBuffer;
WORKPROC_FUNCTION workProcFunction;
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SDBUS_IO_WRITE_PARAMETERS)) ||
(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG_PTR))) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (writeParameters->CmdType == 52) {
workProcFunction = SDWP_WRITEIO;
} else if (writeParameters->CmdType == 53) {
workProcFunction = SDWP_WRITEIO_EXTENDED;
} else {
status = STATUS_INVALID_PARAMETER;
break;
}
status = SdbusBuildWorkPacket(fdoExtension,
workProcFunction,
SdbusPdoIoctlCompletion,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
break;
}
workPacket->PdoExtension = pdoExtension;
workPacket->Parameters.WriteIo.Offset = writeParameters->Offset;
workPacket->Parameters.WriteIo.Buffer = writeParameters->Buffer;
workPacket->Parameters.WriteIo.Length = writeParameters->Length;
IoMarkIrpPending(Irp);
Irp = NULL;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_IO);
status = STATUS_PENDING;
break;
}
#endif
case IOCTL_SD_ACKNOWLEDGE_CARD_IRQ:
ASSERT((pdoExtension->Flags & SDBUS_PDO_CALLBACK_IN_SERVICE) != 0);
pdoExtension->Flags &= ~SDBUS_PDO_CALLBACK_IN_SERVICE;
(*(fdoExtension->FunctionBlock->AcknowledgeEvent))(fdoExtension, SDBUS_EVENT_CARD_INTERRUPT);
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x irp %.08x complete %08x\n", Pdo, Irp, status));
break;
}
if (status != STATUS_PENDING) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %.08x ioctl exits %08x\n", Pdo, status));
return status;
}
VOID
SdbusPdoIoctlCompletion (
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
)
{
PIRP irp = WorkPacket->CompletionContext;
DebugPrint((SDBUS_DEBUG_IOCTL, "pdo %08x irp %08x ioctl complete %08x\n",
WorkPacket->PdoExtension->DeviceObject, irp, status));
if (NT_SUCCESS(status)) {
PULONG_PTR outputBuffer = (PULONG_PTR)irp->AssociatedIrp.SystemBuffer;
// ISSUE make this so the individual worker routine can decide how big the return buffer is
*outputBuffer = WorkPacket->Information;
irp->IoStatus.Information = sizeof(ULONG_PTR);
}
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ExFreePool(WorkPacket);
}