PCI IDE Bus Master implementation

All development related issues welcome

Moderator: Moderator Team

Post Reply
vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

PCI IDE Bus Master implementation

Post by vgal »

reactos\drivers\storage\ide\pciidex\dma.c - new file

Code: Select all

#include "pciidex.h"
#include <initguid.h>
#include <wdmguid.h>

#define NDEBUG
#include <debug.h>

//#define MAX_SG_ELEMENTS 0x20 <-- in reactos\hal\halx86\generic\dma.c

//PDRIVER_LIST_CONTROL
static VOID NTAPI
AdapterListControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PSCATTER_GATHER_LIST ScatterGather,
    IN PVOID DeviceExtension)
{
	PPDO_DEVICE_EXTENSION              ChannelPdoExtension;
	PFDO_DEVICE_EXTENSION              ControllerFdoExtension;
	PPHYSICAL_REGION_DESCRIPTOR_TABLE  TablePRD;
	ULONG                              LengthElement;
	ULONG                              AddressElement;
	ULONG                              BusMasterChannelBase;
	ULONG                              ix, jx;
	ULONG                              len;
	ULONG                              BytesLimit = 0x10000; //64K boundary


	DPRINT("AdapterListControl \n");

	ChannelPdoExtension = (PPDO_DEVICE_EXTENSION)DeviceExtension;
	ChannelPdoExtension->SGList = ScatterGather;

	ix = 0;
	jx = 0;

	if ( ScatterGather->NumberOfElements > 0  )
	{
		for (ix = 0; ix < ScatterGather->NumberOfElements; ix++)
		{
			DPRINT("AdapterListControl: ix - %x\n", ix);

			AddressElement = ScatterGather->Elements[ix].Address.LowPart;
			LengthElement  = ScatterGather->Elements[ix].Length;

			DPRINT("AdapterListControl: AddressElement - %p\n", AddressElement);
			DPRINT("AdapterListControl: LengthElement  - %p\n", LengthElement);

			if ( LengthElement > 0 )
			{
				do
				{
					DPRINT("AdapterListControl: NumberOfMapRegisters - %x\n", ChannelPdoExtension->NumberOfMapRegisters);

					TablePRD = ChannelPdoExtension->CommonBuffer;
					DPRINT("AdapterListControl: TablePRD - %p\n", TablePRD);

					TablePRD->Elements[jx].BaseAddress = AddressElement;
					len = BytesLimit - (USHORT)AddressElement;

					DPRINT("AdapterListControl: AddressElement - %p\n", AddressElement);
					DPRINT("AdapterListControl: len            - %x\n", len);

					if ( len >= LengthElement )
					{
						DPRINT("AdapterListControl: len >= LengthElement\n");

						if ( LengthElement > BytesLimit )
						{
							DPRINT("AdapterListControl: LengthElement > BytesLimit\n");
							TablePRD->Elements[jx].ByteCount = 0;
							AddressElement += BytesLimit;
							LengthElement -= BytesLimit;
						}
						else
						{
							DPRINT("AdapterListControl: LengthElement <= BytesLimit\n");
							TablePRD->Elements[jx].ByteCount = (USHORT)(LengthElement & 0x0000FFFE);
							AddressElement += (USHORT)(LengthElement & 0x0000FFFE);
							LengthElement = 0;
						}
					}
					else
					{
						DPRINT("AdapterListControl: len < LengthElement\n");
						AddressElement += len;
						TablePRD->Elements[jx].ByteCount = (USHORT)len;
						LengthElement -= len;
					}

					TablePRD->Elements[jx].EndTable &= 0x7FFF;

					DPRINT("AdapterListControl: TablePRD->Elements[%x].BaseAddress - %p\n", jx, TablePRD->Elements[jx].BaseAddress);
					DPRINT("AdapterListControl: TablePRD->Elements[%x].ByteCount   - %x\n", jx, TablePRD->Elements[jx].ByteCount);
					DPRINT("AdapterListControl: TablePRD->Elements[%x].EndTable    - %x\n", jx, TablePRD->Elements[jx].EndTable);

					++jx;
				}
				while ( LengthElement );
			}
		}
	}

	if ( jx > 0 )
	  TablePRD->Elements[jx-1].EndTable |= 0x8000;
	else
	  TablePRD->Elements[jx].EndTable |= 0x8000;

	ControllerFdoExtension = (PFDO_DEVICE_EXTENSION)ChannelPdoExtension->ControllerFdo->DeviceExtension;
	BusMasterChannelBase = ControllerFdoExtension->BusMasterBase + 8 * (ChannelPdoExtension->Channel & 1);//BAR4+0 - Primary channel, BAR4+8 - Secondary channel

	DPRINT("AdapterListControl: BusMasterChannelBase - %p\n", BusMasterChannelBase);

	//BusMasterDisable
	WRITE_PORT_UCHAR((PUCHAR)BusMasterChannelBase, 0);
	WRITE_PORT_UCHAR((PUCHAR)(BusMasterChannelBase + 2), 6);

	//Write to Descriptor Table Pointer Register
	DPRINT("AdapterListControl: ChannelPdoExtension->LogicalAddress.LowPart - %p\n", ChannelPdoExtension->LogicalAddress.LowPart);
	WRITE_PORT_ULONG((PULONG)(BusMasterChannelBase + 4), ChannelPdoExtension->LogicalAddress.LowPart);

	((PALLOCATE_ADAPTER)ChannelPdoExtension->AllocateAdapter)(ChannelPdoExtension->AllocateAdapterContext);
}

static NTSTATUS NTAPI
BusMasterPrepare(
	IN PPDO_DEVICE_EXTENSION  DeviceExtension,
	IN PVOID                  CurrentVirtualAddress,
	IN ULONG                  Length,
	IN PMDL                   Mdl,
        IN BOOLEAN                WriteToDevice,
	IN PVOID                  AllocateAdapter,
	IN PDEVICE_OBJECT         AtaXChannelFdo)
{
	NTSTATUS Status;
	PDMA_ADAPTER DmaAdapter = DeviceExtension->DmaAdapter;


	DeviceExtension->WriteToDevice = WriteToDevice;

	DPRINT("BusMasterPrepare: DeviceExtension       - %p\n", DeviceExtension);
	DPRINT("BusMasterPrepare: CurrentVirtualAddress - %p\n", CurrentVirtualAddress);
	DPRINT("BusMasterPrepare: Length                - %p\n", Length);
	DPRINT("BusMasterPrepare: Mdl                   - %p\n", Mdl);
	DPRINT("BusMasterPrepare: WriteToDevice         - %p\n", WriteToDevice);
	DPRINT("BusMasterPrepare: AllocateAdapter       - %p\n", AllocateAdapter);
	DPRINT("BusMasterPrepare: AtaXChannelFdo        - %p\n", AtaXChannelFdo);

	DeviceExtension->AllocateAdapter        = AllocateAdapter;
	DeviceExtension->AllocateAdapterContext = (ULONG)AtaXChannelFdo;

	Status = DmaAdapter->DmaOperations->GetScatterGatherList(
			DmaAdapter,
			DeviceExtension->SelfDevice,
			Mdl,
			CurrentVirtualAddress,
			Length,
			(PDRIVER_LIST_CONTROL)AdapterListControl,
			DeviceExtension,
			WriteToDevice);

	DPRINT("BusMasterPrepare: return - %p\n", Status);
	return Status;
}

static NTSTATUS NTAPI
BusMasterStart(IN PPDO_DEVICE_EXTENSION DeviceExtension)//ChannelPdoExtension
{
	PFDO_DEVICE_EXTENSION  ControllerFdoExtension;
	ULONG  BusMasterChannelBase;


	DPRINT("BusMasterEnable: DeviceExtension - %p\n", DeviceExtension);

	ControllerFdoExtension = DeviceExtension->ControllerFdo->DeviceExtension;
	BusMasterChannelBase = ControllerFdoExtension->BusMasterBase + 8 * (DeviceExtension->Channel & 1);

	if ( DeviceExtension->WriteToDevice )
	{
		DPRINT("BusMasterEnable: Write to device (1). BusMasterChannelBase - %p\n", BusMasterChannelBase);
		//Start Bus Master. PCI bus master reads are performed.
		WRITE_PORT_UCHAR((PUCHAR)BusMasterChannelBase, 1);
	}
	else
	{
		DPRINT("BusMasterEnable: Read from device (9). BusMasterChannelBase - %p\n", BusMasterChannelBase);
		//Start Bus Master. PCI bus master writes are performed.
		WRITE_PORT_UCHAR((PUCHAR)BusMasterChannelBase, 9);
	}

	DPRINT("BusMasterEnable: return STATUS_SUCCESS\n");
	return STATUS_SUCCESS;
}

