summaryrefslogtreecommitdiff
path: root/sd/miniport
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-04-29 09:48:49 -0700
committerDave Wilson <[email protected]>2015-04-29 10:47:29 -0700
commitd40232638faaab19de557e70a3ee938da7a35295 (patch)
tree14e61c973745949af186b7940e3a53d25322f5de /sd/miniport
parent02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff)
samples update for //build
Diffstat (limited to 'sd/miniport')
-rw-r--r--sd/miniport/sdhc/README.md13
-rw-r--r--sd/miniport/sdhc/inbox/sdhc.vcxproj156
-rw-r--r--sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters39
-rw-r--r--sd/miniport/sdhc/sdhc.c3291
-rw-r--r--sd/miniport/sdhc/sdhc.h2091
-rw-r--r--sd/miniport/sdhc/sdhc.inxbin0 -> 11250 bytes
-rw-r--r--sd/miniport/sdhc/sdhc.rc15
-rw-r--r--sd/miniport/sdhc/sdhc.sln28
8 files changed, 5633 insertions, 0 deletions
diff --git a/sd/miniport/sdhc/README.md b/sd/miniport/sdhc/README.md
new file mode 100644
index 00000000..b5c35093
--- /dev/null
+++ b/sd/miniport/sdhc/README.md
@@ -0,0 +1,13 @@
+Standard SD Host Controller Miniport
+===================
+
+This is a sample for a Secure Digital (SD) Host Controller miniport driver. The driver works in conjunction with sdport.sys, which implements SD/SDIO/eMMC protocol and WDM interfaces, to provide the host register interface.
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+This driver, sdhc.sys, provides a functional miniport implementation for a standard SD host controller. However, it does not have support for many more recent features such as:
+
+- UHS-I speed modes.
+- HS400
+- SD 4.0 \ No newline at end of file
diff --git a/sd/miniport/sdhc/inbox/sdhc.vcxproj b/sd/miniport/sdhc/inbox/sdhc.vcxproj
new file mode 100644
index 00000000..04459aa7
--- /dev/null
+++ b/sd/miniport/sdhc/inbox/sdhc.vcxproj
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{696C1C9C-405C-4675-B344-B5FF53BAB93A}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{014CCC56-7545-4368-82D4-5DBD32E969C6}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <Inf Include="..\sdhc.inx">
+ <CopyOutput>.\$(IntDir)\sdhc.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>sdhc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>sdhc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>sdhc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>sdhc</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\sdport.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\sdhc.c" />
+ <ResourceCompile Include="..\sdhc.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters b/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters
new file mode 100644
index 00000000..398abeab
--- /dev/null
+++ b/sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{9BCD4C03-CF88-47B5-BB78-F6C8FF86F96C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{BCF0B6A6-7B9C-4BF8-A56B-6FE9AEF11C02}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{70DA8E30-872B-447B-8759-726797BFE240}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{428B9C34-C4C4-4109-B1A9-9054F8F7C20A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\sdhc.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="..\sdhc.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\sdhc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\sdhc.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sd/miniport/sdhc/sdhc.c b/sd/miniport/sdhc/sdhc.c
new file mode 100644
index 00000000..c7d85274
--- /dev/null
+++ b/sd/miniport/sdhc/sdhc.c
@@ -0,0 +1,3291 @@
+/*++
+
+Copyright (c) 2002-2014 Microsoft Corporation
+
+Module Name:
+
+ sdhc.c
+
+Abstract:
+
+ This file contains the code that interfaces with standard host controller
+ implementations.
+
+Author:
+
+ Greg Garbern (greggar) 01-May-2014
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Greg Garbern (greggar) 12-June-2014
+
+--*/
+
+#include <ntddk.h>
+#include <sdport.h>
+#include "sdhc.h"
+
+#ifdef ALLOC_PRAGMA
+ #pragma alloc_text(INIT, DriverEntry)
+#endif
+
+//-----------------------------------------------------------------------------
+// SlotExtension routines.
+//-----------------------------------------------------------------------------
+
+NTSTATUS
+DriverEntry(
+ _In_ PVOID DriverObject,
+ _In_ PVOID RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for the standard sdhsot miniport driver.
+
+Arguments:
+
+ DriverObject - DriverObject for the standard host controller.
+
+ RegistryPath - Registry path for this standard host controller.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ SDPORT_INITIALIZATION_DATA InitializationData;
+
+ RtlZeroMemory(&InitializationData, sizeof(InitializationData));
+ InitializationData.StructureSize = sizeof(InitializationData);
+
+ //
+ // Initialize the entry points/callbacks for the miniport interface.
+ //
+
+ InitializationData.GetSlotCount = SdhcGetSlotCount;
+ InitializationData.GetSlotCapabilities = SdhcGetSlotCapabilities;
+ InitializationData.Initialize = SdhcSlotInitialize;
+ InitializationData.IssueBusOperation = SdhcSlotIssueBusOperation;
+ InitializationData.GetCardDetectState = SdhcSlotGetCardDetectState;
+ InitializationData.GetWriteProtectState = SdhcSlotGetWriteProtectState;
+ InitializationData.Interrupt = SdhcSlotInterrupt;
+ InitializationData.IssueRequest = SdhcSlotIssueRequest;
+ InitializationData.GetResponse = SdhcSlotGetResponse;
+ InitializationData.ToggleEvents = SdhcSlotToggleEvents;
+ InitializationData.ClearEvents = SdhcSlotClearEvents;
+ InitializationData.RequestDpc = SdhcRequestDpc;
+ InitializationData.SaveContext = SdhcSaveContext;
+ InitializationData.RestoreContext = SdhcRestoreContext;
+
+ //
+ // Provide the number of slots and their size.
+ //
+
+ InitializationData.PrivateExtensionSize = sizeof(SDHC_EXTENSION);
+
+ //
+ // Hook up the IRP dispatch routines.
+ //
+
+ return SdPortInitialize(DriverObject, RegistryPath, &InitializationData);
+}
+
+NTSTATUS
+SdhcGetSlotCount(
+ _In_ PSD_MINIPORT Miniport,
+ _Out_ PUCHAR SlotCount
+ )
+
+/*++
+
+Routine Description:
+
+ Return the number of slots present on this controller.
+
+Arguments:
+
+ Argument - Functional device object for this controller.
+
+Return value:
+
+ STATUS_UNSUCCESSFUL - PCI config space was unable to be queried.
+
+ STATUS_INVALID_PARAMETER - Invalid underlying bus type for the miniport.
+
+ STATUS_SUCCESS - SlotCount returned properly.
+
+--*/
+
+{
+
+ SDPORT_BUS_TYPE BusType;
+ UCHAR Data;
+ NTSTATUS Status;
+
+ *SlotCount = 0;
+ BusType = Miniport->ConfigurationInfo.BusType;
+ switch (BusType) {
+ case SdBusTypeAcpi:
+
+ //
+ // We don't currently have a mechanism to query the slot count for ACPI
+ // enumerated host controllers. Default to one slot.
+ //
+
+ *SlotCount = 1;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case SdBusTypePci:
+ Data = 0;
+ Status = SdPortGetPciConfigSpace(Miniport,
+ SDHC_PCICFG_SLOT_INFORMATION,
+ &Data,
+ sizeof(Data));
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ *SlotCount = (Data >> 4) + 1;
+ if ((*SlotCount) > 6) {
+
+ NT_ASSERT((*SlotCount) <= 6);
+
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ SdhcInitializePciConfigSpace(Miniport);
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+
+ NT_ASSERT((BusType == SdBusTypeAcpi) || (BusType == SdBusTypePci));
+
+ *SlotCount = 1;
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+VOID
+SdhcGetSlotCapabilities(
+ _In_ PVOID PrivateExtension,
+ _Out_ PSDPORT_CAPABILITIES Capabilities
+ )
+
+/*++
+
+Routine Description:
+
+ Override for miniport to provide host register mapping information if the
+ memory range provideed by the underlying bus isn't sufficient.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+ Capabilities - Miniport provided capabilities.
+
+Return value:
+
+ STATUS_SUCCESS - Capabilities returned successfully.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ RtlCopyMemory(Capabilities,
+ &SdhcExtension->Capabilities,
+ sizeof(SdhcExtension->Capabilities));
+}
+
+NTSTATUS
+SdhcSlotInitialize(
+ _In_ PVOID PrivateExtension,
+ _In_ PHYSICAL_ADDRESS PhysicalBase,
+ _In_ PVOID VirtualBase,
+ _In_ ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the miniport for standard host controllers.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ PSDPORT_CAPABILITIES Capabilities;
+ SDHC_CAPABILITIES_REGISTER CapabilitiesReg;
+ SDHC_CAPABILITIES2_REGISTER Capabilities2Reg;
+ ULONG CurrentLimits;
+ ULONG CurrentLimitMax;
+ ULONG CurrentLimitMask;
+ ULONG CurrentLimitShift;
+ UCHAR Index;
+ PSDHC_EXTENSION SdhcExtension;
+ USHORT SpecVersion;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+
+ //
+ // Initialize the SDHC_EXTENSION register space.
+ //
+
+ SdhcExtension->PhysicalBaseAddress = PhysicalBase;
+ SdhcExtension->BaseAddress = VirtualBase;
+ SdhcExtension->BaseAddressSpaceSize = Length;
+ SdhcExtension->BaseAddressDebug =
+ (PSD_HOST_CONTROLLER_REGISTERS) VirtualBase;
+
+ //
+ // Initialize host capabilities.
+ //
+
+ Capabilities = (PSDPORT_CAPABILITIES) &SdhcExtension->Capabilities;
+ CapabilitiesReg.AsUlong =
+ SdhcReadRegisterUlong(SdhcExtension, SDHC_CAPABILITIES);
+
+ Capabilities2Reg.AsUlong =
+ SdhcReadRegisterUlong(SdhcExtension, SDHC_CAPABILITIES2);
+
+ SpecVersion = SdhcReadRegisterUshort(SdhcExtension, SDHC_VERSION);
+ Capabilities->SpecVersion = SpecVersion & 0xFF;
+ Capabilities->MaximumOutstandingRequests = SDHC_MAX_OUTSTANDING_REQUESTS;
+ Capabilities->MaximumBlockSize =
+ (USHORT)(512 << CapabilitiesReg.MaxBlockLength);
+
+ Capabilities->MaximumBlockCount = 0xFFFF;
+ Capabilities->BaseClockFrequencyKhz =
+ CapabilitiesReg.BaseClockFrequency * 1000;
+
+ Capabilities->DmaDescriptorSize =
+ sizeof(SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY) +
+ (CapabilitiesReg.SystemBus64Support ?
+ sizeof(ULONGLONG) : sizeof(ULONG));
+
+ Capabilities->AlignmentRequirement =
+ (CapabilitiesReg.SystemBus64Support ?
+ sizeof(ULONGLONG) : sizeof(ULONG)) - 1;
+
+ if (CapabilitiesReg.Adma2Support) {
+ Capabilities->Supported.ScatterGatherDma = 1;
+ }
+
+ if (CapabilitiesReg.SystemBus64Support) {
+ Capabilities->Supported.Address64Bit = 1;
+ }
+
+ if (CapabilitiesReg.Support8BitBus) {
+ Capabilities->Supported.BusWidth8Bit = 1;
+ }
+
+ if (CapabilitiesReg.HighSpeedSupport) {
+ Capabilities->Supported.HighSpeed = 1;
+ }
+
+ if (Capabilities2Reg.SDR50Support) {
+ Capabilities->Supported.SDR50 = 1;
+ Capabilities->Supported.SignalingVoltage18V = 1;
+ }
+
+ if (Capabilities2Reg.DDR50Support) {
+ Capabilities->Supported.DDR50 = 1;
+ Capabilities->Supported.SignalingVoltage18V = 1;
+ }
+
+ if (Capabilities2Reg.SDR104Support) {
+ Capabilities->Supported.SDR104 = 1;
+ Capabilities->Supported.SignalingVoltage18V = 1;
+ }
+
+ Capabilities->Supported.HS200 = 0;
+ Capabilities->Supported.HS400 = 0;
+
+ if (Capabilities2Reg.DriverTypeA) {
+ Capabilities->Supported.DriverTypeA = 1;
+ }
+
+ if (Capabilities2Reg.DriverTypeC) {
+ Capabilities->Supported.DriverTypeC = 1;
+ }
+
+ if (Capabilities2Reg.DriverTypeD) {
+ Capabilities->Supported.DriverTypeD = 1;
+ }
+
+ Capabilities->Supported.DriverTypeB = 1;
+
+ if (Capabilities2Reg.UseTuningForSDR50) {
+ Capabilities->Supported.TuningForSDR50 = 1;
+ }
+
+ if (Capabilities2Reg.RetuningTimerCount != 0) {
+ Capabilities->TuningTimerCountInSeconds =
+ (1 << (Capabilities2Reg.RetuningTimerCount - 1));
+ }
+
+ if (Capabilities2Reg.RetuningModes == 0) {
+ Capabilities->Supported.SoftwareTuning = 1;
+ }
+
+ if (SpecVersion >= SDHC_SPEC_VERSION_3) {
+ Capabilities->Supported.AutoCmd23 = 1;
+ }
+
+ if (CapabilitiesReg.Voltage18) {
+ Capabilities->Supported.Voltage18V;
+ }
+
+ if (CapabilitiesReg.Voltage30) {
+ Capabilities->Supported.Voltage30V;
+ }
+
+ if (CapabilitiesReg.Voltage33) {
+ Capabilities->Supported.Voltage33V;
+ }
+
+ //
+ // Find the current limits suppported by the controller.
+ //
+
+ CurrentLimitMask = 0;
+ CurrentLimitShift = 0;
+ if (Capabilities->Supported.Voltage33V) {
+ CurrentLimitMask = 0xFF;
+ CurrentLimitShift = 0;
+
+ } else if (Capabilities->Supported.Voltage30V) {
+ CurrentLimitMask = 0xFF00;
+ CurrentLimitShift = 8;
+
+ } else if (Capabilities->Supported.Voltage18V) {
+ CurrentLimitMask = 0xFF0000;
+ CurrentLimitShift = 16;
+ }
+
+ CurrentLimits = SdhcReadRegisterUlong(SdhcExtension, SDHC_MAXIMUM_CURRENT);
+ CurrentLimitMax =
+ ((CurrentLimits & CurrentLimitMask) >> CurrentLimitShift) * 4;
+
+ if (CurrentLimitMax >= 800) {
+ Capabilities->Supported.Limit800mA;
+ }
+
+ if (CurrentLimitMax >= 600) {
+ Capabilities->Supported.Limit600mA;
+ }
+
+ if (CurrentLimitMax >= 400) {
+ Capabilities->Supported.Limit400mA;
+ }
+
+ if (CurrentLimitMax >= 200) {
+ Capabilities->Supported.Limit200mA;
+ }
+
+ //
+ // Initialize our array of outstanding requests to keep track
+ // of what operations are in flight.
+ //
+
+ for (Index = 0;
+ Index < Capabilities->MaximumOutstandingRequests;
+ Index += 1) {
+
+ RtlZeroMemory(&SdhcExtension->OutstandingRequests[Index],
+ sizeof(PSDPORT_REQUEST));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SdhcSlotIssueBusOperation(
+ _In_ PVOID PrivateExtension,
+ _In_ PSDPORT_BUS_OPERATION BusOperation
+ )
+
+/*++
+
+Routine Description:
+
+ Issue host bus operation specified by BusOperation.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+ BusOperation - Bus operation to perform.
+
+Return value:
+
+ NTSTATUS - Return value of the bus operation performed.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+ NTSTATUS Status;
+
+ Status = STATUS_INVALID_PARAMETER;
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ switch (BusOperation->Type) {
+ case SdResetHost:
+ Status = SdhcResetHost(SdhcExtension,
+ BusOperation->Parameters.ResetType);
+
+ break;
+
+ case SdSetClock:
+ Status = SdhcSetClock(SdhcExtension,
+ BusOperation->Parameters.FrequencyKhz);
+
+ break;
+
+ case SdSetVoltage:
+ Status = SdhcSetVoltage(SdhcExtension,
+ BusOperation->Parameters.Voltage);
+
+ break;
+
+ case SdSetBusWidth:
+ Status = SdhcSetBusWidth(SdhcExtension,
+ BusOperation->Parameters.BusWidth);
+
+ break;
+
+ case SdSetBusSpeed:
+ Status = SdhcSetSpeed(SdhcExtension, BusOperation->Parameters.BusSpeed);
+ break;
+
+ case SdSetSignalingVoltage:
+ Status = SdhcSetSignaling(SdhcExtension,
+ BusOperation->Parameters.SignalingVoltage);
+
+ break;
+
+ case SdSetDriveStrength:
+ //Status = SdhcSetDriveStrength(SdhcExtension,
+ // BusOperation->Parameters.DriveStrength);
+ break;
+
+ case SdSetDriverType:
+ //Status = SdhcSetDriverType(SdhcExtension,
+ // BusOperation->Parameters.DriverType);
+
+ break;
+
+ case SdSetPresetValue:
+ Status = SdhcSetPresetValue(
+ SdhcExtension,
+ BusOperation->Parameters.PresetValueEnabled);
+
+ break;
+
+ case SdExecuteTuning:
+ Status = SdhcExecuteTuning(SdhcExtension);
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+BOOLEAN
+SdhcSlotGetCardDetectState(
+ _In_ PVOID PrivateExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a card is inserted in the slot.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ TRUE - Card is inserted.
+
+ FALSE - Slot is empty.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ return SdhcIsCardInserted(SdhcExtension);
+}
+
+BOOLEAN
+SdhcSlotGetWriteProtectState(
+ _In_ PVOID PrivateExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether the slot write protection is engaged.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ TRUE - Slot is write protected.
+
+ FALSE - Slot is writable.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ return SdhcIsWriteProtected(SdhcExtension);
+}
+
+BOOLEAN
+SdhcSlotInterrupt(
+ _In_ PVOID PrivateExtension,
+ _Out_ PULONG Events,
+ _Out_ PULONG Errors,
+ _Out_ PBOOLEAN NotifyCardChange,
+ _Out_ PBOOLEAN NotifySdioInterrupt,
+ _Out_ PBOOLEAN NotifyTuning
+ )
+
+/*++
+
+Routine Description:
+
+ Level triggered DIRQL interrupt handler (ISR) for this controller.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ Whether the interrupt is handled.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ *Events = (ULONG) SdhcGetInterruptStatus(SdhcExtension);
+
+ //
+ // If there aren't any events to handle, then we don't need to
+ // process anything.
+ //
+
+ if (*Events == 0) {
+ return FALSE;
+ }
+
+ if (*Events & SDHC_IS_ERROR_INTERRUPT) {
+ *Errors = (ULONG) SdhcGetErrorStatus(SdhcExtension);
+ }
+
+ //
+ // If a card has changed, notify the port driver.
+ //
+
+ if (*Events & SDHC_IS_CARD_DETECT) {
+ *NotifyCardChange = TRUE;
+ *Events &= ~SDHC_IS_CARD_DETECT;
+ }
+
+ //
+ // If we have an external SDIO interrupt, notify the port driver.
+ //
+
+ if (*Events & SDHC_IS_CARD_INTERRUPT) {
+ *NotifySdioInterrupt = TRUE;
+ *Events &= ~SDHC_IS_CARD_INTERRUPT;
+ }
+
+ //
+ // If there's a tuning request, notify the port driver.
+ //
+
+ if (*Events & SDHC_IS_TUNING_INTERRUPT) {
+ *NotifyTuning = TRUE;
+ *Events &= ~SDHC_IS_TUNING_INTERRUPT;
+ }
+
+ //
+ // Acknowledge/clear interrupt status. Request completions will occur in
+ // the port driver's slot completion DPC. We need to make the members of
+ // SDPORT_REQUEST that only the port driver uses opaque to the miniport.
+ // See how Storport does this (if it does).
+ //
+
+ SdhcAcknowledgeInterrupts(SdhcExtension, (USHORT) *Events);
+ return (*Events != 0);
+}
+
+NTSTATUS
+SdhcSlotIssueRequest(
+ _In_ PVOID PrivateExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Issue hardware request specified by Request.
+
+Arguments:
+
+ PrivateExtension - This driver's device extension (SdhcExtension).
+
+ Request - Request operation to perform.
+
+Return value:
+
+ NTSTATUS - Return value of the request performed.
+
+--*/
+
+{
+
+ ULONG Index;
+ PSDHC_EXTENSION SdhcExtension;
+ NTSTATUS Status;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+
+ //
+ // Insert the request onto the outstanding requests list.
+ //
+
+ for (Index = 0;
+ Index < SdhcExtension->Capabilities.MaximumOutstandingRequests;
+ Index += 1) {
+
+ if (SdhcExtension->OutstandingRequests[Index] == NULL) {
+ SdhcExtension->OutstandingRequests[Index] = Request;
+ break;
+ }
+ }
+
+ //
+ // Dispatch the request based off of the request type.
+ //
+
+ switch (Request->Type) {
+ case SdRequestTypeCommandNoTransfer:
+ case SdRequestTypeCommandWithTransfer:
+ Status = SdhcSendCommand(SdhcExtension, Request);
+ break;
+
+ case SdRequestTypeStartTransfer:
+ Status = SdhcStartTransfer(SdhcExtension, Request);
+ break;
+
+ default:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+VOID
+SdhcSlotGetResponse(
+ _In_ PVOID PrivateExtension,
+ _In_ PSDPORT_COMMAND Command,
+ _Out_ PVOID ResponseBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Return the response data for a given command back to the port driver.
+
+Arguments:
+
+ PrivateExtension - This driver's device extension (SdhcExtension).
+
+ Command - Command for which we're getting the response.
+
+ ResponseBuffer - Response data for the given command.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ PSDHC_EXTENSION SdhcExtension;
+ NTSTATUS Status;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ Status = SdhcGetResponse(SdhcExtension, Command, ResponseBuffer);
+ NT_ASSERT(NT_SUCCESS(Status));
+}
+
+VOID
+SdhcRequestDpc(
+ _In_ PVOID PrivateExtension,
+ _Inout_ PSDPORT_REQUEST Request,
+ _In_ ULONG Events,
+ _In_ ULONG Errors
+ )
+
+/*++
+
+Routine Description:
+
+ DPC for interrupts associated with the given request.
+
+Arguments:
+
+ PrivateExtension - This driver's device extension (SdhcExtension).
+
+ Request - Request operation to perform.
+
+Return value:
+
+ NTSTATUS - Return value of the request performed.
+
+--*/
+
+{
+
+ ULONG Index;
+ PSDHC_EXTENSION SdhcExtension;
+ NTSTATUS Status;
+
+ //
+ // Clear the request's required events if they have completed.
+ //
+
+ Request->RequiredEvents &= ~Events;
+
+ //
+ // Find the index of the request in the outstanding request list.
+ //
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ for (Index = 0; Index < SDHC_MAX_OUTSTANDING_REQUESTS; Index += 1) {
+ if (SdhcExtension->OutstandingRequests[Index] == Request) {
+ break;
+ }
+ }
+
+ //
+ // If there are errors, we need to fail whatever outstanding request
+ // was on the bus. Otherwise, the request succeeded.
+ //
+ // TODO: There's a race condition here--it's possible for a request
+ // to get a transfer complete interrupt and then later receive an
+ // error interrupt for the same transfer. It might be mitigated by
+ // handling request completion in a DPC for ISR.
+ //
+
+ if (Errors) {
+ Request->RequiredEvents = 0;
+ SdhcExtension->OutstandingRequests[Index] = NULL;
+ Status = SdhcConvertErrorToStatus((USHORT) Errors);
+ SdPortCompleteRequest(Request, Status);
+
+ } else if (Request->RequiredEvents == 0) {
+ if (Request->Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ Request->Status = STATUS_SUCCESS;
+ }
+
+ SdhcExtension->OutstandingRequests[Index] = NULL;
+ SdPortCompleteRequest(Request, Request->Status);
+ }
+}
+
+VOID
+SdhcSlotToggleEvents(
+ _In_ PVOID PrivateExtension,
+ _In_ ULONG EventMask,
+ _In_ BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Enable or disable the given event mask.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+ Events - The event mask to toggle.
+
+ Enable - TRUE to enable, FALSE to disable.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT InterruptMask;
+ PSDHC_EXTENSION SdhcExtension;
+
+ InterruptMask = SdhcConvertEventsToHwMask(EventMask);
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ if (Enable) {
+ SdhcEnableInterrupt(SdhcExtension,
+ InterruptMask);
+
+ } else {
+ SdhcDisableInterrupt(SdhcExtension,
+ InterruptMask);
+ }
+}
+
+VOID
+SdhcSlotClearEvents(
+ _In_ PVOID PrivateExtension,
+ _In_ ULONG EventMask
+ )
+
+{
+
+ USHORT Interrupts;
+ PSDHC_EXTENSION SdhcExtension;
+
+ SdhcExtension = (PSDHC_EXTENSION) PrivateExtension;
+ Interrupts = SdhcConvertEventsToHwMask(EventMask);
+ SdhcAcknowledgeInterrupts(SdhcExtension, Interrupts);
+}
+
+VOID
+SdhcSaveContext(
+ _In_ PVOID PrivateExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Save slot register context.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(PrivateExtension);
+}
+
+VOID
+SdhcRestoreContext(
+ _In_ PVOID PrivateExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Restore slot register context from a previously saved context.
+
+Arguments:
+
+ SlotExtension - SlotExtension interface between sdhost and this miniport.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(PrivateExtension);
+}
+
+//-----------------------------------------------------------------------------
+// Host routine implementations.
+//-----------------------------------------------------------------------------
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcResetHost(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ UCHAR ResetType
+ )
+
+/*++
+
+Routine Description:
+
+ Execute a soft reset to the socket specified.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ ResetType - Either full, CMD, or DAT reset.
+
+Return value:
+
+ STATUS_SUCCESS - Reset succeeded.
+
+ STATUS_INVALID_PARAMETER - Invalid reset type chosen.
+
+--*/
+
+{
+
+ UCHAR HostControl;
+ UCHAR Reset;
+ UCHAR Retries;
+ UCHAR Mask;
+
+ switch (ResetType) {
+ case SdResetTypeAll:
+ Mask = SDHC_RESET_ALL;
+ break;
+
+ case SdResetTypeCmd:
+ Mask = SDHC_RESET_CMD;
+ break;
+
+ case SdResetTypeDat:
+ Mask = SDHC_RESET_DAT;
+ break;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Reset the host controller.
+ //
+
+ Retries = 100;
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_RESET, Mask);
+ do {
+ Retries -= 1;
+ if (Retries == 0) {
+ return STATUS_TIMEOUT;
+ }
+
+ Reset = SdhcReadRegisterUchar(SdhcExtension, SDHC_RESET);
+
+ if ((Reset & Mask) != 0) {
+ SdPortWait(1000);
+ }
+
+ } while ((Reset & Mask) != 0);
+
+ //
+ // Set the max HW timeout for bus operations.
+ //
+
+ SdhcWriteRegisterUchar(SdhcExtension,
+ SDHC_TIMEOUT_CONTROL,
+ SDHC_TC_MAX_DATA_TIMEOUT);
+
+ //
+ // Initialize DMA if the controller supports it.
+ //
+
+ HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL);
+ HostControl &= ~SDHC_HC_DMA_SELECT_MASK;
+ if (SdhcExtension->Capabilities.Supported.ScatterGatherDma) {
+ if (SdhcExtension->Capabilities.Supported.Address64Bit) {
+ HostControl |= SDHC_HC_DMA_SELECT_ADMA64;
+
+ } else {
+ HostControl |= SDHC_HC_DMA_SELECT_ADMA32;
+ }
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl);
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetClock(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Frequency
+ )
+
+/*++
+
+Routine Description:
+
+ Set the clock to a given frequency.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Frequency - The target frequency.
+
+Return value:
+
+ STATUS_SUCCESS - The clock was successfuly set.
+
+ STATUS_TIMEOUT - The clock did not stabilize in time.
+
+--*/
+
+{
+
+ ULONG ActualFrequency;
+ USHORT ClockControl;
+ ULONG Delay;
+ USHORT Mask;
+ UCHAR Retries;
+
+ UNREFERENCED_PARAMETER(Frequency);
+
+ ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+ ClockControl &= ~(SDHC_CC_CLOCK_ENABLE | SDHC_CC_INTERNAL_CLOCK_ENABLE);
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+ ClockControl = SdhcCalcClockFrequency(SdhcExtension,
+ Frequency,
+ &ActualFrequency);
+
+ ClockControl |= SDHC_CC_INTERNAL_CLOCK_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+
+ //
+ // Now the frequency is set, delay a few times to wait for it to become
+ // stable.
+ //
+
+ Retries = 100;
+ Mask = SDHC_CC_CLOCK_STABLE;
+ do {
+ Retries -= 1;
+ if (Retries == 0) {
+ return STATUS_TIMEOUT;
+ }
+
+ ClockControl =
+ SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+
+ if ((ClockControl & Mask) == 0) {
+ SdPortWait(1000);
+ }
+
+ } while ((ClockControl & Mask) == 0);
+
+ //
+ // Clock is now stable, now enable it.
+ //
+
+ ClockControl |= SDHC_CC_CLOCK_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+
+ //
+ // Some hardware need more time here to stabilize, but minimize latency
+ // for fixed eMMC devices during runtime Dx transitions.
+ //
+
+ Delay = (SdhcExtension->Removable) ? (10 * 1000) : 50;
+ SdPortWait(Delay);
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetVoltage(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ SDPORT_BUS_VOLTAGE Voltage
+ )
+
+/*++
+
+Routine Description:
+
+ Set the slot's voltage profile.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ VoltageProfile - Indicates which power voltage to use. If 0, turn off the
+ power
+
+Return value:
+
+ STATUS_SUCCESS - The bus voltage was successfully switched.
+
+ STATUS_INVALID_PARAMETER - The voltage profile provided was invalid.
+
+ STATUS_TIMEOUT - The bus voltage did not stabilize in time.
+
+--*/
+
+{
+
+ ULONG Delay;
+ UCHAR Mask;
+ UCHAR PowerControl;
+ UCHAR PowerControlCheck;
+ UCHAR Retries;
+
+ //
+ // Wait 10ms if the slot is removable; otherwise, only wait 50us.
+ //
+
+ Delay = (SdhcExtension->Removable) ? (10* 1000) : 50;
+ SdPortWait(Delay);
+
+ //
+ // Use the highest voltage capable.
+ //
+
+ switch (Voltage) {
+ case SdBusVoltage33:
+ PowerControl = SDHC_PC_3_3V;
+ break;
+
+ case SdBusVoltage30:
+ PowerControl = SDHC_PC_3_0V;
+ break;
+
+ case SdBusVoltage18:
+ PowerControl = SDHC_PC_1_8V;
+ break;
+
+ case SdBusVoltageOff:
+ PowerControl = 0;
+ break;
+
+ default:
+
+ NT_ASSERTMSG("SDHC - Voltage profile invalid.", FALSE);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Retries = 100;
+ Mask = SDHC_PC_VOLTAGE_MASK;
+ do {
+ Retries -= 1;
+ if (Retries == 0) {
+ return STATUS_TIMEOUT;
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl);
+ PowerControlCheck =
+ SdhcReadRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL);
+
+ if ((PowerControlCheck & Mask) != PowerControl) {
+ SdPortWait(1000);
+ }
+
+ } while ((PowerControlCheck & Mask) != PowerControl);
+
+ PowerControl |= SDHC_PC_BUS_POWER;
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl);
+ SdPortWait(Delay);
+
+ Retries = 100;
+ Mask = SDHC_PC_VOLTAGE_MASK | SDHC_PC_BUS_POWER;
+ do {
+ Retries -= 1;
+ if (Retries == 0) {
+ return STATUS_TIMEOUT;
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL, PowerControl);
+ PowerControlCheck =
+ SdhcReadRegisterUchar(SdhcExtension, SDHC_POWER_CONTROL);
+
+ if ((PowerControlCheck & Mask) != PowerControl) {
+ SdPortWait(1000);
+ }
+
+ } while ((PowerControlCheck & Mask) != PowerControl);
+
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetBusWidth(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ UCHAR Width
+ )
+
+/*++
+
+Routine Description:
+
+ Set bus width for host controller.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Width - The data bus width of the slot.
+
+Return value:
+
+ STATUS_SUCCESS - The bus width was properly changed.
+
+--*/
+
+{
+
+ UCHAR HostControl;
+
+ HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL);
+ HostControl &= ~(SDHC_HC_DATA_WIDTH_4BIT | SDHC_HC_DATA_WIDTH_8BIT);
+ switch (Width) {
+ case 1:
+ break;
+
+ case 4:
+ HostControl |= SDHC_HC_DATA_WIDTH_4BIT;
+ break;
+ case 8:
+ HostControl |= SDHC_HC_DATA_WIDTH_8BIT;
+ break;
+
+ default:
+
+ NT_ASSERTMSG("SDHC - Provided bus width is invalid", FALSE);
+
+ break;
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SdhcSetSpeed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ SDPORT_BUS_SPEED Speed
+ )
+
+/*++
+
+Routine Description:
+
+ Based on the capabilities of card and host, turns on the maximum performing
+ speed mode for the host. Caller is expected to know the capabilities of the
+ card before setting the speed mode.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Speed - Bus speed to set.
+
+Return value:
+
+ STATUS_SUCCESS - The selected speed mode was successfully set.
+
+ STATUS_INVALID_PARAMETER - The speed mode selected is not valid.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ USHORT UhsMode;
+
+ switch (Speed) {
+ case SdBusSpeedNormal:
+ Status = SdhcSetHighSpeed(SdhcExtension, FALSE);
+ break;
+
+ case SdBusSpeedHigh:
+ Status = SdhcSetHighSpeed(SdhcExtension, TRUE);
+ break;
+
+ case SdBusSpeedSDR12:
+ case SdBusSpeedSDR25:
+ case SdBusSpeedSDR50:
+ case SdBusSpeedDDR50:
+ case SdBusSpeedSDR104:
+ case SdBusSpeedHS200:
+ case SdBusSpeedHS400:
+ UhsMode = SdhcGetHwUhsMode(Speed);
+ Status = SdhcSetUhsMode(SdhcExtension, UhsMode);
+ break;
+
+ default:
+
+ NT_ASSERTMSG("SDHC - Invalid speed mode selected.", FALSE);
+
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetHighSpeed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Based on the capabilities of card and host, enables or disables high speed.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Enable - TRUE to enable high speed, FALSE to disable.
+
+Return value:
+
+ STATUS_SUCCESS - High speed was successfully enabled.
+
+--*/
+
+{
+
+ UCHAR HostControl;
+
+ HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL);
+ HostControl &= ~SDHC_HC_ENABLE_HIGH_SPEED;
+ if (Enable) {
+ HostControl |= SDHC_HC_ENABLE_HIGH_SPEED;
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl);
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetUhsMode(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ USHORT Mode
+ )
+
+/*++
+
+Routine Description:
+
+ Based on the capabilities of card and host, turns on the maximum performing
+ speed mode for the host. Caller is expected to know the capabilities of the
+ card before setting the speed mode.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Mode - UHS mode to set.
+
+Return value:
+
+ STATUS_SUCCESS - Mode requested is set on the controller.
+
+ STATUS_INVALID_PARAMETER - The mode selected is not a UHS mode.
+
+--*/
+
+{
+
+ USHORT ClockControl;
+ USHORT HostControl2;
+
+ HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2);
+
+ //
+ // If we're already in the requested mode, return.
+ //
+
+ if ((HostControl2 & SDHC_HC2_UHS_MODES) == Mode) {
+ return STATUS_SUCCESS;
+ }
+
+ ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+ ClockControl &= ~SDHC_CC_CLOCK_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+ SdPortWait(10 * 1000);
+
+ //
+ // Set the UHS mode.
+ //
+
+ HostControl2 &= ~SDHC_HC2_UHS_MODES;
+ HostControl2 |= Mode;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2);
+ ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+ ClockControl |= SDHC_CC_CLOCK_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+ SdPortWait(10 * 1000);
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcSetSignaling(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Set signaling voltage (1.8V or 3.3V).
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Enable - TRUE for 1.8V signaling, FALSE for default 3.3V.
+
+Return value:
+
+ STATUS_SUCCESS - Signaling voltage switch successful.
+
+ STATUS_UNSUCCESSFUL - Signaling voltage switch unsuccessful.
+
+--*/
+
+{
+
+ USHORT ClockControl;
+ ULONG DatLines;
+ USHORT HostControl2;
+ USHORT Mask;
+
+ //
+ // Disable the bus clock.
+ //
+
+ ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+ ClockControl &= ~SDHC_CC_CLOCK_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL, ClockControl);
+ SdPortWait(10 * 1000);
+
+ //
+ // DAT[3:0] must be all zeroes.
+ //
+
+ DatLines = 0;
+ DatLines =
+ SDHC_PS_DAT_3_0 &
+ SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE);
+
+ if (DatLines != 0) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Set the signaling voltage.
+ //
+
+ HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2);
+ Mask = SDHC_HC2_1_8V_SIGNALING;
+ if (Enable) {
+ HostControl2 |= Mask;
+
+ } else {
+ HostControl2 &= ~Mask;
+ }
+
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2);
+ SdPortWait(5 * 1000);
+ HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2);
+
+ //
+ // Make sure the signaling voltage latched.
+ //
+
+ if (Enable) {
+ if ((HostControl2 & Mask) == 0) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ } else {
+ if ((HostControl2 & Mask) != 0) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ //
+ // Reenable the bus clock.
+ //
+
+ ClockControl = SdhcReadRegisterUshort(SdhcExtension, SDHC_CLOCK_CONTROL);
+ SdPortWait(10000);
+
+ //
+ // DAT[3:0] must be all ones.
+ //
+
+ DatLines = 0;
+ DatLines =
+ SDHC_PS_DAT_3_0 &
+ SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE);
+
+ if (DatLines != SDHC_PS_DAT_3_0) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+SdhcExecuteTuning(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Tune the bus sampling point due to variations in voltage,
+ temperature, and time.
+
+ Caller guarantees that the bus is in a UHS mode that
+ requires tuning.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ STATUS_SUCCESS - Tuning successful.
+
+--*/
+
+{
+
+ USHORT HostControl2;
+ //UCHAR Retries;
+ SDPORT_REQUEST TuningRequest;
+
+ HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2);
+
+ NT_ASSERT((HostControl2 & SDHC_HC2_EXECUTE_TUNING) == 0);
+
+ //
+ // Disable controller events
+ //
+ // Technically, all controller events should be disabled at tuning execute
+ // time, but some controllers do not follow this requirement.
+ //
+
+ if ((HostControl2 & SDHC_HC2_EXECUTE_TUNING) == 0) {
+ HostControl2 |= SDHC_HC2_EXECUTE_TUNING;
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_HOST_CONTROL2,
+ HostControl2);
+ }
+
+ RtlZeroMemory(&TuningRequest, sizeof(TuningRequest));
+ TuningRequest.Command.TransferType = SdTransferTypeSingleBlock;
+ TuningRequest.Command.TransferDirection = SdTransferDirectionRead;
+ TuningRequest.Command.Class = SdCommandClassStandard;
+ TuningRequest.Command.ResponseType = SdResponseTypeR1;
+ if (SdhcExtension->SpeedMode == SdhcSpeedModeSDR104) {
+ TuningRequest.Command.Index = 19;
+ TuningRequest.Command.BlockSize = 64;
+
+ } else {
+ TuningRequest.Command.Index = 21;
+ TuningRequest.Command.BlockSize = 128;
+ }
+
+ //
+ // TODO: Implement rest of tuning logic as described in
+ // SD Host Controller Specification. This is needed for
+ // SDR104, HS200, and HS400 modes, and sometimes for SDR50.
+ //
+
+ //
+ // Execute the data transfer.
+ //
+
+ //Status = SdhcBuildTransfer()
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+SdhcSetLed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Turn the controller activity LED on/off.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Enable - Indicate whether to enable or disable the LED.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ UCHAR HostControl;
+
+ HostControl = SdhcReadRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL);
+ if (Enable) {
+ HostControl |= SDHC_HC_LED_POWER;
+
+ } else {
+ HostControl &= ~SDHC_HC_LED_POWER;
+ }
+
+ SdhcWriteRegisterUchar(SdhcExtension, SDHC_HOST_CONTROL, HostControl);
+}
+
+NTSTATUS
+SdhcSetPresetValue(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ )
+
+/*++
+
+Routine Description:
+
+ Enable or disable setting of preset values. Caller must
+ ensure that the controller supports preset value.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Enable - Indicate whether to enable or disable preset values.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT HostControl2;
+
+ HostControl2 = SdhcReadRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2);
+
+ NT_ASSERT((HostControl2 & SDHC_HC2_ENABLE_PRESET_VALUE) != 0);
+
+ HostControl2 &= ~SDHC_HC2_ENABLE_PRESET_VALUE;
+ if (Enable) {
+ HostControl2 |= SDHC_HC2_ENABLE_PRESET_VALUE;
+ }
+
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_HOST_CONTROL2, HostControl2);
+ return STATUS_SUCCESS;
+}
+
+VOID
+SdhcSetBlockGapControl(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Continue,
+ _In_ BOOLEAN RequestStop
+ )
+
+/*++
+
+Routine Description:
+
+ Enable block gap interrupt requests.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Continue - Continue after the next block gap.
+
+ RequestStop - Request the block gap interrupt request.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ UCHAR BlockGapControl;
+
+ BlockGapControl = SdhcReadRegisterUchar(SdhcExtension,
+ SDHC_BLOCKGAP_CONTROL);
+
+ BlockGapControl &= ~SDHC_BGC_CONTINUE;
+ BlockGapControl &= ~SDHC_BGC_STOP_NEXT_GAP;
+ if (Continue) {
+ BlockGapControl |= SDHC_BGC_CONTINUE;
+ }
+
+ if (RequestStop) {
+ BlockGapControl |= SDHC_BGC_STOP_NEXT_GAP;
+ }
+}
+
+VOID
+SdhcEnableInterrupt(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG NormalInterruptMask
+ )
+
+/*++
+
+Routine Description:
+
+ Set the host event mask to the new value specified.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ NormalInterruptMask - The new normal events to set.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT InterruptEnable;
+
+ InterruptEnable =
+ SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_SIGNAL_ENABLE);
+
+ InterruptEnable |= NormalInterruptMask;
+
+ //
+ // Enable the interrupt signals from controller to OS.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_INTERRUPT_SIGNAL_ENABLE,
+ InterruptEnable);
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_ERROR_SIGNAL_ENABLE,
+ 0xFFFF);
+
+ //
+ // Enable the interrupt signals on the controller.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_INTERRUPT_STATUS_ENABLE,
+ InterruptEnable);
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_ERROR_STATUS_ENABLE,
+ 0xFFFF);
+}
+
+VOID
+SdhcDisableInterrupt(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG NormalInterruptMask
+ )
+
+/*++
+
+Routine Description:
+
+ Set the host event mask to the new value specified.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ NormalInterruptMask - Normal Interrupts to disable.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ USHORT InterruptDisable;
+
+ InterruptDisable =
+ SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_SIGNAL_ENABLE);
+
+ InterruptDisable &= ~NormalInterruptMask;
+
+ //
+ // Disable the interrupt signals on the controller.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_INTERRUPT_STATUS_ENABLE,
+ InterruptDisable);
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_ERROR_STATUS_ENABLE,
+ 0);
+
+ //
+ // Disable the interrupt signals from controller to OS.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_INTERRUPT_SIGNAL_ENABLE,
+ InterruptDisable);
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_ERROR_SIGNAL_ENABLE,
+ 0);
+}
+
+__forceinline
+USHORT
+SdhcGetInterruptStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Get current pending events from the interrupt status. This function does
+ not acknowledge the interrupt. The caller should acknowledge or disable
+ the corresponding events.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ The event mask.
+
+--*/
+
+{
+
+ USHORT InterruptStatus;
+
+ InterruptStatus =
+ SdhcReadRegisterUshort(SdhcExtension, SDHC_INTERRUPT_STATUS);
+
+ //
+ // 0xFFFF means HC is no longer accessible. This interrupt does not belong
+ // to us.
+ //
+
+ if (InterruptStatus == 0xFFFF) {
+ return 0;
+ }
+
+ return InterruptStatus;
+}
+
+__forceinline
+USHORT
+SdhcGetErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current error status, if any.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ The error interrupt status.
+
+--*/
+
+{
+
+ return SdhcReadRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS);
+}
+
+__forceinline
+USHORT
+SdhcGetAutoCmd12ErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current Auto CMD12 error status, if any.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ The Auto CMD12 error status.
+
+--*/
+
+{
+
+ return SdhcReadRegisterUshort(SdhcExtension, SDHC_AUTO_CMD12_ERROR_STATUS);
+}
+
+USHORT
+SdhcGetAdmaErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current ADMA error status, if any.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ The ADMA error status.
+
+--*/
+
+{
+
+ return SdhcReadRegisterUshort(SdhcExtension, SDHC_ADMA_ERROR_STATUS);
+}
+
+VOID
+SdhcAcknowledgeInterrupts(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ USHORT Interrupts
+ )
+
+/*++
+
+Routine Description:
+
+ Acknowlege the interrupts specified.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Interrupts - event mask to acknowledge (single event only)
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ if ((Interrupts & SDHC_IS_ERROR_INTERRUPT) != 0) {
+
+ //
+ // The Auto CMD12 error interrupt status bit of some Ricoh controllers
+ // can't get cleared by writing to the error status register alone.
+ // Write all-ones and all-zeroes to the Auto CMD12 error status register
+ // first to work around this issue. This write should have no effect on
+ // other types of controllers since the register should be read-only
+ // according to the spec.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_AUTO_CMD12_ERROR_STATUS,
+ 0xFFFF);
+
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_AUTO_CMD12_ERROR_STATUS,
+ 0x0);
+
+ //
+ // Clear the error interrupt by writing all-ones.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS, 0xFFFF);
+ Interrupts &= ~SDHC_IS_ERROR_INTERRUPT;
+ }
+
+ //
+ // Clear other interrupts in the interrupt status register.
+ //
+
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_INTERRUPT_STATUS, Interrupts);
+}
+
+BOOLEAN
+SdhcIsCardInserted(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ To detect whether there is a card in the socket.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ BOOLEAN value to indicate whether there is a card in the socket.
+
+--*/
+
+{
+
+ ULONG PresentState;
+
+ PresentState = SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE);
+ return (BOOLEAN) ((PresentState & SDHC_PS_CARD_INSERTED) != 0);
+}
+
+BOOLEAN
+SdhcIsWriteProtected(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ )
+
+/*++
+
+Routine Description:
+
+ To detect whether the card is write protected.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+Return value:
+
+ BOOLEAN value to indicate whether the card is write protected.
+
+--*/
+
+{
+
+ ULONG PresentState;
+ BOOLEAN WriteProtected;
+
+ //
+ // Write protect is active low.
+ //
+
+ PresentState = SdhcReadRegisterUlong(SdhcExtension, SDHC_PRESENT_STATE);
+ WriteProtected = (BOOLEAN) ((PresentState & SDHC_PS_WRITE_PROTECT) == 0);
+ return WriteProtected;
+}
+
+NTSTATUS
+SdhcSendCommand(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes the SD command package and writes it to the appropriate
+ registers on the host controller. It also computes the proper flag
+ settings.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - Supplies the descriptor for this SD command
+
+Return value:
+
+ STATUS_SUCCESS - Command successfully sent.
+
+ STATUS_INVALID_PARAMETER - Invalid command response type specified.
+
+--*/
+
+{
+
+ PSDPORT_COMMAND Command;
+ USHORT CommandType;
+ USHORT CommandReg;
+ NTSTATUS Status;
+ USHORT TransferMode;
+
+ //
+ // Initialize transfer parameters if this command is a data command.
+ //
+
+ Command = &Request->Command;
+ if ((Command->TransferType != SdTransferTypeNone) &&
+ (Command->TransferType != SdTransferTypeUndefined)) {
+
+ Status = SdhcBuildTransfer(SdhcExtension, Request);
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Set the response parameters based off the given response type.
+ //
+
+ SdhcWriteRegisterUlong(SdhcExtension, SDHC_ARGUMENT, Command->Argument);
+
+ CommandReg = Command->Index << 8;
+ switch (Command->ResponseType) {
+ case SdResponseTypeNone:
+ break;
+
+ case SdResponseTypeR1:
+ case SdResponseTypeR5:
+ case SdResponseTypeR6:
+ CommandReg |= SDHC_CMD_RESPONSE_48BIT_NOBUSY |
+ SDHC_CMD_CRC_CHECK_ENABLE |
+ SDHC_CMD_INDEX_CHECK_ENABLE;
+ break;
+
+ case SdResponseTypeR1B:
+ case SdResponseTypeR5B:
+ CommandReg |= SDHC_CMD_RESPONSE_48BIT_WBUSY |
+ SDHC_CMD_CRC_CHECK_ENABLE |
+ SDHC_CMD_INDEX_CHECK_ENABLE;
+ break;
+
+ case SdResponseTypeR2:
+ CommandReg |= SDHC_CMD_RESPONSE_136BIT |
+ SDHC_CMD_CRC_CHECK_ENABLE;
+ break;
+
+ case SdResponseTypeR3:
+ case SdResponseTypeR4:
+ CommandReg |= SDHC_CMD_RESPONSE_48BIT_NOBUSY;
+ break;
+
+ default:
+
+ NT_ASSERTMSG("SDHC - Invalid response type", FALSE);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Request->Command.TransferType != SdTransferTypeNone) {
+ TransferMode = 0;
+ CommandReg |= SDHC_CMD_DATA_PRESENT;
+
+ } else {
+ TransferMode =
+ SdhcReadRegisterUshort(SdhcExtension, SDHC_TRANSFER_MODE);
+
+ TransferMode &= ~SDHC_TM_DMA_ENABLE;
+ TransferMode &= ~SDHC_TM_AUTO_CMD12_ENABLE;
+ TransferMode &= ~SDHC_TM_AUTO_CMD23_ENABLE;
+ SdhcWriteRegisterUshort(SdhcExtension,
+ SDHC_TRANSFER_MODE,
+ TransferMode);
+ }
+
+ switch (Command->Type) {
+ case SdCommandTypeSuspend:
+ CommandType = SDHC_CMD_TYPE_SUSPEND;
+ break;
+
+ case SdCommandTypeResume:
+ CommandType = SDHC_CMD_TYPE_RESUME;
+ break;
+
+ case SdCommandTypeAbort:
+ CommandType = SDHC_CMD_TYPE_ABORT;
+ break;
+
+ default:
+ CommandType = 0;
+ break;
+ }
+
+ //
+ // Set the bitmask for the required events that will fire after
+ // writing to the command register. Depending on the response
+ // type or whether the command involves data transfer, we will need
+ // to wait on a number of different events.
+ //
+
+ Request->RequiredEvents = SDHC_IS_CMD_COMPLETE;
+ if ((Command->ResponseType == SdResponseTypeR1B) ||
+ (Command->ResponseType == SdResponseTypeR5B)) {
+
+ Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE;
+ }
+
+ if (Request->Command.TransferMethod == SdTransferMethodSgDma) {
+ Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE;
+
+ } else if (Request->Command.TransferMethod == SdTransferMethodPio) {
+ if (Request->Command.TransferDirection == SdTransferDirectionRead) {
+ Request->RequiredEvents |= SDHC_IS_BUFFER_READ_READY;
+
+ } else {
+ Request->RequiredEvents |= SDHC_IS_BUFFER_WRITE_READY;
+ }
+ }
+
+ //
+ // Issue the actual command.
+ //
+
+ CommandReg |= CommandType;
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_COMMAND, CommandReg);
+
+ //
+ // We must wait until the request completes.
+ //
+
+ return STATUS_PENDING;
+}
+
+NTSTATUS
+SdhcGetResponse(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_COMMAND Command,
+ _Out_ PVOID ResponseBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the response of the SD card which is sent over
+ the command line, and stores it in the specified buffer
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - Supplies the descriptor for this SD command.
+
+Return value:
+
+ STATUS_SUCCESS - Response successfully returned.
+
+ STATUS_INVALID_PARAMETER - Invalid response length.
+
+--*/
+
+{
+
+ UCHAR Index;
+ PUCHAR Response;
+ UCHAR ResponseLength;
+
+ ResponseLength = SdhcGetResponseLength(Command);
+ if (ResponseLength > 16) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Response = (PUCHAR) ResponseBuffer;
+ for (Index = 0; Index < ResponseLength; Index += 1) {
+
+#pragma prefast(suppress: 22103, "Response length is guaranteed to be <= ResponseLength.")
+
+ Response[Index] =
+ SdhcReadRegisterUchar(SdhcExtension, SDHC_RESPONSE + Index);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SdhcSetTransferMode(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the host for a data transfer.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Command - Supplies the descriptor for this SD command.
+
+Return value:
+
+ STATUS_SUCCESS - Transfer mode successfully set.
+
+ STATUS_INVALID_PARAMETER - Invalid command transfer parameters.
+
+--*/
+
+{
+
+ USHORT BlockCount;
+ USHORT BlockSize;
+ USHORT TransferMode;
+
+ NT_ASSERT(Request->Command.TransferMethod != SdTransferMethodUndefined);
+
+ BlockCount = Request->Command.BlockCount;
+ if (Request->Command.BlockSize > 2048) {
+
+ NT_ASSERTMSG("SDHC - Invalid block size for command", FALSE);
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if ((Request->Command.TransferDirection != SdTransferDirectionRead) &&
+ (Request->Command.TransferDirection != SdTransferDirectionWrite)) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ TransferMode &= ~(SDHC_TM_AUTO_CMD12_ENABLE |
+ SDHC_TM_AUTO_CMD23_ENABLE |
+ SDHC_TM_DMA_ENABLE |
+ SDHC_TM_BLKCNT_ENABLE |
+ SDHC_TM_MULTIBLOCK);
+
+ // if (Command->TransferType = TransferTypeMultiBlockNoStop) {
+
+ //}
+
+ if (BlockCount > 1) {
+ TransferMode |= SDHC_TM_MULTIBLOCK;
+ TransferMode |= SDHC_TM_BLKCNT_ENABLE;
+ TransferMode |= SDHC_TM_AUTO_CMD12_ENABLE;
+ }
+
+ if (Request->Command.TransferMethod == SdTransferMethodSgDma) {
+ TransferMode |= SDHC_TM_DMA_ENABLE;
+
+ } else {
+
+ NT_ASSERT(Request->Command.TransferMethod == SdTransferMethodPio);
+
+ }
+
+ BlockSize = Request->Command.BlockSize;
+ TransferMode &= ~SDHC_TM_TRANSFER_READ;
+ if (Request->Command.TransferDirection == SdTransferDirectionRead) {
+ TransferMode |= SDHC_TM_TRANSFER_READ;
+ }
+
+ SdhcWriteRegisterUlong(SdhcExtension, SDHC_SYSADDR, BlockCount);
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_BLOCK_SIZE, BlockSize);
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_BLOCK_COUNT, BlockCount);
+ SdhcWriteRegisterUshort(SdhcExtension, SDHC_TRANSFER_MODE, TransferMode);
+ return STATUS_SUCCESS;
+}
+
+VOID
+SdhcReadDataPort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _Out_writes_all_(Length) PUCHAR Buffer,
+ _In_ SIZE_T Length
+ )
+
+/*++
+
+Routine Description:
+
+ The data port must be accessed maintaining DWORD alignment. So for example:
+
+ IN DWORD 130
+ IN DWORD 130
+
+ is the same as
+
+ IN USHORT 130
+ IN USHORT 132
+ IN UCHAR 130
+ IN UCHAR 131
+ IN UCHAR 132
+ IN UCHAR 133
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Buffer - Data buffer to read.
+
+ Length - Length of the data buffer in bytes.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ PUCHAR Port;
+
+ Port = (PUCHAR) SdhcExtension->BaseAddress + SDHC_DATA_PORT;
+ while (Length >= sizeof(ULONG)) {
+ SdhcReadRegisterBufferUlong(SdhcExtension,
+ SDHC_DATA_PORT,
+ (PULONG) Buffer,
+ 1);
+
+ Buffer += sizeof(ULONG);
+ Length -= sizeof(ULONG);
+ }
+
+ if (Length >= sizeof(USHORT)) {
+ SdhcReadRegisterBufferUshort(SdhcExtension,
+ SDHC_DATA_PORT,
+ (PUSHORT) Buffer,
+ 1);
+
+ Buffer += sizeof(USHORT);
+ Length -= sizeof(USHORT);
+ }
+
+ if (Length >= sizeof(UCHAR)) {
+ SdhcReadRegisterBufferUchar(SdhcExtension,
+ SDHC_DATA_PORT + sizeof(USHORT),
+ Buffer,
+ 1);
+ }
+}
+
+VOID
+SdhcWriteDataPort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_reads_(Length) PUCHAR Buffer,
+ _In_ ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ The data port must be accessed maintaining DWORD alignment. So for example:
+
+ IN DWORD 130
+ IN DWORD 130
+
+ is the same as
+
+ IN USHORT 130
+ IN USHORT 132
+ IN UCHAR 130
+ IN UCHAR 131
+ IN UCHAR 132
+ IN UCHAR 133
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Buffer - Data buffer to write.
+
+ Length - Length of the data buffer in bytes.
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+ while (Length >= sizeof(ULONG)) {
+ SdhcWriteRegisterBufferUlong(SdhcExtension,
+ SDHC_DATA_PORT,
+ (PULONG) Buffer,
+ 1);
+
+ Buffer += sizeof(ULONG);
+ Length -= sizeof(ULONG);
+ }
+
+ if (Length >= sizeof(USHORT)) {
+ SdhcWriteRegisterBufferUshort(SdhcExtension,
+ SDHC_DATA_PORT,
+ (PUSHORT) Buffer,
+ 1);
+
+ Buffer += sizeof(USHORT);
+ Length -= sizeof(USHORT);
+ }
+
+ if (Length >= sizeof(UCHAR)) {
+ SdhcWriteRegisterBufferUchar(SdhcExtension,
+ SDHC_DATA_PORT + sizeof(USHORT),
+ Buffer,
+ 1);
+ }
+
+ NT_ASSERT((SdhcReadRegisterUshort(SdhcExtension, SDHC_ERROR_STATUS) &
+ SDHC_ES_BAD_DATA_SPACE_ACCESS) == 0);
+}
+
+NTSTATUS
+SdhcBuildTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Prepare the transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Command - The command for which we're building the transfer request.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ NT_ASSERT(Request->Command.TransferType != SdTransferTypeNone);
+
+ NT_ASSERT(Request->Command.TransferMethod != SdTransferMethodUndefined);
+
+ switch (Request->Command.TransferMethod) {
+ case SdTransferMethodPio:
+ Status = SdhcBuildPioTransfer(SdhcExtension, Request);
+ break;
+
+ case SdTransferMethodSgDma:
+ Status = SdhcBuildAdmaTransfer(SdhcExtension, Request);
+ break;
+
+ default:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+SdhcStartTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Execute the transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - The command for which we're building the transfer request.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ NT_ASSERT(Request->Command.TransferType != SdTransferTypeNone);
+
+ switch (Request->Command.TransferMethod) {
+ case SdTransferMethodPio:
+ Status = SdhcStartPioTransfer(SdhcExtension, Request);
+ break;
+
+ case SdTransferMethodSgDma:
+ Status = SdhcStartAdmaTransfer(SdhcExtension, Request);
+ break;
+
+ default:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+SdhcBuildPioTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Prepare the PIO transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - The command for which we're building the transfer.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ return SdhcSetTransferMode(SdhcExtension, Request);
+}
+
+
+NTSTATUS
+SdhcBuildAdmaTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Prepare the ADMA2 transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - The command for which we're building the transfer.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ ULONG TransferLength;
+
+ Status = SdhcSetTransferMode(SdhcExtension, Request);
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ NT_ASSERT(Request->Command.ScatterGatherList != NULL);
+
+ //
+ // Create the ADMA2 descriptor table in the host's DMA buffer.
+ //
+
+ Status =
+ SdhcCreateAdmaDescriptorTable(
+ Request,
+ (BOOLEAN) SdhcExtension->Capabilities.Supported.Address64Bit,
+ &TransferLength);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ SdhcWriteRegisterUlong(SdhcExtension,
+ SDHC_ADMA_SYSADDR_LOW,
+ Request->Command.DmaPhysicalAddress.LowPart);
+
+ if (SdhcExtension->Capabilities.Supported.Address64Bit) {
+ SdhcWriteRegisterUlong(SdhcExtension,
+ SDHC_ADMA_SYSADDR_HIGH,
+ Request->Command.DmaPhysicalAddress.HighPart);
+ } else {
+
+ NT_ASSERT(Request->Command.DmaPhysicalAddress.HighPart == 0);
+
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+SdhcStartPioTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Execute the PIO transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - The command for which we're building the transfer.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ NT_ASSERT((Request->Command.TransferDirection == SdTransferDirectionRead) ||
+ (Request->Command.TransferDirection == SdTransferDirectionWrite));
+
+ if (Request->Command.TransferDirection == SdTransferDirectionRead) {
+ SdhcReadDataPort(SdhcExtension,
+ Request->Command.DataBuffer,
+ Request->Command.BlockSize);
+
+ } else {
+ SdhcWriteDataPort(SdhcExtension,
+ Request->Command.DataBuffer,
+ Request->Command.BlockSize);
+ }
+
+ Request->Command.BlockCount -= 1;
+ if (Request->Command.BlockCount >= 1) {
+ Request->Command.DataBuffer += Request->Command.BlockSize;
+ if (Request->Command.TransferDirection == SdTransferDirectionRead) {
+ Request->RequiredEvents |= SDHC_IS_BUFFER_READ_READY;
+
+ } else {
+ Request->RequiredEvents |= SDHC_IS_BUFFER_WRITE_READY;
+ }
+
+ Request->Status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else {
+
+ NT_ASSERT(Request->Command.BlockCount == 0);
+
+ Request->RequiredEvents |= SDHC_IS_TRANSFER_COMPLETE;
+ Request->Status = STATUS_SUCCESS;
+ }
+
+ return STATUS_PENDING;
+}
+
+NTSTATUS
+SdhcStartAdmaTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ Execute the ADMA2 transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ Request - The command for which we're building the transfer.
+
+Return value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(SdhcExtension);
+
+ Request->Status = STATUS_SUCCESS;
+ SdPortCompleteRequest(Request, Request->Status);
+ return STATUS_SUCCESS;
+}
+
+USHORT
+SdhcCalcClockFrequency(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG TargetFrequency,
+ _Out_opt_ PULONG ActualFrequency
+ )
+
+/*++
+
+Routine Description:
+
+ Execute the ADMA2 transfer request.
+
+Arguments:
+
+ SdhcExtension - Host controller specific driver context.
+
+ TargetFrequency - The frequency in kHz to which we want to set the bus.
+
+ ActualFrequency - The actual frequency to which the bus is set.
+
+Return value:
+
+ ClockControl - The value of the Clock Control register to be written.
+
+--*/
+
+{
+
+ ULONG BaseFrequency;
+ USHORT ClockControl;
+ ULONG Divisor;
+ USHORT SpecVersion;
+
+ *ActualFrequency = 0;
+ BaseFrequency = SdhcExtension->Capabilities.BaseClockFrequencyKhz;
+ Divisor = MAX(BaseFrequency / TargetFrequency, 1);
+
+ NT_ASSERT(Divisor > 0);
+
+ SpecVersion = SdhcReadRegisterUshort(SdhcExtension, SDHC_VERSION) & 0xFF;
+ if (SpecVersion > SDHC_SPEC_VERSION_3) {
+
+ //
+ // Calculate the fastest available clock frequency which is <=
+ // tthe requested frequency.
+ //
+
+ Divisor = 1;
+ while (((BaseFrequency / Divisor) > TargetFrequency) &&
+ (Divisor < SDHC_MAX_CLOCK_DIVISOR)) {
+
+ Divisor <<= 1;
+ }
+
+ *ActualFrequency = BaseFrequency / Divisor;
+ Divisor >>= 1;
+ ClockControl = ((USHORT) Divisor << 8);
+
+ } else {
+
+ //
+ // Host controller version 3.0 supports the 10-bit divided clock mode.
+ //
+
+ Divisor = BaseFrequency / TargetFrequency;
+ Divisor >>= 1;
+ if ((TargetFrequency < BaseFrequency) &&
+ (TargetFrequency * 2 * Divisor != BaseFrequency)) {
+
+ Divisor += 1;
+ }
+
+ if (Divisor > SDHC_MAX_CLOCK_DIVISOR_SPEC_3 / 2) {
+ Divisor = SDHC_MAX_CLOCK_DIVISOR_SPEC_3 / 2;
+ }
+
+ if (Divisor == 0) {
+ *ActualFrequency = BaseFrequency;
+
+ } else {
+ *ActualFrequency = BaseFrequency / Divisor;
+ *ActualFrequency >>= 1;
+ }
+
+ ClockControl = ((USHORT) Divisor & 0xFF) << 8;
+ Divisor >>= 8;
+ ClockControl |= ((USHORT) Divisor & 0x03) << 6;
+ }
+
+ NT_ASSERT((BaseFrequency <= TargetFrequency) ? (Divisor == 0) : TRUE);
+
+ return ClockControl;
+}
+
+NTSTATUS
+SdhcCreateAdmaDescriptorTable(
+ _In_ PSDPORT_REQUEST Request,
+ _In_ BOOLEAN Use64BitDescriptor,
+ _Out_ PULONG TotalTransferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a ADMA descriptor table based on scattor gatther list
+ given by Sglist.
+
+Arguments:
+
+ Socket - Supplies the pointer to the socket
+
+ Request - Data transfer request for which to build the descriptor table.
+
+ TotalTransferLength - Supplies the pointer to return the total transfer
+ length of the descriptor table
+
+Return value:
+
+ Whether the table was successfully created.
+
+--*/
+
+{
+
+ PUCHAR Buffer;
+ PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY Descriptor;
+ ULONG NumberOfElements;
+ PHYSICAL_ADDRESS NextAddress;
+ ULONG NextLength;
+ ULONG RemainingLength;
+ PSCATTER_GATHER_ELEMENT SglistElement;
+
+ Buffer = Request->Command.DmaVirtualAddress;
+ Descriptor = NULL;
+ NumberOfElements = Request->Command.ScatterGatherList->NumberOfElements;
+ SglistElement = &Request->Command.ScatterGatherList->Elements[0];
+ *TotalTransferLength = 0;
+
+ NT_ASSERT(NumberOfElements > 0);
+
+ //
+ // Iterate through each element in the SG list and convert it into the
+ // descriptor table required by the controller.
+ //
+
+ while (NumberOfElements > 0) {
+ RemainingLength = SglistElement->Length;
+ NextAddress.QuadPart = SglistElement->Address.QuadPart;
+
+ NT_ASSERT(RemainingLength > 0);
+
+ while (RemainingLength > 0) {
+ Descriptor = (PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY) Buffer;
+ Buffer += sizeof(SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY);
+
+ NT_ASSERT((ULONG_PTR) Buffer <
+ (ULONG_PTR) Request->Command.DmaVirtualAddress +
+ Request->Command.Length);
+
+ NextLength = MIN(SDHC_ADMA2_MAX_LENGTH_PER_ENTRY, RemainingLength);
+ RemainingLength -= NextLength;
+
+ //
+ // Set the entry attributes and length.
+ //
+
+ Descriptor->AsUlong = 0;
+ Descriptor->Action = SDHC_ADMA2_ACTION_TRAN;
+ Descriptor->Attribute = SDHC_ADMA2_ATTRIBUTE_VALID;
+ Descriptor->Length = NextLength;
+ *TotalTransferLength += NextLength;
+
+ //
+ // Set the address field.
+ //
+
+ if (Use64BitDescriptor) {
+ *((PULONGLONG) Buffer) = NextAddress.QuadPart;
+ Buffer += sizeof(LONGLONG);
+
+ } else {
+
+ //
+ // The HighPart should not be a non-zero value, since in the
+ // DMA adapter object, we declared that this device only
+ // supports 32-bit addressing.
+ //
+
+ NT_ASSERT(NextAddress.HighPart == 0);
+
+ *((PULONG) Buffer) = NextAddress.LowPart;
+ Buffer += sizeof(ULONG);
+ }
+
+ NextAddress.QuadPart += NextLength;
+ }
+
+ SglistElement += 1;
+ NumberOfElements -= 1;
+
+ //
+ // Set the END bit if we're at the last element.
+ //
+
+ if (NumberOfElements == 0) {
+ Descriptor->Attribute |= SDHC_ADMA2_ATTRIBUTE_END;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+SdhcInitializePciConfigSpace(
+ _In_ PSD_MINIPORT Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the PCI configuration space.
+
+Arguments:
+
+ Argument - Pointer to the functional device object extension for the SD host controller
+
+Return value:
+
+ None.
+
+--*/
+
+{
+
+
+
+
+
+
+
+
+ if (Miniport->ConfigurationInfo.BusType != SdBusTypePci) {
+ return;
+ }
+
+ //
+ // Some PCI based controllers require access to PCI configuration
+ // space to enable certain features. In order to do this, sdport
+ // provides two APIs, SdPortGetPciConfigSpace and
+ // SdPortSetPciConfigSpace to access various PCI configuration
+ // registers. For example, to access offset 0xA0 and unset bit
+ // 31 (hypothetically to turn on or off a feature):
+ //
+ // ULONG PciConfig;
+ //
+ // PciConfig = 0;
+ // SdPortGetPciConfigSpace(Miniport,
+ // 0xA0,
+ // (PUCHAR)&PciConfig,
+ // sizeof(PciConfig));
+ //
+ // PciConfig &= ~(1 << 31);
+ // SdPortSetPciConfigSpace(Miniport,
+ // 0xA0,
+ // (PUCHAR)&PciConfig,
+ // sizeof(PciConfig));
+ //
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/sd/miniport/sdhc/sdhc.h b/sd/miniport/sdhc/sdhc.h
new file mode 100644
index 00000000..e16044b7
--- /dev/null
+++ b/sd/miniport/sdhc/sdhc.h
@@ -0,0 +1,2091 @@
+/*++
+
+Copyright (c) 2014 Microsoft Corporation
+
+Module Name:
+
+ sdhc.h
+
+Abstract:
+
+ Header for default standard host controller implementation.
+
+Author:
+
+ Greg Garbern (greggar) 01-May-2014
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Greg Garbern (greggar) 12-June-2014
+
+--*/
+
+#if defined (_MSC_VER) && (_MSC_VER > 1000)
+#pragma once
+#endif
+
+#pragma warning(disable:4214) // bit field types other than int
+#pragma warning(disable:4201) // nameless struct/union
+#pragma warning(disable:4115) // named type definition in parentheses
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//
+// Memory registers
+//
+
+#define SDHC_SYSADDR 0x00
+#define SDHC_BLOCK_SIZE 0x04
+#define SDHC_BLOCK_COUNT 0x06
+#define SDHC_ARGUMENT 0x08
+#define SDHC_TRANSFER_MODE 0x0c
+#define SDHC_COMMAND 0x0e
+#define SDHC_RESPONSE 0x10
+#define SDHC_DATA_PORT 0x20
+#define SDHC_PRESENT_STATE 0x24
+#define SDHC_HOST_CONTROL 0x28
+#define SDHC_POWER_CONTROL 0x29
+#define SDHC_BLOCKGAP_CONTROL 0x2a
+#define SDHC_WAKEUP_CONTROL 0x2b
+#define SDHC_CLOCK_CONTROL 0x2c
+#define SDHC_TIMEOUT_CONTROL 0x2e
+#define SDHC_RESET 0x2f
+#define SDHC_INTERRUPT_STATUS 0x30
+#define SDHC_ERROR_STATUS 0x32
+#define SDHC_INTERRUPT_STATUS_ENABLE 0x34
+#define SDHC_ERROR_STATUS_ENABLE 0x36
+#define SDHC_INTERRUPT_SIGNAL_ENABLE 0x38
+#define SDHC_ERROR_SIGNAL_ENABLE 0x3a
+#define SDHC_AUTO_CMD12_ERROR_STATUS 0x3c
+#define SDHC_HOST_CONTROL2 0x3e
+#define SDHC_CAPABILITIES 0x40
+#define SDHC_CAPABILITIES2 0x44
+#define SDHC_MAXIMUM_CURRENT 0x48
+#define SDHC_ADMA_ERROR_STATUS 0x54
+#define SDHC_ADMA_SYSADDR_LOW 0x58
+#define SDHC_ADMA_SYSADDR_HIGH 0x5c
+
+
+#define SDHC_SLOT_INFORMATION 0xfc
+#define SDHC_VERSION 0xfe
+
+//
+// Bits defined in SDHC_TRANSFER_MODE
+//
+
+#define SDHC_TM_DMA_ENABLE 0x0001
+#define SDHC_TM_BLKCNT_ENABLE 0x0002
+#define SDHC_TM_AUTO_CMD12_ENABLE 0x0004
+#define SDHC_TM_AUTO_CMD23_ENABLE 0x0008
+#define SDHC_TM_TRANSFER_READ 0x0010
+#define SDHC_TM_MULTIBLOCK 0x0020
+
+//
+// Bits defined in SDHC_COMMAND
+//
+
+#define SDHC_CMD_RESPONSE_136BIT 0x0001
+#define SDHC_CMD_RESPONSE_48BIT_NOBUSY 0x0002
+#define SDHC_CMD_RESPONSE_48BIT_WBUSY 0x0003
+
+#define SDHC_CMD_CRC_CHECK_ENABLE 0x0008
+#define SDHC_CMD_INDEX_CHECK_ENABLE 0x0010
+#define SDHC_CMD_DATA_PRESENT 0x0020
+
+#define SDHC_CMD_TYPE_SUSPEND 0x0040
+#define SDHC_CMD_TYPE_RESUME 0x0080
+#define SDHC_CMD_TYPE_ABORT 0x0060
+
+//
+// Bits defined in SDHC_PRESENT_STATE
+//
+
+#define SDHC_PS_CMD_INHIBIT 0x00000001
+#define SDHC_PS_DAT_INHIBIT 0x00000002
+#define SDHC_PS_DAT_ACTIVE 0x00000004
+#define SDHC_PS_RETUNING_REQUEST 0x00000008
+#define SDHC_PS_WRITE_TRANSFER_ACTIVE 0x00000100
+#define SDHC_PS_READ_TRANSFER_ACTIVE 0x00000200
+#define SDHC_PS_BUFFER_WRITE_ENABLE 0x00000400
+#define SDHC_PS_BUFFER_READ_ENABLE 0x00000800
+
+#define SDHC_PS_CARD_INSERTED 0x00010000
+#define SDHC_PS_CARD_STATE_STABLE 0x00020000
+#define SDHC_PS_CARD_DETECT 0x00040000
+#define SDHC_PS_WRITE_PROTECT 0x00080000
+
+#define SDHC_PS_DAT0_SIGNAL 0x00100000
+#define SDHC_PS_DAT1_SIGNAL 0x00200000
+#define SDHC_PS_DAT2_SIGNAL 0x00400000
+#define SDHC_PS_DAT3_SIGNAL 0x00800000
+
+#define SDHC_PS_DAT_3_0 (SDHC_PS_DAT0_SIGNAL | \
+ SDHC_PS_DAT1_SIGNAL | \
+ SDHC_PS_DAT2_SIGNAL | \
+ SDHC_PS_DAT3_SIGNAL)
+
+#define SDHC_PS_CMD_SIGNAL 0x01000000
+
+//
+// Bits defined in SDHC_HOST_CONTROL
+//
+
+#define SDHC_HC_LED_POWER 0x01
+#define SDHC_HC_DATA_WIDTH_4BIT 0x02
+#define SDHC_HC_ENABLE_HIGH_SPEED 0x04
+#define SDHC_HC_DATA_WIDTH_8BIT 0x20
+
+#define SDHC_HC_DMA_SELECT_MASK 0x18
+#define SDHC_HC_DMA_SELECT_SDMA 0x00
+#define SDHC_HC_DMA_SELECT_ADMA32 0x10
+#define SDHC_HC_DMA_SELECT_ADMA64 0x18
+
+//
+// Bits defined in SDHC_HOST_CONTROL2
+//
+
+#define SDHC_HC2_SDR12 0x0000
+#define SDHC_HC2_SDR25 0x0001
+#define SDHC_HC2_SDR50 0x0002
+#define SDHC_HC2_SDR104 0x0003
+#define SDHC_HC2_DDR50 0x0004
+#define SDHC_HC2_HS200 0x0005
+
+#define SDHC_HC2_UHS_MODES (SDHC_HC2_SDR12 | \
+ SDHC_HC2_SDR25 | \
+ SDHC_HC2_SDR50 | \
+ SDHC_HC2_SDR104| \
+ SDHC_HC2_DDR50 | \
+ SDHC_HC2_HS200)
+
+#define SDHC_HC2_1_8V_SIGNALING 0x0008
+
+#define SDHC_HC2_SELECT_TYPE_B 0x0000
+#define SDHC_HC2_SELECT_TYPE_A 0x0010
+#define SDHC_HC2_SELECT_TYPE_C 0x0020
+#define SDHC_HC2_SELECT_TYPE_D 0x0030
+
+#define SDHC_HC2_EXECUTE_TUNING 0x0040
+#define SDHC_HC2_SELECT_SAMPLING_CLOCK 0x0080
+#define SDHC_HC2_ENABLE_ASYNC_INTERRUPT 0x4000
+#define SDHC_HC2_ENABLE_PRESET_VALUE 0x8000
+
+//
+// Bits defined in SDHC_POWER_CONTROL
+//
+
+#define SDHC_PC_BUS_POWER 0x01
+#define SDHC_PC_1_8V 0x0a
+#define SDHC_PC_3_0V 0x0c
+#define SDHC_PC_3_3V 0x0e
+
+#define SDHC_PC_VOLTAGE_MASK 0x0e
+
+//
+// Bits defined in SDHC_BLOCKGAP_CONTROL
+//
+
+#define SDHC_BGC_STOP_NEXT_GAP 0x01
+#define SDHC_BGC_CONTINUE 0x02
+#define SDHC_BGC_READ_WAIT_ENABLE 0x04
+#define SDHC_BGC_INTERRUPT_ENABLE 0x08
+
+//
+// Bits defined in SDHC_WAKEUP_CONTROL
+//
+
+#define SDHC_WC_CARD_INT_ENABLE 0x01
+#define SDHC_WC_CARD_INSERTION_ENABLE 0x02
+#define SDHC_WC_CARD_REMOVAL_ENABLE 0x04
+#define SDHC_WC_CARD_SUPPORTS_WAKEUP 0x80
+
+
+//
+// Bits defined in SDHC_CLOCK_CONTROL
+//
+
+#define SDHC_CC_INTERNAL_CLOCK_ENABLE 0x0001
+#define SDHC_CC_CLOCK_STABLE 0x0002
+#define SDHC_CC_CLOCK_ENABLE 0x0004
+#define SDHC_CC_CLOCK_DIVISOR_2 0x0100
+#define SDHC_CC_CLOCK_DIVISOR_4 0x0200
+#define SDHC_CC_CLOCK_DIVISOR_8 0x0400
+#define SDHC_CC_CLOCK_DIVISOR_16 0x0800
+#define SDHC_CC_CLOCK_DIVISOR_32 0x1000
+#define SDHC_CC_CLOCK_DIVISOR_64 0x2000
+#define SDHC_CC_CLOCK_DIVISOR_128 0x4000
+#define SDHC_CC_CLOCK_DIVISOR_256 0x8000
+
+
+//
+// Bits defined in SDHC_TIMEOUT_CONTROL
+//
+
+#define SDHC_TC_COUNTER_MASK 0x0f
+#define SDHC_TC_MAX_DATA_TIMEOUT 0x0e
+
+//
+// Bits defined in SDHC_RESET
+//
+
+#define SDHC_RESET_ALL 0x01
+#define SDHC_RESET_CMD 0x02
+#define SDHC_RESET_DAT 0x04
+
+//
+// Bits defined in SDHC_INTERRUPT_STATUS
+// SDHC_INTERRUPT_STATUS_ENABLE
+// SDHC_INTERRUPT_SIGNAL_ENABLE
+//
+
+#define SDHC_IS_CMD_COMPLETE 0x0001
+#define SDHC_IS_TRANSFER_COMPLETE 0x0002
+#define SDHC_IS_BLOCKGAP_EVENT 0x0004
+#define SDHC_IS_DMA_EVENT 0x0008
+#define SDHC_IS_BUFFER_WRITE_READY 0x0010
+#define SDHC_IS_BUFFER_READ_READY 0x0020
+#define SDHC_IS_CARD_INSERTION 0x0040
+#define SDHC_IS_CARD_REMOVAL 0x0080
+#define SDHC_IS_CARD_INTERRUPT 0x0100
+#define SDHC_IS_TUNING_INTERRUPT 0x1000
+
+#define SDHC_IS_ERROR_INTERRUPT 0x8000
+
+#define SDHC_IS_CARD_DETECT (SDHC_IS_CARD_INSERTION | SDHC_IS_CARD_REMOVAL)
+
+//
+// Bits defined in SDHC_ERROR_STATUS
+// Bits defined in SDHC_ERROR_STATUS_ENABLE
+// Bits defined in SDHC_ERROR_SIGNAL_ENABLE
+//
+// PLEASE NOTE: these values need to match exactly the
+// "generic" values in sdbus.h
+//
+
+#define SDHC_ES_CMD_TIMEOUT 0x0001
+#define SDHC_ES_CMD_CRC_ERROR 0x0002
+#define SDHC_ES_CMD_END_BIT_ERROR 0x0004
+#define SDHC_ES_CMD_INDEX_ERROR 0x0008
+#define SDHC_ES_DATA_TIMEOUT 0x0010
+#define SDHC_ES_DATA_CRC_ERROR 0x0020
+#define SDHC_ES_DATA_END_BIT_ERROR 0x0040
+#define SDHC_ES_BUS_POWER_ERROR 0x0080
+#define SDHC_ES_AUTO_CMD12_ERROR 0x0100
+#define SDHC_ES_ADMA_ERROR 0x0200
+#define SDHC_ES_BAD_DATA_SPACE_ACCESS 0x2000
+
+//
+// Bits defined in SDHC_AUTO_CMD12_ERROR_STATUS
+//
+
+#define SDHC_ACMD12_NOT_EXECUTED 0x0001
+#define SDHC_ACMD12_RESPONSE_TIMEOUT 0x0002
+#define SDHC_ACMD12_RESPONSE_CRC_ERROR 0x0004
+#define SDHC_ACMD12_END_BIT_ERROR 0x0008
+#define SDHC_ACMD12_INDEX_ERROR 0x0010
+#define SDHC_ACMD12_CWODAT_NOT_EXECUTED 0x0080
+
+
+#define SDHC_MAX_CLOCK_DIVISOR 256
+#define SDHC_MAX_CLOCK_DIVISOR_SPEC_3 2046
+
+
+//
+// determines the poll interval for host reset and clock setting (10ms)
+//
+
+#define SDHC_DEFAULT_POLL_INTERVAL 10000
+
+//
+// determines the poll count (10 ms * 100 tries = 1 second)
+//
+
+#define SDHC_DEFAULT_POLL_COUNT 100
+
+#define SDHC_MAX_SET_POWER_RETRIES 5
+
+#define SDHC_ALIGNMENT_SDMA 1
+#define SDHC_ALIGNMENT_ADMA2 3
+#define SDHC_ALIGNMENT_ADMA2_64 7
+
+#define SDHC_SPEC_VERSION_1 0
+#define SDHC_SPEC_VERSION_2 1
+#define SDHC_SPEC_VERSION_3 2
+
+//----------------------------------------------------------------------------
+// Host register layout
+//----------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+//
+// SD card information
+//
+// ---------------------------------------------------------------------------
+
+#pragma pack(push)
+#pragma pack(1)
+
+//
+// The entire layout of an SD host controller in memory for debug purposes.
+//
+
+typedef struct _SD_HOST_CONTROLLER_REGISTERS {
+
+ union {
+ struct {
+ USHORT Low;
+ USHORT High;
+ } Argument2;
+ struct {
+ USHORT Low;
+ USHORT High;
+ } SDMAAddress;
+ } Argument2;
+
+ USHORT BlockSize; // 04h
+
+ USHORT BlockCount; // 06h
+
+ union {
+ struct {
+ USHORT Low; // 08h
+ USHORT High; // 0Ah
+ } Argument1;
+ ULONG Ulong;
+ } Argument1;
+
+ union {
+ struct {
+ USHORT DMAEnable : 1;
+ USHORT BlockCountEnable : 1;
+ USHORT AutoCommandEnable : 2;
+ USHORT DataTransferDirectionSelect : 1;
+ USHORT MultiBlockSelect : 1;
+ USHORT Reserved0 : 10;
+ } Flags;
+ USHORT Value; // 0Ch
+ } TransferMode;
+
+ union {
+ struct {
+ USHORT ResponseTypeSelect : 2;
+ USHORT Reserved0 : 1;
+ USHORT CommandCRCCheckEnable : 1;
+ USHORT CommandIndexCheckEnable : 1;
+ USHORT DataPresentSelect : 1;
+ USHORT CommandType : 2;
+ USHORT CommandIndex : 6;
+ USHORT Reserved1 : 2;
+ } Flags;
+ USHORT Value; // 0Eh
+ } Command;
+
+ union {
+
+ struct {
+ union {
+ struct {
+ ULONG ReservedManufacturerTest0 : 1;
+ ULONG ReservedManufacturerTest1 : 1;
+ ULONG ReservedAppspecific : 1;
+ ULONG AKE_SEQ_ERROR : 1;
+ ULONG ReservedSDIO : 1;
+ ULONG APP_CMD : 1;
+ ULONG Reserved0 : 2;
+ ULONG READY_FOR_DATA : 1;
+ ULONG CURRENT_STATE : 4;
+ ULONG ERASE_RESSET : 1;
+ ULONG CARD_ECC_DISABLE : 1;
+ ULONG WP_ERASE_SKIP : 1;
+ ULONG CSD_OVERWRITE : 1;
+ ULONG RESERVED_DEFERRED_RESPONSE : 1;
+ ULONG RESERVED : 1;
+ ULONG ERROR : 1;
+ ULONG CC_ERROR : 1;
+ ULONG CARD_ECC_FAILED : 1;
+ ULONG ILLEGAL_COMMAND : 1;
+ ULONG COM_CRC_ERROR : 1;
+ ULONG LOCK_UNLOCK_FAILED : 1;
+ ULONG CARD_IS_LOCKED : 1;
+ ULONG WP_VIOLATION : 1;
+ ULONG ERASE_PARAM : 1;
+ ULONG ERASE_SEQ_ERROR : 1;
+ ULONG BLOCK_LEN_ERROR : 1;
+ ULONG ADDRESS_ERROR : 1;
+ ULONG OUT_OF_RANGE : 1;
+ } Flags;
+ ULONG Ulong;
+ } CardStatus;
+ } R1;
+
+ struct {
+ ULONG Reserved0[3];
+ ULONG CardStatus;
+ } R1b;
+
+ struct {
+ union {
+
+ struct {
+ USHORT ManufacturingData : 12;
+ USHORT Reserved0 : 4;
+ ULONG SerialNumber;
+ UCHAR Revision;
+ UCHAR ProductName[5];
+ USHORT ApplicationID;
+ UCHAR ManufactureID;
+ } CID;
+
+ struct {
+ UCHAR Reserved0 : 2;
+ UCHAR FILE_FORMAT : 2;
+ UCHAR TMP_WRITE_PROTECT : 1;
+ UCHAR PERM_WRITE_PROTECT : 1;
+ UCHAR COPY : 1;
+ UCHAR FILE_FORMAT_GRP : 1;
+
+ USHORT Reserved1 : 5;
+ USHORT WRITE_BL_PARTIAL : 1;
+ USHORT WRITE_BL_LEN : 4;
+ USHORT R2W_FACTOR : 3;
+ USHORT Reserved2 : 2;
+ USHORT WP_GRP_ENABLE : 1;
+
+ ULONG WP_GRP_SIZE : 7;
+ ULONG SECTOR_SIZE : 7;
+ ULONG ERASE_BLK_EN : 1;
+ ULONG C_SIZE_MULT : 3;
+ ULONG VDD_W_CURR_MAX : 3;
+ ULONG VDD_W_CURR_MIN : 3;
+ ULONG VDD_R_CURR_MAX : 3;
+ ULONG VDD_R_CURR_MIN : 3;
+ ULONG C_SIZE_LOW : 2;
+
+ ULONG C_SIZE_HIGH : 10;
+ ULONG Reserved3 : 2;
+ ULONG DSR_IMP : 1;
+ ULONG READ_BLK_MISALIGN : 1;
+ ULONG WRITE_BLK_MISALIGN : 1;
+ ULONG READ_BL_PARTIAL : 1;
+ ULONG READ_BL_LEN : 4;
+ ULONG CCC : 12;
+
+ UCHAR TRAN_SPEED;
+ UCHAR NSAC;
+ UCHAR TAAC;
+
+ UCHAR Reserved4 : 6;
+ UCHAR CSD_STRUCTURE : 2;
+ } CSDv1;
+
+ struct {
+ UCHAR Reserved0 : 2;
+ UCHAR FILE_FORMAT : 2;
+ UCHAR TMP_WRITE_PROTECT : 1;
+ UCHAR PERM_WRITE_PROTECT : 1;
+ UCHAR COPY : 1;
+ UCHAR FILE_FORMAT_GRP : 1;
+
+ USHORT Reserved1 : 5;
+ USHORT WRITE_BL_PARTIAL : 1;
+ USHORT WRITE_BL_LEN : 4;
+ USHORT R2W_FACTOR : 3;
+ USHORT Reserved2 : 2;
+ USHORT WP_GRP_ENABLE : 1;
+
+ ULONG WP_GRP_SIZE : 7;
+ ULONG SECTOR_SIZE : 7;
+ ULONG ERASE_BLK_EN : 1;
+ ULONG Reserved3 : 1;
+ ULONG DeviceSizeLow : 16;
+
+ ULONG DeviceSizeHigh : 6;
+ ULONG Reserved4 : 6;
+ ULONG DSR_IMP : 1;
+ ULONG READ_BLK_MISALIGN : 1;
+ ULONG WRITE_BLK_MISALIGN : 1;
+ ULONG READ_BL_PARTIAL : 1;
+ ULONG READ_BL_LEN : 4;
+ ULONG CCC : 12;
+
+ UCHAR TRAN_SPEED : 8;
+ UCHAR NSAC : 8;
+ UCHAR TAAC : 8;
+ UCHAR Reserved5 : 6;
+ UCHAR CSD_STRUCTURE : 2;
+ } CSDv2;
+ } Register;
+ } R2;
+
+ struct {
+ union {
+ struct {
+ ULONG Reserved0 : 7;
+ ULONG ReservedLowVoltageRange : 1;
+ ULONG Reserved1 : 7;
+ ULONG Voltage27V_28V : 1;
+ ULONG Voltage28V_29V : 1;
+ ULONG Voltage29V_30V : 1;
+ ULONG Voltage30V_31V : 1;
+ ULONG Voltage31V_32V : 1;
+ ULONG Voltage32V_33V : 1;
+ ULONG Voltage33V_34V : 1;
+ ULONG Voltage34V_35V : 1;
+ ULONG Voltage35V_36V : 1;
+ ULONG SwitchingTo18VAccepted : 1;
+ ULONG Reserved2 : 5;
+ ULONG CardCapacityStatus : 1;
+ ULONG CardPowerUpStatus : 1;
+ } Flags;
+ ULONG ULong;
+ } Ocr;
+ } R3;
+
+ struct {
+ UCHAR Buffer[16];
+ } R4;
+
+ struct {
+ UCHAR Buffer[16];
+ } R5;
+
+ struct {
+ union {
+ struct {
+ USHORT ReservedManufacturerTest0 : 1;
+ USHORT ReservedManufacturerTest1 : 1;
+ USHORT ReservedAppspecific : 1;
+ USHORT AKE_SEQ_ERROR : 1;
+ USHORT ReservedSDIO : 1;
+ USHORT APP_CMDEnable : 1;
+ USHORT Reserved0 : 2;
+ USHORT READY_FOR_DATA : 1;
+ USHORT CurrentState : 4;
+
+ USHORT ERROR : 1;
+ USHORT ILLEGAL_COMMAND : 1;
+ USHORT COM_CRC_ERROR : 1;
+ } Flags;
+ USHORT Register;
+ } CardStatusBits;
+
+ USHORT NewRCA : 16;
+ } R6;
+
+ struct {
+ ULONG CheckPattern : 8;
+ ULONG VoltageAccepted : 4;
+ ULONG Reserved : 20;
+ } R7;
+
+ struct {
+ USHORT Response0; // 10h
+ USHORT Response1; // 12h
+ USHORT Response2; // 14h
+ USHORT Response3; // 16h
+ USHORT Response4; // 18h
+ USHORT Response5; // 1Ah
+ USHORT Response6; // 1Ch
+ USHORT Response7; // 1Eh
+ } Words;
+ UCHAR Buffer[16];
+ } Response;
+
+ union {
+ struct {
+ USHORT BufferDataPort0; // 20h
+ USHORT BufferDataPort1; // 22h
+ } Words;
+ ULONG Port;
+ } BufferDataPort;
+
+ union {
+ struct {
+ USHORT PresentState0; // 24h
+ USHORT PresentState1; // 26h
+ } Words;
+ struct {
+ ULONG CommandInhibitCMD : 1;
+ ULONG CommandInhibitDAT : 1;
+ ULONG DATLineActive : 1;
+ ULONG ReTuningRequest : 1;
+ ULONG Reserved0 : 4;
+ ULONG WriteTransferActive : 1;
+ ULONG ReadTransferActive : 1;
+ ULONG BufferWriteEnable : 1;
+ ULONG BufferReadEnable : 1;
+ ULONG Reserved1 : 4;
+ ULONG CardInserted : 1;
+ ULONG CardStateStable : 1;
+ ULONG CardDetectPinLevel : 1;
+ ULONG WriteProtectSwitchPinLevel : 1;
+ ULONG DATLineSignalLevel : 4;
+ ULONG CMDLineSignalLevel : 1;
+ ULONG Reserved2 : 7;
+ } Flags;
+ } PresentState;
+
+ union {
+ struct {
+ UCHAR LEDControlOn : 1;
+ UCHAR DataTransferWidth4Bit : 1;
+ UCHAR HighSpeedEnable : 1;
+ UCHAR DMASelect : 2;
+ UCHAR ExtendedDataTransferWidth8Bit : 1;
+ UCHAR CardDetectTestLevelCardInserted : 1;
+ UCHAR CardDetectSignalSelectionEnable : 1;
+ } Flags;
+ UCHAR Byte; // 28h
+ } HostControl1;
+
+ union {
+ struct {
+ UCHAR SDBusPowerOn : 1;
+ UCHAR SDBUSVoltageSelect : 3;
+ UCHAR Reserved0 : 4;
+ } Flags;
+ UCHAR Byte; // 29h
+ } PowerControl;
+
+ union {
+ struct {
+ UCHAR StopAtBlockGapRequest : 1;
+ UCHAR ContinueRequest : 1;
+ UCHAR ReadWaitControlEnable : 1;
+ UCHAR InterruptAtBlockGapEnable : 1;
+ UCHAR Reserved0 : 4;
+ } Flags;
+ UCHAR Byte; // 2Ah
+ } BlockGapControl;
+
+ union {
+ struct {
+ UCHAR WakeupEventEnableOnSDCardInterrupt : 1;
+ UCHAR WakeupEventEnableOnSDCardInsertion : 1;
+ UCHAR WakeupEventEnableOnSDCardRemoval : 1;
+ UCHAR Reserved0 : 5;
+ } Flags;
+ UCHAR Byte; // 2Bh
+ } WakeupControl;
+
+ union {
+ struct {
+ USHORT InternalClockEnable : 1;
+ USHORT InternalClockStable : 1;
+ USHORT SDClockEnable : 1;
+ USHORT Reserved0 : 2;
+ USHORT ClockGeneratorSelectProgrammable : 1;
+ USHORT FrequencySelectUpperBits : 2;
+ USHORT FrequencySelectLowerBits : 8;
+ } Flags;
+ USHORT Word; // 2Ch
+ } ClockControl;
+
+ union {
+ struct {
+ UCHAR DataTimeoutCounterValue : 4;
+ UCHAR Reserved0 : 4;
+ } Flags;
+ UCHAR Byte; // 2Eh
+ } TimeoutControl;
+
+ union {
+ struct {
+ UCHAR SoftwareResetForAll : 1;
+ UCHAR SoftwareResetForCMDLine : 1;
+ UCHAR SoftwareResetForDATLine : 1;
+ UCHAR Reserved0 : 5;
+ } Flags;
+ UCHAR Byte; // 2Fh
+ } SoftwareReset;
+
+ union {
+ struct {
+ USHORT CommandComplete : 1;
+ USHORT TransferComplete : 1;
+ USHORT BlockGapEvent : 1;
+ USHORT DMAInterrupt : 1;
+ USHORT BufferWriteReady : 1;
+ USHORT BufferReadReady : 1;
+ USHORT CardInsertion : 1;
+ USHORT CardRemoval : 1;
+ USHORT CardInterrupt : 1;
+ USHORT INT_A : 1;
+ USHORT INT_B : 1;
+ USHORT INT_C : 1;
+ USHORT RetuningEvent : 1;
+ USHORT Reserved0 : 2;
+ USHORT ErrorInterrupt : 1;
+ } Flags;
+ USHORT Word;
+ } NormalInterruptStatus;
+
+ union {
+ struct {
+ USHORT CommandTimeoutError : 1;
+ USHORT CommandCRCError : 1;
+ USHORT CommandEndBitError : 1;
+ USHORT CommandIndexError : 1;
+ USHORT DataTimeoutError : 1;
+ USHORT DataCRCError : 1;
+ USHORT DataEndBitError : 1;
+ USHORT CurrentLimitError : 1;
+ USHORT AutoCMD12Error : 1;
+ USHORT ADMAError : 1;
+ USHORT TuningError : 1;
+ USHORT Reserved0 : 1;
+ USHORT VendorSpecific : 4;
+ } Flags;
+ USHORT Word;
+ } ErrorInterruptStatus;
+
+ union {
+ struct {
+ USHORT CommandCompleteStatusEnable : 1;
+ USHORT TransferCompleteStatusEnable : 1;
+ USHORT BlockGapEventStatusEnable : 1;
+ USHORT DMAInterruptStatusEnable : 1;
+ USHORT BufferWriteReadyStatusEnable : 1;
+ USHORT BufferReadReadyStatusEnable : 1;
+ USHORT CardInsertionStatusEnable : 1;
+ USHORT CardRemovalStatusEnable : 1;
+ USHORT CardInterruptStatusEnable : 1;
+ USHORT INT_AStatusEnable : 1;
+ USHORT INT_BStatusEnable : 1;
+ USHORT INT_CStatusEnable : 1;
+ USHORT RetuningEventStatusEnable : 1;
+ USHORT Reserved0 : 2;
+ USHORT FixedToZero : 1;
+ } Flags;
+ USHORT Word; // 34h
+ } NormalInterruptStatusEnable;
+
+ union {
+ struct {
+ USHORT CommandTimeoutErrorStatusEnable : 1;
+ USHORT CommandCRCErrorStatusEnable : 1;
+ USHORT CommandEndBitErrorStatusEnable : 1;
+ USHORT CommandIndexErrorStatusEnable : 1;
+ USHORT DataTimeoutErrorStatusEnable : 1;
+ USHORT DataCRCErrorStatusEnable : 1;
+ USHORT DataEndBitErrorStatusEnable : 1;
+ USHORT CurrentLimitErrorStatusEnable : 1;
+ USHORT AutoCMD12ErrorStatusEnable : 1;
+ USHORT ADMAErrorStatusEnable : 1;
+ USHORT TuningErrorStatusEnable : 1;
+ USHORT Reserved0 : 1;
+ USHORT VendorSpecificStatusEnable : 4;
+ } Flags;
+ USHORT Word;
+ } ErrorInterruptStatusEnable; // 36h
+
+ union {
+ struct {
+ USHORT CommandCompleteSignalEnable : 1;
+ USHORT TransferCompleteSignalEnable : 1;
+ USHORT BlockGapEventSignalEnable : 1;
+ USHORT DMAInterruptSignalEnable : 1;
+ USHORT BufferWriteReadySignalEnable : 1;
+ USHORT BufferReadReadySignalEnable : 1;
+ USHORT CardInsertionSignalEnable : 1;
+ USHORT CardRemovalSignalEnable : 1;
+ USHORT CardInterruptSignalEnable : 1;
+ USHORT INT_ASignalEnable : 1;
+ USHORT INT_BSignalEnable : 1;
+ USHORT INT_CSignalEnable : 1;
+ USHORT RetuningEventSignalEnable : 1;
+ USHORT Reserved0 : 2;
+ USHORT FixedToZero : 1;
+ } Flags;
+ USHORT Word;
+ } NormalInterruptSignalEnable; // 38h
+
+ union {
+ struct {
+ USHORT CommandTimeoutErrorSignalEnable : 1;
+ USHORT CommandCRCErrorSignalEnable : 1;
+ USHORT CommandEndBitErrorSignalEnable : 1;
+ USHORT CommandIndexErrorSignalEnable : 1;
+ USHORT DataTimeoutErrorSignalEnable : 1;
+ USHORT DataCRCErrorSignalEnable : 1;
+ USHORT DataEndBitErrorSignalEnable : 1;
+ USHORT CurrentLimitErrorSignalEnable : 1;
+ USHORT AutoCMD12ErrorSignalEnable : 1;
+ USHORT ADMAErrorSignalEnable : 1;
+ USHORT TuningErrorSignalEnable : 1;
+ USHORT Reserved0 : 1;
+ USHORT VendorSpecificSignalEnable : 4;
+ } Flags;
+ USHORT Word;
+ } ErrorInterruptSignalEnable; // 3Ah
+
+ union {
+ struct {
+ USHORT AutoCMD12NotExecuted : 1;
+ USHORT AutoCMD12TimeoutError : 1;
+ USHORT AutoCMD12CRCError : 1;
+ USHORT AutoCMD12EndBitError : 1;
+ USHORT AutoCMDIndexError : 1;
+ USHORT Reserved0 : 2;
+ USHORT CommandNotIssuedByAutoCMD12Error : 1;
+ USHORT Reserved1 : 8;
+ } Flags;
+ USHORT Word;
+ } AutoCMDErrorStatus; // 3Ch
+
+ union {
+ struct {
+ USHORT UHSModeSelect : 3;
+ USHORT Signalling18V : 1;
+ USHORT DriverStrengthSelect : 2;
+ USHORT ExecuteTuning : 1;
+ USHORT SamplingClockSelect : 1;
+ USHORT Reserved : 6;
+ USHORT AsynchronousInterruptEnable : 1;
+ USHORT PresetValueEnable : 1;
+ } Flags;
+ USHORT Word;
+ } HostControl2; // 3Eh
+
+ union {
+ struct {
+ ULONGLONG TimeoutClockFrequency : 6;
+ ULONGLONG Reserved0 : 1;
+ ULONGLONG TimeoutClockUnit : 1;
+ ULONGLONG BaseClockFrequencyForSDClock : 8;
+ ULONGLONG MaxBlockLength : 2;
+ ULONGLONG EmbeddedDrive8Bit : 1;
+ ULONGLONG ADMA2SUpport : 1;
+ ULONGLONG Reserved1 : 1;
+ ULONGLONG HighSpeedSupport : 1;
+ ULONGLONG SDMASupport : 1;
+ ULONGLONG SuspendResumeSupport : 1;
+ ULONGLONG VoltageSupport33 : 1;
+ ULONGLONG VoltageSupport30 : 1;
+ ULONGLONG VoltageSupport18 : 1;
+ ULONGLONG Reserved2 : 1;
+ ULONGLONG SystemBus64bitSupport : 1;
+ ULONGLONG AsynchronousInterruptSupport : 1;
+ ULONGLONG SlotType : 2;
+ ULONGLONG SDR50Support : 1;
+ ULONGLONG SDR104Support : 1;
+ ULONGLONG DDR50Support : 1;
+ ULONGLONG Reserved3 : 1;
+ ULONGLONG DriverTypeASupport : 1;
+ ULONGLONG DriverTypeCSupport : 1;
+ ULONGLONG DriverTypeDSupport : 1;
+ ULONGLONG Reserved4 : 1;
+ ULONGLONG TimerCountForRetuning : 4;
+ ULONGLONG Reserved5 : 1;
+ ULONGLONG UseTuningForSDR50 : 1;
+ ULONGLONG RetuningModes : 2;
+ ULONGLONG ClockMultiplier : 8;
+ ULONGLONG Reserved6 : 8;
+ } Flags;
+ struct {
+ USHORT Capabilities0; // 40h
+ USHORT Capabilities1; // 42h
+ USHORT Capabilities2; // 44h
+ USHORT Capabilities3; // 46h
+ } Words;
+ ULONGLONG ULongLong;
+ } Capabilities;
+
+ union {
+ struct {
+ ULONGLONG MaxCurrent33V : 8;
+ ULONGLONG MaxCurrent30V : 8;
+ ULONGLONG MaxCurrent18V : 8;
+ ULONGLONG Reserved0 : 40;
+ } Flags;
+ struct {
+ USHORT MaxCurrentCaps0; // 48h
+ USHORT MaxCurrentCaps1; // 4Ah
+ USHORT MaxCurrentCaps2; // 4Ch
+ USHORT MaxCurrentCaps3; // 4Eh
+ } Words;
+ ULONGLONG ULongLong;
+ } MaxCurrentCaps;
+
+ union {
+ struct {
+ USHORT ForceEventForAutoCMD12NotExecuted : 1;
+ USHORT ForceEventForAutoCMD12TimeoutError : 1;
+ USHORT ForceEventForAutoCMD12CRCError : 1;
+ USHORT ForceEventForAutoCMD12EndBitError : 1;
+ USHORT ForceEventForAutoCMD12IndexError : 1;
+ USHORT Reserved0 : 2;
+ USHORT ForceEventForCommandNotIssuedByAutoCMD12Error : 1;
+ USHORT Reserved1 : 8;
+ } Flags;
+ USHORT Word; // 50h
+ } ForceEventAutoCMDError;
+
+ union {
+ struct {
+ USHORT ForceCommandTimeoutError : 1;
+ USHORT ForceCommandCRCError : 1;
+ USHORT ForceCommandEndBitError : 1;
+ USHORT ForceCommandIndexError : 1;
+ USHORT ForceDataTimeoutError : 1;
+ USHORT ForceDataCRCError : 1;
+ USHORT ForceDataEndBitError : 1;
+ USHORT ForceCurrentLimitError : 1;
+ USHORT ForceAutoCMD12Error : 1;
+ USHORT ForceADMAError : 1;
+ USHORT Reserved0 : 2;
+ USHORT VendorSpecific : 4;
+ } Flags;
+ USHORT Word; // 52h
+ } ForceEventInterruptError;
+
+ union {
+ struct {
+ UCHAR ADMAErrorStates : 2;
+ UCHAR ADMALengthMismatchError : 1;
+ UCHAR Reserved0 : 5;
+ } Flags;
+ UCHAR Byte;
+ } ADMAErrorStatus;
+
+ UCHAR Reserved0; // 55h
+ USHORT Reserved1; // 56h
+
+ union {
+ struct {
+ USHORT ADMASystemAddress0; // 58h
+ USHORT ADMASystemAddress1; // 5Ah
+ USHORT ADMASystemAddress2; // 5Ch
+ USHORT ADMASystemAddress3; // 5Eh
+ } Words;
+ ULONGLONG ULongLong;
+ } ADMASystemAddress;
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueInit; // 60h
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueDefaultSpeed; // 62h
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueHighSpeed; // 64h
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueSDR12; // 66h
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueSDR25; // 68h
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueSDR50; // 6Ah
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueSDR104; // 6Ch
+
+ union {
+ struct {
+ USHORT SDCLKFrequencySelectValue : 10;
+ USHORT ClockGeneratorSelectValue : 1;
+ USHORT Reserved0 : 3;
+ USHORT DriverStrengthSelectValue : 2;
+ } Flags;
+ USHORT Word;
+ } PresetValueDDR50; // 6Eh
+
+ UCHAR Reserved2[112]; // 70h - DFh
+
+ union {
+ struct {
+ ULONG NumberOfClockPins : 3;
+ ULONG Reserved0 : 1;
+ ULONG NumberOfInterruptInputPins : 2;
+ ULONG Reserved1 : 2;
+ ULONG BusWidthPreset : 7;
+ ULONG Reserved2 : 1;
+ ULONG ClockPinSelect : 3;
+ ULONG Reserved3 : 1;
+ ULONG InterruptPinSelect : 3;
+ ULONG Reserved4 : 1;
+ ULONG BackEndPowerControl : 7;
+ ULONG Reserved5 : 1;
+ } Flags;
+ struct {
+ USHORT Low; // E0h
+ USHORT High; // E2h
+ } Words;
+ ULONG Ulong;
+ } SharedBusControl;
+
+ UCHAR Reserved3[12]; // E4h - EFh
+ UCHAR Reserved4[12]; // F0h - FBh
+
+ union {
+ struct {
+ USHORT Slot1 : 1;
+ USHORT Slot2 : 1;
+ USHORT Slot3 : 1;
+ USHORT Slot4 : 1;
+ USHORT Slot5 : 1;
+ USHORT Slot6 : 1;
+ USHORT Slot7 : 1;
+ USHORT Slot8 : 1;
+ USHORT Reserved0 : 8;
+ } Flags;
+ USHORT Word; // FCh
+ } SlotInterruptStatus;
+
+ union {
+ struct {
+ USHORT SpecificationVersionNumber : 8;
+ USHORT VendorVersionNumber : 8;
+ } Flags;
+ USHORT Word; // FEh
+ } HostControllerVersion;
+
+} SD_HOST_CONTROLLER_REGISTERS, *PSD_HOST_CONTROLLER_REGISTERS;
+
+// the size of the SD_CONTROLLER_REGISTER structure must always be 256 bytes
+C_ASSERT(sizeof(SD_HOST_CONTROLLER_REGISTERS) == 256);
+
+#pragma pack(pop)
+
+// ---------------------------------------------------------------------------
+//
+// Register layout definitions
+//
+// ---------------------------------------------------------------------------
+
+#pragma pack(1)
+
+//
+// Host control register
+//
+
+typedef union _SDHC_HOST_CONTROL_REGISTER {
+ struct {
+ UCHAR LedControl:1;
+ UCHAR DataTransferWidth:1;
+ UCHAR HgihSpeedEnable:1;
+ UCHAR DmaSelect:2;
+ UCHAR Reserved1:1;
+ UCHAR CardDetectTestLevel:1;
+ UCHAR CardDetectSignalSlection:1;
+ };
+ UCHAR AsUchar;
+} SDHC_HOST_CONTROL_REGISTER, *PSDHC_HOST_CONTROL_REGISTER;
+
+typedef union _SDHC_HOST_CONTROL2_REGISTER {
+ struct {
+ USHORT UhsModeSelect:3;
+ USHORT SignalingEnable1_8V:1;
+ USHORT DriverStrengthSelect:2;
+ USHORT ExecuteTuning:1;
+ USHORT SamplingClockSelect:1;
+ USHORT Reserved:6;
+ USHORT AsyncInterruptEnable:1;
+ USHORT PresetValueEnable:1;
+ };
+ USHORT AsUshort;
+} SDHC_HOST_CONTROL2_REGISTER, *PSDHC_HOST_CONTROL2_REGISTER;
+
+
+//
+// Power control register
+//
+
+typedef union _SDHC_POWER_CONTROL_REGISTER {
+ struct {
+ UCHAR SdBusPower:1;
+ UCHAR SdBusPowerSelect:3;
+ UCHAR Reserved1:4;
+ };
+ UCHAR AsUchar;
+} SDHC_POWER_CONTROL_REGISTER, *PSDHC_POWER_CONTROL_REGISTER;
+
+
+//
+// Clock control register
+//
+
+typedef union _SDHC_CLOCK_CONTROL_REGISTER {
+ struct {
+ USHORT InternalClockEnable:1;
+ USHORT InternalClockStable:1;
+ USHORT SdClockEnable:1;
+ USHORT Reserved1:4;
+ USHORT SdclkFrequencySelect:8;
+ };
+ UCHAR AsUshort;
+} SDHC_CLOCK_CONTROL_REGISTER, *PSDHC_CLOCK_CONTROL_REGISTER;
+
+
+//
+// Transfer mode register
+//
+
+typedef union _SDHC_TRANSFER_MODE_REGISTER {
+ struct {
+ USHORT DmaEnable:1;
+ USHORT BlockCountEnable:1;
+ USHORT AutoCmd12Enable:1;
+ USHORT AutoCmd23Enable:1;
+ USHORT DataTranferDirectionSelect:1;
+ USHORT BlockModeSelect:1;
+ USHORT Reserved2:10;
+ };
+ USHORT AsUshort;
+} SDHC_TRANSFER_MODE_REGISTER, *PSDHC_TRANSFER_MODE_REGISTER;
+
+
+//
+// Capabilities register
+//
+
+typedef union _SDHC_CAPABILITIES_REGISTER {
+ struct {
+ ULONG TimeoutClockFrequency:6;
+ ULONG Reserved1:1;
+ ULONG TimeoutClockUnit:1;
+ ULONG BaseClockFrequency:8;
+ ULONG MaxBlockLength:2;
+ ULONG Support8BitBus:1;
+ ULONG Adma2Support:1;
+ ULONG Reserved2:1;
+ ULONG HighSpeedSupport:1;
+ ULONG DmaSupport:1;
+ ULONG SuspendResumeSupport:1;
+ ULONG Voltage33:1;
+ ULONG Voltage30:1;
+ ULONG Voltage18:1;
+ ULONG Reserved3:1;
+ ULONG SystemBus64Support:1;
+ ULONG AsynchronousInterruptSupport:1;
+ ULONG SlotType:2;
+ };
+ ULONG AsUlong;
+} SDHC_CAPABILITIES_REGISTER, *PSDHC_CAPABILITIES_REGISTER;
+
+typedef union _SDHC_CAPABILITIES2_REGISTER {
+ struct {
+ ULONG SDR50Support:1;
+ ULONG SDR104Support:1;
+ ULONG DDR50Support:1;
+ ULONG Reserved1:1;
+ ULONG DriverTypeA:1;
+ ULONG DriverTypeC:1;
+ ULONG DriverTypeD:1;
+ ULONG Reserved2:1;
+ ULONG RetuningTimerCount:4;
+ ULONG Reserved3:1;
+ ULONG UseTuningForSDR50:1;
+ ULONG RetuningModes:2;
+ ULONG ClockMultiplier:8;
+ ULONG Reserved4:8;
+ };
+ ULONG AsUlong;
+} SDHC_CAPABILITIES2_REGISTER, *PSDHC_CAPABILITIES2_REGISTER;
+
+// ---------------------------------------------------------------------------
+//
+// ADMA2 descriptor table definitions
+//
+// ---------------------------------------------------------------------------
+
+//
+// Bits defined in descriptor->attribute
+//
+
+#define SDHC_ADMA2_ATTRIBUTE_VALID 0x00000001
+#define SDHC_ADMA2_ATTRIBUTE_END 0x00000002
+#define SDHC_ADMA2_ATTRIBUTE_INT 0x00000004
+
+//
+// Bits defined in descriptor->Action
+//
+
+#define SDHC_ADMA2_ACTION_NOP 0x00000000
+#define SDHC_ADMA2_ACTION_TRAN 0x00000002
+#define SDHC_ADMA2_ACTION_LINK 0x00000003
+
+//
+// Max transfer length per descriptor entry
+//
+// SD Host Controller Spec 1.13.4
+// Length field is 16 bit field so we can go up to 64K (0xFFFF).
+// However, we need to limit max length to 0xF000 because using 0xFFFF
+// can cause un-aligned, In addition, some HC require the length to be
+// multiple of 0x1000 (except 1st and last descriptor)
+//
+#define SDHC_ADMA2_MAX_LENGTH_PER_ENTRY 0x0000F000
+
+//
+// Layout of a descriptor (excluding the Address field)
+//
+
+typedef union _SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY {
+ struct {
+ ULONG Attribute:3;
+ ULONG Reserved1:1;
+ ULONG Action:2;
+ ULONG Reserved2:10;
+ ULONG Length:16;
+ };
+ ULONG AsUlong;
+} SDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY, *PSDHC_ADMA2_DESCRIPTOR_TABLE_ENTRY;
+
+#pragma pack()
+
+//
+// Voltage profile
+//
+
+typedef union _SDHC_VOLTAGE_PROFILE {
+ struct {
+ ULONG Reserved1 : 7;
+ ULONG VoltageLow : 1;
+ ULONG Voltage20 : 1;
+ ULONG Voltage21 : 1;
+ ULONG Voltage22 : 1;
+ ULONG Voltage23 : 1;
+ ULONG Voltage24 : 1;
+ ULONG Voltage25 : 1;
+ ULONG Voltage26 : 1;
+ ULONG Voltage27 : 1;
+ ULONG Voltage28 : 1;
+ ULONG Voltage29 : 1;
+ ULONG Voltage30 : 1;
+ ULONG Voltage31 : 1;
+ ULONG Voltage32 : 1;
+ ULONG Voltage33 : 1;
+ ULONG Voltage34 : 1;
+ ULONG Voltage35 : 1;
+ };
+ ULONG AsUlong;
+} SDHC_VOLTAGE_PROFILE, *PSDHC_VOLTAGE_PROFILE;
+
+typedef enum _SDHC_SPEED_MODE {
+ SdhcSpeedModeNormal = 0,
+ SdhcSpeedModeHigh,
+ SdhcSpeedModeSDR50,
+ SdhcSpeedModeDDR50,
+ SdhcSpeedModeSDR104,
+ SdhcSpeedModeHS200,
+ SdhcSpeedModeHS400
+} SDHC_SPEED_MODE;
+
+#define SDHC_MAX_OUTSTANDING_REQUESTS 1
+
+typedef struct _SDHC_EXTENSION {
+
+ BOOLEAN Removable;
+
+ //
+ // Host register space.
+ //
+
+ PHYSICAL_ADDRESS PhysicalBaseAddress;
+ PVOID BaseAddress;
+ SIZE_T BaseAddressSpaceSize;
+ PSD_HOST_CONTROLLER_REGISTERS BaseAddressDebug;
+
+ //
+ // Capabilities.
+ //
+
+ SDPORT_CAPABILITIES Capabilities;
+ SDHC_SPEED_MODE SpeedMode;
+ UCHAR SpecVersion;
+
+ //
+ // Requests to handle.
+ //
+
+ PSDPORT_REQUEST OutstandingRequests[SDHC_MAX_OUTSTANDING_REQUESTS];
+ USHORT UnhandledEvents;
+
+} SDHC_EXTENSION, *PSDHC_EXTENSION;
+
+// ---------------------------------------------------------------------------
+// PCI Config definitions
+// ---------------------------------------------------------------------------
+
+#define SDHC_PCICFG_SLOT_INFORMATION 0x40
+
+NTSTATUS
+DriverEntry(
+ _In_ PVOID DriverObject,
+ _In_ PVOID RegistryPath
+ );
+
+//-----------------------------------------------------------------------------
+// SlotExtension callbacks.
+//-----------------------------------------------------------------------------
+
+SDPORT_GET_SLOT_COUNT SdhcGetSlotCount;
+/*
+NTSTATUS
+SdhcGetSlotCount(
+ _In_ PVOID Argument,
+ _In_ SDPORT_BUS_TYPE BusType
+ );
+*/
+
+SDPORT_GET_SLOT_CAPABILITIES SdhcGetSlotCapabilities;
+/*
+VOID
+SdhcGetSlotCapabilities(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _Inout_ PSDPORT_CAPABILITIES Capabilities
+ );
+*/
+
+SDPORT_INITIALIZE SdhcSlotInitialize;
+/*
+NTSTATUS
+SdhcSlotInitialize(
+ _Inout_ PSDPORT_SLOT_EXTENSION SlotExtension
+ );
+*/
+
+SDPORT_ISSUE_BUS_OPERATION SdhcSlotIssueBusOperation;
+/*
+NTSTATUS
+SdhcSlotIssueBusOperation(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+*/
+
+SDPORT_GET_CARD_DETECT_STATE SdhcSlotGetCardDetectState;
+/*
+BOOLEAN
+SdhcSlotGetCardDetectState(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension
+ );
+*/
+
+SDPORT_GET_WRITE_PROTECT_STATE SdhcSlotGetWriteProtectState;
+/*
+BOOLEAN
+SdhcSlotGetWriteProtectState(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension
+ );
+*/
+
+SDPORT_INTERRUPT SdhcSlotInterrupt;
+/*
+BOOLEAN
+SdhcSlotInterrupt(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _Out_ PULONG Events,
+ _Out_ PULONG Errors,
+ _Out_ PBOOLEAN NotifyCardChange,
+ _Out_ PBOOLEAN NotifySdioInterrupt,
+ _Out_ PBOOLEAN NotifyTuning
+ );
+*/
+
+SDPORT_ISSUE_REQUEST SdhcSlotIssueRequest;
+/*
+NTSTATUS
+SdhcSlotIssueRequest(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+*/
+
+SDPORT_GET_RESPONSE SdhcSlotGetResponse;
+/*
+VOID
+SdhcSlotGetResponse(
+ _In_ PVOID PrivateExtension,
+ _In_ PSDPORT_COMMAND Command,
+ _Out_ PVOID ResponseBuffer
+ );
+*/
+
+SDPORT_TOGGLE_EVENTS SdhcSlotToggleEvents;
+/*
+VOID
+SdhcSlotToggleEevnts(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _In_ ULONG EventMask,
+ _In_ BOOLEAN Enable
+ );
+*/
+
+SDPORT_CLEAR_EVENTS SdhcSlotClearEvents;
+/*
+VOID
+SdhcSlotClearEvents(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension,
+ _In_ ULONG EventMask
+ );
+*/
+
+SDPORT_REQUEST_DPC SdhcRequestDpc;
+/*
+VOID
+SdhcRequestDpc(
+ _In_ PVOID PrivateExtension,
+ _Inout_ PSDPORT_REQUEST Request,
+ _In_ ULONG Events,
+ _In_ ULONG Errors
+ );
+*/
+
+SDPORT_SAVE_CONTEXT SdhcSaveContext;
+/*
+VOID
+SdhcSaveContext(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension
+ );
+*/
+
+SDPORT_RESTORE_CONTEXT SdhcRestoreContext;
+/*
+VOID
+SdhcRestoreContext(
+ _In_ PSDPORT_SLOT_EXTENSION SlotExtension
+ );
+*/
+
+//-----------------------------------------------------------------------------
+// Hardware access routines.
+//-----------------------------------------------------------------------------
+
+NTSTATUS
+SdhcResetHost(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ UCHAR ResetType
+ );
+
+NTSTATUS
+SdhcSetVoltage(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ SDPORT_BUS_VOLTAGE VoltageProfile
+ );
+
+NTSTATUS
+SdhcSetClock(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Frequency
+ );
+
+NTSTATUS
+SdhcSetBusWidth(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ UCHAR BusWidth
+ );
+
+NTSTATUS
+SdhcSetSpeed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ SDPORT_BUS_SPEED Speed
+ );
+
+NTSTATUS
+SdhcSetHighSpeed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ );
+
+NTSTATUS
+SdhcSetUhsMode(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ USHORT Mode
+ );
+
+NTSTATUS
+SdhcSetSignaling(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ );
+
+NTSTATUS
+SdhcExecuteTuning(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+VOID
+SdhcSetLed(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ );
+
+NTSTATUS
+SdhcSetPresetValue(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Enable
+ );
+
+VOID
+SdhcSetBlockGapControl(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Continue,
+ _In_ BOOLEAN RequestStop
+ );
+
+VOID
+SdhcSetBlockGapControl(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ BOOLEAN Continue,
+ _In_ BOOLEAN RequestStop
+ );
+
+VOID
+SdhcEnableInterrupt(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG NormalMask
+ );
+
+VOID
+SdhcDisableInterrupt(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG NormalMask
+ );
+
+USHORT
+SdhcGetInterruptStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+USHORT
+SdhcGetErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+USHORT
+SdhcGetAutoCmd12ErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+USHORT
+SdhcGetAdmaErrorStatus(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+VOID
+SdhcAcknowledgeInterrupts(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ USHORT Interrupts
+ );
+
+BOOLEAN
+SdhcIsCardInserted(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+BOOLEAN
+SdhcIsWriteProtected(
+ _In_ PSDHC_EXTENSION SdhcExtension
+ );
+
+NTSTATUS
+SdhcSendCommand(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcGetResponse(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_COMMAND Command,
+ _Out_ PVOID ResponseBuffer
+ );
+
+NTSTATUS
+SdhcSetTransferMode(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+VOID
+SdhcReadDataPort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _Out_writes_all_(Length) PUCHAR Buffer,
+ _In_ SIZE_T Length
+ );
+
+VOID
+SdhcWriteDataPort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_reads_(Length) PUCHAR Buffer,
+ _In_ ULONG Length
+ );
+
+NTSTATUS
+SdhcBuildTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcStartTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcBuildPioTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcBuildAdmaTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcStartPioTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+NTSTATUS
+SdhcStartAdmaTransfer(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ PSDPORT_REQUEST Request
+ );
+
+//-----------------------------------------------------------------------------
+// General utility functions.
+//-----------------------------------------------------------------------------
+
+USHORT
+SdhcCalcClockFrequency(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG TargetFrequency,
+ _Out_opt_ PULONG ActualFrequency
+ );
+
+USHORT
+SdhcConvertEventsToHwMask(
+ _In_ ULONG Events
+ );
+
+NTSTATUS
+SdhcConvertErrorToStatus(
+ _In_ USHORT Error
+ );
+
+NTSTATUS
+SdhcCreateAdmaDescriptorTable(
+ _In_ PSDPORT_REQUEST Request,
+ _In_ BOOLEAN Use64BitDescriptor,
+ _Out_ PULONG TotalTransferLength
+ );
+
+VOID
+SdhcInitializePciConfigSpace(
+ _In_ PSD_MINIPORT Miniport
+ );
+
+__forceinline
+USHORT
+SdhcGetHwUhsMode(
+ _In_ SDPORT_BUS_SPEED BusSpeed
+ )
+
+{
+
+ NT_ASSERT(BusSpeed != SdBusSpeedNormal);
+
+ NT_ASSERT(BusSpeed != SdBusSpeedHigh);
+
+ switch (BusSpeed) {
+ case SdBusSpeedSDR12:
+ return SDHC_HC2_SDR12;
+
+ case SdBusSpeedSDR25:
+ return SDHC_HC2_SDR25;
+
+ case SdBusSpeedSDR50:
+ return SDHC_HC2_SDR50;
+
+ case SdBusSpeedDDR50:
+ return SDHC_HC2_SDR50;
+
+ case SdBusSpeedSDR104:
+ return SDHC_HC2_SDR50;
+
+ //
+ // PCI controllers don't support the higher speed eMMC modes.
+ //
+
+ case SdBusSpeedHS200:
+ case SdBusSpeedHS400:
+ default:
+ break;
+ }
+
+ NT_ASSERTMSG("SDHC - Invalid bus speed selected", FALSE);
+
+ return 0;
+}
+
+__forceinline
+USHORT
+SdhcConvertEventsToHwMask(
+ _In_ ULONG EventMask
+ )
+
+{
+
+ return EventMask & 0xFFFF;
+}
+
+__forceinline
+USHORT
+SdhcConvertErrorsToHwMask(
+ _In_ ULONG ErrorMask
+ )
+
+{
+
+ return ErrorMask & 0xFFFF;
+}
+
+__forceinline
+NTSTATUS
+SdhcConvertErrorToStatus(
+ _In_ USHORT Error
+ )
+
+{
+
+ if (Error == 0) {
+ return STATUS_SUCCESS;
+ }
+
+ if (Error & (SDHC_ES_CMD_TIMEOUT | SDHC_ES_DATA_TIMEOUT)) {
+ return STATUS_IO_TIMEOUT;
+ }
+
+ if (Error & (SDHC_ES_CMD_CRC_ERROR | SDHC_ES_DATA_CRC_ERROR)) {
+ return STATUS_CRC_ERROR;
+ }
+
+ if (Error & (SDHC_ES_CMD_END_BIT_ERROR | SDHC_ES_DATA_END_BIT_ERROR)) {
+ return STATUS_DEVICE_DATA_ERROR;
+ }
+
+ if (Error & SDHC_ES_CMD_INDEX_ERROR) {
+ return STATUS_DEVICE_PROTOCOL_ERROR;
+ }
+
+ if (Error & SDHC_ES_BUS_POWER_ERROR) {
+ return STATUS_DEVICE_POWER_FAILURE;
+ }
+
+ return STATUS_IO_DEVICE_ERROR;
+}
+
+
+//-----------------------------------------------------------------------------
+// Register access macros.
+//-----------------------------------------------------------------------------
+
+__forceinline
+VOID
+SdhcWriteRegisterUlong(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_ ULONG Data
+ )
+
+{
+
+ SdPortWriteRegisterUlong(SdhcExtension->BaseAddress, Register, Data);
+ return;
+}
+
+__forceinline
+VOID
+SdhcWriteRegisterUshort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_ USHORT Data
+ )
+
+{
+
+ SdPortWriteRegisterUshort(SdhcExtension->BaseAddress, Register, Data);
+ return;
+}
+
+__forceinline
+VOID
+SdhcWriteRegisterUchar(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_ UCHAR Data
+ )
+
+{
+
+ SdPortWriteRegisterUchar(SdhcExtension->BaseAddress, Register, Data);
+ return;
+}
+
+__forceinline
+ULONG
+SdhcReadRegisterUlong(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register
+ )
+
+{
+ return SdPortReadRegisterUlong(SdhcExtension->BaseAddress, Register);
+}
+
+__forceinline
+USHORT
+SdhcReadRegisterUshort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register
+ )
+
+{
+ return SdPortReadRegisterUshort(SdhcExtension->BaseAddress, Register);
+}
+
+__forceinline
+UCHAR
+SdhcReadRegisterUchar(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register
+ )
+
+{
+ return SdPortReadRegisterUchar(SdhcExtension->BaseAddress, Register);
+}
+
+__forceinline
+VOID
+SdhcReadRegisterBufferUlong(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _Out_writes_all_(Length) PULONG Buffer,
+ _In_ ULONG Length)
+
+{
+ SdPortReadRegisterBufferUlong(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+}
+
+__forceinline
+VOID
+SdhcReadRegisterBufferUshort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _Out_writes_all_(Length) PUSHORT Buffer,
+ _In_ ULONG Length)
+
+{
+ SdPortReadRegisterBufferUshort(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+}
+
+__forceinline
+VOID
+SdhcReadRegisterBufferUchar(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _Out_writes_all_(Length) PUCHAR Buffer,
+ _In_ ULONG Length)
+
+{
+ SdPortReadRegisterBufferUchar(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+}
+
+__forceinline
+VOID
+SdhcWriteRegisterBufferUlong(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_reads_(Length) PULONG Buffer,
+ _In_ ULONG Length
+ )
+
+{
+
+ SdPortWriteRegisterBufferUlong(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+}
+
+__forceinline
+VOID
+SdhcWriteRegisterBufferUshort(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_reads_(Length) PUSHORT Buffer,
+ _In_ ULONG Length
+ )
+
+{
+
+ SdPortWriteRegisterBufferUshort(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+}
+
+__forceinline
+VOID
+SdhcWriteRegisterBufferUchar(
+ _In_ PSDHC_EXTENSION SdhcExtension,
+ _In_ ULONG Register,
+ _In_reads_(Length) PUCHAR Buffer,
+ _In_ ULONG Length
+ )
+
+{
+
+ SdPortWriteRegisterBufferUchar(SdhcExtension->BaseAddress,
+ Register,
+ Buffer,
+ Length);
+
+}
+
+__forceinline
+UCHAR
+SdhcGetResponseLength(
+ _In_ PSDPORT_COMMAND Command
+ )
+
+/*++
+
+Routine Description:
+
+ Return the number of bytes associated with a given response type.
+
+Arguments:
+
+ ResponseType
+
+Return value:
+
+ Length of response.
+
+--*/
+
+{
+
+ UCHAR Length;
+
+ switch (Command->ResponseType) {
+ case SdResponseTypeR1:
+ case SdResponseTypeR3:
+ case SdResponseTypeR4:
+ case SdResponseTypeR5:
+ case SdResponseTypeR6:
+ case SdResponseTypeR1B:
+ case SdResponseTypeR5B:
+ Length = 4;
+ break;
+
+ case SdResponseTypeR2:
+ Length = 16;
+ break;
+
+ case SdResponseTypeNone:
+ Length = 0;
+ break;
+
+ default:
+
+ NT_ASSERTMSG("Invalid response type", FALSE);
+
+ Length = 0;
+ break;
+ }
+
+ return Length;
+}
+
+#define MIN(x,y) ((x) > (y) ? (y) : (x)) // return minimum among x & y
+#define MAX(x,y) ((x) > (y) ? (x) : (y)) // return maximum among x & y
+#define DIV_CEIL(x, y) (((x) + (y) - 1) / (y))
diff --git a/sd/miniport/sdhc/sdhc.inx b/sd/miniport/sdhc/sdhc.inx
new file mode 100644
index 00000000..7e7f7abb
--- /dev/null
+++ b/sd/miniport/sdhc/sdhc.inx
Binary files differ
diff --git a/sd/miniport/sdhc/sdhc.rc b/sd/miniport/sdhc/sdhc.rc
new file mode 100644
index 00000000..87580888
--- /dev/null
+++ b/sd/miniport/sdhc/sdhc.rc
@@ -0,0 +1,15 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "SD Host Controller Standard Driver"
+#define VER_INTERNALNAME_STR "sdhc.sys"
+#define VER_ORIGINALFILENAME_STR "sdhc.sys"
+
+#include "common.ver"
+
diff --git a/sd/miniport/sdhc/sdhc.sln b/sd/miniport/sdhc/sdhc.sln
new file mode 100644
index 00000000..9e343b4a
--- /dev/null
+++ b/sd/miniport/sdhc/sdhc.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdhc", "inbox\sdhc.vcxproj", "{696C1C9C-405C-4675-B344-B5FF53BAB93A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|Win32.Build.0 = Debug|Win32
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|Win32.ActiveCfg = Release|Win32
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|Win32.Build.0 = Release|Win32
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|x64.ActiveCfg = Debug|x64
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Debug|x64.Build.0 = Debug|x64
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|x64.ActiveCfg = Release|x64
+ {696C1C9C-405C-4675-B344-B5FF53BAB93A}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal