diff options
| author | Dave Wilson <[email protected]> | 2015-04-29 09:48:49 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-04-29 10:47:29 -0700 |
| commit | d40232638faaab19de557e70a3ee938da7a35295 (patch) | |
| tree | 14e61c973745949af186b7940e3a53d25322f5de /sd/miniport | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'sd/miniport')
| -rw-r--r-- | sd/miniport/sdhc/README.md | 13 | ||||
| -rw-r--r-- | sd/miniport/sdhc/inbox/sdhc.vcxproj | 156 | ||||
| -rw-r--r-- | sd/miniport/sdhc/inbox/sdhc.vcxproj.Filters | 39 | ||||
| -rw-r--r-- | sd/miniport/sdhc/sdhc.c | 3291 | ||||
| -rw-r--r-- | sd/miniport/sdhc/sdhc.h | 2091 | ||||
| -rw-r--r-- | sd/miniport/sdhc/sdhc.inx | bin | 0 -> 11250 bytes | |||
| -rw-r--r-- | sd/miniport/sdhc/sdhc.rc | 15 | ||||
| -rw-r--r-- | sd/miniport/sdhc/sdhc.sln | 28 |
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 Binary files differnew file mode 100644 index 00000000..7e7f7abb --- /dev/null +++ b/sd/miniport/sdhc/sdhc.inx 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 |