static NTSTATUS NTAPI
BusMasterStop(IN PPDO_DEVICE_EXTENSION DeviceExtension)//ChannelPdoExtension
{
	PFDO_DEVICE_EXTENSION  ControllerFdoExtension;
	ULONG  BusMasterChannelBase;


	DPRINT("BusMasterDisable: DeviceExtension - %p\n", DeviceExtension);

	ControllerFdoExtension = DeviceExtension->ControllerFdo->DeviceExtension;

	BusMasterChannelBase = ControllerFdoExtension->BusMasterBase + 8 * (DeviceExtension->Channel & 1);
	DPRINT("BusMasterDisable: BusMasterChannelBase - %p\n", BusMasterChannelBase);

	/*
	Start/Stop Bus Master: Writing a '1' to this bit enables bus master operation of the controller.
	Bus master operation begins when this bit is detected changing from a zero to a one. The
	controller will transfer data between the IDE device and memory only when this bit is set.
	Master operation can be halted by writing a '0' to this bit.  All state information is lost when a '0'
	is written; Master mode operation cannot be stopped and then resumed.  If this bit is reset while
	bus master operation is still active (i.e., the Bus Master IDE Active bit of the Bus Master IDE
	Status register for that IDE channel is set) and the drive has not yet finished its data transfer (The
	Interupt bit in the Bus Master IDE Status register for that IDE channel is not set), the bus master
	command is said to be aborted and data transfered from the drive may be discarded before being
	written to system memory. This bit is intended to be reset after the data transfer is completed, as
	indicated by either the  Bus Master IDE Active bit or the Interrupt bit of the Bus Master IDE
	Status register for that IDE channel being set, or both. */

	WRITE_PORT_UCHAR((PUCHAR)BusMasterChannelBase, 0);          //Stop Bus Master (Bus Master IDE Command Register)

	/*
	Interrupt:  This bit is set by the rising edge of the IDE interrupt line.  This bit is cleared when a
	'1' is written to it by software.  Software can use this bit to determine if an IDE device has
	asserted its interrupt line. When this bit is read as a one, all data transfered from the drive is
	visible in system memory. */

	WRITE_PORT_UCHAR((PUCHAR)(BusMasterChannelBase + 2), 4);    //Clear Interrupt bit (Bus Master IDE Status Register)

	DPRINT("BusMasterDisable: return STATUS_SUCCESS\n");
	return STATUS_SUCCESS;
}

static ULONG NTAPI
BusMasterReadStatus(IN PPDO_DEVICE_EXTENSION DeviceExtension)//ChannelPdoExtension
{
	PFDO_DEVICE_EXTENSION  ControllerFdoExtension;
	ULONG                  BusMasterChannelBase;
	ULONG                  Status = 0;
        UCHAR                  Result;


	DPRINT("BusMasterReadStatus: DeviceExtension - %p\n", DeviceExtension);

	ControllerFdoExtension = DeviceExtension->ControllerFdo->DeviceExtension;
	BusMasterChannelBase = ControllerFdoExtension->BusMasterBase + 8 * (DeviceExtension->Channel & 1);

	Result = READ_PORT_UCHAR((PUCHAR)(BusMasterChannelBase + 2));
	DPRINT("BusMasterReadStatus: Result - %p\n", Result);

	/* Bus Master IDE Active: This bit is set when the Start bit is written to the Command  register.
	  This bit is cleared when the last transfer for a region is performed, where EOT for that region is
	  set in the region descriptor. It is also cleared when the Start bit is cleared in the Command
	  register. When this bit is read as a zero, all data transfered from the drive during the previous
	  bus master command is visible in system memory, unless the bus master command was aborted.
	*/
	if ( Result & 1 )
	  Status = 1;

	/* Error: This bit is set when the controller encounters an error in transferring data to/from
	  memory. The exact error condition is bus specific and can be determined in a bus specific
	  manner. This bit is cleared when a '1' is written to it by software.
	*/
	if ( Result & 2 )
	  Status |= 2;

	/* Interrupt:  This bit is set by the rising edge of the IDE interrupt line.  This bit is cleared when a
	  '1' is written to it by software. Software can use this bit to determine if an IDE device has
	  asserted its interrupt line. When this bit is read as a one, all data transfered from the drive is
	  visible in system memory.
	*/
	if ( Result & 4 )
	  Status |= 4;

	DPRINT("BusMasterReadStatus: return - %p\n", Status);
	return Status;
}

static NTSTATUS NTAPI
BusMasterComplete(IN PPDO_DEVICE_EXTENSION DeviceExtension)//ChannelPdoExtension
{
	PDMA_ADAPTER DmaAdapter = DeviceExtension->DmaAdapter;

	DPRINT("BusMasterComplete: DeviceExtension - %p\n", DeviceExtension);

	DmaAdapter->DmaOperations->PutScatterGatherList(
			DeviceExtension->DmaAdapter,
			DeviceExtension->SGList,
			DeviceExtension->WriteToDevice);

	DeviceExtension->SGList                 = 0;
	DeviceExtension->AllocateAdapter        = 0;
	DeviceExtension->AllocateAdapterContext = 0;

	DPRINT("BusMasterComplete: return STATUS_SUCCESS\n");
	return STATUS_SUCCESS;
}

NTSTATUS NTAPI
QueryBusMasterInterface(IN PPDO_DEVICE_EXTENSION DeviceExtension, IN PIO_STACK_LOCATION Stack)
{
	PBUS_MASTER_INTERFACE BusMasterInterface;
	PFDO_DEVICE_EXTENSION FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->ControllerFdo->DeviceExtension;

	DPRINT("QueryBusMasterInterface: FdoDeviceExtension - %p, BusMasterBase - %p\n", FdoDeviceExtension, FdoDeviceExtension->BusMasterBase);

	BusMasterInterface = (PBUS_MASTER_INTERFACE)Stack->Parameters.QueryInterface.Interface;
	BusMasterInterface->Size = sizeof(BUS_MASTER_INTERFACE);
	DPRINT("QueryBusMasterInterface: BusMasterInterface->Size - %p \n", BusMasterInterface->Size);

	BusMasterInterface->ChannelPdoExtension = DeviceExtension;
	BusMasterInterface->BusMasterBase       = FdoDeviceExtension->BusMasterBase;
	BusMasterInterface->BusMasterPrepare    = (PBUS_MASTER_PREPARE)BusMasterPrepare;
	BusMasterInterface->BusMasterStart      = (PBUS_MASTER_START)BusMasterStart;
	BusMasterInterface->BusMasterStop       = (PBUS_MASTER_STOP)BusMasterStop;
	BusMasterInterface->BusMasterReadStatus = (PBUS_MASTER_READ_STATUS)BusMasterReadStatus;
	BusMasterInterface->BusMasterComplete   = (PBUS_MASTER_COMPLETE)BusMasterComplete;

	DPRINT("QueryBusMasterInterface: return STATUS_SUCCESS\n");
	return STATUS_SUCCESS;
}
reactos\drivers\storage\ide\bmaster.h -new file

Code: Select all

typedef NTSTATUS
(NTAPI *PBUS_MASTER_PREPARE)(
  IN PVOID           DeviceExtension,
  IN PVOID           CurrentVirtualAddress,
  IN ULONG           Length,
  IN PMDL            Mdl,
  IN BOOLEAN         WriteToDevice,
  IN PVOID           AllocateAdapter,
  IN PDEVICE_OBJECT  AtaXChannelFdo);

typedef NTSTATUS
(NTAPI *PBUS_MASTER_START)(IN PVOID  DeviceExtension);

typedef NTSTATUS
(NTAPI *PBUS_MASTER_STOP)(IN PVOID  DeviceExtension);

typedef NTSTATUS
(NTAPI *PBUS_MASTER_READ_STATUS)(IN PVOID  DeviceExtension);

typedef NTSTATUS
(NTAPI *PBUS_MASTER_COMPLETE)(IN PVOID  DeviceExtension);

typedef struct _BUS_MASTER_INTERFACE {

  // generic interface header
  USHORT                   Size;
  USHORT                   Version;
  PVOID                    Context;
  PINTERFACE_REFERENCE     InterfaceReference;
  PINTERFACE_DEREFERENCE   InterfaceDereference;

  // bus master interface
  PVOID                    ChannelPdoExtension;
  ULONG                    BusMasterBase;
  PBUS_MASTER_PREPARE      BusMasterPrepare;
  PBUS_MASTER_START        BusMasterStart;
  PBUS_MASTER_STOP         BusMasterStop;
  PBUS_MASTER_READ_STATUS  BusMasterReadStatus;
  PBUS_MASTER_COMPLETE     BusMasterComplete;

} BUS_MASTER_INTERFACE, *PBUS_MASTER_INTERFACE;

typedef struct _PHYSICAL_REGION_DESCRIPTOR {

  ULONG   BaseAddress;
  USHORT  ByteCount;
  USHORT  EndTable;

} PHYSICAL_REGION_DESCRIPTOR, *PPHYSICAL_REGION_DESCRIPTOR;

typedef struct _PHYSICAL_REGION_DESCRIPTOR_TABLE {

  PHYSICAL_REGION_DESCRIPTOR  Elements[1];

} PHYSICAL_REGION_DESCRIPTOR_TABLE, *PPHYSICAL_REGION_DESCRIPTOR_TABLE;

fdo.c

Code: Select all

/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         PCI IDE bus driver extension
 * FILE:            drivers/storage/pciidex/fdo.c
 * PURPOSE:         IRP_MJ_PNP operations for FDOs
 * PROGRAMMERS:     Hervй Poussineau (hpoussin@reactos.org)
 */

#include "pciidex.h"

//#define NDEBUG
#include <debug.h>

#include <initguid.h>
#include <wdmguid.h>

