Files
reactos/drivers/storage/ide/atapi/atapi.c
Dmitry Borisov ac33647888 [ATAPI] Add ATA storage driver
CORE-17256
CORE-17191
CORE-17716
CORE-17977
CORE-13976
CORE-16216
2026-04-21 15:01:22 -05:00

766 lines
22 KiB
C

/*
* PROJECT: ReactOS ATA Port Driver
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Driver entrypoint and utility functions
* COPYRIGHT: Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
*/
/* INCLUDES *******************************************************************/
#include "atapi.h"
/* GLOBALS ********************************************************************/
UNICODE_STRING AtapDriverRegistryPath;
BOOLEAN AtapInPEMode;
ATAPORT_PAGED_DATA
static const struct
{
PCSTR DeviceType;
PCSTR GenericType;
PCSTR PeripheralId;
} AtapGenericDeviceNames[] =
{
{"Disk", "GenDisk", "DiskPeripheral" }, // DIRECT_ACCESS_DEVICE
{"Sequential", "GenSequential", "TapePeripheral" }, // SEQUENTIAL_ACCESS_DEVICE
{"Printer", "GenPrinter", "PrinterPeripheral" }, // PRINTER_DEVICE
{"Processor", "GenProcessor", "ProcessorPeripheral" }, // PROCESSOR_DEVICE
{"Worm", "GenWorm", "WormPeripheral" }, // WRITE_ONCE_READ_MULTIPLE_DEVICE
{"CdRom", "GenCdRom", "CdRomPeripheral" }, // READ_ONLY_DIRECT_ACCESS_DEVICE
{"Scanner", "GenScanner", "ScannerPeripheral" }, // SCANNER_DEVICE
{"Optical", "GenOptical", "OpticalDiskPeripheral" }, // OPTICAL_DEVICE
{"Changer", "GenChanger", "MediumChangerPeripheral" }, // MEDIUM_CHANGER
{"Net", "GenNet", "CommunicationsPeripheral"}, // COMMUNICATION_DEVICE
{"Other", "IdeOther", "OtherPeripheral" }, // 10
};
/* FUNCTIONS ******************************************************************/
CODE_SEG("PAGE")
PCSTR
AtaTypeCodeToName(
_In_ PATAPORT_DEVICE_EXTENSION DevExt,
_In_ DEVICE_TYPE_NAME Type)
{
ULONG DeviceType;
PAGED_CODE();
DeviceType = DevExt->InquiryData.DeviceType;
DeviceType = min(DeviceType, RTL_NUMBER_OF(AtapGenericDeviceNames) - 1);
switch (Type)
{
case GetDeviceType:
return AtapGenericDeviceNames[DeviceType].DeviceType;
case GetPeripheralId:
return AtapGenericDeviceNames[DeviceType].PeripheralId;
case GetGenericType:
if (DevExt->Device.DeviceFlags & DEVICE_IS_SUPER_FLOPPY)
return "GenSFloppy"; // Install the Super Floppy storage class driver
else
return AtapGenericDeviceNames[DeviceType].GenericType;
default:
ASSERT(FALSE);
UNREACHABLE;
}
}
CODE_SEG("PAGE")
NTSTATUS
AtaOpenRegistryKey(
_Out_ PHANDLE KeyHandle,
_In_ HANDLE RootKey,
_In_ PUNICODE_STRING KeyName,
_In_ BOOLEAN Create)
{
NTSTATUS Status;
ULONG Disposition;
OBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes,
KeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
RootKey,
NULL);
if (Create)
{
Status = ZwCreateKey(KeyHandle,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
&Disposition);
}
else
{
Status = ZwOpenKey(KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
}
return Status;
}
CODE_SEG("PAGE")
VOID
AtaGetRegistryKey(
_In_ PATAPORT_CHANNEL_EXTENSION ChanExt,
_In_ UCHAR TargetId,
_In_ PCWSTR KeyName,
_Out_ PULONG KeyValue,
_In_ ULONG DefaultValue)
{
UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(*KeyValue)];
HANDLE HwKeyHandle, TargetKeyHandle;
UNICODE_STRING ValueName, TargetKeyName;
NTSTATUS Status;
WCHAR TargetKeyBuffer[sizeof("Target99")];
ULONG ResultLength;
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer;
PAGED_CODE();
Status = IoOpenDeviceRegistryKey(ChanExt->Pdo,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&HwKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to open device hardware key, status 0x%lx\n", Status);
return;
}
/* Open or create the 'TargetX' key */
Status = RtlStringCbPrintfW(TargetKeyBuffer,
sizeof(TargetKeyBuffer),
L"Target%u",
TargetId);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&TargetKeyName, TargetKeyBuffer);
Status = AtaOpenRegistryKey(&TargetKeyHandle, HwKeyHandle, &TargetKeyName, TRUE);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to create '%wZ' key, status 0x%lx\n", &TargetKeyName, Status);
goto Cleanup;
}
RtlInitUnicodeString(&ValueName, KeyName);
Status = ZwQueryValueKey(TargetKeyHandle,
&ValueName,
KeyValuePartialInformation,
PartialInfo,
sizeof(Buffer),
&ResultLength);
ZwClose(TargetKeyHandle);
if (!NT_SUCCESS(Status) ||
(PartialInfo->Type != REG_DWORD) ||
(PartialInfo->DataLength != sizeof(*KeyValue)))
{
TRACE("Failed to read '%wZ' key, status 0x%lx\n", &ValueName, Status);
*KeyValue = DefaultValue;
goto Cleanup;
}
*KeyValue = *(PULONG)&PartialInfo->Data;
Cleanup:
ZwClose(HwKeyHandle);
}
CODE_SEG("PAGE")
VOID
AtaSetRegistryKey(
_In_ PATAPORT_CHANNEL_EXTENSION ChanExt,
_In_ UCHAR TargetId,
_In_ PCWSTR KeyName,
_In_ ULONG KeyValue)
{
HANDLE HwKeyHandle, TargetKeyHandle;
UNICODE_STRING ValueName, TargetKeyName;
NTSTATUS Status;
WCHAR TargetKeyBuffer[sizeof("Target99")];
PAGED_CODE();
Status = IoOpenDeviceRegistryKey(ChanExt->Pdo,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&HwKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to open device hardware key, status 0x%lx\n", Status);
return;
}
/* Open or create the 'TargetX' key */
Status = RtlStringCbPrintfW(TargetKeyBuffer,
sizeof(TargetKeyBuffer),
L"Target%u",
TargetId);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&TargetKeyName, TargetKeyBuffer);
Status = AtaOpenRegistryKey(&TargetKeyHandle, HwKeyHandle, &TargetKeyName, TRUE);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to create '%wZ' key, status 0x%lx\n", &TargetKeyName, Status);
goto Cleanup;
}
RtlInitUnicodeString(&ValueName, KeyName);
Status = ZwSetValueKey(TargetKeyHandle,
&ValueName,
0,
REG_DWORD,
&KeyValue,
sizeof(KeyValue));
ZwClose(TargetKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to set '%wZ' key, status 0x%lx\n", &ValueName, Status);
}
Cleanup:
ZwClose(HwKeyHandle);
}
CODE_SEG("PAGE")
VOID
AtaSetPortRegistryKey(
_In_ PATAPORT_CHANNEL_EXTENSION ChanExt,
_In_ PCWSTR KeyName,
_In_ ULONG KeyValue)
{
HANDLE HwKeyHandle;
UNICODE_STRING ValueName;
NTSTATUS Status;
PAGED_CODE();
Status = IoOpenDeviceRegistryKey(ChanExt->Pdo,
PLUGPLAY_REGKEY_DEVICE,
KEY_ALL_ACCESS,
&HwKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to open device hardware key, status 0x%lx\n", Status);
return;
}
RtlInitUnicodeString(&ValueName, KeyName);
Status = ZwSetValueKey(HwKeyHandle,
&ValueName,
0,
REG_DWORD,
&KeyValue,
sizeof(KeyValue));
ZwClose(HwKeyHandle);
if (!NT_SUCCESS(Status))
{
TRACE("Failed to set '%wZ' key, status 0x%lx\n", &ValueName, Status);
}
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaDispatchCreateClose(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp)
{
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
VOID
NTAPI
AtaUnload(
_In_ PDRIVER_OBJECT DriverObject)
{
PAGED_CODE();
RtlFreeUnicodeString(&AtapDriverRegistryPath);
}
VOID
NTAPI
AtaStorageNotificationWorker(
_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context)
{
PIO_WORKITEM WorkItem = Context;
PDEVICE_OBJECT TopDeviceObject;
PIRP Irp;
KEVENT Event;
IO_STATUS_BLOCK IoStatus;
STORAGE_EVENT_NOTIFICATION EventObject;
NTSTATUS Status;
TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
EventObject.Version = STORAGE_EVENT_NOTIFICATION_VERSION_V1;
EventObject.Size = sizeof(EventObject);
EventObject.Events = STORAGE_EVENT_ALL;
Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_EVENT_NOTIFICATION,
TopDeviceObject,
&EventObject,
sizeof(EventObject),
NULL,
0,
FALSE,
&Event,
&IoStatus);
if (!Irp)
{
ERR("IoBuildDeviceIoControlRequest() failed\n");
goto Exit;
}
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
TRACE("Notification result %08lx\n", Status);
Exit:
ObDereferenceObject(TopDeviceObject);
IoFreeWorkItem(WorkItem);
}
VOID
NTAPI
AtaStorageNotificationlDpc(
_In_ PKDPC Dpc,
_In_opt_ PVOID DeferredContext,
_In_opt_ PVOID SystemArgument1,
_In_opt_ PVOID SystemArgument2)
{
PATAPORT_PORT_DATA PortData = DeferredContext;
ULONG DeviceBitmap = PtrToUlong(SystemArgument1);
PATAPORT_CHANNEL_EXTENSION ChanExt;
ULONG i;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument2);
ChanExt = CONTAINING_RECORD(PortData, ATAPORT_CHANNEL_EXTENSION, PortData);
for (i = 0; i < ATA_MAX_DEVICE; ++i)
{
PATAPORT_DEVICE_EXTENSION DevExt;
PIO_WORKITEM WorkItem;
if (!(DeviceBitmap & (1 << i)))
continue;
DevExt = AtaFdoFindDeviceByPath(ChanExt,
AtaMarshallScsiAddress(PortData->PortNumber, i, 0),
AtaStorageNotificationlDpc);
if (!DevExt)
continue;
WorkItem = IoAllocateWorkItem(DevExt->Common.Self);
if (!WorkItem)
{
ERR("Failed to allocate workitem");
}
else
{
IoQueueWorkItem(WorkItem, AtaStorageNotificationWorker, CriticalWorkQueue, WorkItem);
}
IoReleaseRemoveLock(&DevExt->Common.RemoveLock, AtaStorageNotificationlDpc);
}
}
CODE_SEG("PAGE")
NTSTATUS
AtaPnpQueryInterface(
_In_ PATAPORT_COMMON_EXTENSION CommonExt,
_In_ const GUID* Guid,
_Out_ PVOID Interface,
_In_ ULONG Version,
_In_ ULONG Size)
{
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
PAGED_CODE();
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
CommonExt->LowerDeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (!Irp)
return STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoStack = IoGetNextIrpStackLocation(Irp);
IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
IoStack->Parameters.QueryInterface.InterfaceType = Guid;
IoStack->Parameters.QueryInterface.Size = Size;
IoStack->Parameters.QueryInterface.Version = Version;
IoStack->Parameters.QueryInterface.Interface = Interface;
IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(CommonExt->LowerDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatusBlock.Status;
}
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPnpRepeatRequest(
_In_ PATAPORT_COMMON_EXTENSION CommonExt,
_In_ PIRP Irp,
_In_opt_ PDEVICE_CAPABILITIES DeviceCapabilities)
{
PATAPORT_COMMON_EXTENSION FdoExt = CommonExt->FdoExt;
PDEVICE_OBJECT TopDeviceObject;
PIO_STACK_LOCATION IoStack, SubStack;
PIRP SubIrp;
KEVENT Event;
NTSTATUS Status;
PAGED_CODE();
ASSERT(!IS_FDO(CommonExt));
TopDeviceObject = IoGetAttachedDeviceReference(FdoExt->Self);
SubIrp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
if (!SubIrp)
{
ObDereferenceObject(TopDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(&Event, NotificationEvent, FALSE);
IoStack = IoGetCurrentIrpStackLocation(Irp);
SubStack = IoGetNextIrpStackLocation(SubIrp);
RtlCopyMemory(SubStack, IoStack, sizeof(*SubStack));
if (DeviceCapabilities)
SubStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
IoSetCompletionRoutine(SubIrp,
AtaPdoCompletionRoutine,
&Event,
TRUE,
TRUE,
TRUE);
SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Status = IoCallDriver(TopDeviceObject, SubIrp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
ObDereferenceObject(TopDeviceObject);
Status = SubIrp->IoStatus.Status;
IoFreeIrp(SubIrp);
return Status;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPnpQueryDeviceUsageNotification(
_In_ PATAPORT_COMMON_EXTENSION CommonExt,
_In_ PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
volatile LONG* Counter;
PAGED_CODE();
if (!IS_FDO(CommonExt))
{
Status = AtaPnpRepeatRequest(CommonExt, Irp, NULL);
}
else
{
if (!NT_VERIFY(IoForwardIrpSynchronously(CommonExt->LowerDeviceObject, Irp)))
return STATUS_UNSUCCESSFUL;
Status = Irp->IoStatus.Status;
}
if (!NT_SUCCESS(Status))
return Status;
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch (IoStack->Parameters.UsageNotification.Type)
{
case DeviceUsageTypePaging:
Counter = &CommonExt->PageFiles;
break;
case DeviceUsageTypeHibernation:
Counter = &CommonExt->HibernateFiles;
break;
case DeviceUsageTypeDumpFile:
Counter = &CommonExt->DumpFiles;
break;
default:
return Status;
}
IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
if (!IS_FDO(CommonExt))
IoInvalidateDeviceState(CommonExt->Self);
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
NTSTATUS
AtaPnpQueryPnpDeviceState(
_In_ PATAPORT_COMMON_EXTENSION CommonExt,
_In_ PIRP Irp)
{
PAGED_CODE();
if (CommonExt->PageFiles || CommonExt->HibernateFiles || CommonExt->DumpFiles)
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
if (IS_FDO(CommonExt))
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
VOID
AtaPnpInitializeCommonExtension(
_In_ PATAPORT_COMMON_EXTENSION CommonExt,
_In_ PDEVICE_OBJECT SelfDeviceObject,
_In_ ULONG Flags)
{
PAGED_CODE();
CommonExt->Flags = Flags;
CommonExt->Self = SelfDeviceObject;
CommonExt->DevicePowerState = PowerDeviceD0;
CommonExt->SystemPowerState = PowerSystemWorking;
IoInitializeRemoveLock(&CommonExt->RemoveLock, ATAPORT_TAG, 0, 0);
}
CODE_SEG("PAGE")
NTSTATUS
NTAPI
AtaAddChannel(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
{
NTSTATUS Status;
PDEVICE_OBJECT Fdo;
UNICODE_STRING DeviceName;
PATAPORT_CHANNEL_EXTENSION ChanExt;
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\IdePort99999")];
DECLARE_PAGED_WSTRING(FdoFormat, L"\\Device\\Ide\\IdePort%lu");
static ULONG AtapFdoNumber = 0;
PAGED_CODE();
Status = RtlStringCbPrintfW(DeviceNameBuffer,
sizeof(DeviceNameBuffer),
FdoFormat,
AtapFdoNumber);
ASSERT(NT_SUCCESS(Status));
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
INFO("%s(%p, %p) '%wZ'\n", __FUNCTION__, DriverObject, PhysicalDeviceObject, &DeviceName);
Status = IoCreateDevice(DriverObject,
sizeof(*ChanExt),
&DeviceName,
FILE_DEVICE_CONTROLLER,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&Fdo);
if (!NT_SUCCESS(Status))
{
ERR("Failed to create the FDO with status 0x%lx\n", Status);
return Status;
}
ChanExt = Fdo->DeviceExtension;
RtlZeroMemory(ChanExt, sizeof(*ChanExt));
AtaPnpInitializeCommonExtension(&ChanExt->Common, Fdo, DO_IS_FDO);
ChanExt->Common.LowerDeviceObject = IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
if (!ChanExt->Common.LowerDeviceObject)
{
ERR("Failed to attach the FDO\n");
Status = STATUS_DEVICE_REMOVED;
goto Failure;
}
ChanExt->DeviceObjectNumber = AtapFdoNumber++;
ChanExt->Pdo = PhysicalDeviceObject;
/* DMA buffers alignment */
Fdo->AlignmentRequirement = ChanExt->Common.LowerDeviceObject->AlignmentRequirement;
Fdo->AlignmentRequirement = max(Fdo->AlignmentRequirement, ATA_MIN_BUFFER_ALIGNMENT);
KeInitializeSpinLock(&ChanExt->PdoListLock);
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
Failure:
if (ChanExt->Common.LowerDeviceObject)
IoDetachDevice(ChanExt->Common.LowerDeviceObject);
IoDeleteDevice(Fdo);
return Status;
}
static
CODE_SEG("INIT")
BOOLEAN
AtaInPEMode(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
NTSTATUS Status;
DECLARE_PAGED_UNICODE_STRING(
KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\MiniNT");
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
ZwClose(KeyHandle);
return TRUE;
}
return FALSE;
}
static
CODE_SEG("INIT")
VOID
AtaCreateIdeDirectory(VOID)
{
HANDLE Handle;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
DECLARE_PAGED_UNICODE_STRING(DirectoryName, L"\\Device\\Ide");
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes,
&DirectoryName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = ZwCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* We don't need a handle for a permanent object */
ZwClose(Handle);
}
/*
* Ignore directory creation failures (don't report them as a driver initialization error)
* as the directory may have already been created by another driver.
* We will handle fatal errors later via IoCreateDevice() call.
*/
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
INFO("ATAPI driver entry\n");
// FIXME: No crashdump/hibernation support
if (!DriverObject)
return STATUS_NOT_IMPLEMENTED;
/* Make a copy of the registry path */
AtapDriverRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
AtapDriverRegistryPath.Buffer =
ExAllocatePoolUninitialized(NonPagedPool,
AtapDriverRegistryPath.MaximumLength,
ATAPORT_TAG);
if (!AtapDriverRegistryPath.Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyUnicodeString(&AtapDriverRegistryPath, RegistryPath);
AtapDriverRegistryPath.Buffer[RegistryPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
DriverObject->MajorFunction[IRP_MJ_CREATE] = AtaDispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = AtaDispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AtaDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SCSI] = AtaDispatchScsi;
DriverObject->MajorFunction[IRP_MJ_POWER] = AtaDispatchPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AtaDispatchWmi;
DriverObject->MajorFunction[IRP_MJ_PNP] = AtaDispatchPnp;
DriverObject->DriverExtension->AddDevice = AtaAddChannel;
DriverObject->DriverUnload = AtaUnload;
KeInitializeDpc(&AtapCompletionDpc, AtaReqCompletionDpc, NULL);
InitializeSListHead(&AtapCompletionQueueList);
/* Create a directory to hold the driver's device objects */
AtaCreateIdeDirectory();
AtapInPEMode = AtaInPEMode();
return STATUS_SUCCESS;
}