static NTSTATUS
GetBusInterface(
	IN PFDO_DEVICE_EXTENSION DeviceExtension)
{
	PBUS_INTERFACE_STANDARD BusInterface = NULL;
	KEVENT Event;
	IO_STATUS_BLOCK IoStatus;
	PIRP Irp;
	PIO_STACK_LOCATION Stack;
	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	if (DeviceExtension->BusInterface)
	{
		DPRINT("We already have the bus interface\n");
		goto cleanup;
	}

	BusInterface = ExAllocatePool(PagedPool, sizeof(BUS_INTERFACE_STANDARD));
	if (!BusInterface)
	{
		DPRINT("ExAllocatePool() failed\n");
		Status = STATUS_INSUFFICIENT_RESOURCES;
		goto cleanup;
	}

	KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
	Irp = IoBuildSynchronousFsdRequest(
		IRP_MJ_PNP,
		DeviceExtension->LowerDevice,
		NULL,
		0,
		NULL,
		&Event,
		&IoStatus);
	if (!Irp)
	{
		DPRINT("IoBuildSynchronousFsdRequest() failed\n");
		Status = STATUS_INSUFFICIENT_RESOURCES;
		goto cleanup;
	}

	Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
	Irp->IoStatus.Information = 0;

	Stack = IoGetNextIrpStackLocation(Irp);
	Stack->MajorFunction = IRP_MJ_PNP;
	Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
	Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
	Stack->Parameters.QueryInterface.Version = 1;
	Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
	Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
	Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;

	Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
	if (Status == STATUS_PENDING)
	{
		KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
		Status = IoStatus.Status;
	}
	if (!NT_SUCCESS(Status))
		goto cleanup;

	DeviceExtension->BusInterface = BusInterface;
	BusInterface = NULL;
	Status = STATUS_SUCCESS;

cleanup:
	if (BusInterface) ExFreePool(BusInterface);
	return Status;
}

static NTSTATUS
ReleaseBusInterface(
	IN PFDO_DEVICE_EXTENSION DeviceExtension)
{
	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	if (DeviceExtension->BusInterface)
	{
		(*DeviceExtension->BusInterface->InterfaceDereference)(
			DeviceExtension->BusInterface->Context);
		DeviceExtension->BusInterface = NULL;
		Status = STATUS_SUCCESS;
	}

	return Status;
}

NTSTATUS NTAPI
PciIdeXAddDevice(
	IN PDRIVER_OBJECT DriverObject,
	IN PDEVICE_OBJECT Pdo)
{
	PPCIIDEX_DRIVER_EXTENSION DriverExtension;
	PFDO_DEVICE_EXTENSION DeviceExtension;
	PDEVICE_OBJECT Fdo;
	ULONG BytesRead;
	PCI_COMMON_CONFIG PciConfig;
	NTSTATUS Status;

	DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo);

	DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
	ASSERT(DriverExtension);

	Status = IoCreateDevice(
		DriverObject,
		sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize,
		NULL,
		FILE_DEVICE_BUS_EXTENDER,
		FILE_DEVICE_SECURE_OPEN,
		TRUE,
		&Fdo);
	if (!NT_SUCCESS(Status))
	{
		DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
		return Status;
	}

	DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
	RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));

	DeviceExtension->Common.IsFDO = TRUE;

	Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
	if (!NT_SUCCESS(Status))
	{
		DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
		return Status;
	}

	Status = GetBusInterface(DeviceExtension);
	if (!NT_SUCCESS(Status))
	{
		DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status);
		IoDetachDevice(DeviceExtension->LowerDevice);
		return Status;
	}

	BytesRead = (*DeviceExtension->BusInterface->GetBusData)(
		DeviceExtension->BusInterface->Context,
		PCI_WHICHSPACE_CONFIG,
		&PciConfig,
		0,
		PCI_COMMON_HDR_LENGTH);
	if (BytesRead != PCI_COMMON_HDR_LENGTH)
	{
		DPRINT("BusInterface->GetBusData() failed()\n");
		ReleaseBusInterface(DeviceExtension);
		IoDetachDevice(DeviceExtension->LowerDevice);
		return STATUS_IO_DEVICE_ERROR;
	}

  /*
  DPRINT("PciConfig.VendorID                 - %x\n", PciConfig.VendorID);
  DPRINT("PciConfig.DeviceID                 - %x\n", PciConfig.DeviceID);
  DPRINT("PciConfig.Command                  - %x\n", PciConfig.Command);
  DPRINT("PciConfig.Status                   - %x\n", PciConfig.Status);
  DPRINT("PciConfig.RevisionID               - %x\n", PciConfig.RevisionID);
  DPRINT("PciConfig.ProgIf                   - %x\n", PciConfig.ProgIf);
  DPRINT("PciConfig.SubClass                 - %x\n", PciConfig.SubClass);
  DPRINT("PciConfig.BaseClass                - %x\n", PciConfig.BaseClass);
  DPRINT("PciConfig.CacheLineSize            - %x\n", PciConfig.CacheLineSize);
  DPRINT("PciConfig.LatencyTimer             - %x\n", PciConfig.LatencyTimer);
  DPRINT("PciConfig.HeaderType               - %x\n", PciConfig.HeaderType);
  DPRINT("PciConfig.BIST                     - %x\n", PciConfig.BIST);
  DPRINT("PciConfig.u.type0.BaseAddresses[0] - %x\n", PciConfig.u.type0.BaseAddresses[0]);
  DPRINT("PciConfig.u.type0.BaseAddresses[1] - %x\n", PciConfig.u.type0.BaseAddresses[1]);
  DPRINT("PciConfig.u.type0.BaseAddresses[2] - %x\n", PciConfig.u.type0.BaseAddresses[2]);
  DPRINT("PciConfig.u.type0.BaseAddresses[3] - %x\n", PciConfig.u.type0.BaseAddresses[3]);
  DPRINT("PciConfig.u.type0.BaseAddresses[4] - %x\n", PciConfig.u.type0.BaseAddresses[4]);
  DPRINT("PciConfig.u.type0.BaseAddresses[5] - %x\n", PciConfig.u.type0.BaseAddresses[5]);
  DPRINT("PciConfig.u.type0.CIS              - %x\n", PciConfig.u.type0.CIS);
  DPRINT("PciConfig.u.type0.SubVendorID      - %x\n", PciConfig.u.type0.SubVendorID);
  DPRINT("PciConfig.u.type0.SubSystemID      - %x\n", PciConfig.u.type0.SubSystemID);
  DPRINT("PciConfig.u.type0.ROMBaseAddress   - %x\n", PciConfig.u.type0.ROMBaseAddress);
  DPRINT("PciConfig.u.type0.CapabilitiesPtr  - %x\n", PciConfig.u.type0.CapabilitiesPtr);
  DPRINT("PciConfig.u.type0.Reserved1[0]     - %x\n", PciConfig.u.type0.Reserved1[0]);
  DPRINT("PciConfig.u.type0.Reserved1[1]     - %x\n", PciConfig.u.type0.Reserved1[1]);
  DPRINT("PciConfig.u.type0.Reserved1[2]     - %x\n", PciConfig.u.type0.Reserved1[2]);
  DPRINT("PciConfig.u.type0.Reserved2        - %x\n", PciConfig.u.type0.Reserved2);
  DPRINT("PciConfig.u.type0.InterruptLine    - %x\n", PciConfig.u.type0.InterruptLine);
  DPRINT("PciConfig.u.type0.InterruptPin     - %x\n", PciConfig.u.type0.InterruptPin);
  DPRINT("PciConfig.u.type0.MinimumGrant     - %x\n", PciConfig.u.type0.MinimumGrant);
  DPRINT("PciConfig.u.type0.MaximumLatency   - %x\n", PciConfig.u.type0.MaximumLatency);
  */

	DeviceExtension->VendorId = PciConfig.VendorID;
	DeviceExtension->DeviceId = PciConfig.DeviceID;

	DeviceExtension->ControllerMode[PRIMARY_CHANNEL]   = 
        DeviceExtension->ControllerMode[SECONDARY_CHANNEL] = FALSE; // compatible BM PCI IDE mode 

        if ((PciConfig.BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
            (PciConfig.SubClass  == PCI_SUBCLASS_MSC_IDE_CTLR))
        {
		UCHAR PrimaryMode, SecondaryMode, PrimaryFixed, SecondaryFixed, ProgIf;

		ProgIf = PciConfig.ProgIf;
		PrimaryMode  = (ProgIf & 1) == 1; // Primary channel mode is PCI (native mode)
		PrimaryFixed = (ProgIf & 2) == 0; // Primary channel mode can changed == FALSE
		SecondaryMode   = (ProgIf & 4) == 4; // Secondary channel mode is PCI (native mode)
		SecondaryFixed  = (ProgIf & 8) == 0;// Secondary channel mode can changed == FALSE

	 	if ((ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
	 	{
	 		DPRINT("PciIdeXAddDevice: found IDE Bus Master controller!\n");
	 		DeviceExtension->BusMasterBase = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
	 		DPRINT("PciIdeXAddDevice: IDE Bus Master Registers at IO %lx\n", DeviceExtension->BusMasterBase);

			/*
			 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
			 * ATA controller from compatible mode to native mode, the following must be
			 * true:
			 *
			 * - The controller must indicate in its programming interface that both channels
			 *   can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
			 *   not support switching only one IDE channel to native mode. See the PCI IDE
			 *   Controller Specification Revision 1.0 for details.
			 */
			if ((PrimaryMode != SecondaryMode) || (PrimaryFixed != SecondaryFixed))
			{
				/* does not support this configuration, fail */
				DPRINT1("PciIdeXAddDevice: unsupported IDE controller configuration for VEN_%04x&DEV_%04x!\n",
				        DeviceExtension->VendorId, DeviceExtension->DeviceId);
	 			DeviceExtension->BusMasterBase = 0;
			}
			else
			{
				if ( !(PciConfig.Command & 4) )
				{
					PciConfig.Command |= 4; //enable bus master PCI

					//write Command register
					BytesRead = (*DeviceExtension->BusInterface->SetBusData)(
							DeviceExtension->BusInterface->Context,
							PCI_WHICHSPACE_CONFIG,
							&PciConfig.Command,
							FIELD_OFFSET(PCI_COMMON_HEADER, Command),
							sizeof(PciConfig.Command));

					if (BytesRead != sizeof(PciConfig.Command))
					{
						DPRINT("PciIdeXAddDevice: BusInterface->SetBusData() failed: BytesRead - %lx\n", BytesRead);
					}
				}

				/* Check if the controller is already in native mode */
				if ((PrimaryMode) && (SecondaryMode))
				{
					/* The controller is now in native mode */
					DeviceExtension->ControllerMode[PRIMARY_CHANNEL]   = 
				        DeviceExtension->ControllerMode[SECONDARY_CHANNEL] = TRUE; //native BM PCI IDE mode 
				}
				else
				{
					DPRINT1("PciIdeXAddDevice: FIXME! Enable NATIVE PCI IDE mode!\n");
				}
			}
	 	}
	 	else
	 	{
	 		DeviceExtension->BusMasterBase = 0;
	 	}
        }

	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;

	return STATUS_SUCCESS;
}

static NTSTATUS NTAPI
PciIdeXGetTransferModes(
	IN IDENTIFY_DATA IdentifyData,
	OUT PULONG BestXferMode,
	OUT PULONG CurrentXferMode)
{
	ULONG Best = PIO_MODE0;
	ULONG Current = PIO_MODE0;

	DPRINT("PciIdeXGetTransferModes(%lu, %p %p)\n",
		IdentifyData, BestXferMode, CurrentXferMode);

	/* FIXME: if current mode is a PIO mode, how to get it?
	 * At the moment, PIO_MODE0 is always returned...
	 */

	if (IdentifyData.TranslationFieldsValid & 0x2)
	{
		/* PIO modes and some DMA modes are supported */
		if (IdentifyData.AdvancedPIOModes & 0x02)
			Best = PIO_MODE4;
		else if (IdentifyData.AdvancedPIOModes & 0x01)
			Best = PIO_MODE3;
		else if (IdentifyData.PioCycleTimingMode == 0x02)
			Best = PIO_MODE2;
		else if (IdentifyData.PioCycleTimingMode == 0x01)
			Best = PIO_MODE1;
		else if (IdentifyData.PioCycleTimingMode == 0x00)
			Best = PIO_MODE0;
		else
			Best = PIO_MODE0;

		DPRINT("PciIdeXGetTransferModes: PIO Best - %x)\n", Best);

		if (IdentifyData.SingleWordDMASupport & 0x4)
			Best = SWDMA_MODE2;
		else if (IdentifyData.SingleWordDMASupport & 0x2)
			Best = SWDMA_MODE1;
		else if (IdentifyData.SingleWordDMASupport & 0x1)
			Best = SWDMA_MODE0;

		if (IdentifyData.SingleWordDMAActive & 0x4)
			Current = SWDMA_MODE2;
		else if (IdentifyData.SingleWordDMAActive & 0x2)
			Current = SWDMA_MODE1;
		else if (IdentifyData.SingleWordDMAActive & 0x1)
			Current = SWDMA_MODE0;

		DPRINT("PciIdeXGetTransferModes: SingleWordDMA Best - %x)\n", Best);

		if (IdentifyData.MultiWordDMASupport & 0x4)
			Best = MWDMA_MODE2;
		else if (IdentifyData.MultiWordDMASupport & 0x2)
			Best = MWDMA_MODE1;
		else if (IdentifyData.MultiWordDMASupport & 0x1)
			Best = MWDMA_MODE0;

		if (IdentifyData.MultiWordDMAActive & 0x4)
			Current = MWDMA_MODE2;
		else if (IdentifyData.MultiWordDMAActive & 0x2)
			Current = MWDMA_MODE1;
		else if (IdentifyData.MultiWordDMAActive & 0x1)
			Current = MWDMA_MODE0;

		DPRINT("PciIdeXGetTransferModes: MultiWordDMA Best - %x)\n", Best);
	}

	if (IdentifyData.TranslationFieldsValid & 0x4)
	{
		/* UDMA modes are supported */
		if (IdentifyData.UltraDMAActive & 0x10)
			Current = UDMA_MODE4;
		else if (IdentifyData.UltraDMAActive & 0x8)
			Current = UDMA_MODE3;
		else if (IdentifyData.UltraDMAActive & 0x4)
			Current = UDMA_MODE2;
		else if (IdentifyData.UltraDMAActive & 0x2)
			Current = UDMA_MODE1;
		else if (IdentifyData.UltraDMAActive & 0x1)
			Current = UDMA_MODE0;

		if (IdentifyData.UltraDMASupport & 0x10)
			Best = UDMA_MODE4;
		else if (IdentifyData.UltraDMASupport & 0x8)
			Best = UDMA_MODE3;
		else if (IdentifyData.UltraDMASupport & 0x4)
			Best = UDMA_MODE2;
		else if (IdentifyData.UltraDMASupport & 0x2)
			Best = UDMA_MODE1;
		else if (IdentifyData.UltraDMASupport & 0x1)
			Best = UDMA_MODE0;
	}

	DPRINT("PciIdeXGetTransferModes: Best    - %x)\n", Best);
	DPRINT("PciIdeXGetTransferModes: Current - %x)\n", Best);

	*BestXferMode = Best;
	*CurrentXferMode = Current;
	return TRUE;
}

static NTSTATUS
PciIdeXFdoStartDevice(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp)
{
	PPCIIDEX_DRIVER_EXTENSION DriverExtension;
	PFDO_DEVICE_EXTENSION DeviceExtension;
	PCM_RESOURCE_LIST ResourceList;
	NTSTATUS Status;

	DPRINT("PciIdeXStartDevice(%p %p)\n", DeviceObject, Irp);

	DriverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject);
	ASSERT(DriverExtension);
	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	ASSERT(DeviceExtension);
	ASSERT(DeviceExtension->Common.IsFDO);

	DeviceExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
	DeviceExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
	Status = DriverExtension->HwGetControllerProperties(
		DeviceExtension->MiniControllerExtension,
		&DeviceExtension->Properties);
	if (!NT_SUCCESS(Status))
		return Status;

	DriverExtension->HwUdmaModesSupported = DeviceExtension->Properties.PciIdeUdmaModesSupported;
	if (!DriverExtension->HwUdmaModesSupported)
		/* This method is optional, so provide our own one */
		DriverExtension->HwUdmaModesSupported = PciIdeXGetTransferModes;

	/* Get bus master port base, if any */
	ResourceList = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
	if (ResourceList
		&& ResourceList->Count == 1
		&& ResourceList->List[0].PartialResourceList.Count == 1
		&& ResourceList->List[0].PartialResourceList.Version == 1
		&& ResourceList->List[0].PartialResourceList.Revision == 1
		&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type == CmResourceTypePort
		&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length == 16)
	{
		DeviceExtension->BusMasterPortBase = ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start;
	}
	return STATUS_SUCCESS;
}

static NTSTATUS
PciIdeXFdoQueryBusRelations(
	IN PDEVICE_OBJECT DeviceObject,
	OUT PDEVICE_RELATIONS* pDeviceRelations)
{
	PFDO_DEVICE_EXTENSION DeviceExtension;
	PDEVICE_RELATIONS DeviceRelations = NULL;
	PDEVICE_OBJECT Pdo;
	PPDO_DEVICE_EXTENSION PdoDeviceExtension;
	ULONG i, j;
	ULONG PDOs = 0;
	IDE_CHANNEL_STATE ChannelState;
	NTSTATUS Status;

	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	ASSERT(DeviceExtension);
	ASSERT(DeviceExtension->Common.IsFDO);

	for (i = 0; i < MAX_IDE_CHANNEL; i++)
	{
		if (DeviceExtension->Pdo[i])
		{
			PDOs++;
			continue;
		}
		ChannelState = DeviceExtension->Properties.PciIdeChannelEnabled(
			DeviceExtension->MiniControllerExtension, i);
		if (ChannelState == ChannelDisabled)
		{
			DPRINT("Channel %lu is disabled\n", i);
			continue;
		}

		/* Need to create a PDO */
		Status = IoCreateDevice(
			DeviceObject->DriverObject,
			sizeof(PDO_DEVICE_EXTENSION),
			NULL,
			FILE_DEVICE_CONTROLLER,
			FILE_AUTOGENERATED_DEVICE_NAME,
			FALSE,
			&Pdo);
		if (!NT_SUCCESS(Status))
			/* FIXME: handle error */
			continue;

		PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
		RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
		PdoDeviceExtension->Common.IsFDO = FALSE;
		PdoDeviceExtension->Channel = i;
		PdoDeviceExtension->ControllerFdo = DeviceObject;
		PdoDeviceExtension->SelfDevice = Pdo;
		Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
		Pdo->Flags &= ~DO_DEVICE_INITIALIZING;

		DeviceExtension->Pdo[i] = Pdo;
		PDOs++;
	}

	if (PDOs == 0)
	{
		DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
			PagedPool,
			sizeof(DEVICE_RELATIONS));
	}
	else
	{
		DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
			PagedPool,
			sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PDOs - 1));
	}
	if (!DeviceRelations)
		return STATUS_INSUFFICIENT_RESOURCES;

	DeviceRelations->Count = PDOs;
	for (i = 0, j = 0; i < MAX_IDE_CHANNEL; i++)
	{
		if (DeviceExtension->Pdo[i])
		{
			ObReferenceObject(DeviceExtension->Pdo[i]);
			DeviceRelations->Objects[j++] = DeviceExtension->Pdo[i];
		}
	}

	*pDeviceRelations = DeviceRelations;
	return STATUS_SUCCESS;
}

NTSTATUS NTAPI
PciIdeXFdoPnpDispatch(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp)
{
	ULONG MinorFunction;
	PIO_STACK_LOCATION Stack;
	ULONG_PTR Information = Irp->IoStatus.Information;
	NTSTATUS Status;

	Stack = IoGetCurrentIrpStackLocation(Irp);
	MinorFunction = Stack->MinorFunction;

	switch (MinorFunction)
	{
		case IRP_MN_START_DEVICE: /* 0x00 */
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
			/* Call lower driver */
			Status = ForwardIrpAndWait(DeviceObject, Irp);
			if (NT_SUCCESS(Status))
				Status = PciIdeXFdoStartDevice(DeviceObject, Irp);
			break;
		}
                case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
                {
                        DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
                        Status = STATUS_UNSUCCESSFUL;
                        break;
                }
		case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
		{
			switch (Stack->Parameters.QueryDeviceRelations.Type)
			{
				case BusRelations:
				{
					PDEVICE_RELATIONS DeviceRelations = NULL;
					DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
					Status = PciIdeXFdoQueryBusRelations(DeviceObject, &DeviceRelations);
					Information = (ULONG_PTR)DeviceRelations;
					break;
				}
				default:
				{
					DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
						Stack->Parameters.QueryDeviceRelations.Type);
					Status = STATUS_NOT_IMPLEMENTED;
					break;
				}
			}
			break;
		}
                case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
                {
                        DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
                        Information |= PNP_DEVICE_NOT_DISABLEABLE;
                        Status = STATUS_SUCCESS;
                        break;
                }
		case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
			return ForwardIrpAndForget(DeviceObject, Irp);
		}
		default:
		{
			DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
			return ForwardIrpAndForget(DeviceObject, Irp);
		}
	}

	Irp->IoStatus.Information = Information;
	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Status;
}
pdo.c

Code: Select all

/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         PCI IDE bus driver extension
 * FILE:            drivers/storage/pciidex/pdo.c
 * PURPOSE:         IRP_MJ_PNP operations for PDOs
 * PROGRAMMERS:     Hervй Poussineau (hpoussin@reactos.org)
 */

#include "pciidex.h"

#include <stdio.h>
#include <wdmguid.h>

//#define NDEBUG
#include <debug.h>


static NTSTATUS
PciIdeXPdoQueryId(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp,
	OUT ULONG_PTR* Information)
{
	PPDO_DEVICE_EXTENSION DeviceExtension;
	PFDO_DEVICE_EXTENSION FdoDeviceExtension;
	WCHAR Buffer[256];
	ULONG Index = 0;
	ULONG IdType;
	UNICODE_STRING SourceString;
	UNICODE_STRING String;
	NTSTATUS Status;

	IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
	DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->ControllerFdo->DeviceExtension;

	switch (IdType)
	{
		case BusQueryDeviceID:
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
			RtlInitUnicodeString(&SourceString, L"PCIIDE\\IDEChannel");
			break;
		}
		case BusQueryHardwareIDs:
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");

			switch (FdoDeviceExtension->VendorId)
			{
				case 0x0e11:
					Index += swprintf(&Buffer[Index], L"Compaq-%04x", FdoDeviceExtension->DeviceId) + 1;
					break;
				case 0x1039:
					Index += swprintf(&Buffer[Index], L"SiS-%04x", FdoDeviceExtension->DeviceId) + 1;
					break;
				case 0x1050:
					Index += swprintf(&Buffer[Index], L"WinBond-%04x", FdoDeviceExtension->DeviceId) + 1;
					break;
				case 0x1095:
					Index += swprintf(&Buffer[Index], L"CMD-%04x", FdoDeviceExtension->DeviceId) + 1;
					break;
				case 0x8086:
				{
					switch (FdoDeviceExtension->DeviceId)
					{
						case 0x1230:
							Index += swprintf(&Buffer[Index], L"Intel-PIIX") + 1;
							break;
						case 0x7010:
							Index += swprintf(&Buffer[Index], L"Intel-PIIX3") + 1;
							break;
						case 0x7111:
							Index += swprintf(&Buffer[Index], L"Intel-PIIX4") + 1;
							break;
						default:
							Index += swprintf(&Buffer[Index], L"Intel-%04x", FdoDeviceExtension->DeviceId) + 1;
							break;
					}
					break;
				}
				default:
					break;
			}
			if (DeviceExtension->Channel == 0)
				Index += swprintf(&Buffer[Index], L"Primary_IDE_Channel") + 1;
			else
				Index += swprintf(&Buffer[Index], L"Secondary_IDE_Channel") + 1;
			Index += swprintf(&Buffer[Index], L"*PNP0600") + 1;
			Buffer[Index] = UNICODE_NULL;
			SourceString.Length = SourceString.MaximumLength = Index * sizeof(WCHAR);
			SourceString.Buffer = Buffer;
			break;
		}
		case BusQueryCompatibleIDs:
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");

			Index += swprintf(&Buffer[Index], L"*PNP0600") + 1;
			Buffer[Index] = UNICODE_NULL;
			SourceString.Length = SourceString.MaximumLength = Index * sizeof(WCHAR);
			SourceString.Buffer = Buffer;
			break;
		}
		case BusQueryInstanceID:
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
			swprintf(Buffer, L"%lu", DeviceExtension->Channel);
			RtlInitUnicodeString(&SourceString, Buffer);
			break;
		}
		default:
			DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
			ASSERT(FALSE);
			return STATUS_NOT_SUPPORTED;
	}

	Status = DuplicateUnicodeString(
		RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
		&SourceString,
		&String);
	*Information = (ULONG_PTR)String.Buffer;
	return Status;
}

static NTSTATUS
GetCurrentResources(
	IN PDEVICE_OBJECT DeviceObject,
	OUT PULONG CommandPortBase,
	OUT PULONG ControlPortBase,
	OUT PULONG BusMasterPortBase,
	OUT PULONG InterruptVector)
{
	PPDO_DEVICE_EXTENSION DeviceExtension;
	PFDO_DEVICE_EXTENSION FdoDeviceExtension;
	ULONG BaseIndex;
	ULONG BytesRead;
	PCI_COMMON_CONFIG PciConfig;
	NTSTATUS ret = STATUS_UNSUCCESSFUL;

	DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->ControllerFdo->DeviceExtension;
	BaseIndex = DeviceExtension->Channel * 2;

	BytesRead = (*FdoDeviceExtension->BusInterface->GetBusData)(
		FdoDeviceExtension->BusInterface->Context,
		PCI_WHICHSPACE_CONFIG,
		&PciConfig,
		0,
		PCI_COMMON_HDR_LENGTH);
	if (BytesRead != PCI_COMMON_HDR_LENGTH)
		return STATUS_IO_DEVICE_ERROR;

	/* We have found a known native pci ide controller */
	if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
	{
		DPRINT("Found IDE Bus Master controller!\n");
		*BusMasterPortBase = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
		DPRINT("  IDE Bus Master Registers at IO %lx\n", *BusMasterPortBase);
	}
	else
	{
		*BusMasterPortBase = 0;
	}

	if ((PciConfig.ProgIf >> BaseIndex) & 0x1)
	{
		/* Native mode */
		if ((PciConfig.u.type0.BaseAddresses[BaseIndex + 0] & PCI_ADDRESS_IO_SPACE) &&
		    (PciConfig.u.type0.BaseAddresses[BaseIndex + 1] & PCI_ADDRESS_IO_SPACE))
		{
			/* Channel is enabled */
			*CommandPortBase = PciConfig.u.type0.BaseAddresses[BaseIndex + 0] & PCI_ADDRESS_IO_ADDRESS_MASK;
			*ControlPortBase = PciConfig.u.type0.BaseAddresses[BaseIndex + 1] & PCI_ADDRESS_IO_ADDRESS_MASK;
			*InterruptVector = PciConfig.u.type0.InterruptLine;
			ret = STATUS_SUCCESS;
		}
	}
	else
	{
		/* Compatibility mode */
		switch (DeviceExtension->Channel)
		{
			case 0:
				if (IoGetConfigurationInformation()->AtDiskPrimaryAddressClaimed)
					ret = STATUS_INSUFFICIENT_RESOURCES;
				else
				{
					*CommandPortBase = 0x1F0;
					*ControlPortBase = 0x3F6;
					*InterruptVector = 14;
					ret = STATUS_SUCCESS;
				}
				break;
			case 1:
				if (IoGetConfigurationInformation()->AtDiskSecondaryAddressClaimed)
					ret = STATUS_INSUFFICIENT_RESOURCES;
				else
				{
					*CommandPortBase = 0x170;
					*ControlPortBase = 0x376;
					*InterruptVector = 15;
					ret = STATUS_SUCCESS;
				}
				break;
		}
	}

	return ret;
}

static NTSTATUS
PciIdeXPdoQueryResourceRequirements(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp,
	OUT ULONG_PTR* Information)
{
	ULONG CommandPortBase;
	ULONG ControlPortBase;
	ULONG BusMasterPortBase;
	ULONG InterruptVector;
	ULONG ListSize;
	PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
	PIO_RESOURCE_DESCRIPTOR Descriptor;
	NTSTATUS Status;

	Status = GetCurrentResources(DeviceObject, &CommandPortBase,
		&ControlPortBase, &BusMasterPortBase, &InterruptVector);
	if (!NT_SUCCESS(Status))
		return Status;

	DPRINT("IDE Channel %lu: IO %x and %x, BM %lx, Irq %lu\n",
		((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Channel,
		CommandPortBase, ControlPortBase,
		BusMasterPortBase, InterruptVector);

	/* FIXME: what to do with BusMasterPortBase? */

	ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
		+ 2 * sizeof(IO_RESOURCE_DESCRIPTOR);
	RequirementsList = ExAllocatePool(PagedPool, ListSize);
	if (!RequirementsList)
		return STATUS_INSUFFICIENT_RESOURCES;

	RtlZeroMemory(RequirementsList, ListSize);
	RequirementsList->ListSize = ListSize;
	RequirementsList->AlternativeLists = 1;

	RequirementsList->List[0].Version = 1;
	RequirementsList->List[0].Revision = 1;
	RequirementsList->List[0].Count = 3;

	Descriptor = &RequirementsList->List[0].Descriptors[0];

	/* Command port base */
	Descriptor->Option = 0; /* Required */
	Descriptor->Type = CmResourceTypePort;
	Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
	Descriptor->Flags = CM_RESOURCE_PORT_IO |
	                    CM_RESOURCE_PORT_16_BIT_DECODE |
	                    CM_RESOURCE_PORT_POSITIVE_DECODE;
	Descriptor->u.Port.Length = 8;
	Descriptor->u.Port.Alignment = 1;
	Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)CommandPortBase;
	Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(CommandPortBase + 8 - 1);
	Descriptor++;

	/* Control port base */
	Descriptor->Option = 0; /* Required */
	Descriptor->Type = CmResourceTypePort;
	Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
	Descriptor->Flags = CM_RESOURCE_PORT_IO |
	                    CM_RESOURCE_PORT_16_BIT_DECODE |
	                    CM_RESOURCE_PORT_POSITIVE_DECODE;
	Descriptor->u.Port.Length = 1;
	Descriptor->u.Port.Alignment = 1;
	Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)ControlPortBase;
	Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(ControlPortBase + 1 - 1);
	Descriptor++;

	/* Interrupt */
	Descriptor->Option = 0; /* Required */
	Descriptor->Type = CmResourceTypeInterrupt;
	Descriptor->ShareDisposition = CmResourceShareShared;
	Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_LATCHED_BITS; //CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;  (?? CM_RESOURCE_INTERRUPT_LATCHED == CM_RESOURCE_INTERRUPT_LEVEL_LATCHED_BITS);
	Descriptor->u.Interrupt.MinimumVector = InterruptVector;
	Descriptor->u.Interrupt.MaximumVector = InterruptVector;

	*Information = (ULONG_PTR)RequirementsList;
	return STATUS_SUCCESS;
}

static NTSTATUS
PciIdeXPdoQueryDeviceText(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp,
	OUT ULONG_PTR* Information)
{
	PPDO_DEVICE_EXTENSION DeviceExtension;
	ULONG DeviceTextType;
	PCWSTR SourceString;
	UNICODE_STRING String;

	DeviceTextType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryDeviceText.DeviceTextType;
	DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

	switch (DeviceTextType)
	{
		case DeviceTextDescription:
		case DeviceTextLocationInformation:
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / %S\n",
				DeviceTextType == DeviceTextDescription ? L"DeviceTextDescription" : L"DeviceTextLocationInformation");
			if (DeviceExtension->Channel == 0)
				SourceString = L"Primary channel";
			else
				SourceString = L"Secondary channel";
			break;
		}
		default:
			DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n", DeviceTextType);
			ASSERT(FALSE);
			return STATUS_NOT_SUPPORTED;
	}

	if (RtlCreateUnicodeString(&String, SourceString))
	{
		*Information = (ULONG_PTR)String.Buffer;
		return STATUS_SUCCESS;
	}
	else
		return STATUS_INSUFFICIENT_RESOURCES;
}

static NTSTATUS
PciIdeXPdoQueryDeviceRelations(
	IN PDEVICE_OBJECT DeviceObject,
	OUT PDEVICE_RELATIONS* pDeviceRelations)
{
	PFDO_DEVICE_EXTENSION DeviceExtension;
	PDEVICE_RELATIONS DeviceRelations;

	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	ASSERT(DeviceExtension->Common.IsFDO);

	DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
		PagedPool,
		sizeof(DEVICE_RELATIONS));
	if (!DeviceRelations)
		return STATUS_INSUFFICIENT_RESOURCES;

	ObReferenceObject(DeviceObject);
	DeviceRelations->Count = 1;
	DeviceRelations->Objects[0] = DeviceObject;

	*pDeviceRelations = DeviceRelations;
	return STATUS_SUCCESS;
}

static NTSTATUS
PciIdeXStartChannel(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp)
{
	PPDO_DEVICE_EXTENSION DeviceExtension;
	PFDO_DEVICE_EXTENSION FdoDeviceExtension; //ControllerFdoExtension
	PDMA_ADAPTER          DmaAdapter;
	PDMA_OPERATIONS       DmaOperations;
	DEVICE_DESCRIPTION    DeviceDescription;
	PVOID                 CommonBuffer;
	ULONG                 Length;


	DPRINT("PciIdeXStartChannel: DeviceObject - %p, Irp - %p\n", DeviceObject, Irp);

	DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->ControllerFdo->DeviceExtension;

        RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));

	DeviceDescription.Version           = DEVICE_DESCRIPTION_VERSION;
	DeviceDescription.Master            = TRUE;
	DeviceDescription.ScatterGather     = TRUE;
	DeviceDescription.DemandMode        = FALSE;
	DeviceDescription.AutoInitialize    = FALSE;
	DeviceDescription.Dma32BitAddresses = TRUE;
	DeviceDescription.IgnoreCount       = FALSE;
	DeviceDescription.InterfaceType     = PCIBus; //?InterfaceTypeUndefined
	DeviceDescription.MaximumLength     = 0x20000;

	DmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
				     &DeviceDescription,
				     &DeviceExtension->NumberOfMapRegisters);

	if ( DmaAdapter == NULL )
	{
		DPRINT1("PciIdeXStartChannel: IoGetDmaAdapter() failed\n");
	}
	else
	{
		DeviceExtension->DmaAdapter = DmaAdapter;
		DPRINT("PciIdeXStartChannel: DmaAdapter - %p, *DmaAdapter - %p\n", DmaAdapter, *(PULONG)DmaAdapter);

		DmaOperations = DmaAdapter->DmaOperations;
		DPRINT("PciIdeXStartChannel: DmaOperations - %x\n", DmaOperations);
 
		Length = DeviceExtension->NumberOfMapRegisters * sizeof(PHYSICAL_ADDRESS);
		DPRINT("PciIdeXStartChannel: Length - %x\n", Length);

		CommonBuffer = DmaOperations->AllocateCommonBuffer(
					DmaAdapter, 
					Length, 
					(PPHYSICAL_ADDRESS)&DeviceExtension->LogicalAddress,
					FALSE); //CacheEnabled

		DPRINT("PciIdeXStartChannel: CommonBuffer - %x\n", CommonBuffer);
		DPRINT("PciIdeXStartChannel: DeviceExtension->LogicalAddress.LowPart - %x\n", DeviceExtension->LogicalAddress.LowPart);
		DPRINT("PciIdeXStartChannel: DeviceExtension->LogicalAddress.HighPart - %x\n", DeviceExtension->LogicalAddress.HighPart);

		DeviceExtension->CommonBuffer = CommonBuffer;

		if ( !DeviceExtension->CommonBuffer )
			DPRINT(" PciIdeXStartChannel: No RDT!\n");
		
		if ( !DeviceExtension->LogicalAddress.QuadPart )
			DPRINT(" PciIdeXStartChannel: No PRDT!\n");
		
		if ( DeviceExtension->CommonBuffer )
		{
			RtlZeroMemory(DeviceExtension->CommonBuffer, Length);
		}
	}

	return STATUS_SUCCESS;
}

NTSTATUS NTAPI
PciIdeXPdoPnpDispatch(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp)
{
	ULONG MinorFunction;
	PIO_STACK_LOCATION Stack;
	ULONG_PTR Information = Irp->IoStatus.Information;
	NTSTATUS Status;
	PPDO_DEVICE_EXTENSION DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
	PFDO_DEVICE_EXTENSION FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->ControllerFdo->DeviceExtension;

	Stack = IoGetCurrentIrpStackLocation(Irp);
	MinorFunction = Stack->MinorFunction;

	switch (MinorFunction)
	{
		/* FIXME:
		 * Those are required:
		 *    IRP_MN_START_DEVICE (done)
		 *    IRP_MN_QUERY_STOP_DEVICE
		 *    IRP_MN_STOP_DEVICE
		 *    IRP_MN_CANCEL_STOP_DEVICE
		 *    IRP_MN_QUERY_REMOVE_DEVICE
		 *    IRP_MN_REMOVE_DEVICE
		 *    IRP_MN_CANCEL_REMOVE_DEVICE
		 *    IRP_MN_SURPRISE_REMOVAL
		 *    IRP_MN_QUERY_CAPABILITIES (done)
		 *    IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelations (done)
		 *    IRP_MN_QUERY_ID / BusQueryDeviceID (done)
		 * Those may be required/optional:
		 *    IRP_MN_DEVICE_USAGE_NOTIFICATION
		 *    IRP_MN_QUERY_RESOURCES
		 *    IRP_MN_QUERY_RESOURCE_REQUIREMENTS (done)
		 *    IRP_MN_QUERY_DEVICE_TEXT
		 *    IRP_MN_QUERY_BUS_INFORMATION
		 *    IRP_MN_QUERY_INTERFACE
		 *    IRP_MN_READ_CONFIG
		 *    IRP_MN_WRITE_CONFIG
		 *    IRP_MN_EJECT
		 *    IRP_MN_SET_LOCK
		 * Those are optional:
		 *    IRP_MN_QUERY_DEVICE_RELATIONS / EjectionRelations
		 *    IRP_MN_QUERY_ID / BusQueryHardwareIDs (done)
		 *    IRP_MN_QUERY_ID / BusQueryCompatibleIDs (done)
		 *    IRP_MN_QUERY_ID / BusQueryInstanceID (done)
		 */
		case IRP_MN_START_DEVICE: /* 0x00 */
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
			Status = PciIdeXStartChannel(DeviceObject, Irp);
			break;
		}
                case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
                {
                        DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
                        Status = STATUS_UNSUCCESSFUL;
                        break;
                }
		case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
		{
			switch (Stack->Parameters.QueryDeviceRelations.Type)
			{
				case TargetDeviceRelation:
				{
					PDEVICE_RELATIONS DeviceRelations = NULL;
					DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
					Status = PciIdeXPdoQueryDeviceRelations(DeviceObject, &DeviceRelations);
					Information = (ULONG_PTR)DeviceRelations;
					break;
				}
				default:
				{
					DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
						Stack->Parameters.QueryDeviceRelations.Type);
					ASSERT(FALSE);
					Status = STATUS_NOT_SUPPORTED;
					break;
				}
			}
			break;
		}
		case IRP_MN_QUERY_INTERFACE: /* 0x08 */
		{
			// It get pseudo Interface.  QueryInterface.Size - type Interface.  QueryInterface.Interface - pointer on Interface.
			// and replace GUID_BUS_INTERFACE_STANDARD on ... ?
			if (IsEqualGUIDAligned(Stack->Parameters.QueryInterface.InterfaceType, &GUID_BUS_INTERFACE_STANDARD))
			{
				switch (Stack->Parameters.QueryInterface.Size)
				{
					case 1: //QueryControllerProperties
						DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / QueryControllerProperties\n");
						*(PVOID *)Stack->Parameters.QueryInterface.Interface = &FdoDeviceExtension->Properties;
						*(PVOID *)((PULONG)Stack->Parameters.QueryInterface.Interface + 1) = FdoDeviceExtension->MiniControllerExtension;
                                                DPRINT("PciIdeXPdoPnpDispatch: DeviceObject - %p\n", DeviceObject);
						Status = STATUS_SUCCESS;
						break;

					case 3: //QueryPciBusInterface
						DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / QueryPciBusInterface\n");
						*(PVOID *)Stack->Parameters.QueryInterface.Interface = FdoDeviceExtension->BusInterface;
                                                DPRINT("PciIdeXPdoPnpDispatch: BusInterface - %p\n", FdoDeviceExtension->BusInterface);
						Status = STATUS_SUCCESS;
						break;

					case 5: //QueryBusMasterInterface
						DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / QueryBusMasterInterface\n");
						if (FdoDeviceExtension->BusMasterBase)
						  Status = QueryBusMasterInterface(DeviceExtension, Stack);
						else
						  Status = STATUS_NOT_IMPLEMENTED;
						break;

					case 7: //QueryAhciInterface
						DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / QueryAhciInterface. NOT_SUPPORTED\n");
						Status = STATUS_NOT_SUPPORTED;
						break;

					default:
						DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / Unknown Size\n");
						Status = STATUS_NOT_SUPPORTED;
						break;
				}
				break;
			}
			else
			{
				DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_INTERFACE / Unknown type\n");
				ASSERT(FALSE);
				Status = STATUS_NOT_SUPPORTED;
				break;
			}
		}
		case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
		{
			PDEVICE_CAPABILITIES DeviceCapabilities;
			ULONG i;
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");

			DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
			/* FIXME: capabilities can change with connected device */
			DeviceCapabilities->LockSupported = FALSE;
			DeviceCapabilities->EjectSupported = FALSE;
			DeviceCapabilities->Removable = TRUE;
			DeviceCapabilities->DockDevice = FALSE;
			DeviceCapabilities->UniqueID = FALSE;
			DeviceCapabilities->SilentInstall = FALSE;
			DeviceCapabilities->RawDeviceOK = FALSE;
			DeviceCapabilities->SurpriseRemovalOK = TRUE;
			DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
			//DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
			DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
			for (i = 0; i < PowerSystemMaximum; i++)
				DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
			//DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
			DeviceCapabilities->D1Latency = 0; /* FIXME */
			DeviceCapabilities->D2Latency = 0; /* FIXME */
			DeviceCapabilities->D3Latency = 0; /* FIXME */
			Status = STATUS_SUCCESS;
			break;
		}
		case IRP_MN_QUERY_RESOURCES: /* 0x0a */
		{
			/* This IRP is optional; do nothing */
			Information = Irp->IoStatus.Information;
			Status = Irp->IoStatus.Status;
			break;
		}
		case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
			Status = PciIdeXPdoQueryResourceRequirements(DeviceObject, Irp, &Information);
			break;
		}
		case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
		{
			Status = PciIdeXPdoQueryDeviceText(DeviceObject, Irp, &Information);
			break;
		}
		case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
		{
			DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
			Information = Irp->IoStatus.Information;
			Status = Irp->IoStatus.Status;
			break;
		}
		case IRP_MN_QUERY_ID: /* 0x13 */
		{
			Status = PciIdeXPdoQueryId(DeviceObject, Irp, &Information);
			break;
		}
                case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
                {
                        DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
                        Information |= PNP_DEVICE_NOT_DISABLEABLE;
                        Status = STATUS_SUCCESS;
                        break;
                }
		case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
		{
			PPNP_BUS_INFORMATION BusInfo;
			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");

			BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
			if (!BusInfo)
				Status = STATUS_INSUFFICIENT_RESOURCES;
			else
			{
				/*RtlCopyMemory(
					&BusInfo->BusTypeGuid,
					&GUID_DEVINTERFACE_XXX,
					sizeof(GUID));*/
				BusInfo->LegacyBusType = PNPBus;
				BusInfo->BusNumber = 0; /* FIXME */
				Information = (ULONG_PTR)BusInfo;
				Status = STATUS_SUCCESS;
			}
			break;
		}
		default:
		{
			/* We can't forward request to the lower driver, because
			 * we are a Pdo, so we don't have lower driver... */
			DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
			ASSERT(FALSE);
			Information = Irp->IoStatus.Information;
			Status = Irp->IoStatus.Status;
		}
	}

	Irp->IoStatus.Information = Information;
	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Status;
}

justincase
Posts: 441
Joined: Sat Nov 15, 2008 4:13 pm

Re: PCI IDE Bus Master implementation

Post by justincase »

What is this? A patch?
If so, you should file a report for it on JIRA, and attach it in Unified Diff format as a .patch file.
Please also make sure to explain what it's for.
I reserve the right to ignore any portion of any post if I deem it not constructive or likely to cause the discussion to degenerate.

vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

Re: PCI IDE Bus Master implementation

Post by vgal »

Little patience, my friend. I yet did not finish.

pciidex.h

Code: Select all

#ifndef _PCIIDEX_PCH_
#define _PCIIDEX_PCH_

#include <ntifs.h>
#include <ide.h>
#include <..\bmaster.h>


#define PRIMARY_CHANNEL		0x00
#define SECONDARY_CHANNEL	0x01

typedef NTSTATUS
(NTAPI *PALLOCATE_ADAPTER)(IN ULONG AllocateAdapterContext);

typedef struct _PCIIDEX_DRIVER_EXTENSION
{
	PCONTROLLER_PROPERTIES HwGetControllerProperties;
	ULONG MiniControllerExtensionSize;
	PCIIDE_UDMA_MODES_SUPPORTED HwUdmaModesSupported;
} PCIIDEX_DRIVER_EXTENSION, *PPCIIDEX_DRIVER_EXTENSION;

typedef struct _COMMON_DEVICE_EXTENSION
{
	BOOLEAN IsFDO;
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;

typedef struct _FDO_DEVICE_EXTENSION
{
	COMMON_DEVICE_EXTENSION Common;

	PBUS_INTERFACE_STANDARD BusInterface;
	IDE_CONTROLLER_PROPERTIES Properties;
	PHYSICAL_ADDRESS BusMasterPortBase;
	ULONG BusMasterBase;
	PDEVICE_OBJECT LowerDevice;
	PDEVICE_OBJECT Pdo[MAX_IDE_CHANNEL];
	USHORT VendorId;
	USHORT DeviceId;
        BOOLEAN ControllerMode[MAX_IDE_CHANNEL]; //TRUE - Native, FALSE - Compatible

	PUCHAR MiniControllerExtension[0];
} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;

typedef struct _PDO_DEVICE_EXTENSION
{
	COMMON_DEVICE_EXTENSION Common;

	ULONG Channel;
	PDEVICE_OBJECT ControllerFdo;

	PDEVICE_OBJECT SelfDevice;
	PDMA_ADAPTER DmaAdapter;
	ULONG NumberOfMapRegisters;
	PVOID CommonBuffer;
	PHYSICAL_ADDRESS LogicalAddress;
	PSCATTER_GATHER_LIST SGList;
	PVOID AllocateAdapter;
	ULONG AllocateAdapterContext;
	BOOLEAN WriteToDevice;
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;

/* dma.c */

NTSTATUS NTAPI
QueryBusMasterInterface(
	IN PPDO_DEVICE_EXTENSION DeviceExtension,
	IN PIO_STACK_LOCATION Stack);

/* fdo.c */

DRIVER_ADD_DEVICE PciIdeXAddDevice;
NTSTATUS NTAPI
PciIdeXAddDevice(
	IN PDRIVER_OBJECT DriverObject,
	IN PDEVICE_OBJECT Pdo);

NTSTATUS NTAPI
PciIdeXFdoPnpDispatch(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp);

/* misc.c */

IO_COMPLETION_ROUTINE PciIdeXGenericCompletion;
NTSTATUS NTAPI
PciIdeXGenericCompletion(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp,
	IN PVOID Context);

NTSTATUS
ForwardIrpAndWait(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp);

NTSTATUS NTAPI
ForwardIrpAndForget(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp);

NTSTATUS
DuplicateUnicodeString(
	IN ULONG Flags,
	IN PCUNICODE_STRING SourceString,
	OUT PUNICODE_STRING DestinationString);

/* pdo.c */

NTSTATUS NTAPI
PciIdeXPdoPnpDispatch(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp);

#endif /* _PCIIDEX_PCH_ */
CMakeLists.txt

Code: Select all

spec2def(pciidex.sys pciidex.spec ADD_IMPORTLIB)

list(APPEND SOURCE
    dma.c
    fdo.c
    miniport.c
    misc.c
    pciidex.c
    pdo.c
    pciidex.h)

add_library(pciidex SHARED
    ${SOURCE}
    pciidex.rc
    ${CMAKE_CURRENT_BINARY_DIR}/pciidex.def)

add_pch(pciidex pciidex.h SOURCE)
set_module_type(pciidex kernelmodedriver)
add_importlibs(pciidex ntoskrnl hal)
add_cd_file(TARGET pciidex DESTINATION reactos/system32/drivers NO_CAB FOR all)
miniport.c, misc.c, pciidex.c - without changes.

vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

Re: PCI IDE Bus Master implementation

Post by vgal »

reactos\drivers\storage\ide\pciide\pciide.c

Code: Select all

/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         PCI IDE bus driver
 * FILE:            drivers/storage/pciide/pciide.c
 * PURPOSE:         Main file
 * PROGRAMMERS:     Hervй Poussineau (hpoussin@reactos.org)
 */

#include "pciide.h"

//#define NDEBUG
#include <debug.h>

#define UDMA_MODE5  (1 << 16)
#define UDMA_MODE6  (1 << 17)

IDE_CHANNEL_STATE NTAPI
PciIdeChannelEnabled(
	IN PVOID DeviceExtension,
	IN ULONG Channel)
{
	PCI_COMMON_CONFIG PciConfig;
	NTSTATUS Status;

	DPRINT("PciIdeChannelEnabled(%p, %lu)\n", DeviceExtension, Channel);

	Status = PciIdeXGetBusData(
		DeviceExtension,
		&PciConfig,
		0,
		PCI_COMMON_HDR_LENGTH);
	if (!NT_SUCCESS(Status))
	{
		DPRINT("PciIdeXGetBusData() failed with status 0x%08lx\n", Status);
		return ChannelStateUnknown;
	}

	if (PCI_CONFIGURATION_TYPE(&PciConfig) != PCI_DEVICE_TYPE)
	{
		DPRINT("Wrong PCI card type. Disabling IDE channel #%lu\n", Channel);
		return ChannelDisabled;
	}

	if (PciConfig.BaseClass != PCI_CLASS_MASS_STORAGE_CTLR || PciConfig.SubClass != PCI_SUBCLASS_MSC_IDE_CTLR)
	{
		DPRINT("Wrong PCI card base class/sub class. Disabling IDE channel #%lu\n", Channel);
		return ChannelDisabled;
	}

	return ChannelStateUnknown;
}

BOOLEAN NTAPI
PciIdeSyncAccessRequired(
	IN PVOID DeviceExtension)
{
	DPRINT1("PciIdeSyncAccessRequired %p\n", DeviceExtension);

	return FALSE; /* FIXME */
}

NTSTATUS NTAPI
PciIdeTransferModeSelect(
	IN PVOID DeviceExtension,
	IN PPCIIDE_TRANSFER_MODE_SELECT XferMode)
{
	ULONG i;

	DPRINT1("PciIdeTransferModeSelect(%p %p)\n", DeviceExtension, XferMode);

	for (i = 0; i < MAX_IDE_DEVICE; i++)
		XferMode->DevicePresent[i] = FALSE; /* FIXME */

	return STATUS_SUCCESS;
}

ULONG NTAPI
PciIdeUseDma(
	IN PVOID DeviceExtension,
	IN PUCHAR CdbCommand,
	IN PUCHAR Slave)
{
	DPRINT("PciIdeUseDma(%p %p %p)\n", DeviceExtension, CdbCommand, Slave);

	/* Nothing should prevent us to use DMA */
	return 1;
}

NTSTATUS NTAPI
PciIdeGetControllerProperties(
	IN PVOID DeviceExtension,
	OUT PIDE_CONTROLLER_PROPERTIES ControllerProperties)
{
	if (ControllerProperties->Size != sizeof(IDE_CONTROLLER_PROPERTIES))
		return STATUS_REVISION_MISMATCH;

	ControllerProperties->PciIdeChannelEnabled = PciIdeChannelEnabled;
	ControllerProperties->PciIdeSyncAccessRequired = PciIdeSyncAccessRequired;
	ControllerProperties->PciIdeTransferModeSelect = PciIdeTransferModeSelect;
	ControllerProperties->IgnoreActiveBitForAtaDevice = FALSE;
	ControllerProperties->AlwaysClearBusMasterInterrupt = TRUE;
	ControllerProperties->PciIdeUseDma = PciIdeUseDma;
	ControllerProperties->AlignmentRequirement = 1;
	ControllerProperties->DefaultPIO = 0; /* FIXME */
	ControllerProperties->PciIdeUdmaModesSupported = NULL; /* optional */
	
	ControllerProperties->SupportedTransferMode[0][0] =
	ControllerProperties->SupportedTransferMode[0][1] =
	ControllerProperties->SupportedTransferMode[1][0] =
	ControllerProperties->SupportedTransferMode[1][1] =
		PIO_MODE0 | PIO_MODE1 | PIO_MODE2 | PIO_MODE3 | PIO_MODE4 |
		SWDMA_MODE0 | SWDMA_MODE1 | SWDMA_MODE2 |
		MWDMA_MODE0 | MWDMA_MODE1 | MWDMA_MODE2 |
		UDMA_MODE0 | UDMA_MODE1 | UDMA_MODE2 | UDMA_MODE3 | UDMA_MODE4 | UDMA_MODE5 | UDMA_MODE6;

	return STATUS_SUCCESS;
}

NTSTATUS NTAPI
DriverEntry(
	IN PDRIVER_OBJECT DriverObject,
	IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS Status;

	Status = PciIdeXInitialize(
		DriverObject,
		RegistryPath,
		PciIdeGetControllerProperties,
		0);

	return Status;
}
pciide_reg.inf

Code: Select all

; PCIIde miniport driver
[AddReg]
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","ErrorControl",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","Group",0x00000000,"System Bus Extender"
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","ImagePath",0x00020000,"system32\drivers\pciide.sys"
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","Start",0x00010001,0x00000000
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","Type",0x00010001,0x00000001
HKLM,"SYSTEM\CurrentControlSet\Services\PCIIde","Tag",0x00010001,0x00000010
CMakeLists.txt

Code: Select all

add_library(pciide SHARED pciide.c pciide.rc)
set_module_type(pciide kernelmodedriver)
add_importlibs(pciide pciidex ntoskrnl)
add_cd_file(TARGET pciide DESTINATION reactos/system32/drivers NO_CAB FOR all)
add_registry_inf(pciide_reg.inf)

vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

Re: PCI IDE Bus Master implementation

Post by vgal »

It not a patch. It has been added for my driver Atax. That it was possible to transfer the data in UDMA a mode.

There are two moments.

1. #define MAX_SG_ELEMENTS 0x10 (in reactos\hal\halx86\generic\dma.c)
One SG_ELEMENTS - minimind 4 kB. 16*4= 64 kB. It is not enough for IDE. It is necessary twice more - 128 kB. (#define MAX_SG_ELEMENTS 0x20).

2. Pciide.sys (the general mini-driver PCI IDE of the controller) uses the general-purpose library PciideX.sys. Above in a stack driver AtaX - driver ATA-ATAPI of the channel (port). For request of pointers on functions (Interface) I used IRP_MN_QUERY_INTERFACE. But it is non-standard. Stack-> Parameters. QueryInterface. Size - it not the size, it kind requested Interface. Stack->Parameters.QueryInterface.InterfaceType (LPGUID) - not important what, important identical both in PciideX and in AtaX.

PurpleGurl
Posts: 1788
Joined: Fri Aug 07, 2009 5:11 am
Location: USA

Re: PCI IDE Bus Master implementation

Post by PurpleGurl »

Doesn't UNIATA already do this?

If you really want to take a challenge, maybe you could work on the USB drivers, SMP, maybe parts of HAL, or other functionality that is missing or broken.

User avatar
EmuandCo
Developer
Posts: 4439
Joined: Sun Nov 28, 2004 7:52 pm
Location: Germany, Bavaria, Steinfeld
Contact:

Re: PCI IDE Bus Master implementation

Post by EmuandCo »

Well, if this one is better working and clean code, we can discuss this, but first you really should make a patch file and make a report in our Jira reporting system.
ReactOS is still in alpha stage, meaning it is not feature-complete and is recommended only for evaluation and testing purposes.

vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

Re: PCI IDE Bus Master implementation

Post by vgal »

PurpleGurl, I answered here viewtopic.php?f=9&t=14462

vgal
Posts: 88
Joined: Mon Jan 26, 2015 7:38 am

Re: PCI IDE Bus Master implementation

Post by vgal »

EmuandCo, I think it is useless. RoS now do not use a functional pciide.sys (+pciidex.sys).
It seems, here it is more useful. Problem with PnP Manager (Enumerate Devices)

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest