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 /smartcrd/pscr | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'smartcrd/pscr')
| -rw-r--r-- | smartcrd/pscr/Pscr.vcxproj | 183 | ||||
| -rw-r--r-- | smartcrd/pscr/Pscr.vcxproj.Filters | 51 | ||||
| -rw-r--r-- | smartcrd/pscr/pscr.htm | 867 | ||||
| -rw-r--r-- | smartcrd/pscr/pscr.inx | bin | 0 -> 6292 bytes | |||
| -rw-r--r-- | smartcrd/pscr/pscr.rc | 48 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrcb.c | 1008 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrcb.h | 84 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrcmd.c | 981 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrcmd.h | 107 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrlog.mc | 103 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrnt.c | 1687 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrnt.h | 187 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrrdwr.c | 509 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrrdwr.h | 366 | ||||
| -rw-r--r-- | smartcrd/pscr/pscrvers.h | 43 |
15 files changed, 6224 insertions, 0 deletions
diff --git a/smartcrd/pscr/Pscr.vcxproj b/smartcrd/pscr/Pscr.vcxproj new file mode 100644 index 00000000..88bc7891 --- /dev/null +++ b/smartcrd/pscr/Pscr.vcxproj @@ -0,0 +1,183 @@ +<?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>{E963C756-D675-4202-A229-6B3ADB94B252}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{1C4F5FFD-0F09-4478-A3F7-DEF422837617}</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>KMDF</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>KMDF</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>KMDF</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>KMDF</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=".\pscr.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\pscr.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>Pscr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>Pscr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>Pscr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>Pscr</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\smclib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="PscrCB.c" /> + <ClCompile Include="PscrCmd.c" /> + <ClCompile Include="PscrNT.c" /> + <ClCompile Include="PscrRdWr.c" /> + <MessageCompile Include="PscrLog.mc" /> + <ResourceCompile Include="pscr.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/smartcrd/pscr/Pscr.vcxproj.Filters b/smartcrd/pscr/Pscr.vcxproj.Filters new file mode 100644 index 00000000..55f941f4 --- /dev/null +++ b/smartcrd/pscr/Pscr.vcxproj.Filters @@ -0,0 +1,51 @@ +<?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>{7EB6DC3A-11A4-48F2-9730-419C9A104242}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{2AAA41D4-E19E-409F-87C1-EA4C640F0BAA}</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>{9FEF86B3-6289-44F6-B036-2C15E61CDDDE}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{A832F7F9-C73F-4032-83DF-1CA14DE6C0FF}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\pscr.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\pscr.inx"> + <Filter>Driver Files</Filter> + </Inf> + <MessageCompile Include="PscrLog.mc"> + <Filter>Driver Files</Filter> + </MessageCompile> + </ItemGroup> + <ItemGroup> + <ClCompile Include="PscrCB.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PscrCmd.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PscrNT.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PscrRdWr.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="pscr.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/smartcrd/pscr/pscr.htm b/smartcrd/pscr/pscr.htm new file mode 100644 index 00000000..934a4c0e --- /dev/null +++ b/smartcrd/pscr/pscr.htm @@ -0,0 +1,867 @@ +<html xmlns:v="urn:schemas-microsoft-com:vml" +xmlns:o="urn:schemas-microsoft-com:office:office" +xmlns:w="urn:schemas-microsoft-com:office:word" +xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" +xmlns="http://www.w3.org/TR/REC-html40"> + +<head> +<meta http-equiv=Content-Type content="text/html; charset=windows-1252"> +<meta name=ProgId content=Word.Document> +<meta name=Generator content="Microsoft Word 12"> +<meta name=Originator content="Microsoft Word 12"> +<link rel=File-List href="pscr2_files/filelist.xml"> +<title>PSCR.SYS�PCMCIA Smart Card Driver</title> +<!--[if gte mso 9]><xml> + <o:DocumentProperties> + <o:Author>Michael Tsang</o:Author> + <o:LastAuthor>Michael Tsang</o:LastAuthor> + <o:Revision>2</o:Revision> + <o:TotalTime>75</o:TotalTime> + <o:Created>2009-02-13T19:09:00Z</o:Created> + <o:LastSaved>2009-02-13T19:09:00Z</o:LastSaved> + <o:Pages>1</o:Pages> + <o:Words>838</o:Words> + <o:Characters>4780</o:Characters> + <o:Company>Microsoft</o:Company> + <o:Lines>39</o:Lines> + <o:Paragraphs>11</o:Paragraphs> + <o:CharactersWithSpaces>5607</o:CharactersWithSpaces> + <o:Version>12.00</o:Version> + </o:DocumentProperties> +</xml><![endif]--> +<link rel=themeData href="pscr2_files/themedata.thmx"> +<link rel=colorSchemeMapping href="pscr2_files/colorschememapping.xml"> +<!--[if gte mso 9]><xml> + <w:WordDocument> + <w:Zoom>125</w:Zoom> + <w:SpellingState>Clean</w:SpellingState> + <w:GrammarState>Clean</w:GrammarState> + <w:TrackMoves>false</w:TrackMoves> + <w:TrackFormatting/> + <w:ValidateAgainstSchemas/> + <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> + <w:IgnoreMixedContent>false</w:IgnoreMixedContent> + <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> + <w:DoNotPromoteQF/> + <w:LidThemeOther>EN-US</w:LidThemeOther> + <w:LidThemeAsian>X-NONE</w:LidThemeAsian> + <w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript> + <w:Compatibility> + <w:BreakWrappedTables/> + <w:SnapToGridInCell/> + <w:WrapTextWithPunct/> + <w:UseAsianBreakRules/> + <w:DontGrowAutofit/> + <w:SplitPgBreakAndParaMark/> + <w:DontVertAlignCellWithSp/> + <w:DontBreakConstrainedForcedTables/> + <w:DontVertAlignInTxbx/> + <w:Word11KerningPairs/> + <w:CachedColBalance/> + </w:Compatibility> + <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> + <m:mathPr> + <m:mathFont m:val="Cambria Math"/> + <m:brkBin m:val="before"/> + <m:brkBinSub m:val="--"/> + <m:smallFrac m:val="off"/> + <m:dispDef/> + <m:lMargin m:val="0"/> + <m:rMargin m:val="0"/> + <m:defJc m:val="centerGroup"/> + <m:wrapIndent m:val="1440"/> + <m:intLim m:val="subSup"/> + <m:naryLim m:val="undOvr"/> + </m:mathPr></w:WordDocument> +</xml><![endif]--><!--[if gte mso 9]><xml> + <w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true" + DefSemiHidden="true" DefQFormat="false" DefPriority="99" + LatentStyleCount="267"> + <w:LsdException Locked="false" Priority="0" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Normal"/> + <w:LsdException Locked="false" Priority="9" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="heading 1"/> + <w:LsdException Locked="false" Priority="9" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="heading 2"/> + <w:LsdException Locked="false" Priority="9" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="heading 3"/> + <w:LsdException Locked="false" Priority="9" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="heading 4"/> + <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/> + <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/> + <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/> + <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/> + <w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/> + <w:LsdException Locked="false" Priority="39" Name="toc 1"/> + <w:LsdException Locked="false" Priority="39" Name="toc 2"/> + <w:LsdException Locked="false" Priority="39" Name="toc 3"/> + <w:LsdException Locked="false" Priority="39" Name="toc 4"/> + <w:LsdException Locked="false" Priority="39" Name="toc 5"/> + <w:LsdException Locked="false" Priority="39" Name="toc 6"/> + <w:LsdException Locked="false" Priority="39" Name="toc 7"/> + <w:LsdException Locked="false" Priority="39" Name="toc 8"/> + <w:LsdException Locked="false" Priority="39" Name="toc 9"/> + <w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/> + <w:LsdException Locked="false" Priority="10" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Title"/> + <w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/> + <w:LsdException Locked="false" Priority="11" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/> + <w:LsdException Locked="false" Priority="22" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Strong"/> + <w:LsdException Locked="false" Priority="20" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/> + <w:LsdException Locked="false" Priority="59" SemiHidden="false" + UnhideWhenUsed="false" Name="Table Grid"/> + <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/> + <w:LsdException Locked="false" Priority="1" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 1"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 1"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 1"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/> + <w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/> + <w:LsdException Locked="false" Priority="34" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/> + <w:LsdException Locked="false" Priority="29" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Quote"/> + <w:LsdException Locked="false" Priority="30" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 1"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 1"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 2"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 2"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 2"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 2"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 2"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 3"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 3"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 3"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 3"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 3"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 4"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 4"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 4"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 4"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 4"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 5"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 5"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 5"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 5"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 5"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/> + <w:LsdException Locked="false" Priority="60" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Shading Accent 6"/> + <w:LsdException Locked="false" Priority="61" SemiHidden="false" + UnhideWhenUsed="false" Name="Light List Accent 6"/> + <w:LsdException Locked="false" Priority="62" SemiHidden="false" + UnhideWhenUsed="false" Name="Light Grid Accent 6"/> + <w:LsdException Locked="false" Priority="63" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/> + <w:LsdException Locked="false" Priority="64" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/> + <w:LsdException Locked="false" Priority="65" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/> + <w:LsdException Locked="false" Priority="66" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/> + <w:LsdException Locked="false" Priority="67" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/> + <w:LsdException Locked="false" Priority="68" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/> + <w:LsdException Locked="false" Priority="69" SemiHidden="false" + UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/> + <w:LsdException Locked="false" Priority="70" SemiHidden="false" + UnhideWhenUsed="false" Name="Dark List Accent 6"/> + <w:LsdException Locked="false" Priority="71" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/> + <w:LsdException Locked="false" Priority="72" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful List Accent 6"/> + <w:LsdException Locked="false" Priority="73" SemiHidden="false" + UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/> + <w:LsdException Locked="false" Priority="19" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/> + <w:LsdException Locked="false" Priority="21" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/> + <w:LsdException Locked="false" Priority="31" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/> + <w:LsdException Locked="false" Priority="32" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/> + <w:LsdException Locked="false" Priority="33" SemiHidden="false" + UnhideWhenUsed="false" QFormat="true" Name="Book Title"/> + <w:LsdException Locked="false" Priority="37" Name="Bibliography"/> + <w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/> + </w:LatentStyles> +</xml><![endif]--> +<style> +<!-- + /* Font Definitions */ + @font-face + {font-family:Courier; + panose-1:2 7 4 9 2 2 5 2 4 4; + mso-font-charset:0; + mso-generic-font-family:modern; + mso-font-format:other; + mso-font-pitch:fixed; + mso-font-signature:3 0 0 0 1 0;} +@font-face + {font-family:"Cambria Math"; + panose-1:2 4 5 3 5 4 6 3 2 4; + mso-font-charset:0; + mso-generic-font-family:roman; + mso-font-pitch:variable; + mso-font-signature:-1610611985 1107304683 0 0 415 0;} +@font-face + {font-family:Consolas; + panose-1:2 11 6 9 2 2 4 3 2 4; + mso-font-charset:0; + mso-generic-font-family:modern; + mso-font-pitch:fixed; + mso-font-signature:-520092929 1073806591 9 0 415 0;} +@font-face + {font-family:Verdana; + panose-1:2 11 6 4 3 5 4 4 2 4; + mso-font-charset:0; + mso-generic-font-family:swiss; + mso-font-pitch:variable; + mso-font-signature:-1593833729 1073750107 16 0 415 0;} +@font-face + {font-family:"MS Sans Serif"; + panose-1:0 0 0 0 0 0 0 0 0 0; + mso-font-alt:"Times New Roman"; + mso-font-charset:0; + mso-generic-font-family:roman; + mso-font-format:other; + mso-font-pitch:auto; + mso-font-signature:0 0 0 0 0 0;} +@font-face + {font-family:"MS Shell Dlg"; + panose-1:2 11 6 4 2 2 2 2 2 4; + mso-font-charset:0; + mso-generic-font-family:swiss; + mso-font-pitch:variable; + mso-font-signature:-520082689 -1073741822 8 0 66047 0;} + /* Style Definitions */ + p.MsoNormal, li.MsoNormal, div.MsoNormal + {mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-parent:""; + margin:0in; + margin-bottom:.0001pt; + mso-pagination:widow-orphan; + font-size:12.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman";} +h2 + {mso-style-priority:9; + mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-link:"Heading 2 Char"; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + mso-outline-level:2; + font-size:18.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:minor-fareast; + font-weight:bold;} +h3 + {mso-style-priority:9; + mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-link:"Heading 3 Char"; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + mso-outline-level:3; + font-size:13.5pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:minor-fareast; + font-weight:bold;} +h4 + {mso-style-priority:9; + mso-style-unhide:no; + mso-style-qformat:yes; + mso-style-link:"Heading 4 Char"; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + mso-outline-level:4; + font-size:12.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:minor-fareast; + font-weight:bold;} +a:link, span.MsoHyperlink + {mso-style-noshow:yes; + mso-style-priority:99; + color:blue; + text-decoration:underline; + text-underline:single;} +a:visited, span.MsoHyperlinkFollowed + {mso-style-noshow:yes; + mso-style-priority:99; + color:purple; + text-decoration:underline; + text-underline:single;} +p + {mso-style-noshow:yes; + mso-style-priority:99; + mso-margin-top-alt:auto; + margin-right:0in; + mso-margin-bottom-alt:auto; + margin-left:0in; + mso-pagination:widow-orphan; + font-size:12.0pt; + font-family:"Times New Roman","serif"; + mso-fareast-font-family:"Times New Roman";} +pre + {mso-style-noshow:yes; + mso-style-priority:99; + mso-style-link:"HTML Preformatted Char"; + margin:0in; + margin-bottom:.0001pt; + mso-pagination:widow-orphan; + tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt; + font-size:10.0pt; + font-family:"Courier New"; + mso-fareast-font-family:"Times New Roman";} +span.Heading2Char + {mso-style-name:"Heading 2 Char"; + mso-style-noshow:yes; + mso-style-priority:9; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"Heading 2"; + mso-ansi-font-size:13.0pt; + mso-bidi-font-size:13.0pt; + font-family:"Cambria","serif"; + mso-ascii-font-family:Cambria; + mso-ascii-theme-font:major-latin; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:major-fareast; + mso-hansi-font-family:Cambria; + mso-hansi-theme-font:major-latin; + mso-bidi-font-family:"Times New Roman"; + mso-bidi-theme-font:major-bidi; + color:#4F81BD; + mso-themecolor:accent1; + font-weight:bold;} +span.Heading3Char + {mso-style-name:"Heading 3 Char"; + mso-style-noshow:yes; + mso-style-priority:9; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"Heading 3"; + mso-ansi-font-size:12.0pt; + mso-bidi-font-size:12.0pt; + font-family:"Cambria","serif"; + mso-ascii-font-family:Cambria; + mso-ascii-theme-font:major-latin; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:major-fareast; + mso-hansi-font-family:Cambria; + mso-hansi-theme-font:major-latin; + mso-bidi-font-family:"Times New Roman"; + mso-bidi-theme-font:major-bidi; + color:#4F81BD; + mso-themecolor:accent1; + font-weight:bold;} +span.Heading4Char + {mso-style-name:"Heading 4 Char"; + mso-style-noshow:yes; + mso-style-priority:9; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"Heading 4"; + mso-ansi-font-size:12.0pt; + mso-bidi-font-size:12.0pt; + font-family:"Cambria","serif"; + mso-ascii-font-family:Cambria; + mso-ascii-theme-font:major-latin; + mso-fareast-font-family:"Times New Roman"; + mso-fareast-theme-font:major-fareast; + mso-hansi-font-family:Cambria; + mso-hansi-theme-font:major-latin; + mso-bidi-font-family:"Times New Roman"; + mso-bidi-theme-font:major-bidi; + color:#4F81BD; + mso-themecolor:accent1; + font-weight:bold; + font-style:italic;} +span.HTMLPreformattedChar + {mso-style-name:"HTML Preformatted Char"; + mso-style-noshow:yes; + mso-style-priority:99; + mso-style-unhide:no; + mso-style-locked:yes; + mso-style-link:"HTML Preformatted"; + font-family:Consolas; + mso-ascii-font-family:Consolas; + mso-hansi-font-family:Consolas; + mso-bidi-font-family:Consolas;} +span.SpellE + {mso-style-name:""; + mso-spl-e:yes;} +span.GramE + {mso-style-name:""; + mso-gram-e:yes;} +.MsoChpDefault + {mso-style-type:export-only; + mso-default-props:yes; + font-size:10.0pt; + mso-ansi-font-size:10.0pt; + mso-bidi-font-size:10.0pt;} +@page Section1 + {size:8.5in 11.0in; + margin:1.0in 1.25in 1.0in 1.25in; + mso-header-margin:.5in; + mso-footer-margin:.5in; + mso-paper-source:0;} +div.Section1 + {page:Section1;} + /* List Definitions */ + @list l0 + {mso-list-id:1673945939; + mso-list-type:hybrid; + mso-list-template-ids:-2047047524 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} +@list l0:level1 + {mso-level-tab-stop:none; + mso-level-number-position:left; + text-indent:-.25in;} +ol + {margin-bottom:0in;} +ul + {margin-bottom:0in;} +--> +</style> +<!--[if gte mso 10]> +<style> + /* Style Definitions */ + table.MsoNormalTable + {mso-style-name:"Table Normal"; + mso-tstyle-rowband-size:0; + mso-tstyle-colband-size:0; + mso-style-noshow:yes; + mso-style-priority:99; + mso-style-qformat:yes; + mso-style-parent:""; + mso-padding-alt:0in 5.4pt 0in 5.4pt; + mso-para-margin:0in; + mso-para-margin-bottom:.0001pt; + mso-pagination:widow-orphan; + font-size:10.0pt; + font-family:"Times New Roman","serif";} +</style> +<![endif]--><!--[if gte mso 9]><xml> + <u1:shapedefaults u2:ext="edit" spidmax="4098"/> +</xml><![endif]--><!--[if gte mso 9]><xml> + <u3:shapelayout u4:ext="edit"> + <u3:idmap u4:ext="edit" data="1"/> + </u3:shapelayout> +</xml><![endif]--><!--[if gte mso 9]><xml> + <u1:shapedefaults u2:ext="edit" spidmax="3074"/> +</xml><![endif]--><!--[if gte mso 9]><xml> + <u3:shapelayout u4:ext="edit"> + <u3:idmap u4:ext="edit" data="1"/> + </u3:shapelayout> +</xml><![endif]--><!--[if gte mso 9]><xml> + <u1:shapedefaults u2:ext="edit" spidmax="2050"/> +</xml><![endif]--><!--[if gte mso 9]><xml> + <u3:shapelayout u4:ext="edit"> + <u3:idmap u4:ext="edit" data="1"/> + </u3:shapelayout> +</xml><![endif]--><!--[if gte mso 9]><xml> + <o:shapedefaults v:ext="edit" spidmax="3074"/> +</xml><![endif]--><!--[if gte mso 9]><xml> + <o:shapelayout v:ext="edit"> + <o:idmap v:ext="edit" data="1"/> + </o:shapelayout></xml><![endif]--> +</head> + +<body bgcolor=white lang=EN-US link=blue vlink=purple style='tab-interval:.5in' +leftmargin=8> + +<div class=Section1> + +<h2><a name=MYSAMPLE></a><a name="_top"></a><span style='mso-bookmark:MYSAMPLE'><span +style='font-family:"Verdana","sans-serif";mso-fareast-font-family:"Times New Roman"'>PSCR.SYS�PCMCIA +Smart Card Driver</span></span><u5:p></u5:p><u6:p></u6:p><span +style='mso-bookmark:MYSAMPLE'></span><span style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span></h2> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'><u7:p></u7:p>SUMMARY<u7:p></u7:p></span><span +style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span></h3> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>The PCMCIA +Smart Card Driver is used for the SCM PCMCIA smart card reader. <u7:p></u7:p>This +driver is written using Kernel-Mode Driver Framework. </span></p> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>This +driver implements Plug and Play and Power Management and is compliant with +64-bit versions of Microsoft� Windows�.<u7:p></u7:p></span></p> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>BUILDING PSCR.SYS<u7:p></u7:p></span><span style='mso-fareast-font-family: +"Times New Roman"'><o:p></o:p></span></h3> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>To build +the Pscr.sys driver, select either the checked or free DDK environment, +navigate to the Bulltlp3 directory, and type <b>build</b>. This driver +uses services provided by the smart card driver library (Smclib.sys), which are +explained in detail in the accompanying documentation.<u7:p></u7:p></span></p> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>INSTALLING PSCR.SYS<u7:p></u7:p></span><span +style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span></h3> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>The +PSCR.SYS driver is included in-box in the Windows Operating Systems. Therefore, +when the SCM 488 PCMCIA reader is inserted, the system will automatically +install the in-box driver. However, if you want to customize the source code of +this driver and would like to replace the in-box driver with your driver, you +can follow the instructions below.<o:p></o:p></span></p> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>To install +your driver, you will need to provide the INF file (on a disk), WDF <span +class=SpellE>coinstaller</span> from the %BASEDIR%\<span class=SpellE>redist</span>\<span +class=SpellE>wdf</span>\ directory and the driver file, which will be copied to +your System32\Drivers directory. The INF file makes a reference to the WDF <span +class=SpellE>coinstaller</span>. </span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>1.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Launch �Device +Manager� by clicking the �Windows� button and type �devmgmt.msc� in the �Search +programs and files� box.<o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>2.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Locate the SCM 488 +Smartcard reader device from the �Smart cards readers� category.<o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>3.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Right click on the +reader device and select �Update Driver Software�<span class=GramE>�.</span><o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>4.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Select �Browse my +computer for driver software�.<o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>5.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Select �Let me pick +from a list of device drivers on my computer�.<o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>6.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Click the �Have +Disk�� button and point it to the folder that contains your driver, INF and +coinstaller.<o:p></o:p></span></p> + +<p style='margin-left:.5in;text-indent:-.25in;mso-list:l0 level1 lfo1'><![if !supportLists]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +Verdana;mso-bidi-font-family:Verdana'><span style='mso-list:Ignore'>7.<span +style='font:7.0pt "Times New Roman"'> </span></span></span><![endif]><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Follow the +instructions of the device installation wizard to finish the installation.<o:p></o:p></span></p> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>TOOLS</span><span style='mso-fareast-font-family:"Times New Roman"'><o:p></o:p></span></h3> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Microsoft +offers a test tool (Ifdtest.exe) that allows you to use a smart card reader +directly from the command line. Normally, the smart card resource manager is +connected to a reader. To use Ifdtest.exe, you must stop the smart card +resource manager (Scardsvr.exe) by typing <b>net stop <span class=SpellE>scardsvr</span></b> +at the command line. Ifdtest.exe is also used for the smart card reader logo +test.<u7:p></u7:p><o:p></o:p></span></p> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>The driver +will not unload as long as you have Ifdtest.exe running and connected to the +driver. <u7:p></u7:p></span></p> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>You can +download Ifdtest.exe from </span><span style='font-size:10.0pt;font-family: +"Verdana","sans-serif";mso-bidi-font-family:"MS Shell Dlg"'><a +href="http://www.microsoft.com/whdc/whql/default.mspx">http://www.microsoft.com/whdc/whql/default.mspx</a></span><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'> by following the +links for smart cards. You need to order special test smart cards to have your +smart card reader qualify for the "Designed for Windows" logo. You +can find ordering information at </span><span style='font-size:10.0pt; +font-family:"Verdana","sans-serif";mso-bidi-font-family:"MS Shell Dlg"'><a +href="http://www.microsoft.com/whdc/whql/default.mspx">http://www.microsoft.com/whdc/whql/default.mspx</a></span><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>. <u7:p></u7:p> <u7:p></u7:p></span></p> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>RESOURCES<u7:p></u7:p></span><span style='mso-fareast-font-family: +"Times New Roman"'><o:p></o:p></span></h3> + +<p><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>ISO 7816 +Part 3 describes smart cards and smart card protocols in detail. Refer to the +PC99 Handbook for smart card reader requirements.<u7:p></u7:p></span></p> + +<h3><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>CODE TOUR<u7:p></u7:p></span><span style='mso-fareast-font-family: +"Times New Roman"'><o:p></o:p></span></h3> + +<h4><span style='font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>File Manifest<u7:p></u7:p></span><span style='mso-fareast-font-family: +"Times New Roman"'><o:p></o:p></span></h4> + +<pre><u>Files<span style='mso-spacerun:yes'>�������� </span>Description<u7:p></u7:p></u></pre><pre>PSCR.HTM<span style='mso-spacerun:yes'>����� </span>The documentation for this sample (this file).</pre><pre>PSCR.RC<span style='mso-spacerun:yes'>������ </span>Resource <span +class=GramE>definition file</span> for driver.</pre><pre><span class=GramE><span +style='font-family:Courier'>SOURCES<span style='mso-spacerun:yes'>������ </span>The generic file for building the code sample.<u7:p></u7:p></span></span></pre><pre><span +style='font-family:Courier'>MAKEFILE<span style='mso-spacerun:yes'>����� </span><span +class=SpellE>Makefile</span> required <span class=GramE>to build</span> the driver.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCR.INF<span style='mso-spacerun:yes'>����� </span>The INF <span +class=GramE>file</span> for installing the code sample.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRCB.C<span style='mso-spacerun:yes'>����� </span>Source file that contains the callback functions for the smart card library.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRCB.H<span style='mso-spacerun:yes'>����� </span>Function prototypes for the previous file.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRCMD.C<span style='mso-spacerun:yes'>���� </span>Implements the reader commands.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRCMD.H<span style='mso-spacerun:yes'>���� </span>Function prototypes for the previous file.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRLOG.MC<span style='mso-spacerun:yes'>��� </span>Error messages for this driver.<u7:p></u7:p></span></pre><pre><span +style='font-family:Courier'>PSCRNT.C<span style='mso-spacerun:yes'>����� </span>The main source file (load, unload, Plug and Play, Power Management).<u7:p></u7:p></span></pre><pre><span +class=GramE><span style='font-family:Courier'>PSCRNT.H<span style='mso-spacerun:yes'>����� </span>Data definitions and prototypes for the previous file.<u7:p></u7:p></span></span></pre><pre><span +style='font-family:Courier'>PSCRRDWR.C<span style='mso-spacerun:yes'>��� </span>Implements read/write operations.<u7:p></u7:p></span></pre><pre><span +class=GramE><span style='font-family:Courier'>PSCRRDWR.H<span style='mso-spacerun:yes'>��� </span>Data definitions and constant definitions for this reader.<u7:p></u7:p></span></span></pre><pre><span +class=GramE><span style='font-family:Courier'>PSCRVERS.H<span style='mso-spacerun:yes'>��� </span>Driver-specific version information.<u7:p></u7:p></span></span></pre><pre><span +style='font-family:"Verdana","sans-serif"'> </span><o:p></o:p></pre> + +<h4 style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-family:"Verdana","sans-serif";mso-fareast-font-family:"Times New Roman"'><u7:p></u7:p><u5:p></u5:p><u6:p></u6:p>Programming +Tour<u7:p></u7:p><o:p></o:p></span></h4> + +<h4 style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman"'>Driver Design<o:p></o:p></span></h4> + +<h4 style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif";mso-fareast-font-family: +"Times New Roman";font-weight:normal;mso-bidi-font-weight:bold'>This driver in its +original form was written in WDM. It was converted to KMDF to avail all the +benefits provided by KMDF in terms of reducing complexity and making it robust. +Since this driver still had to work with the existing smartcard library to +handle smartcard specific processing, I couldn�t restrict the driver to using +only KMDF interfaces. I have to escape out of KMDF for processing I/O requests +to get the underlying IRPs and provide that to smartcard library, and use +advanced IRP handling techniques to work around the limitations imposed by +smartcard library. Except for this quirk, the driver as a whole is fully +functional KMDF driver. As a sample, it also makes it easier for somebody to +adapt this driver for USB devices because KMDF has good support for interfacing +with USB devices.<o:p></o:p></span></h4> + +<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><b><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Power Management</span></b><u5:p></u5:p><u6:p></u6:p><o:p></o:p></p> + +<u7:p></u7:p> + +<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Power Management is +described in detail in the DDK documentation. There is, however, one situation +that is specific to smart card readers: how to deal with smart card insertions +and removals while the system is in standby or hibernation mode. <u7:p></u7:p></span></p> + +<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Your reader will +not see any card insertion or removal events in these modes, because the bus +might not even have power. You must save the card state before your reader goes +into standby or hibernation mode. After the system returns from these modes, +you need to determine what the state of the card is. You must complete card +tracking calls whenever there was a card in the reader before standby or +hibernation mode <i>or</i> whenever there is a card in the reader after these +modes. This step is necessary because the user could have changed the card +while the system was in a low-power mode. <u7:p></u7:p></span></p> + +<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'> </p> + +<p align=center style='text-align:center;tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><a +href="#_top"><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'>Top +of page</span></a><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'> +</span><o:p></o:p></p> + +<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=499 + style='width:5.2in;mso-cellspacing:0in;mso-yfti-tbllook:1184;mso-padding-alt: + 0in 5.4pt 0in 5.4pt'> + <tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes; + height:1.2pt'> + <td style='background:aqua;padding:.75pt .75pt .75pt .75pt;height:1.2pt'> + <p class=MsoNormal><span style='color:black'><u7:p><u7:p></u7:p><u5:p></u5:p><u6:p></u6:p> </u7:p></span></p> + </td> + </tr> +</table> + +<p style='tab-stops:45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt'><span +style='font-size:7.5pt;font-family:"MS Sans Serif","serif"'>� 2004 Microsoft +Corporation</span><span style='font-size:10.0pt;font-family:"Verdana","sans-serif"'> +</span><o:p></o:p></p> + +</div> + +<u6:p></u6:p><u5:p></u5:p><u7:p></u7:p> +</body> + +</html> diff --git a/smartcrd/pscr/pscr.inx b/smartcrd/pscr/pscr.inx Binary files differnew file mode 100644 index 00000000..28e93816 --- /dev/null +++ b/smartcrd/pscr/pscr.inx diff --git a/smartcrd/pscr/pscr.rc b/smartcrd/pscr/pscr.rc new file mode 100644 index 00000000..4bf91809 --- /dev/null +++ b/smartcrd/pscr/pscr.rc @@ -0,0 +1,48 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// +// Copyright (C) SCM Microsystems, 1998 - 1999 +// +// File: pscr.rc +// +// Notes: +// +// The file pscr.rc was reviewed by LCA in June 2011 and per license is +// acceptable for Microsoft use under Dealpoint ID 178449. +// +//-------------------------------------------------------------------------- + +#include <windows.h> +#include <ntverp.h> + +/* These need to be defined before including common.ver: */ +/*-----------------------------------------------------------------*/ +/* String Equate Default Value (if not defined) */ +/* ------------------------ -------------------------------- */ +/* VER_LEGALCOPYRIGHT_STR VER_LEGALCOPYRIGHT_YEARS */ +/* VER_FILETYPE */ +/* VER_FILESUBTYPE */ +/* VER_FILEDESCRIPTION_STR */ +/* VER_INTERNALNAME_STR */ +/* VER_FILEVERSION VER_PRODUCTVERSION */ +/* VER_FILEVERSION_STR VER_PRODUCTVERSION_STR */ +/* VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR */ +/*-----------------------------------------------------------------*/ + + +#define VER_LEGALCOPYRIGHT_YEARS "1997-1999" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) SCM Microsystems, Inc. " VER_LEGALCOPYRIGHT_YEARS + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "SCM PCMCIA Smart Card Reader" +#define VER_INTERNALNAME_STR "pscr.sys" +#define VER_ORIGINALFILENAME_STR "pscr.sys" + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "SCM Microsystems, Inc." + +#include "common.ver" +#include "pscrlog.rc" + diff --git a/smartcrd/pscr/pscrcb.c b/smartcrd/pscr/pscrcb.c new file mode 100644 index 00000000..4b89680c --- /dev/null +++ b/smartcrd/pscr/pscrcb.c @@ -0,0 +1,1008 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCB.c + +Abstract: + + callback handler for PSCR.xxx driver + +Author: + + Andreas Straub + +Environment: + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrcb.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 8/18/1997 1.00 Initial Version + Andreas Straub 9/24/1997 1.02 Flush Interface if card tracking + requested + +--*/ + +#include <PscrNT.h> +#include <PscrRdWr.h> +#include <PscrCmd.h> +#include <PscrCB.h> + + +NTSTATUS +CBCardPower( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBCardPower: + callback handler for SMCLIB RDF_CARD_POWER + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_BUFFER_TOO_SMALL + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR ATRBuffer[ ATR_SIZE ], TLVList[16]; + ULONG Command, + ATRLength = 0; + PREADER_EXTENSION ReaderExtension; + BYTE CardState; + KIRQL irql; +#if DBG || DEBUG + static PCHAR request[] = { "PowerDown", "ColdReset", "WarmReset"}; +#endif + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardPower: Enter, Request = %s\n", + request[SmartcardExtension->MinorIoControlCode]) + ); + + ReaderExtension = SmartcardExtension->ReaderExtension; + + // + // update actual power state + // + Command = SmartcardExtension->MinorIoControlCode; + + switch ( Command ) { + case SCARD_WARM_RESET: + + // if the card was not powerd, fall thru to cold reset + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + + if ( SmartcardExtension->ReaderCapabilities.CurrentState > + SCARD_SWALLOWED ) { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + // reset the card + ATRLength = ATR_SIZE; + NTStatus = CmdReset( + ReaderExtension, + ReaderExtension->Device, + TRUE, // warm reset + ATRBuffer, + &ATRLength + ); + + break; + } else { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + } + + // warm reset not possible because card was not powerd + case SCARD_COLD_RESET: + + // reset the card + ATRLength = ATR_SIZE; + NTStatus = CmdReset( + ReaderExtension, + ReaderExtension->Device, + FALSE, // cold reset + ATRBuffer, + &ATRLength + ); + break; + + case SCARD_POWER_DOWN: + ATRLength = 0; + NTStatus = CmdDeactivate( + ReaderExtension, + ReaderExtension->Device + ); + + // discard old card status + CardState = CBGetCardState(SmartcardExtension); + CBUpdateCardState(SmartcardExtension, CardState, FALSE); + break; + } + + if (NT_SUCCESS(NTStatus)) { + + // + // Set the 'restart of work waiting time' counter for T=0 + // This will send a WTX request for n NULL bytes received + // + TLVList[0] = TAG_SET_NULL_BYTES; + TLVList[1] = 1; + TLVList[2] = 0x05; + + NTStatus = CmdSetInterfaceParameter( + ReaderExtension, + DEVICE_READER, + TLVList, + 3 + ); + } + + // Removing this assert as this causes unnecessary confusion. The driver + // passes ifdtest even with an error here. + // NT_ASSERT(NT_SUCCESS(NTStatus)); + + // finish the request + if ( NT_SUCCESS( NTStatus )) { + // update all neccessary data if an ATR was received + if ( ATRLength > 2 ) { + // + // the lib expects only the ATR, so we skip the + // 900x from the reader + // + ATRLength -= 2; + + // copy ATR to user buffer buffer + if ( ATRLength <= SmartcardExtension->IoRequest.ReplyBufferLength ) { + SysCopyMemory( + SmartcardExtension->IoRequest.ReplyBuffer, + ATRBuffer, + ATRLength + ); + *SmartcardExtension->IoRequest.Information = ATRLength; + } + + // copy ATR to card capability buffer + if ( ATRLength <= MAXIMUM_ATR_LENGTH ) { + SysCopyMemory( + SmartcardExtension->CardCapabilities.ATR.Buffer, + ATRBuffer, + ATRLength + ); + + SmartcardExtension->CardCapabilities.ATR.Length = + ( UCHAR )ATRLength; + + // let the lib update the card capabilities + NTStatus = SmartcardUpdateCardCapabilities( + SmartcardExtension + ); + } else { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + } + } + + if ( !NT_SUCCESS( NTStatus )) { + switch ( NTStatus ) { + case STATUS_NO_MEDIA: + case STATUS_BUFFER_TOO_SMALL: + break; + + case STATUS_TIMEOUT: + NTStatus = STATUS_IO_TIMEOUT; + break; + + default: + NTStatus = STATUS_UNRECOGNIZED_MEDIA; + break; + } + if( NTStatus != STATUS_SUCCESS ) + { + + // notify resman if card was removed + CBUpdateCardState( + SmartcardExtension, + CBGetCardState( SmartcardExtension ), + FALSE + ); + + // resman requires status ok to translate ntstatus to scard... error. + if( SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT ) + { + SmartcardUpdateCardCapabilities( SmartcardExtension ); + NTStatus = STATUS_SUCCESS; + } + } + } + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + // Clearing the buffers + RtlZeroMemory (ATRBuffer, ATR_SIZE); + RtlZeroMemory (TLVList, 16); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardPower: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBSetProtocol( + PSMARTCARD_EXTENSION SmartcardExtension + ) + +/*++ + +CBSetProtocol: + callback handler for SMCLIB RDF_SET_PROTOCOL + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_BUFFER_TOO_SMALL + STATUS_INVALID_DEVICE_STATE + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_PENDING; + USHORT SCLibProtocol; + UCHAR TLVList[ TLV_BUFFER_SIZE ]; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + KIRQL irql; + + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + + if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC) { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + + return STATUS_SUCCESS; + } else { + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBSetProtocol: Enter\n" ) + ); + + SCLibProtocol = ( USHORT )( SmartcardExtension->MinorIoControlCode ); + + if (SCLibProtocol & (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)) { + // + // setup the TLV list for the Set Interface Parameter List + // + TLVList[ 0 ] = TAG_ICC_PROTOCOLS; + TLVList[ 1 ] = 0x01; + TLVList[ 2 ] = + (SCLibProtocol & SCARD_PROTOCOL_T1 ? PSCR_PROTOCOL_T1 : PSCR_PROTOCOL_T0); + + // do the PTS + NTStatus = CmdSetInterfaceParameter( + ReaderExtension, + ReaderExtension->Device, + TLVList, + 3 // size of list + ); + + } else { + + // we don't support other modi + NTStatus = STATUS_INVALID_DEVICE_REQUEST; + } + + // if protocol selection failed, prevent from calling invalid protocols + if ( NT_SUCCESS( NTStatus )) { + + KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, + &irql); + SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC; + SCLibProtocol = (SCLibProtocol & SCARD_PROTOCOL_T1 & + SmartcardExtension->CardCapabilities.Protocol.Supported) ? + SCARD_PROTOCOL_T1 : + SCARD_PROTOCOL_T0; + + KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, + irql); + } else { + SCLibProtocol = SCARD_PROTOCOL_UNDEFINED; + } + + // Return the selected protocol to the caller. + SmartcardExtension->CardCapabilities.Protocol.Selected = SCLibProtocol; + *( PULONG )( SmartcardExtension->IoRequest.ReplyBuffer ) = SCLibProtocol; + *( SmartcardExtension->IoRequest.Information ) = sizeof( ULONG ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBSetProtocol: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBTransmit: + callback handler for SMCLIB RDF_TRANSMIT + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBTransmit: Enter\n" ) + ); + + // dispatch on the selected protocol + switch ( SmartcardExtension->CardCapabilities.Protocol.Selected ) { + case SCARD_PROTOCOL_T0: + NTStatus = CBT0Transmit( SmartcardExtension ); + break; + + case SCARD_PROTOCOL_T1: + NTStatus = CBT1Transmit( SmartcardExtension ); + break; + + case SCARD_PROTOCOL_RAW: + NTStatus = CBRawTransmit( SmartcardExtension ); + break; + + default: + NTStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBTransmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBRawTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBRawTransmit: + finishes the callback RDF_TRANSMIT for the RAW protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR TLVList[ TLV_BUFFER_SIZE ], + Val, + Len; + ULONG TLVListLen; + PREADER_EXTENSION ReaderExtension; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBRawTransmit: Enter\n" ) + ); + + ReaderExtension = SmartcardExtension->ReaderExtension; + // + // read the status file of ICC1 from the reader + // + TLVListLen = TLV_BUFFER_SIZE; + NTStatus = CmdReadStatusFile( + ReaderExtension, + ReaderExtension->Device, + TLVList, + &TLVListLen + ); + + // + // check the active protocol of the reader + // + if ( NT_SUCCESS( NTStatus )) { + Len = sizeof(Val); + NTStatus = CmdGetTagValue( + TAG_ICC_PROTOCOLS, + TLVList, + TLVListLen, + &Len, + ( PVOID ) &Val + ); + + // execute the active protocol + if ( NT_SUCCESS( NTStatus )) { + + // translate the actual protocol to a value the lib can understand + switch ( Val ) { + case PSCR_PROTOCOL_T0: + NTStatus = CBT0Transmit( SmartcardExtension ); + break; + case PSCR_PROTOCOL_T1: + NTStatus = CBT1Transmit( SmartcardExtension ); + break; + default: + NTStatus = STATUS_UNSUCCESSFUL; + break; + } + } + } + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBRawTransmit: Exit (%lx)\n", NTStatus ) + ); + return( NTStatus ); +} + +NTSTATUS +CBT1Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBT1Transmit: + finishes the callback RDF_TRANSMIT for the T1 protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + ULONG IOBytes; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: Enter\n" ) + ); + // + // use the lib support to construct the T=1 packets + // + do { + // + // no header for the T=1 protocol + // + SmartcardExtension->SmartcardRequest.BufferLength = 0; + // + // SCM-TM: Siemens 4440 accepts only NAD=0!!! + // + SmartcardExtension->T1.NAD = 0; + // + // let the lib setup the T=1 APDU & check for errors + // + NTStatus = SmartcardT1Request( SmartcardExtension ); + if ( NT_SUCCESS( NTStatus )) { + + // send command (don't calculate LRC because CRC may be used!) + IOBytes = 0; + NTStatus = PscrWriteDirect( + SmartcardExtension->ReaderExtension, + SmartcardExtension->SmartcardRequest.Buffer, + SmartcardExtension->SmartcardRequest.BufferLength, + &IOBytes + ); + if ( !NT_SUCCESS(NTStatus)) { + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: PscrWriteDirect error (%lx)\n", NTStatus ) + ); + } + // + // extend the timeout if a Wtx request was sent by the card. if the + // card responds before the waiting time extension expires, the data are + // buffered in the reader. A delay without polling the reader status + // slows down the performance of the driver, but wtx is an exeption, + // not the rule. + // + if (SmartcardExtension->T1.Wtx) { + SysDelay( + (( SmartcardExtension->T1.Wtx * + SmartcardExtension->CardCapabilities.T1.BWT + 999L )/ + 1000L) + ); + + } + + // get response + SmartcardExtension->SmartcardReply.BufferLength = 0; + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + SmartcardExtension->SmartcardReply.Buffer, + MAX_T1_BLOCK_SIZE, + &SmartcardExtension->SmartcardReply.BufferLength + ); + + // if PscrRead detects an LRC error, ignore it (maybe CRC used) + if ( NTStatus == STATUS_CRC_ERROR ) { + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: PscrRead CRC error (%lx)\n", NTStatus ) + ); + } + + // + // We even continue if the prev. read failed. + // We let the smart card library continue, because it might + // send a resynch. request in case of a timeout + // + NTStatus = SmartcardT1Reply( SmartcardExtension ); + } + + // continue if the lib wants to send the next packet + } while ( NTStatus == STATUS_MORE_PROCESSING_REQUIRED ); + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT1Transmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBT0Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBT0Transmit: + finishes the callback RDF_TRANSMIT for the T0 protocol + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_TIMEOUT + STATUS_INVALID_DEVICE_REQUEST + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + PUCHAR pRequest,pReply; + ULONG IOBytes, APDULength, RequestLength; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + UCHAR WtxReply[16]; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT0Transmit: Enter\n" ) + ); + + SysFillMemory( SmartcardExtension->SmartcardReply.Buffer, 0xCC, MAX_T1_BLOCK_SIZE ); + + pRequest = SmartcardExtension->SmartcardRequest.Buffer; + pReply = SmartcardExtension->SmartcardReply.Buffer; + + // setup the command header + pRequest[ PSCR_NAD ] = + ( SmartcardExtension->ReaderExtension->Device == DEVICE_ICC1 ) ? + NAD_TO_ICC1 : NAD_TO_ICC1; + + pRequest[ PSCR_PCB ] = PCB_DEFAULT; + // + // get the length of the user data packet & set the appropriate LEN + // information the complete user packet consists of a SCARD_IO_REQUEST + // structure followed by the APDU. the length of SCARD_IO_REQUEST is + // transferred in the member cbPciLength of the structure + // + APDULength = SmartcardExtension->IoRequest.RequestBufferLength; + if ((((PSCARD_IO_REQUEST) SmartcardExtension->IoRequest.RequestBuffer)->cbPciLength) >= APDULength) { + // Prevent integer underflow + return (STATUS_INSUFFICIENT_RESOURCES); + } + APDULength -= ((PSCARD_IO_REQUEST) SmartcardExtension-> + IoRequest.RequestBuffer)->cbPciLength; + // + // a 4 byte APDU will be patched to a 5 byte TPDU by the lib; see + // annex of the ISO + // + if ( APDULength == 4 ) APDULength++; + // + // if the total length of the T1 (reader) packet is larger than 0xFF + // the extended length notation will be used + // + if ( APDULength >= 0xFF ) { + pRequest[ PSCR_LEN ] = 0xFF; + pRequest[ PSCR_LEN+1 ] = HIBYTE( APDULength ); + pRequest[ PSCR_LEN+2 ] = LOBYTE( APDULength ); + SmartcardExtension->SmartcardRequest.BufferLength = + PSCR_EXT_PROLOGUE_LENGTH; + } else { + pRequest[ PSCR_LEN ] = ( UCHAR ) APDULength; + SmartcardExtension->SmartcardRequest.BufferLength = + PSCR_PROLOGUE_LENGTH; + } + + // let the lib setup the T=1 APDU & check for errors + NTStatus = SmartcardT0Request( SmartcardExtension ); + RequestLength = SmartcardExtension->SmartcardRequest.BufferLength; + + while ( NT_SUCCESS( NTStatus )) { + + // check to see if device is busy. + { + PPSCR_REGISTERS IOBase; + UCHAR Status; + + IOBase = SmartcardExtension->ReaderExtension->IOBase; + + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + + if( 0x03 == Status ) + { + NTStatus = STATUS_DEVICE_BUSY; + break; + } + } + + // send command + IOBytes = 0; + NTStatus = PscrWrite( + SmartcardExtension->ReaderExtension, + pRequest, + RequestLength, + &IOBytes + ); + + // get response + if ( NT_SUCCESS( NTStatus )) { + IOBytes = 0; + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + // extract APDU from T=1 transport packet + if ( NT_SUCCESS( NTStatus )) { + + if (IOBytes < 4) { + + NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; + break; + + } + if (IOData[ PSCR_PCB ] == WTX_REQUEST) { + + WtxReply[PSCR_NAD] = NAD_TO_PSCR; + WtxReply[PSCR_PCB] = WTX_REPLY; + WtxReply[PSCR_LEN] = 1; + WtxReply[PSCR_INF] = IOData[PSCR_INF]; + + RequestLength = 4; + pRequest = WtxReply; + continue; + } + + if ( IOData[ PSCR_LEN ] == 0xFF ) { + // + // extended length byte used + // + APDULength = IOData[ PSCR_LEN + 1 ] << 8; + APDULength += IOData[ PSCR_LEN + 2 ]; + + SmartcardExtension->SmartcardReply.BufferLength = APDULength ; + if (APDULength >= (sizeof(IOData) - (PSCR_APDU + 2))) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + break; + } + SysCopyMemory( pReply, &IOData[ PSCR_APDU + 2 ], APDULength ); + } else { + + if ((IOData[PSCR_LEN] > SmartcardExtension->SmartcardReply.BufferSize) || + (IOData[PSCR_LEN] > MAX_T1_BLOCK_SIZE + PSCR_APDU)) { + NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; + break; + } + SmartcardExtension->SmartcardReply.BufferLength = + IOData[ PSCR_LEN ]; + + SysCopyMemory( + pReply, + &IOData[ PSCR_APDU ], + IOData[ PSCR_LEN ] + ); + } + + if( SmartcardExtension->ReaderCapabilities.CurrentState <= + SCARD_ABSENT ) + { + NTStatus = STATUS_NO_MEDIA; + } + else + { + // let the lib evaluate the result & tansfer the data + NTStatus = SmartcardT0Reply( SmartcardExtension ); + } + break; + } + } + } + + // start freeze routine, if an interrupt was sent, but no freeze data was read + if( SmartcardExtension->ReaderExtension->RequestInterrupt ) + PscrFreeze( SmartcardExtension ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBT0Transmit: Exit (%lx)\n", NTStatus ) + ); + + return( NTStatus ); +} + +NTSTATUS +CBCardTracking( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBCardTracking: + callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was + validated by the smclib (i.e. a card removal request will only be passed + if a card is present). + for a win95 build STATUS_PENDING will be returned without any other action. + for NT the cancel routine for the irp will be set to the drivers cancel + routine. + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_PENDING + +--*/ +{ + WDFREQUEST request; + PDEVICE_EXTENSION DeviceExtension; + NTSTATUS status; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardTracking: Enter\n" ) + ); + + request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->NotificationIrp); + + DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(WdfRequestGetIoQueue(request))); + + IoMarkIrpPending(SmartcardExtension->OsData->NotificationIrp); + + // + // Move the stack pointer back to where it was when the IRP + // was delivered to the driver. This compensates for the + // IoSetNextIrpStackLocation that we did when we presented the IRP + // to the smartcard libarary. + // + IoSkipCurrentIrpStackLocation(SmartcardExtension->OsData->NotificationIrp); + + status = WdfRequestForwardToIoQueue(request, + DeviceExtension->NotificationQueue); + if (!NT_SUCCESS(status)) { + NT_ASSERT(NT_SUCCESS(status)); + InterlockedExchangePointer( + &(SmartcardExtension->OsData->NotificationIrp), + NULL + ); + WdfRequestComplete(request, status); + } + + status = STATUS_PENDING; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBCardTracking: Exit \n" ) + ); + + return status; +} + +VOID +CBUpdateCardState( + PSMARTCARD_EXTENSION SmartcardExtension, + UCHAR IccState, + BOOLEAN SystemWakeUp + ) +{ + ULONG oldState; + NTSTATUS status; + KIRQL irql; + WDFREQUEST request; + PDEVICE_EXTENSION DeviceExtension; + + + KeAcquireSpinLock( + &SmartcardExtension->OsData->SpinLock, + &irql + ); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBUpdateCardState: Enter \n" ) + ); + + oldState = + (SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ? + SCARD_PRESENT : SCARD_ABSENT); + + SmartcardExtension->ReaderCapabilities.CurrentState = + (IccState == PSCR_ICC_PRESENT ? SCARD_PRESENT : SCARD_ABSENT); + + SmartcardDebug( + DEBUG_DRIVER, + ( "PSCR!CBUpdateCardState: Smart card %s\n", + IccState == PSCR_ICC_PRESENT ? "inserted" : "removed") + ); + + if ( SmartcardExtension->OsData->NotificationIrp != NULL && + (SystemWakeUp && + (oldState == SCARD_PRESENT || + SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_PRESENT) || + SmartcardExtension->ReaderCapabilities.CurrentState != oldState)) { + PIRP notificationIrp ; + + notificationIrp = InterlockedExchangePointer( + &(SmartcardExtension->OsData->NotificationIrp), + NULL + ); + + DeviceExtension = GetDeviceExtension(WdfWdmDeviceGetWdfDeviceHandle(SmartcardExtension->OsData->DeviceObject)); + + KeReleaseSpinLock( + &SmartcardExtension->OsData->SpinLock, + irql + ); + + status = WdfIoQueueRetrieveNextRequest( + DeviceExtension->NotificationQueue, + &request); + if (NT_SUCCESS(status)) { + + SmartcardDebug( + DEBUG_DRIVER, + ( "PSCR!CBUpdateCardState: Completing Irp %p\n", + notificationIrp) + ); + + WdfRequestCompleteWithInformation(request, status, 0); + } + else { + NT_ASSERTMSG("WdfIoQueueRetrieveNextRequest failed", + status == STATUS_NO_MORE_ENTRIES); + } + } else { + KeReleaseSpinLock( + &SmartcardExtension->OsData->SpinLock, + irql + ); + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!CBUpdateCardState: Exit \n" ) + ); +} + +UCHAR +CBGetCardState( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +CBUpdateCardState: + updates the variable CurrentState in SmartcardExtension + +Arguments: + SmartcardExtension context of call + +Return Value: + STATUS_SUCCESS + +--*/ +{ + UCHAR TLVList[ TLV_BUFFER_SIZE ], Val, Len; + ULONG TLVListLen; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + + // read the status file of ICC1 from the reader + TLVListLen = TLV_BUFFER_SIZE; + + if ( NT_SUCCESS( CmdReadStatusFile( + ReaderExtension, + ReaderExtension->Device, + TLVList, + &TLVListLen + ))) { + + // get reader status value + Len = sizeof(Val); + CmdGetTagValue( + TAG_READER_STATUS, + TLVList, + TLVListLen, + &Len, + ( PVOID ) &Val + ); + } else { + // IO-error is interpreted as card absent + Val = PSCR_ICC_ABSENT; + } + + return Val; +} + +// -------------------------------- END OF FILE ------------------------------ + + + diff --git a/smartcrd/pscr/pscrcb.h b/smartcrd/pscr/pscrcb.h new file mode 100644 index 00000000..51a161a8 --- /dev/null +++ b/smartcrd/pscr/pscrcb.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCB.h + +Abstract: + + prototypes of callback handlers for pscr.xxx + +Author: + + Andreas Straub + +Environment: + + Win 95 + NT 4.0 + +Notes: + + The file pscrcb.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_CALLBACK_H__ ) +#define __PSCR_CALLBACK_H__ + +NTSTATUS +CBCardPower( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBSetProtocol( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBT0Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBT1Transmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBRawTransmit( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +NTSTATUS +CBCardTracking( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +CBUpdateCardState( + PSMARTCARD_EXTENSION SmartcardExtension, + UCHAR CardState, + BOOLEAN SystemWakeUp + ); + +UCHAR +CBGetCardState( + PSMARTCARD_EXTENSION SmartcardExtension + ); +#endif // __PSCR_CALLBACK_H__ + +// ------------------------------- END OF FILE ------------------------------- diff --git a/smartcrd/pscr/pscrcmd.c b/smartcrd/pscr/pscrcmd.c new file mode 100644 index 00000000..ff694089 --- /dev/null +++ b/smartcrd/pscr/pscrcmd.c @@ -0,0 +1,981 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCmd.c + +Abstract: + + Basic command functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Environment: + + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrcmd.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 8/18/1997 1.00 Initial Version + Andreas Straub 9/24/1997 1.02 delay for read/write removed + +--*/ + +#include <PscrNT.h> +#include <PscrRdWr.h> +#include <PscrCmd.h> + +NTSTATUS +CmdResetInterface( + PREADER_EXTENSION ReaderExtension + ) +/*++ +CmdResetInterface: + + Performs a reset of the reader interface (NOT of the PCMCIA controller) + - flush available data + - set RESET bit + - perform a buffer size exchange between reader & host + - enables interrupts for freeze events + - disables default PTS + +Arguments: + ReaderExtension context of call + +Return Value: + STATUS_SUCCESS + STATUS_IO_DEVICE_ERROR + +--*/ +{ + + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR Len, + Tag, + Cnt, + InData[ TLV_BUFFER_SIZE ] = {0}; + PPSCR_REGISTERS IOBase; + UCHAR EnableInterrupts[] = { 0x28, 0x01, 0x01}; + + + IOBase = ReaderExtension->IOBase; + + // discard any data + PscrFlushInterface( ReaderExtension ); + + // reset reader + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_RESET_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + + NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT ); + + // read & check vendor string + if ( NT_SUCCESS( NTStatus )) { + + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // get actual len from TLV list + // + READ_PORT_UCHAR( &IOBase->SizeMSReg ); + READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + Tag = READ_PORT_UCHAR( &IOBase->DataReg ); + Len = READ_PORT_UCHAR( &IOBase->DataReg ); + // + // avoid overwrite of buffer + // + if ( Len > TLV_BUFFER_SIZE ) { + Len = TLV_BUFFER_SIZE; + } + for ( Cnt = 0; Cnt < Len; Cnt++ ) { + InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); + } + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + // + // check vendor string + // + if ( SysCompareMemory( + InData, + PSCR_ID_STRING, + sizeof( PSCR_ID_STRING ) + )) { + NTStatus = STATUS_IO_DEVICE_ERROR; + } else { + // + // vendor string was correct, check buffer size + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_READ_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT ); + // + // reader ready to transfer interface buffer size + // + if ( NT_SUCCESS( NTStatus )) { + // + // set size read & host control + // + WRITE_PORT_UCHAR( + &IOBase->CmdStatusReg, + PSCR_SIZE_READ_BIT | PSCR_HOST_CONTROL_BIT + ); + + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // read buffer length + // + Len = READ_PORT_UCHAR( &IOBase->SizeMSReg ); + Len = READ_PORT_UCHAR( &IOBase->SizeLSReg ); + // + // avoid overwrite of buffer + // + if ( Len > TLV_BUFFER_SIZE ) { + Len = TLV_BUFFER_SIZE; + } + for ( Cnt = 0; Cnt < Len; Cnt++ ) { + InData[ Cnt ] = READ_PORT_UCHAR( &IOBase->DataReg ); + } + // + // transfer of interface buffer size okay + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + // + // notify the reader about the supported buffer size + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_WRITE_PSCR_REG ); + + WRITE_PORT_UCHAR( &IOBase->SizeMSReg, 0 ); + WRITE_PORT_UCHAR( &IOBase->SizeLSReg, 2 ); + // + // Write the same data buffer size as the one we just got. + // + if (Len >= 1) { + WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 0 ] ); + WRITE_PORT_UCHAR( &IOBase->DataReg, InData[ 1 ] ); + } + // + // store the size to report to the lib + // The maximum buffer size of the reader is to betrieved with + // ((ULONG)InData[ 1 ] << 8) | InData[ 0 ] + // + ReaderExtension->MaxIFSD = 254; + + // + // let the reader process the size write command + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_SIZE_WRITE_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_FREE_BIT ); + } + } + } + // + // clean up any host control settings + // + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + // + // enable interrupts + // + CmdSetInterfaceParameter( + ReaderExtension, + ReaderExtension->Device, + EnableInterrupts, + sizeof( EnableInterrupts ) + ); + + return( NTStatus ); +} + +NTSTATUS +CmdReset( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + BOOLEAN WarmReset, + PUCHAR pATR, + PULONG pATRLength + ) +/*++ +CmdReset: + performs a reset of the reader / ICC + +Arguments: + ReaderExtension context of call + Device device requested ( ICC_1, ICC_2, PSCR ) + WarmReset kind of ICC reset + pATR ptr to ATR buffer, NULL if no ATR required + pATRLength size of ATR buffer / length of ATR + +Return Value: + STATUS_SUCCESS + STATUS_NO_MEDIA + STATUS_UNRECOGNIZED_MEDIA + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ], + P2; + USHORT ICCStatus; + ULONG IOBytes; + + // ATR from the smartcard requestet? P2 = 1 + P2 = 0; + if (( pATR != NULL ) && ( pATRLength != NULL )) { + if ( *pATRLength > 0 ) + P2 = 0x01; + } + + // build the RESET command. + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05; + + if ( WarmReset == TRUE ) { + IOData[ PSCR_INF+0 ] = CLA_WARM_RESET; + IOData[ PSCR_INF+1 ] = INS_WARM_RESET; + } else { + IOData[ PSCR_INF+0 ] = CLA_RESET; + IOData[ PSCR_INF+1 ] = INS_RESET; + } + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = P2; + IOData[ PSCR_INF+4 ] = 0x00; + + // write command + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // read data + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + // error detection + if ( NT_SUCCESS( NTStatus )) { + // + // the location of the error code in the buffer + // is: ( data ) - STATUS_MSB - STATUS_LSB - EPILOGUE + // + ICCStatus = (( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-2 ]) << 8; + ICCStatus |= ( USHORT )IOData[ IOBytes-PSCR_EPILOGUE_LENGTH-1 ]; + + switch ( ICCStatus ) { + case PSCR_SW_SYNC_ATR_SUCCESS: + case PSCR_SW_ASYNC_ATR_SUCCESS: + break; + + case PSCR_SW_NO_ICC: + NTStatus = STATUS_NO_MEDIA; + break; + + case PSCR_SW_NO_PROTOCOL: + case PSCR_SW_NO_ATR: + case PSCR_SW_NO_ATR_OR_PROTOCOL: + case PSCR_SW_NO_ATR_OR_PROTOCOL2: + case PSCR_SW_ICC_NOT_ACTIVE: + case PSCR_SW_NON_SUPPORTED_PROTOCOL: + case PSCR_SW_PROTOCOL_ERROR: + default: + NTStatus = STATUS_UNRECOGNIZED_MEDIA; + } + // + // copy ATR if required + // + if ( NT_SUCCESS( NTStatus )) { + if ( P2 == 0x01 ) { + IOBytes -= PSCR_PROLOGUE_LENGTH + PSCR_EPILOGUE_LENGTH; + if ( IOBytes > *pATRLength ) { + IOBytes = *pATRLength; + } + SysCopyMemory( + pATR, + &IOData[ PSCR_PROLOGUE_LENGTH ], + IOBytes + ); + *pATRLength = IOBytes; + } + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdDeactivate( + PREADER_EXTENSION ReaderExtension, + UCHAR Device + ) +/*++ +CmdDeactivate: + Deactivates the requested device + +Arguments: + ReaderExtension context of call + Device requested device + +Return Value: + STATUS_SUCCESS + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + ULONG IOBytes; + + // + // build the DEACTIVATE command. + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05; + + IOData[ PSCR_INF+0 ] = CLA_DEACTIVATE; + IOData[ PSCR_INF+1 ] = INS_DEACTIVATE; + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = 0x00; + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // read data to trap communication errors + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + } + return( NTStatus ); +} + +NTSTATUS +CmdReadBinary( + PREADER_EXTENSION ReaderExtension, + USHORT Offset, + PUCHAR pBuffer, + PULONG pBufferLength + ) +/*++ +CmdReadBinary: + read binary data from an PSCR data file + +Arguments: + ReaderExtension context of call + Offset offset in file + pBuffer ptr to data buffer + pBufferLength length of buffer / number of bytes read + +Return Value: + + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + // + // check parameters + // + if (( pBuffer == NULL ) || ( pBufferLength == NULL)) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + // + // build the READ BINARY command + // + IOData[ PSCR_NAD] = NAD_TO_PSCR; + IOData[ PSCR_PCB] = PCB_DEFAULT; + IOData[ PSCR_LEN] = 0x05; + + IOData[ PSCR_INF+0 ] = CLA_READ_BINARY; + IOData[ PSCR_INF+1 ] = INS_READ_BINARY; + IOData[ PSCR_INF+2 ] = HIBYTE( Offset ); + IOData[ PSCR_INF+3 ] = LOBYTE( Offset ); + IOData[ PSCR_INF+4 ] = 0x00; + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // read data + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // error check + // + ICCStatus = + ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ]; + + switch ( ICCStatus ) { + case PSCR_SW_FILE_NO_ACCEPPTED_AUTH: + case PSCR_SW_FILE_NO_ACCESS: + case PSCR_SW_FILE_BAD_OFFSET: + case PSCR_SW_END_OF_FILE_READ: + NTStatus = STATUS_UNSUCCESSFUL; + break; + default: + break; + } + // + // copy data + // + if ( NT_SUCCESS( NTStatus )) { + if ( *pBufferLength < + IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH ) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } else { + ( *pBufferLength ) = + IOBytes-PSCR_PROLOGUE_LENGTH-PSCR_STATUS_LENGTH; + SysCopyMemory( + pBuffer, + &IOData[ PSCR_PROLOGUE_LENGTH ], + *pBufferLength + ); + } + } + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdSelectFile( + PREADER_EXTENSION ReaderExtension, + USHORT FileId + ) +/*++ +CmdSelectFile: + selects a file/directoy of the reader + +Arguments: + ReaderExtension context of call + FileId ID of file + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + error values from PscrRead / PscrWrite +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + + // + // build the SELECT FILE command + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x07; + + IOData[ PSCR_INF+0 ] = CLA_SELECT_FILE; + IOData[ PSCR_INF+1 ] = INS_SELECT_FILE; + IOData[ PSCR_INF+2 ] = 0x00; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = 0x02; + IOData[ PSCR_INF+5 ] = HIBYTE( FileId ); + IOData[ PSCR_INF+6 ] = LOBYTE( FileId ); + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 10, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // get the response of the reader + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // check errors + // + ICCStatus = + ((USHORT)IOData[ IOBytes-2-PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes-1-PSCR_EPILOGUE_LENGTH ]; + + if ( ICCStatus == PSCR_SW_FILE_NOT_FOUND ) { + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdSetInterfaceParameter( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + PUCHAR pTLVList, + UCHAR TLVListLen + ) +/*++ +CmdSetInterfaceParameter: + Sets the interface pareameter of the ICC interface to the values specified + in the TLV list + +Arguments: + ReaderExtension context of call + Device device + pTLVList ptr to list of tag-len-value's specified by caller + TLVListLen length of list + +Return Value: + STATUS_SUCCESS + STATUS_INVALID_PARAMETER + STATUS_INVALID_DEVICE_STATE + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + USHORT ICCStatus; + ULONG IOBytes; + + // + // check parameter + // + if ( pTLVList == NULL ) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + // + // build the SET INTERFACE PARAMETER command + // + IOData[ PSCR_NAD ] = NAD_TO_PSCR; + IOData[ PSCR_PCB ] = PCB_DEFAULT; + IOData[ PSCR_LEN ] = 0x05 + TLVListLen; + + IOData[ PSCR_INF+0 ] = CLA_SET_INTERFACE_PARAM; + IOData[ PSCR_INF+1 ] = INS_SET_INTERFACE_PARAM; + IOData[ PSCR_INF+2 ] = Device; + IOData[ PSCR_INF+3 ] = 0x00; + IOData[ PSCR_INF+4 ] = TLVListLen; + + SysCopyMemory( &IOData[ PSCR_INF+5 ], pTLVList, TLVListLen ); + // + // write command + // + NTStatus = PscrWrite( + ReaderExtension, + IOData, + 8 + TLVListLen, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + + // do an dummy read to catch errors. + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + + // check error + ICCStatus = + ((USHORT)IOData[ IOBytes - 2 - PSCR_EPILOGUE_LENGTH ]) << 8; + ICCStatus |= + (USHORT)IOData[ IOBytes - 1 - PSCR_EPILOGUE_LENGTH ]; + + if ( ICCStatus != 0x9000 ) { + NTStatus = STATUS_INVALID_DEVICE_STATE; + } + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdReadStatusFile ( + PREADER_EXTENSION ReaderExtension, + UCHAR Device, + PUCHAR pTLVList, + PULONG pTLVListLen + ) +/*++ +CmdReadStatusFile: + read the status file of the requested device from the reader filesystem + +Arguments: + ReaderExtension context of call + Device requested device + pTLVList ptr to list (i.e. the status file) + pTLVListLen length of buffer / returned list + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ]; + ULONG IOBytes; + + // select ICC status file if it's not the active file + if ( ReaderExtension->StatusFileSelected == FALSE ) { + + // select master file on reader + NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER ); + + // select ICC directory + if ( NT_SUCCESS( NTStatus )) { + if ( Device != DEVICE_ICC1 ) { + NTStatus = STATUS_UNSUCCESSFUL; + } else { + NTStatus = CmdSelectFile( + ReaderExtension, + FILE_ICC1_DIR + ); + + // select status file + if ( NT_SUCCESS( NTStatus )) { + NTStatus = CmdSelectFile( + ReaderExtension, + FILE_ICC1_DIR_STATUS + ); + if ( NT_SUCCESS( NTStatus )) { + ReaderExtension->StatusFileSelected = TRUE; + } + } + } + } + } + + // read status file if successful selected + if ( ReaderExtension->StatusFileSelected == TRUE ) { + IOBytes = MAX_T1_BLOCK_SIZE; + NTStatus = CmdReadBinary( + ReaderExtension, + 0, + IOData, + &IOBytes + ); + + // copy data to user buffer + if ( NT_SUCCESS( NTStatus )) { + if (( pTLVList != NULL ) && ( IOBytes < *pTLVListLen )) { + *pTLVListLen = IOBytes; + SysCopyMemory( pTLVList, IOData, IOBytes ); + } else { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + } + } + return( NTStatus ); +} + + +NTSTATUS +CmdGetFirmwareRevision ( + PREADER_EXTENSION ReaderExtension + ) +/*++ +CmdGetFirmwareRevision: + get the firmware revision of the reader. Ther firmware revision is found + in the PSCR configuration file (ID 0x0020) in the master directory. + The tag of the revision is 0x0F, and the value is coded as an ASCII string, + p.E. "2.20" + +Arguments: + ReaderExtension context of call + +Return Value: + STATUS_SUCCESS + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR TLVList[ MAX_T1_BLOCK_SIZE ], + Len; + char Revision[ 0x10 ], + UpdateKey[ 0x10 ]; + ULONG IOBytes; + // + // select master file on reader + // + NTStatus = CmdSelectFile( ReaderExtension, FILE_MASTER ); + // + // select pscr configuration file + // + if ( NT_SUCCESS( NTStatus )) { + NTStatus = CmdSelectFile( ReaderExtension, FILE_PSCR_CONFIG ); + // + // read confiuration file + // + if ( NT_SUCCESS( NTStatus )) { + IOBytes = MAX_T1_BLOCK_SIZE; + NTStatus = CmdReadBinary( + ReaderExtension, + 0, + TLVList, + &IOBytes + ); + // + // get the value of revison + // + if ( NT_SUCCESS( NTStatus )) { + Len = sizeof(Revision); + CmdGetTagValue( + TAG_SOFTWARE_REV, + TLVList, + IOBytes, + &Len, + Revision + ); + // + // the coding is always X.YY (in ASCII), so we can get the numeric + // values hardcoded by taking the low nibbles of the char's. + // + ReaderExtension->FirmwareMajor = Revision[0] & 0x0F; + ReaderExtension->FirmwareMinor = ( Revision[2] & 0x0F ) << 4; + ReaderExtension->FirmwareMinor |= Revision[3] & 0x0F; + // + // get value of update key + // + Len = sizeof(UpdateKey); + CmdGetTagValue( + TAG_UPDATE_KEY, + TLVList, + IOBytes, + &Len, + UpdateKey + ); + + ReaderExtension->UpdateKey = UpdateKey[0]; + } + } + } + ReaderExtension->StatusFileSelected = FALSE; + return( NTStatus ); +} + +NTSTATUS +CmdPscrCommand ( + PREADER_EXTENSION ReaderExtension, + PUCHAR pInData, + ULONG InDataLen, + PUCHAR pOutData, + ULONG OutDataLen, + PULONG pNBytes + ) +/*++ +CmdPscrCommand: + send a command transparent to the reader + +Arguments: + ReaderExtension context of call + pInData, ptr to input buffer + InDataLen, len of input buffer + pOutData, ptr to output buffer + OutDataLen, len of output buffer + pNBytes number of bytes transferred + +Return Value: + STATUS_SUCCESS + STATUS_INVALID_PARAMETER + error values from PscrRead / PscrWrite + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR IOData[ MAX_T1_BLOCK_SIZE ] = { 0}; + ULONG IOBytes; + // + // the function is used for generic ioctl's, so carful ALL + // parametes will be checked! + // + if ( ( pInData == NULL ) || + ( pOutData == NULL ) || + ( pNBytes == NULL ) || + (InDataLen == 0 ) || + (OutDataLen == 0 ) + ) { + NTStatus = STATUS_INVALID_PARAMETER; + } else { + IOBytes = 0; + NTStatus = PscrWriteDirect( + ReaderExtension, + pInData, + InDataLen, + &IOBytes + ); + + if ( NT_SUCCESS( NTStatus )) { + // + // get result. ignore all reader errors + // + IOBytes = 0; + NTStatus = PscrRead( + ReaderExtension, + IOData, + MAX_T1_BLOCK_SIZE, + &IOBytes + ); + // + // tranfer data + // + if ( IOBytes > OutDataLen ) { + NTStatus = STATUS_BUFFER_TOO_SMALL; + } else { + *pNBytes = IOBytes; + SysCopyMemory( pOutData, IOData, IOBytes ); + } + } + } + return( NTStatus ); +} + +NTSTATUS +CmdGetTagValue ( + UCHAR Tag, + PUCHAR pTLVList, + ULONG TLVListLen, + PUCHAR pTagLen, + PVOID pTagVal + ) +/*++ +CmdGetTagValue: + scans a TLV list for the value of a user specified tag + it is assumed, the caller knows the kind of the requested + field, so only the ptr to the buffer will be checked + +Arguments: + Tag requested Tag + pTLVList ptr to list + TLVListLen length of list + pTagLen ptr to length + pTagVal ptr to value + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + STATUS_INVALID_PARAMETER + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + ULONG Idx; + UCHAR maxLen; + // + // step through the given list + // + if (( pTLVList != NULL ) && ( pTagVal != NULL ) && ( pTagLen != NULL )) { + maxLen = *pTagLen; + // + // look for requested tag + // + Idx = 0; + while ( Idx < TLVListLen ) { + if ( pTLVList[ Idx ] == Tag ) { + // + // ASSUMED THE CALLER KNOWS KIND OF FIELD!!! + // + + if (pTLVList[Idx+1] > maxLen) { + NTStatus = STATUS_UNSUCCESSFUL; + break; + } + *pTagLen = pTLVList[ Idx + 1 ]; + SysCopyMemory( + pTagVal, + &pTLVList[ Idx+2 ], + pTLVList[ Idx+1 ] + ); + + break; + } + Idx += pTLVList[ Idx+1 ] + 2; + } + if ( Idx >= TLVListLen ) { + NTStatus = STATUS_UNSUCCESSFUL; + } + } else { + NTStatus = STATUS_INVALID_PARAMETER; + } + return( NTStatus ); +} + +// ------------------------------- END OF FILE ------------------------------- + diff --git a/smartcrd/pscr/pscrcmd.h b/smartcrd/pscr/pscrcmd.h new file mode 100644 index 00000000..57a4bdea --- /dev/null +++ b/smartcrd/pscr/pscrcmd.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrCmd.h + +Abstract: + + Prototypes of basic command functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Notes: + + The file pscrcmd.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_CMD_H__ ) +#define __PSCR_CMD_H__ + +NTSTATUS +CmdResetInterface( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +CmdReset( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + BOOLEAN WarmReset, // TRUE: Warm, FALSE: cold Reset + PUCHAR pATR, // ptr to ATR buffer + PULONG ATRLength // len of ATR + ); + +NTSTATUS +CmdDeactivate( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device // device + ); + +NTSTATUS +CmdReadBinary( + PREADER_EXTENSION ReaderExtension, // context of call + USHORT Offset, // offset in file + PUCHAR pData, // data buffer + PULONG pNBytes // length of bytes read + ); + +NTSTATUS +CmdSelectFile( + PREADER_EXTENSION ReaderExtension, // context of call + USHORT FileId // File Id + ); + +NTSTATUS +CmdSetInterfaceParameter( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + PUCHAR pTLVList, // ptr to TLV list + UCHAR TLVListLen // len of TLV list + ); + +NTSTATUS +CmdReadStatusFile ( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Device, // device + PUCHAR pTLVList, // ptr to TLV list + PULONG TLVListLen // len of TLV list + ); + +NTSTATUS +CmdPscrCommand ( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pInData, // ptr to input buffer + ULONG InDataLen, // len of input buffer + PUCHAR pOutData, // ptr to ouput buffer + ULONG OutDataLen, // len of output buffer + PULONG pNBytes // number of bytes transferred + ); + +NTSTATUS +CmdGetFirmwareRevision ( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +CmdGetTagValue ( + UCHAR Tag, // tag to be searched + PUCHAR pTLVList, // ptr to TLV list + ULONG TLVListLen, // len of TLV list + PUCHAR pTagLen, // tag length + PVOID pTagVal // tag value + ); + +#endif // __PSCR_CMD_H__ + +//------------------------------- END OF FILE -------------------------------*/ diff --git a/smartcrd/pscr/pscrlog.mc b/smartcrd/pscr/pscrlog.mc new file mode 100644 index 00000000..6a608ddd --- /dev/null +++ b/smartcrd/pscr/pscrlog.mc @@ -0,0 +1,103 @@ +;// BUILD Version: 0001 // Increment this if a change has global effects + +;/*++ +; +;Copyright (c) 1997 SCM Microsystems, Inc +; +;Module Name: +; +; PscrLog.mc +; +;Abstract: +; +; Constant definitions for the I/O error code log values. +; +;Notes: +; +; The file pscrlog.mc was reviewed by LCA in June 2011 and per license is +; acceptable for Microsoft use under Dealpoint ID 178449. +; +;Revision History: +; +;--*/ +; +;#ifndef __PSCRLOG_H__ +;#define __PSCRLOG_H__ +; +;// +;// Status values are 32 bit values layed out as follows: +;// +;// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +;// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +;// +---+-+-------------------------+-------------------------------+ +;// |Sev|C| Facility | Code | +;// +---+-+-------------------------+-------------------------------+ +;// +;// where +;// +;// Sev - is the severity code +;// +;// 00 - Success +;// 01 - Informational +;// 10 - Warning +;// 11 - Error +;// +;// C - is the Customer code flag +;// +;// Facility - is the facility code +;// +;// Code - is the facility's status code +;// +; +MessageIdTypedef=NTSTATUS + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR + ) + +FacilityNames=(System=0x0 + RpcRuntime=0x2:FACILITY_RPC_RUNTIME + RpcStubs=0x3:FACILITY_RPC_STUBS + Io=0x4:FACILITY_IO_ERROR_CODE + Smartcard=0x10:FACILITY_SCARD + ) + +MessageId=0x0001 Facility=Smartcard Severity=Error SymbolicName=PSCR_NO_DEVICE_FOUND +Language=English +No PSCR Smart Card reader found in the system. +. +MessageId=0x0002 Facility=Smartcard Severity=Error SymbolicName=PSCR_CANT_INITIALIZE_READER +Language=English +The reader inserted is not working properly. +Please try to change the 'Input/Output Range' and/or 'Interrupt Request' +settings in Device Manager. +. +MessageId=0x0003 Facility=Smartcard Severity=Error SymbolicName=PSCR_INSUFFICIENT_RESOURCES +Language=English +Insufficient system resources to start device. +. +MessageId=0x0004 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_INTERRUPT +Language=English +Can't connect to the interrupt provided by the system. +Please try to change the 'Interrupt Request' setting in Device Manager. +. +MessageId=0x0005 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_IO_PORT +Language=English +No I/O port specified or port can not be mapped. +Please try to change the 'Input/Output Range' setting in the Device Manager. +. +MessageId=0x0006 Facility=Smartcard Severity=Error SymbolicName=PSCR_ERROR_CLAIM_RESOURCES +Language=English +Resources can not be claimed or an resource conflict exists. +. +MessageId=0x0007 Facility=Io Severity=Error SymbolicName=PSCR_NO_MEMORY +Language=English +The system does not have enough memory. +. +MessageId=0x0007 Facility=Smartcard Severity=Warning SymbolicName=PSCR_WRONG_FIRMWARE +Language=English +Your reader needs firmware version 2.30 or higher to work with this driver. +. +;#endif // __PSCRLOG_H__ diff --git a/smartcrd/pscr/pscrnt.c b/smartcrd/pscr/pscrnt.c new file mode 100644 index 00000000..75d37304 --- /dev/null +++ b/smartcrd/pscr/pscrnt.c @@ -0,0 +1,1687 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrNT.c + +Abstract: + + Main Driver Module - NT Version + +Author: + + Andreas Straub + +Notes: + + The file pscrnt.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + + Andreas Straub 1.00 8/18/1997 Initial Version + Klaus Schuetz 1.01 9/20/1997 Timing changed + Andreas Straub 1.02 9/24/1997 Low Level error handling, + minor bugfixes, clanup + Andreas Straub 1.03 10/8/1997 Timing changed, generic SCM + interface changed + Andreas Straub 1.04 10/18/1997 Interrupt handling changed + Andreas Straub 1.05 10/19/1997 Generic IOCTL's added + Andreas Straub 1.06 10/25/1997 Timeout limit for FW update variable + Andreas Straub 1.07 11/7/1997 Version information added + Klaus Schuetz 1.08 11/10/1997 PnP capabilities added + Klaus Schuetz Cleanup added + Calai Bhoopathi 6/12/2006 Changed retry count in Dpc routine + Eliyas Yakub 10/6/2006 Ported to KMDF + +--*/ + +#include <PscrNT.h> +#include <PscrCmd.h> +#include <PscrCB.h> +#include <PscrLog.h> +#include <PscrVers.h> + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, PscrEvtDeviceAdd) +#pragma alloc_text(PAGE, PscrRegisterWithSmcLib) +#pragma alloc_text(PAGE, PscrEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, PscrEvtDeviceD0Exit) +#pragma alloc_text(PAGE, PscrEvtFileCleanup) +#pragma alloc_text(PAGE, PscrGetRegistryValue) + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +DriverEntry: + entry function of the driver. setup the callbacks for the OS and try to + initialize a device object for every device in the system + +Arguments: + DriverObject context of the driver + RegistryPath path to the registry entry for the driver + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!DriverEntry: Enter - KMDF Version Built %s %s\n", + __DATE__, __TIME__ ) + ); + + WDF_DRIVER_CONFIG_INIT(&config, PscrEvtDeviceAdd); + + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + SmartcardDebug( + DEBUG_TRACE, + ("PSCR!DriverEntry: Exit %x\n", + status) + ); + + return status; +} + +NTSTATUS +PscrEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + PscrEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a WDF device object to + represent a new instance of toaster device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS +--*/ +{ + NTSTATUS status; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDEVICE device; + PDEVICE_EXTENSION DeviceExtension; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDF_INTERRUPT_CONFIG interruptConfig; + WDF_FILEOBJECT_CONFIG fileobjectConfig; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrAddDevice: Enter\n" ) + ); + + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SMARTCARD); + + WdfDeviceInitSetExclusive(DeviceInit, TRUE); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + pnpPowerCallbacks.EvtDevicePrepareHardware = PscrEvtDevicePrepareHardware; + + pnpPowerCallbacks.EvtDeviceD0Entry = PscrEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = PscrEvtDeviceD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Register close callback so that we can clear the notification irp. + // + WDF_FILEOBJECT_CONFIG_INIT( + &fileobjectConfig, + WDF_NO_EVENT_CALLBACK, // Create + WDF_NO_EVENT_CALLBACK, // Close + PscrEvtFileCleanup // Cleanup + ); + + WdfDeviceInitSetFileObjectConfig( + DeviceInit, + &fileobjectConfig, + WDF_NO_OBJECT_ATTRIBUTES + ); + // + // Initialize attributes and a context area for the device object. + // + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); + attributes.EvtCleanupCallback = PscrEvtDeviceContextCleanup; + + // + // Create a framework device object.This call will in turn create + // a WDM device object, attach to the lower stack, and set the + // appropriate flags and attributes. + // + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + return status; + } + + // + // Get the device context by using the accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_EXTENSION. + // + DeviceExtension = GetDeviceExtension(device); + + DeviceExtension->Device = device; + + InterlockedIncrement((PLONG)&DeviceExtension->DeviceInstanceNo); + + // + // Add an extra stack location to the IRP disaptched to our device so + // that we can use that to workaround the problem of scmlib completing + // ioctl IRPs. + // + WdfDeviceWdmGetDeviceObject(DeviceExtension->Device)->StackSize++; + + // + // Tell the Framework that this device will need an interface + // + status = WdfDeviceCreateDeviceInterface( + device, + &SmartCardReaderGuid, + NULL // ReferenceString + ); + + if (!NT_SUCCESS (status)) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + + return status; + } + + // + // Create a parallel queue for dispatching ioctl requests. + // + + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchParallel + ); + + ioQueueConfig.EvtIoDeviceControl = PscrEvtIoDeviceControl; + + + status = WdfIoQueueCreate ( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->IoctlQueue + ); + + if(!NT_SUCCESS (status)){ + return status; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + DeviceExtension->IoctlQueue, + WdfRequestTypeDeviceControl); + + if(!NT_SUCCESS (status)){ + return status; + } + + // + // Manual queue for parking smartcard notification request. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchManual + ); + + // + // Since this request dispatch from this queue doesn't touch the + // hardware, it doesn't have to be power managed. + // + ioQueueConfig.PowerManaged = WdfFalse; + + // + // Smartcard library keeps track of last outstanding notification + // request provided to the client driver. When the client driver + // completes the request, it has to clear the field in the data- + // structure maintained by the library. Since we keep the request + // in a queue, we need a notification from the framework when the + // request is cancelled so that we can clear the field. + // + ioQueueConfig.EvtIoCanceledOnQueue = PscrEvtIoCanceledOnQueue; + + status = WdfIoQueueCreate ( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->NotificationQueue + ); + + if(!NT_SUCCESS (status)){ + return status; + } + + // + // Create WDFINTERRUPT object. Framework will take care of parsing + // the interrupt resource and connecting and disconnecting the ISR + // at the appropriate PNP/POWER state changes. + // + + WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, + PscrEvtInterruptServiceRoutine, + PscrEvtInterruptDpc); + + status = WdfInterruptCreate(device, + &interruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DeviceExtension->Interrupt); + if (!NT_SUCCESS (status)) { + return status; + } + + // + // Register with smartcard libarary. + // + status = PscrRegisterWithSmcLib(DeviceExtension); + if (!NT_SUCCESS (status)) { + return status; + } + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrAddDevice: Exit %x\n", + status) + ); + + return status; +} + +VOID +PscrEvtDeviceContextCleanup ( + WDFOBJECT Object + ) +/*++ + +Routine Description: + + Called when the device object is deleted by the framework in response + to REMOVE_DEVICE request. Here, free up all the resources that wouldn't + cleaned up by the framework automatically due to parent child relationship. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + VOID + +--*/ +{ + WDFDEVICE Device; + PDEVICE_EXTENSION DeviceExtension; + + Device = (WDFDEVICE)Object; + DeviceExtension = GetDeviceExtension(Device); + + InterlockedDecrement((PLONG)&DeviceExtension->DeviceInstanceNo); + + if (DeviceExtension->SmartcardExtension.ReaderExtension != NULL) { + + ExFreePoolWithTag(DeviceExtension->SmartcardExtension.ReaderExtension, + SMARTCARD_POOL_TAG); + + DeviceExtension->SmartcardExtension.ReaderExtension = NULL; + } +} + +NTSTATUS +PscrRegisterWithSmcLib( + PDEVICE_EXTENSION DeviceExtension + ) +{ + PREADER_EXTENSION ReaderExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + UNICODE_STRING vendorNameU, ifdTypeU; + ANSI_STRING vendorNameA, ifdTypeA; + WDFSTRING vendorNameStr, ifdTypeStr; + NTSTATUS status; + + PAGED_CODE(); + + vendorNameStr = NULL; + ifdTypeStr = NULL; + + RtlZeroMemory(&vendorNameA, sizeof(vendorNameA)); + RtlZeroMemory(&ifdTypeA, sizeof(ifdTypeA)); + + // set up the device extension. + SmartcardExtension = &DeviceExtension->SmartcardExtension; + + // allocate the reader extension + ReaderExtension = ExAllocatePoolWithTag( + NonPagedPool, + sizeof( READER_EXTENSION ), + SMARTCARD_POOL_TAG + ); + + if ( ReaderExtension == NULL ) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + RtlZeroMemory( ReaderExtension, sizeof( READER_EXTENSION )); + + SmartcardExtension->ReaderExtension = ReaderExtension; + + ReaderExtension->CompletionRoutine = CBUpdateCardState; + ReaderExtension->TrackingContext = SmartcardExtension; + + ReaderExtension->dataRatesSupported[0] = (ULONG) 9600; + ReaderExtension->dataRatesSupported[1] = (ULONG) 38400; + ReaderExtension->dataRatesSupported[2] = (ULONG) 57600; + ReaderExtension->dataRatesSupported[3] = (ULONG) 115200; + + // Initialize the RequestInterrupt flag + ReaderExtension->RequestInterrupt = FALSE; + + // setup smartcard extension - callback's + SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CBCardPower; + SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CBTransmit; + SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CBCardTracking; + SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CBSetProtocol; + SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = PscrGenericIOCTL; + + // setup smartcard extension - vendor attribute + RtlCopyMemory( + SmartcardExtension->VendorAttr.VendorName.Buffer, + PSCR_VENDOR_NAME, + sizeof( PSCR_VENDOR_NAME ) + ); + SmartcardExtension->VendorAttr.VendorName.Length = + sizeof( PSCR_VENDOR_NAME ); + + RtlCopyMemory( + SmartcardExtension->VendorAttr.IfdType.Buffer, + PSCR_IFD_TYPE, + sizeof( PSCR_IFD_TYPE ) + ); + SmartcardExtension->VendorAttr.IfdType.Length = + sizeof( PSCR_IFD_TYPE ); + + SmartcardExtension->VendorAttr.UnitNo = DeviceExtension->DeviceInstanceNo; + + SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = 0; + + // store firmware revision in ifd version + SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = + ReaderExtension->FirmwareMajor; + SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = + ReaderExtension->FirmwareMinor; + SmartcardExtension->VendorAttr.IfdSerialNo.Length = 0; + + // setup smartcard extension - reader capabilities + SmartcardExtension->ReaderCapabilities.SupportedProtocols = + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; + + SmartcardExtension->ReaderCapabilities.ReaderType = + SCARD_READER_TYPE_PCMCIA; + SmartcardExtension->ReaderCapabilities.MechProperties = 0; + SmartcardExtension->ReaderCapabilities.Channel = 0; + + SmartcardExtension->ReaderCapabilities.CLKFrequency.Default = 4000; + SmartcardExtension->ReaderCapabilities.CLKFrequency.Max = 4000; + + // reader could support higher data rates + SmartcardExtension->ReaderCapabilities.DataRatesSupported.List = + ReaderExtension->dataRatesSupported; + SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries = MAX_DATARATES; + SmartcardExtension->ReaderCapabilities.DataRate.Default = ReaderExtension->dataRatesSupported[0]; + SmartcardExtension->ReaderCapabilities.DataRate.Max = + ReaderExtension->dataRatesSupported[ MAX_DATARATES-1 ]; + + // enter correct version of the lib + SmartcardExtension->Version = SMCLIB_VERSION; + SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE; + SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE; + + SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; + + status = SmartcardInitialize(SmartcardExtension); + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_INSUFFICIENT_RESOURCES, + NULL, + 0 + ); + // + // No need to worry about freeing the pool we allocated earlier. + // It will be freed in the cleanup callback when the device is + // deleted by the framework as a result of failing this call. + // + return status; + } + + SmartcardExtension->OsData->DeviceObject = + WdfDeviceWdmGetDeviceObject(DeviceExtension->Device); + + vendorNameStr = PscrGetRegistryValue(DeviceExtension->Device, L"VendorName"); + if (vendorNameStr != NULL) { + + WdfStringGetUnicodeString(vendorNameStr, &vendorNameU); + + status = RtlUnicodeStringToAnsiString( + &vendorNameA, + &vendorNameU, + TRUE + ); + if (NT_SUCCESS(status)) { + if (vendorNameA.Length > 0 && vendorNameA.Length < MAXIMUM_ATTR_STRING_LENGTH) { + RtlCopyMemory( + SmartcardExtension->VendorAttr.VendorName.Buffer, + vendorNameA.Buffer, + vendorNameA.Length + ); + SmartcardExtension->VendorAttr.VendorName.Length = vendorNameA.Length; + } + RtlFreeAnsiString(&vendorNameA); + } + + // + // We have copied the string to the extension. No need to keep the object + // around and waste memory. + // + WdfObjectDelete(vendorNameStr); + vendorNameStr = NULL; + } else { + status = STATUS_UNSUCCESSFUL; + } + + if (!NT_SUCCESS(status)) { + return status; + } + + ifdTypeStr = PscrGetRegistryValue(DeviceExtension->Device, L"IfdType"); + if (ifdTypeStr != NULL) { + + WdfStringGetUnicodeString(ifdTypeStr, &ifdTypeU); + + status = RtlUnicodeStringToAnsiString( + &ifdTypeA, + &ifdTypeU, + TRUE + ); + if (NT_SUCCESS(status)) { + if (ifdTypeA.Length > 0 && ifdTypeA.Length < MAXIMUM_ATTR_STRING_LENGTH) { + RtlCopyMemory( + SmartcardExtension->VendorAttr.IfdType.Buffer, + ifdTypeA.Buffer, + ifdTypeA.Length + ); + SmartcardExtension->VendorAttr.IfdType.Length = ifdTypeA.Length; + } + RtlFreeAnsiString(&ifdTypeA); + } + + WdfObjectDelete(ifdTypeStr); + ifdTypeStr = NULL; + } else { + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + + +NTSTATUS +PscrEvtDevicePrepareHardware ( + WDFDEVICE Device, + WDFCMRESLIST Resources, + WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDevicePrepareHardware event callback performs operations that are necessary + to make the driver's device operational. The framework calls the driver's + EvtDeviceStart callback when the PnP manager sends an IRP_MN_START_DEVICE + request to the driver stack. + +Arguments: + + Device - Handle to a framework device object. + + Resources - Handle to a collection of framework resource objects. + This collection identifies the raw (bus-relative) hardware + resources that have been assigned to the device. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + WDF status code + +--*/ +{ + PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; + PDEVICE_EXTENSION DeviceExtension = GetDeviceExtension(Device); + PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension; + PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension; + NTSTATUS status; + ULONG i; + + UNREFERENCED_PARAMETER(Resources); + UNREFERENCED_PARAMETER(ResourcesTranslated); + + PAGED_CODE(); + + for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); + + switch(descriptor->Type) { + + case CmResourceTypePort: + + KdPrint(("I/O Port: (%x) Length: (%d)\n", + descriptor->u.Port.Start.LowPart, + descriptor->u.Port.Length)); + + ReaderExtension->IOBase = + (PPSCR_REGISTERS) UlongToPtr(descriptor->u.Port.Start.LowPart); + + NT_ASSERT(descriptor->u.Port.Length >= 4); + + break; + + case CmResourceTypeMemory: + + KdPrint(("Memory: (%x) Length: (%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Length)); + break; + case CmResourceTypeInterrupt: + // + // Framework will parse the interrupt resource and connect and + // disconnect interrupt. We don't have to do anything here. + // + KdPrint(("Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0x\n", + descriptor->u.Interrupt.Level, + descriptor->u.Interrupt.Vector, + descriptor->u.Interrupt.Affinity)); + + break; + + default: + break; + } + + } + + + if ( ReaderExtension->IOBase == NULL ) { + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_ERROR_IO_PORT, + NULL, + 0 + ); + + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + + ReaderExtension->Device = DEVICE_ICC1; + ReaderExtension->MaxRetries = PSCR_MAX_RETRIES; + status = CmdResetInterface( ReaderExtension ); + + SmartcardExtension->ReaderCapabilities.MaxIFSD = + ReaderExtension->MaxIFSD; + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_CANT_INITIALIZE_READER, + NULL, + 0 + ); + + return status; + } + + status = CmdReset( + ReaderExtension, + 0x00, // reader + FALSE, // cold reset + NULL, // no atr + NULL + ); + + if (status != STATUS_SUCCESS) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_CANT_INITIALIZE_READER, + NULL, + 0 + ); + + return status; + } + + PscrFlushInterface(DeviceExtension->SmartcardExtension.ReaderExtension); + + CmdGetFirmwareRevision( + DeviceExtension->SmartcardExtension.ReaderExtension + ); + + // If you change the min. firmware version here, please update + // the .mc file for the correct error message, too + if (SmartcardExtension->ReaderExtension->FirmwareMajor < 2 || + SmartcardExtension->ReaderExtension->FirmwareMajor == 2 && + SmartcardExtension->ReaderExtension->FirmwareMinor < 0x34) { + + SmartcardLogError( + WdfDriverWdmGetDriverObject(WdfGetDriver()), + PSCR_WRONG_FIRMWARE, + NULL, + 0 + ); + } + + // store firmware revision in ifd version + SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = + ReaderExtension->FirmwareMajor; + SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = + ReaderExtension->FirmwareMinor; + + // reader could support higher data rates + SmartcardExtension->ReaderCapabilities.DataRatesSupported.List = + ReaderExtension->dataRatesSupported; + SmartcardExtension->ReaderCapabilities.DataRate.Default = ReaderExtension->dataRatesSupported[0]; + + SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries = 2; + SmartcardExtension->ReaderCapabilities.DataRate.Max = + ReaderExtension->dataRatesSupported[ 1 ]; + + NT_ASSERT(status == STATUS_SUCCESS); + + return status; +} + +NTSTATUS +PscrEvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + EvtDeviceD0Entry event callback must perform any operations that are + necessary before the specified device is used. It will be called every + time the hardware needs to be (re-)initialized. This includes after + IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, + IRP_MN_SET_POWER-D0. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + PreviousState - Device power state which the device was in most recently. + If the device is being newly started, this will be + PowerDeviceUnspecified. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + UCHAR state; + WDF_INTERRUPT_INFO interruptInfo; + + // + //MikeTs(10/15/2008): http://msdn.microsoft.com/en-us/library/bb725862.aspx + // explains although the callback function is called at PASSIVE_LEVEL, + // callback functions that leave a lower device state returning to + // working state should not be pageable. + // + DeviceExtension = GetDeviceExtension(Device); + + // + // Find out if the interrupt is shared. + // + WDF_INTERRUPT_INFO_INIT(&interruptInfo); + WdfInterruptGetInfo(DeviceExtension->Interrupt, &interruptInfo); + DeviceExtension->bSharedIRQ = + (interruptInfo.ShareDisposition == CmResourceShareShared); + + SmartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + status = CmdResetInterface(SmartcardExtension->ReaderExtension); + NT_ASSERT(status == STATUS_SUCCESS); + + SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE; + state = CBGetCardState(SmartcardExtension); + + + // save the current power state of the reader + SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking; + + // + // We will use PreviousState to differetiate whether EvtDeviceD0Entry is + // called due to implicit power when the device is first started or when + // the device is resume power a low power state (due to explicit power up). + // + if (PreviousState != WdfPowerDeviceD3Final) { + // + // The device is resuming from a suspended state. + // + CBUpdateCardState(SmartcardExtension, state, TRUE); + } else { + // + // The device is starting up for the first time. + // + CBUpdateCardState(SmartcardExtension, state, FALSE); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +PscrEvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in EvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device is + stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + Note that interrupts have already been disabled by the time that this + callback is invoked. + + EvtDeviceD0Exit event callback must perform any operations that are + necessary before the specified device is moved out of the D0 state. If the + driver needs to save hardware state before the device is powered down, then + that should be done here. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + TargetState - Device power state which the device will be put in once this + callback is complete. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + + PAGED_CODE(); + + DeviceExtension = GetDeviceExtension(Device); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + switch (TargetState) { + case WdfPowerDeviceD1: + case WdfPowerDeviceD2: + case WdfPowerDeviceD3: + + smartcardExtension->ReaderExtension->CardPresent = + smartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ? TRUE: FALSE; + + if (smartcardExtension->ReaderExtension->CardPresent) { + smartcardExtension->MinorIoControlCode = SCARD_POWER_DOWN; + status = CBCardPower(smartcardExtension); + NT_ASSERT(NT_SUCCESS(status)); + } + // save the current power state of the reader + smartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderOff; + break; + + case WdfPowerDevicePrepareForHibernation: + + // + // Fill in any code to save hardware state here. Do not put in any + // code to shut the device off. If this device cannot support being + // in the paging path (or being a parent or grandparent of a paging + // path device) then this whole case can be deleted. + // + NT_ASSERT(FALSE); // This driver shouldn't get this. + break; + + case WdfPowerDeviceD3Final: + // + // Reset and put the device into a known initial state we're shutting + // down for the last time. + // + break; + + default: + break; + } + + return STATUS_SUCCESS; +} + + +VOID +PscrEvtFileCleanup( + IN WDFFILEOBJECT FileObject + ) +/*++ + + EvtFileClose is called when all the handles represented by the FileObject + is closed and all the references to FileObject is removed. This callback + may get called in an arbitrary thread context instead of the thread that + called CloseHandle. If you want to delete any per FileObject context that + must be done in the context of the user thread that made the Create call, + you should do that in the EvtDeviceCleanp callback. + +Arguments: + + FileObject - Pointer to fileobject that represents the open handle. + +Return Value: + + VOID + +--*/ + +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + NTSTATUS status; + WDFREQUEST request; + + PAGED_CODE(); + + //KdPrint(("PscrEvtFileCleanup called\n")); + + // + // After cleanup callback is invoked, framework flushes all the queues + // by fileobject to cancel irps belonging to the file handle being closed. + // Since framework version 1.5 and less have a bug in that on cleanup- + // flush the EvtIoCanceledOnQueue callback is not invoked, we will + // retrive the request by fileobject ourselves and complete the request + // and clear the NotificaitonIrp field. + // + DeviceExtension = GetDeviceExtension(WdfFileObjectGetDevice(FileObject)); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + do { + status = WdfIoQueueRetrieveRequestByFileObject( + DeviceExtension->NotificationQueue, + FileObject, + &request); + + if (NT_SUCCESS(status)) { + + NT_ASSERT(smartcardExtension->OsData->NotificationIrp == + WdfRequestWdmGetIrp(request)); + + InterlockedExchangePointer( + &(smartcardExtension->OsData->NotificationIrp), + NULL + ); + + WdfRequestComplete(request, STATUS_CANCELLED); + } + }while (NT_SUCCESS(status)); + + NT_ASSERT(status == STATUS_NO_MORE_ENTRIES); + + return; +} + +_Function_class_(IO_COMPLETION_ROUTINE) +NTSTATUS +PscrSmcLibComplete ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +/*++ + +Routine Description: + + Completion routine is called when the IRP is completed by the smclib. + We will interrupt the completion of the IRP, and inturn complete the + WDFREQUEST given to us by the framework. + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + + //KdPrint(("<-- PscrSmcLibComplete called %x Request %x\n", + // Irp->IoStatus.Status, Context)); + + WdfRequestComplete((WDFREQUEST)Context, Irp->IoStatus.Status); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +VOID +PscrEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION deviceExtension; + PIRP irp; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(IoControlCode); + + //KdPrint(("--> PscrEvtIoDeviceControl called %s Request 0x%x\n", + // GetIoctlName(IoControlCode), Request)); + + deviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(Queue)); + + // + // Since smartcard library expects an IRP, we will get the underlying + // irp. + // + irp = WdfRequestWdmGetIrp(Request); + + // + // We will store the Request handle in the IRP DriverContext field so + // that we can get the handle back in vendor-ioctl callback routine. + // + SET_REQUEST_IN_IRP(irp, Request); + + // + // To workaround the problem of smartcard completing the IRP we provided. + // we will use the extra stack location to set a completion routine so that + // when it completes the IRP, our completion routine will be called, where + // we can interrupt the completion and complete the actual WDFREQUEST. + // + IoCopyCurrentIrpStackLocationToNext(irp); + + IoSetCompletionRoutine (irp, + PscrSmcLibComplete, + Request, + TRUE, + TRUE, + TRUE + ); + + IoSetNextIrpStackLocation(irp); + + // + // Ignore the return value because framework has marked the irp pending + // and will return status-pending when we return from this routine. + // + (VOID) SmartcardDeviceControl(&(deviceExtension->SmartcardExtension), irp); + + return; +} + +NTSTATUS +PscrGenericIOCTL( + PSMARTCARD_EXTENSION SmartcardExtension + ) +/*++ + +PscrGenericIOCTL: + Performs generic callbacks to the reader + +Arguments: + SmartcardExtension context of the call + +Return Value: + STATUS_SUCCESS + +--*/ +{ + NTSTATUS status; + PIRP Irp; + WDFREQUEST request; + ULONG bytesTransfered; + size_t inBufLen, outBufLen; + PVOID inBuf, outBuf; + PIO_STACK_LOCATION IrpStack; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrGenericIOCTL: Enter\n" ) + ); + + // + // get pointer to current IRP stack location + // + Irp = SmartcardExtension->OsData->CurrentIrp; + IrpStack = IoGetCurrentIrpStackLocation( Irp ); + + // + // Get the request from the IRP so that we can call framework functions + // to retreive the buffers. + // + request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->CurrentIrp); + + status = WdfRequestRetrieveInputBuffer(request, 0, &inBuf, &inBufLen); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfRequestRetrieveOutputBuffer(request, 0, &outBuf, &outBufLen); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // assume error + // + status = STATUS_INVALID_DEVICE_REQUEST; + bytesTransfered = 0; + + // + // dispatch IOCTL + // + switch ( IrpStack->Parameters.DeviceIoControl.IoControlCode ) { + case IOCTL_PSCR_COMMAND: + + status = CmdPscrCommand( + SmartcardExtension->ReaderExtension, + (PUCHAR) inBuf, + (ULONG) inBufLen, + (PUCHAR) outBuf, + (ULONG) outBufLen, + (PULONG) &bytesTransfered + ); + // + // the command could change the active file in the reader file + // system, so make sure that the status file will be selected + // before the next read + // + SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE; + break; + + case IOCTL_GET_VERSIONS: + + if ( outBufLen < SIZEOF_VERSION_CONTROL ) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + PVERSION_CONTROL VersionControl; + + VersionControl = (PVERSION_CONTROL)outBufLen; + + VersionControl->SmclibVersion = SmartcardExtension->Version; + VersionControl->DriverMajor = PSCR_MAJOR_VERSION; + VersionControl->DriverMinor = PSCR_MINOR_VERSION; + + // update firmware version (changed after update) + CmdGetFirmwareRevision( + SmartcardExtension->ReaderExtension + ); + VersionControl->FirmwareMajor = + SmartcardExtension->ReaderExtension->FirmwareMajor; + + VersionControl->FirmwareMinor = + SmartcardExtension->ReaderExtension->FirmwareMinor; + + VersionControl->UpdateKey = + SmartcardExtension->ReaderExtension->UpdateKey; + + bytesTransfered = SIZEOF_VERSION_CONTROL; + status = STATUS_SUCCESS; + } + break; + + case IOCTL_SET_TIMEOUT: + { + ULONG NewLimit; + // + // get new timeout limit + // + if ( inBufLen == sizeof( ULONG )) { + NewLimit = *(PULONG)inBuf; + } else { + NewLimit = 0; + } + + // + // report actual timeout limit + // + if (outBufLen == sizeof( ULONG )) { + + *(PULONG)outBuf = SmartcardExtension->ReaderExtension->MaxRetries + * DELAY_PSCR_WAIT; + bytesTransfered = sizeof( ULONG ); + } + + // + // set new timeout limit + // + if ( (NewLimit != 0) || + (NewLimit == MAXULONG-DELAY_PSCR_WAIT+2 )) { + SmartcardExtension->ReaderExtension->MaxRetries = + (NewLimit + DELAY_PSCR_WAIT - 1) / DELAY_PSCR_WAIT; + } + } + status = STATUS_SUCCESS; + break; + + case IOCTL_GET_CONFIGURATION: + // + // return IOBase and IRQ + // + if (outBufLen < SIZEOF_PSCR_CONFIGURATION ) { + status = STATUS_BUFFER_TOO_SMALL; + } else { + PPSCR_CONFIGURATION PSCRConfiguration; + + PSCRConfiguration = (PPSCR_CONFIGURATION) outBuf; + PSCRConfiguration->IOBase = + SmartcardExtension->ReaderExtension->IOBase; + PSCRConfiguration->IRQ = + SmartcardExtension->ReaderExtension->CurrentIRQ; + + bytesTransfered = SIZEOF_PSCR_CONFIGURATION; + status = STATUS_SUCCESS; + } + break; + + default: + break; + } + + // + // set status of the packet + // + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = bytesTransfered; + + // + // The request will be completed the smartcard library. + // + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrGenericIOCTL: Exit\n" ) + ); + + return( status ); +} + + +VOID +PscrEvtIoCanceledOnQueue( + IN WDFQUEUE Queue, + IN WDFREQUEST Request + ) +/*++ + +PscrEvtIoCanceledOnQueue: + + This routine is called when the request is cancelled on the queue. + + We will use the notificatio to clear the NotificationIrp field set by + the smartcard library. + +Arguments: + +Return Value: + VOID + +--*/ +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION smartcardExtension; + + DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(Queue)); + smartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + + //KdPrint(("Cancelled on queue 0x%x\n", WdfRequestWdmGetIrp(Request))); + + InterlockedExchangePointer( + &(smartcardExtension->OsData->NotificationIrp), + NULL + ); + + WdfRequestComplete(Request, STATUS_CANCELLED); +} + +BOOLEAN +PscrEvtInterruptServiceRoutine( + IN WDFINTERRUPT Interrupt, + IN ULONG MessageID + ) +/*++ + +PscrIrqServiceRoutine: + + Because the device not supports shared interrupts, the call is passed + to the DPC routine immediately and the IRQ is reported as served. + +Arguments: + +Return Value: + STATUS_SUCCESS + +--*/ +{ + LARGE_INTEGER Time; + TIME_FIELDS TimeFields; + TIME_FIELDS SaveTimeFields; + BOOLEAN Status = TRUE; + PDEVICE_EXTENSION DeviceExtension; + + UNREFERENCED_PARAMETER(MessageID); + + DeviceExtension= GetDeviceExtension(WdfInterruptGetDevice(Interrupt)); + + KeQuerySystemTime( &Time ); + RtlTimeToTimeFields( &Time, &TimeFields ); + RtlTimeToTimeFields( &DeviceExtension->SaveTime, &SaveTimeFields ); + + SmartcardDebug( + DEBUG_TRACE, + ("PSCR!PscrIrqServiceRoutine: Enter\n") + ); + + // if the interrupt is shared the PscrIrqServiceRoutine shall return always FALSE + // since te driver can't detect if the interrupt was sending from the reader when + // the firmware <2.50 is using + // if the interrupt is used exclusiv and the PscrIrqServiceRoutine returns FALSE, + // no more interrupts will be sended + if(( DeviceExtension->bSharedIRQ ) && + ( TimeFields.Minute == SaveTimeFields.Minute ) && + ( TimeFields.Second == SaveTimeFields.Second ) && + ( TimeFields.Milliseconds < SaveTimeFields.Milliseconds+50 )) + { + KdPrint(( "****** Status FALSE ******\n" )); + SysDelay( 5 ); + Status = FALSE; + } + else + { + // + // When someone yanks out the card the interrupt handler gets called, + // but since there is no card anymore when don't need to schedule a DPC + // + + // + // the interrupt is caused by a freeze event. the interface will be + // cleared either by PscrRead() or the DPC routine (depending on + // which is called first) + // + // DeviceExtension->SmartcardExtension.ReaderExtension->FreezePending = TRUE; + + InterlockedIncrement((PLONG)&DeviceExtension->PendingInterrupts); + + WdfInterruptQueueDpcForIsr( Interrupt ); + + if( DeviceExtension->bSharedIRQ ) { + Status = FALSE; + } + } + + DeviceExtension->SaveTime.QuadPart = Time.QuadPart; + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrIrqServiceRoutine: Exit\n" ) + ); + + return Status ; +} + +VOID +PscrEvtInterruptDpc( + IN WDFINTERRUPT Interrupt, + IN WDFOBJECT Device + ) +/*++ + +PscrDpcRoutine: + finishes interrupt requests. the freeze event data of the reader will be read + & the card state will be updated if data valid + +Arguments: + +Return Value: + void + +--*/ +{ + PDEVICE_EXTENSION DeviceExtension; + PSMARTCARD_EXTENSION SmartcardExtension; + + UNREFERENCED_PARAMETER(Interrupt); + + DeviceExtension= GetDeviceExtension(Device); + SmartcardExtension = (PSMARTCARD_EXTENSION) &DeviceExtension->SmartcardExtension; + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrInterruptEvent: IoBase %p\n", + SmartcardExtension->ReaderExtension->IOBase) + ); + + // + // In case of a card change the reader provides a TLV packet describing + // the event ('freeze event'). If PscrRead was called before the DPC + // routine is called, this event was cleared; in this case the card state + // will be updated by reading the card status file + // + do { + + + NT_ASSERT(DeviceExtension->PendingInterrupts < 10); + + SmartcardDebug( + DEBUG_TRACE, + ( "PSCR!PscrInterruptEvent: PendingInterrupts = %ld\n", + DeviceExtension->PendingInterrupts) + ); + + if( !SmartcardExtension->ReaderExtension->RequestPending ) + { + PscrFreeze( SmartcardExtension ); + } + else + { + // sometimes the fw doesn't send the freeze data + SmartcardExtension->ReaderExtension->RequestInterrupt = TRUE; + } + + } while (InterlockedDecrement((PLONG)&DeviceExtension->PendingInterrupts) > 0); +} + +void +PscrFreeze( + PSMARTCARD_EXTENSION SmartcardExtension + ) + +/*++ +PscrFreeze: + Read & evaluate freeze data + +Arguments: + ReaderExtension context of call + pDevice device which causes the freeze event + +Return Value: + STATUS_SUCCESS + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + UCHAR TLVList[9]; + ULONG NBytes; + ULONG Retries; + UCHAR ReadFreeze[] = { 0x12, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x01, 0xA6}; + + for (Retries = 0; Retries < 2; Retries++) // CB - code sync - 7/13/2006 + { + + PscrWriteDirect( + SmartcardExtension->ReaderExtension, + (PUCHAR)ReadFreeze, + sizeof( ReadFreeze ), + &NBytes + ); + + SysDelay( 20 ); + + NTStatus = PscrRead( + SmartcardExtension->ReaderExtension, + (PUCHAR) TLVList, + sizeof( TLVList ), + &NBytes + ); + + if( NT_SUCCESS( NTStatus )) + { + // + // get result + // + if( ( TLVList[ PSCR_NAD ] == 0x21 ) && + ( TLVList[ PSCR_INF ] == TAG_FREEZE_EVENTS )) + { + break; + } + } + } +} + +WDFSTRING +PscrGetRegistryValue( + _In_ WDFDEVICE Device, + _In_ LPCWSTR Name + ) +/*++ + +Routine Description: + + Get the registry values from the device parameters key. + +Arguments: + + +Return Value: + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + WDFSTRING string = NULL; + + PAGED_CODE(); + + status = WdfDeviceOpenRegistryKey(Device, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + if (NT_SUCCESS (status)) { + + status = WdfStringCreate( + NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &string + ); + if (NT_SUCCESS (status)) { + RtlInitUnicodeString(&valueName, Name); + + status = WdfRegistryQueryString(hKey, &valueName, string); + if (!NT_SUCCESS (status)) { + WdfObjectDelete(string); + string = NULL; + } + } + + WdfRegistryClose(hKey); + } + + return string; +} + +void +SysDelay( + ULONG Timeout + ) +/*++ + +SysDelay: + performs a required delay. The usage of KeStallExecutionProcessor is + very nasty, but it happends only if SysDelay is called in the context of + our DPC routine (which is only called if a card change was detected). + + For 'normal' IO we have Irql < DISPATCH_LEVEL, so if the reader is polled + while waiting for response we will not block the entire system + +Arguments: + Timeout delay in milli seconds + +Return Value: + void + +--*/ +{ + LARGE_INTEGER SysTimeout; + + if ( KeGetCurrentIrql() >= DISPATCH_LEVEL ) { + ULONG Cnt = 20 * Timeout; + + while ( Cnt-- ) { + // KeStallExecutionProcessor: counted in us + KeStallExecutionProcessor( 50 ); + } + } else { + SysTimeout.QuadPart = (LONGLONG)-10 * 1000 * Timeout; + + // KeDelayExecutionThread: counted in 100 ns + KeDelayExecutionThread( KernelMode, FALSE, &SysTimeout ); + } + return; +} + +PCHAR +GetIoctlName( + ULONG IoControlCode + ) +{ + switch (IoControlCode) { + case IOCTL_SMARTCARD_POWER: return "IOCTL_SMARTCARD_POWER"; + case IOCTL_SMARTCARD_GET_ATTRIBUTE: return "IOCTL_SMARTCARD_GET_ATTRIBUTE"; + case IOCTL_SMARTCARD_SET_ATTRIBUTE: return "IOCTL_SMARTCARD_SET_ATTRIBUTE"; + case IOCTL_SMARTCARD_CONFISCATE: return "IOCTL_SMARTCARD_CONFISCATE"; + case IOCTL_SMARTCARD_TRANSMIT: return "IOCTL_SMARTCARD_TRANSMIT"; + case IOCTL_SMARTCARD_EJECT: return "IOCTL_SMARTCARD_EJECT"; + case IOCTL_SMARTCARD_SWALLOW: return "IOCTL_SMARTCARD_SWALLOW"; + case IOCTL_SMARTCARD_IS_PRESENT: return "IOCTL_SMARTCARD_IS_PRESENT"; + case IOCTL_SMARTCARD_IS_ABSENT: return "IOCTL_SMARTCARD_IS_ABSENT"; + case IOCTL_SMARTCARD_SET_PROTOCOL: return "IOCTL_SMARTCARD_SET_PROTOCOL"; + case IOCTL_SMARTCARD_GET_STATE: return "IOCTL_SMARTCARD_GET_STATE"; + case IOCTL_SMARTCARD_GET_LAST_ERROR: return "IOCTL_SMARTCARD_GET_LAST_ERROR"; + default: return "Unknow_ioctl"; + } +} diff --git a/smartcrd/pscr/pscrnt.h b/smartcrd/pscr/pscrnt.h new file mode 100644 index 00000000..959b9b22 --- /dev/null +++ b/smartcrd/pscr/pscrnt.h @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrNT.h + +Abstract: + + Driver header - NT Version + +Author: + + Andreas Straub (SCM Microsystems, Inc.) + Klaus Schuetz (Microsoft Corp.) + +Notes: + + The file pscrnt.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 1.00 8/18/1997 Initial Version + Klaus Schuetz 1.01 9/20/1997 Timing changed + Andreas Straub 1.02 9/24/1997 Low Level error handling, + minor bugfixes, clanup + Andreas Straub 1.03 10/8/1997 Timing changed, generic SCM + interface changed + Andreas Straub 1.04 10/18/1997 Interrupt handling changed + Andreas Straub 1.05 10/19/1997 Generic IOCTL's added + Andreas Straub 1.06 10/25/1997 Timeout limit for FW update variable + Andreas Straub 1.07 11/7/1997 Version information added + Andreas Straub 1.08 11/10/1997 Generic IOCTL GET_CONFIGURATION + Klaus Schuetz 1998 PnP and Power Management added + +--*/ + +#if !defined ( __PSCR_NT_DRV_H__ ) +#define __PSCR_NT_DRV_H__ +#define SMARTCARD_POOL_TAG '4SCS' + +#include <ntddk.h> +#include <wdf.h> +#include <DEVIOCTL.H> + +#pragma warning(push) +#pragma warning(disable:4201) +#include "SMCLIB.h" +#pragma warning(pop) + +#include "PscrRdWr.h" + +_Analysis_mode_(_Analysis_code_type_kernel_driver_) + +#if !defined( STATUS_DEVICE_REMOVED ) +#define STATUS_DEVICE_REMOVED STATUS_UNSUCCESSFUL +#endif + +#define SysCompareMemory( p1, p2, Len ) ( RtlCompareMemory( p1,p2, Len ) != Len ) +#define SysCopyMemory( pDest, pSrc, Len ) RtlCopyMemory( pDest, pSrc, Len ) +#define SysFillMemory( pDest, Value, Len ) RtlFillMemory( pDest, Len, Value ) + +#define DELAY_WRITE_PSCR_REG 1 +#define DELAY_PSCR_WAIT 5 + +#define LOBYTE( any ) ((UCHAR)( any & 0xFF ) ) +#define HIBYTE( any ) ((UCHAR)( ( any >> 8) & 0xFF )) + +// +// These macros will store and retrieve the request handle from the IRP. +// We will use the first slot of DriverContext because framework reserves +// the use of 3rd & 4rd slot of DriverContext for its own purpose. +// +#define GET_WDFREQUEST_FROM_IRP(Irp) (WDFREQUEST)Irp->Tail.Overlay.DriverContext[0] +#define SET_REQUEST_IN_IRP(Irp, Request) {Irp->Tail.Overlay.DriverContext[0] = (PVOID)Request;} + +typedef struct _DEVICE_EXTENSION +{ + SMARTCARD_EXTENSION SmartcardExtension; + + WDFDEVICE Device; + + // Out interrupt resource + WDFINTERRUPT Interrupt; + + WDFQUEUE IoctlQueue; + + WDFQUEUE NotificationQueue; + + // Flag that indicates if we need to unmap the port upon stop + BOOLEAN UnMapPort; + + // Number of pending card tracking interrupts + ULONG PendingInterrupts; + + // If the PCMCIA works in PCI mode, check the time between two interrupts + BOOLEAN bSharedIRQ; + LARGE_INTEGER SaveTime; + + ULONG DeviceInstanceNo; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +// +// This macro defines an accessor function which will be used to get the context +// pointer from the device handle. +// +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, GetDeviceExtension) + +#define IOCTL_PSCR_COMMAND SCARD_CTL_CODE( 0x8000 ) +#define IOCTL_GET_VERSIONS SCARD_CTL_CODE( 0x8001 ) +#define IOCTL_SET_TIMEOUT SCARD_CTL_CODE( 0x8002 ) +#define IOCTL_GET_CONFIGURATION SCARD_CTL_CODE( 0x8003 ) + +typedef struct _VERSION_CONTROL +{ + ULONG SmclibVersion; + UCHAR DriverMajor, + DriverMinor, + FirmwareMajor, + FirmwareMinor, + UpdateKey; +} VERSION_CONTROL, *PVERSION_CONTROL; + +#define SIZEOF_VERSION_CONTROL sizeof( VERSION_CONTROL ) + +typedef struct _PSCR_CONFIGURATION +{ + PPSCR_REGISTERS IOBase; + ULONG IRQ; + +} PSCR_CONFIGURATION, *PPSCR_CONFIGURATION; + +#define SIZEOF_PSCR_CONFIGURATION sizeof( PSCR_CONFIGURATION ) + + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD PscrEvtDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP PscrEvtDeviceContextCleanup; + +EVT_WDF_DEVICE_D0_ENTRY PscrEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT PscrEvtDeviceD0Exit; +EVT_WDF_DEVICE_PREPARE_HARDWARE PscrEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PscrEvtIoDeviceControl; +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE PscrEvtIoCanceledOnQueue; + +EVT_WDF_FILE_CLEANUP PscrEvtFileCleanup; + +EVT_WDF_INTERRUPT_ISR PscrEvtInterruptServiceRoutine; +EVT_WDF_INTERRUPT_DPC PscrEvtInterruptDpc; + +NTSTATUS +PscrGenericIOCTL( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +PscrFreeze( + PSMARTCARD_EXTENSION SmartcardExtension + ); + +VOID +SysDelay( + ULONG Timeout + ); + +NTSTATUS +PscrRegisterWithSmcLib( + PDEVICE_EXTENSION DeviceExtension + ); + +WDFSTRING +PscrGetRegistryValue( + _In_ WDFDEVICE Device, + _In_ LPCWSTR Name + ); + +PCHAR +GetIoctlName( + ULONG IoControlCode + ); + +#endif // __PSCR_NT_DRV_H__ diff --git a/smartcrd/pscr/pscrrdwr.c b/smartcrd/pscr/pscrrdwr.c new file mode 100644 index 00000000..82ebb03d --- /dev/null +++ b/smartcrd/pscr/pscrrdwr.c @@ -0,0 +1,509 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrRdWr.c + +Abstract: + + Hardware access functions for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Environment: + + Win 95 Sys... calls are resolved by Pscr95Wrap.asm functions and + Pscr95Wrap.h macros, resp. + + NT 4.0 Sys... functions resolved by PscrNTWrap.c functions and + PscrNTWrap.h macros, resp. + +Notes: + + The file pscrrdwr.c was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 1.00 Initial Version + Klaus Schuetz 9/20/1997 1.01 Timing changed + Andreas Straub 9/24/1997 1.02 Low Level error handling, + minor bugfixes, clanup + +--*/ + +#include <PscrNT.h> +#include <PscrCmd.h> +#include <PscrRdWr.h> + +#pragma optimize( "", off ) +VOID +PscrFlushInterface( PREADER_EXTENSION ReaderExtension ) +/*++ + +PscrFlushInterface: + Read & discard data from the pcmcia interface + +Arguments: + ReaderExtension context of call + +Return Value: + void + +--*/ +{ + UCHAR Status; + ULONG Length; + PPSCR_REGISTERS IOBase; + + IOBase = ReaderExtension->IOBase; + + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + if (( Status & PSCR_DATA_AVAIL_BIT ) && ( Status & PSCR_FREE_BIT )) { + + // take control over + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + + // get number of available bytes + Length = ((ULONG)READ_PORT_UCHAR( &IOBase->SizeMSReg )) << 8; + Length |= READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + // perform a dummy read + while ( Length-- ) { + READ_PORT_UCHAR( &IOBase->DataReg ); + } + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + } + return; +} + + +NTSTATUS +PscrRead( + _In_ PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + _In_ ULONG DataLen, // length of data + _Out_ PULONG pNBytes // number of bytes read + ) +/*++ +PscrRead: + wait until data available & transfer data from reader to host + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer + pNBytes number of bytes returned + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + ULONG NBytes = 0; + + NTStatus = PscrReadDirect( + ReaderExtension, + pData, + DataLen, + &NBytes + ); + + if( NTStatus == STATUS_SUCCESS ) + { + // error check + if( pData[ NBytes - 1 ] != + PscrCalculateLRC( pData, (USHORT)( NBytes-1 ))) + { + NTStatus = STATUS_CRC_ERROR; + } + else + { + USHORT ReaderStatus; + // + // Evaluation of reader errors. A reader error is indicated + // if the T1 length is 2 and the Nad indicates that this + // packet came from the reader + // + if( ( ( pData[ PSCR_NAD ] & 0x0F ) == 0x01 ) && + ( pData[ PSCR_LEN ] == 0x02 ) + ) + { + ReaderStatus = (( USHORT ) pData[3] ) << 8; + ReaderStatus |= (( USHORT ) pData[4] ); + + if( ( ReaderStatus != 0x9000 ) && + ( ReaderStatus != 0x9001 ) + ) + { + NBytes = 0; + + if( ReaderStatus == PSCR_SW_PROTOCOL_ERROR ) + { + NTStatus = STATUS_IO_TIMEOUT; + } + else if( ReaderStatus == PSCR_SW_NO_ICC ) + { + NTStatus = STATUS_NO_MEDIA; + } + else + { + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + + // check freeze data + if( ( NBytes == 9 ) && + ( pData[ PSCR_NAD ] == 0x21 ) && + ( pData[ PSCR_INF ] == TAG_FREEZE_EVENTS )) + { + UCHAR CardState; + + CardState = pData[PSCR_INF + 2] == DEVICE_ICC1 ? + PSCR_ICC_PRESENT : PSCR_ICC_ABSENT; + + if( ( ReaderExtension->CompletionRoutine != NULL ) && + ( ReaderExtension->TrackingContext != NULL )) + { + + // Freeze Data read + ReaderExtension->RequestInterrupt = FALSE; // set in DPC/reset here + + (ReaderExtension->CompletionRoutine)( + ReaderExtension->TrackingContext, + CardState, + FALSE + ); + } + NBytes = 0; + + if( CardState == PSCR_ICC_ABSENT ) + { + NTStatus = STATUS_NO_MEDIA; + } + } + } + } + + // write number of bytes received + *pNBytes = NBytes; + + if( NBytes ) + { + NTStatus = STATUS_SUCCESS; + } + + return ( NTStatus ); +} + + +NTSTATUS +PscrReadDirect( + PREADER_EXTENSION ReaderExtension, + _Out_writes_bytes_(DataLen) PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) +/*++ +PscrReadDirect: + wait until data available & transfer data from reader to host + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer + pNBytes number of bytes returned + +Return Value: + STATUS_SUCCESS + STATUS_BUFFER_TOO_SMALL + STATUS_UNSUCCESSFUL + +--*/ +{ + NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; + PPSCR_REGISTERS IOBase; + USHORT InDataLen; + ULONG Idx; + + IOBase = ReaderExtension->IOBase; + + // wait until interface is ready to transfer + InDataLen = 0; + + if( NT_SUCCESS( NTStatus = PscrWait( ReaderExtension, PSCR_DATA_AVAIL_BIT | PSCR_FREE_BIT ))) + { + + // take control over + + SysDelay( DELAY_PSCR_WAIT ); + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + SysDelay( DELAY_PSCR_WAIT ); + + // get number of available bytes + InDataLen = ( READ_PORT_UCHAR( &IOBase->SizeMSReg ) << 8 ); + InDataLen |= READ_PORT_UCHAR( &IOBase->SizeLSReg ); + + // check buffer size. if buffer to small, the data will be discarded + if( ( ULONG )InDataLen <= DataLen ) + { + // read data + for (Idx = 0; Idx < InDataLen; Idx++) { + + pData[ Idx ] = READ_PORT_UCHAR( &IOBase->DataReg ); + if(( READ_PORT_UCHAR( &IOBase->CmdStatusReg )) == 0x02 ) + { + Idx++; + break; + } + + } + + if( Idx < ( ULONG )InDataLen ) + { + if(( InDataLen - Idx ) == 1 ) + { + pData[ Idx ] = PscrCalculateLRC( pData, ( USHORT ) Idx ); + } + else + { + InDataLen = 0; + NTStatus = STATUS_UNSUCCESSFUL; + } + } + } + else + { + // flush interface in case of wrong buffer size + do + { + READ_PORT_UCHAR( &IOBase->DataReg ); + } while( --InDataLen ); + NTStatus = STATUS_BUFFER_TOO_SMALL; + } + // clean up + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + + } + + ReaderExtension->RequestPending = FALSE; + + // write number of bytes received + if( InDataLen ) + { + if( pNBytes != NULL ) + { + ( *pNBytes ) = ( ULONG ) InDataLen; + } + NTStatus = STATUS_SUCCESS; + } + return ( NTStatus ); +} + +NTSTATUS +PscrWrite( + PREADER_EXTENSION ReaderExtension, + PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) +/*++ +PscrWrite: + calculates the LRC of the buffer & sends command to the reader + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer (exclusive LRC!) + pNBytes number of bytes written + +Return Value: + return value of PscrWriteDirect + +--*/ +{ + NTSTATUS NTStatus; + + // Add the EDC field to the end of the data + pData[ DataLen ] = PscrCalculateLRC( pData, ( USHORT ) DataLen ); + + // Send buffer + NTStatus = PscrWriteDirect( + ReaderExtension, + pData, + DataLen + PSCR_EPILOGUE_LENGTH, + pNBytes + ); + + return( NTStatus ); +} + +NTSTATUS +PscrWriteDirect( + PREADER_EXTENSION ReaderExtension, + PUCHAR pData, + ULONG DataLen, + PULONG pNBytes + ) + +/*++ +PscrWriteDirect: + sends command to the reader. The LRC / CRC must be calculated by caller! + +Arguments: + ReaderExtension context of call + pData ptr to data buffer + DataLen length of data buffer (exclusive LRC!) + pNBytes number of bytes written + +Return Value: + STATUS_SUCCESS + STATUS_DEVICE_BUSY + +--*/ +{ + NTSTATUS NTStatus = STATUS_SUCCESS; + UCHAR Status; + PPSCR_REGISTERS IOBase; + + IOBase = ReaderExtension->IOBase; + + // in case of card change, there may be data available + Status = READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + if ( Status & PSCR_DATA_AVAIL_BIT ) { + NTStatus = STATUS_DEVICE_BUSY; + + } else { + // + // wait until reader is ready + // + ReaderExtension->RequestPending = TRUE; + + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + NTStatus = PscrWait( ReaderExtension, PSCR_FREE_BIT ); + + if ( NT_SUCCESS( NTStatus )) { + ULONG Idx; + + // take control over + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, PSCR_HOST_CONTROL_BIT ); + + // write the buffer size + WRITE_PORT_UCHAR( &IOBase->SizeMSReg, ( UCHAR )( DataLen >> 8 )); + SysDelay( DELAY_WRITE_PSCR_REG ); + WRITE_PORT_UCHAR( &IOBase->SizeLSReg, ( UCHAR )( DataLen & 0x00FF )); + SysDelay( DELAY_WRITE_PSCR_REG ); + + // write data + for (Idx = 0; Idx < DataLen; Idx++) { + + WRITE_PORT_UCHAR( &IOBase->DataReg, pData[ Idx ] ); + } + + if ( pNBytes != NULL ) { + *pNBytes = DataLen; + } + } + + // clean up + WRITE_PORT_UCHAR( &IOBase->CmdStatusReg, CLEAR_BIT ); + } + + return( NTStatus ); +} + +UCHAR +PscrCalculateLRC( + PUCHAR pData, + USHORT DataLen + ) +/*++ + +PscrCalculateLRC: + calculates the XOR LRC of a buffer. + +Arguments: + pData ptr to data buffer + DataLen length of range + +Return Value: + LRC + +--*/ +{ + UCHAR Lrc; + USHORT Idx; + + // + // Calculate LRC by XORing all the bytes. + // + Lrc = pData[ 0 ]; + for ( Idx = 1 ; Idx < DataLen; Idx++ ) { + Lrc ^= pData[ Idx ]; + } + return( Lrc ); +} + +NTSTATUS +PscrWait( + PREADER_EXTENSION ReaderExtension, + UCHAR Mask + ) +/*++ +PscrWait: + Test the status port of the reader until ALL bits in the mask are set. + The maximum of time until DEVICE_BUSY is returned is approx. + MaxRetries * DELAY_PSCR_WAIT if MaxRetries != 0. + If MaxRetries = 0 the driver waits until the requested status is reported or the + user defines a timeout. + +Arguments: + ReaderExtension context of call + Mask mask of bits to test the status register + +Return Value: + STATUS_SUCCESS + STATUS_DEVICE_BUSY + +--*/ +{ + NTSTATUS NTStatus; + PPSCR_REGISTERS IOBase; + ULONG Retries; + + IOBase = ReaderExtension->IOBase; + NTStatus = STATUS_DEVICE_BUSY; + + // wait until condition fulfilled or specified timeout expired + for ( Retries = 0; Retries < ReaderExtension->MaxRetries; Retries++) { + + if (( (READ_PORT_UCHAR( &IOBase->CmdStatusReg )) == 0x01) && + ReaderExtension->InvalidStatus) { + NTStatus = STATUS_CANCELLED; + break; + } + + // test requested bits + if (( (READ_PORT_UCHAR( &IOBase->CmdStatusReg )) & Mask ) == Mask ) { + NTStatus = STATUS_SUCCESS; + break; + } + SysDelay( DELAY_PSCR_WAIT ); + } + + (void) READ_PORT_UCHAR( &IOBase->CmdStatusReg ); + + return NTStatus; +} + +#pragma optimize( "", on ) + + diff --git a/smartcrd/pscr/pscrrdwr.h b/smartcrd/pscr/pscrrdwr.h new file mode 100644 index 00000000..4a1a2bff --- /dev/null +++ b/smartcrd/pscr/pscrrdwr.h @@ -0,0 +1,366 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrRdWr.h + +Abstract: + + Constants & access function prototypes for SCM PSCR smartcard reader + +Author: + + Andreas Straub + +Notes: + + The file pscrrdwr.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + + Andreas Straub 7/16/1997 Initial Version + +--*/ + +#if !defined( __PSCR_RDWR_H__ ) +#define __PSCR_RDWR_H__ + +#pragma pack( 1 ) +// +// The usage of the PSCR_REGISTERS struct is a little bit tricky: +// We set the address of that stucture to the IO Base Port, then +// the other reg's can accessed by their address. +// p.E. &PscrRegs = 0x320 --> &PscrRegs->CmdStatusReg = 0x321... +// +typedef struct _PSCR_REGISTERS { + + UCHAR DataReg; + UCHAR CmdStatusReg; + UCHAR SizeLSReg; + UCHAR SizeMSReg; + + } PSCR_REGISTERS, *PPSCR_REGISTERS; + +#define SIZEOF_PSCR_REGISTERS ( sizeof( PSCR_REGISTERS ) + +#pragma pack() + + +typedef enum _READER_POWER_STATE { + PowerReaderUnspecified = 0, + PowerReaderWorking, + PowerReaderOff +} READER_POWER_STATE, *PREADER_POWER_STATE; + +typedef void ( *PTRACKING_COMPLETION )( PVOID TrackingContext, UCHAR Status, BOOLEAN Wakeup ); + +#define MAX_DATARATES 4 + +typedef struct _READER_EXTENSION { + + // I/O address where the reader is configured. + PPSCR_REGISTERS IOBase; + ULONG IOWindow; + ULONG MaxIFSD; + + // IRQ assigned by the system + ULONG CurrentIRQ; + + // + // limit for read timeout. the absolute timeout limit is + // MaxRetries * DELAY_PSCR_WAIT + // + + ULONG MaxRetries; + + // Source/Destination byte always used by the PCMCIA (PC Card) reader. + UCHAR Device; + + // Software revision ID of the SwapSmart firmware. + UCHAR FirmwareMajor, FirmwareMinor, UpdateKey; + + // + // Interrupt status; the flag is raised if an freeze event was detected + // and cleared if the interface was cleared (int service routine or + // PscrRead) + // + BOOLEAN FreezePending; + + // + // Selected file in the reader file system; the flag is raised if the + // ICC1 status file was selected & is cleared if any generic ioctl was + // issued (in this case another file may be selected) + // + BOOLEAN StatusFileSelected; + + // used to cancel a read request + BOOLEAN RequestPending; + // set TRUE if an interrupt is sending, but the reader is busy + BOOLEAN RequestInterrupt; + + BOOLEAN InvalidStatus; + + BOOLEAN CardPresent; + + // Current reader power state. + READER_POWER_STATE ReaderPowerState; + + PTRACKING_COMPLETION CompletionRoutine; + + PVOID TrackingContext; + + ULONG dataRatesSupported[MAX_DATARATES]; + +} READER_EXTENSION, *PREADER_EXTENSION; + +#define SIZEOF_READER_EXTENSION ( sizeof( READER_EXTENSION )) + +// +// Constants ----------------------------------------------------------------- +// +#define PSCR_ID_STRING "SCM SwapSmart 2." + +#define TLV_BUFFER_SIZE 0x20 +#define ATR_SIZE 0x40 // TS + 32 + SW + PROLOGUE + EPILOGUE... + +#define PSCR_MAX_RETRIES 1000 + +#define CLEAR_BIT 0x00 + +#define DEFAULT_WAIT_TIME 0x01 + +#define PSCR_PROLOGUE_LENGTH 0x03 +#define PSCR_EXT_PROLOGUE_LENGTH 0x05 +#define PSCR_STATUS_LENGTH 0x02 + +#define PSCR_LRC_LENGTH 0x01 +#define PSCR_CRC_LENGTH 0x02 + +#define PSCR_EPILOGUE_LENGTH PSCR_LRC_LENGTH + +#define PCB_DEFAULT 0x00 + +#define MAX_T1_BLOCK_SIZE 270 +// +// data buffer idx +// +#define PSCR_NAD 0x00 +#define PSCR_PCB 0x01 +#define PSCR_LEN 0x02 +#define PSCR_INF 0x03 +#define PSCR_APDU PSCR_INF +// +// device identifier for reset, deactivate +// +#define DEVICE_READER 0x00 +#define DEVICE_ICC1 0x01 +#define DEVICE_ICC2 0x02 +// +// NAD's +// +#define NAD_TO_ICC1 0x02 +#define NAD_TO_ICC2 0x42 +#define NAD_TO_PSCR 0x12 +#define REMOTE_NAD_TO_ICC1 0x03 +#define REMOTE_NAD_TO_ICC2 0x43 +#define REMOTE_NAD_TO_PSCR 0x13 +// +// PSCR Commands +// +#define CLA_SET_INTERFACE_PARAM 0x80 +#define CLA_FREEZE 0x80 +#define CLA_RESET 0x20 +#define CLA_DEACTIVATE 0x20 +#define CLA_SELECT_FILE 0x00 +#define CLA_READ_BINARY 0x00 +#define CLA_WRITE_BINARY 0x00 +#define CLA_VERIFY 0x00 +#define CLA_WARM_RESET 0x20 +#define CLA_SOFTWARE_UPDATE 0x80 +#define CLA_SET_MODE 0x80 + +#define INS_SET_INTERFACE_PARAM 0x60 +#define INS_FREEZE 0x70 +#define INS_RESET 0x10 +#define INS_DEACTIVATE 0x14 +#define INS_SELECT_FILE 0xA4 +#define INS_READ_BINARY 0xB0 +#define INS_WRITE_BINARY 0xD0 +#define INS_VERIFY 0x20 +#define INS_WARM_RESET 0x1F +#define INS_SOFTWARE_UPDATE 0xFF +#define INS_SET_MODE 0x61 + +// +// Status Read Only Register +// +#define PSCR_DATA_AVAIL_BIT 0x80 +#define PSCR_FREE_BIT 0x40 +#define PSCR_WRITE_ERROR_BIT 0x02 +#define PSCR_READ_ERROR_BIT 0x01 +// +// Command Write Only Register... +// +#define PSCR_RESET_BIT 0x08 +#define PSCR_SIZE_READ_BIT 0x04 +#define PSCR_SIZE_WRITE_BIT 0x02 +#define PSCR_HOST_CONTROL_BIT 0x01 +// +// Tags... +// +#define TAG_MODULE 0x02 +#define TAG_MEMORY_SIZE 0x03 +#define TAG_UPDATE_KEY 0x08 +#define TAG_SOFTWARE_REV 0x0F +#define TAG_BLOCK_COMP_OPTION 0x13 +#define TAG_READER_MECH_OPTIONS 0x20 +#define TAG_READER_STATUS 0x21 +#define TAG_ICC_PROTOCOLS 0x22 +#define TAG_BI 0x23 +#define TAG_FI 0x24 +#define TAG_PTS_PARAM 0x25 +#define TAG_PROTOCOL_STATUS 0x26 +#define TAG_SET_NULL_BYTES 0x2d +#define TAG_FREEZE_EVENTS 0x30 +#define TAG_BIT_LENGTH 0x40 +#define TAG_CGT 0x41 +#define TAG_BWT 0x42 +#define TAG_CWT 0x43 +#define TAG_PROTOCOL_PARAM 0x44 +// +// card power definitions ( Tag 0x21 ) +// +#define PSCR_ICC_ABSENT 0x00 +#define PSCR_ICC_PRESENT 0x01 +#define PSCR_ICC_POWERED 0x02 +#define PSCR_ICC_IN_TRANSP_MODE 0xA0 +#define PSCR_ICC_UNKNOWN 0xFF +// +// protocol definitions ( Tag 0x22 ) +// +#define PSCR_PROTOCOL_UNDEFINED 0x00 +#define PSCR_PROTOCOL_T0 0x01 +#define PSCR_PROTOCOL_T1 0x02 +#define PSCR_PROTOCOL_T14 0x03 +#define PSCR_PROTOCOL_I2C 0x80 +#define PSCR_PROTOCOL_3WIRE 0x81 +#define PSCR_PROTOCOL_2WIRE 0x81 + +#define WTX_REQUEST 0xC3 +#define WTX_REPLY 0xE3 +// +// File ID's +// +#define FILE_MASTER 0x3F00 +#define FILE_PSCR_CONFIG 0x0020 +#define FILE_PSCR_DIR 0x7F60 +#define FILE_PSCR_DIR_CONFIG 0x6020 +#define FILE_PSCR_DIR_STATUS 0x6021 +#define FILE_PSCR_DIR_FREEZE_CONFIG 0x6030 +#define FILE_PSCR_DIR_FREEZE_STATUS 0x6031 +#define FILE_ICC1_DIR 0x7F70 +#define FILE_ICC1_DIR_CONFIG 0x7020 +#define FILE_ICC1_DIR_STATUS 0x7021 +#define FILE_ICC2_DIR_CONFIG 0x7120 +#define FILE_ICC2_DIR_STATUS 0x7121 +// +// Status Word Definitions +// +#define PSCR_SW_COMMAND_FAIL 0x6985 +#define PSCR_SW_INVALID_PARAM 0x6A80 +#define PSCR_SW_INCONSISTENT_DATA 0x6A85 +#define PSCR_SW_NO_PROTOCOL_SUPPORT 0x62A3 +#define PSCR_SW_SYNC_ATR_SUCCESS 0x9000 +#define PSCR_SW_ASYNC_ATR_SUCCESS 0x9001 +#define PSCR_SW_NO_PROTOCOL 0x62A5 +#define PSCR_SW_NO_ATR 0x62A6 +#define PSCR_SW_NO_ATR_OR_PROTOCOL 0x62A7 +#define PSCR_SW_NO_ICC 0x64A1 +#define PSCR_SW_ICC_NOT_ACTIVE 0x64A2 +#define PSCR_SW_NON_SUPPORTED_PROTOCOL 0x64A3 +#define PSCR_SW_PROTOCOL_ERROR 0x64A8 +#define PSCR_SW_NO_ATR_OR_PROTOCOL2 0x64A7 +#define PSCR_SW_FILE_NOT_FOUND 0x6A82 +#define PSCR_SW_FILE_NO_ACCEPPTED_AUTH 0x6982 +#define PSCR_SW_FILE_NO_ACCESS 0x6985 +#define PSCR_SW_FILE_BAD_OFFSET 0x6B00 +#define PSCR_SW_END_OF_FILE_READ 0x6282 +#define PSCR_SW_END_OF_FILE_WRITE 0x6301 +#define PSCR_SW_WRITE_FILE_FAIL 0x6500 +#define PSCR_SW_NO_PASSWORD 0x6200 +#define PSCR_SW_WRONG_PASSWORD 0x6300 +#define PSCR_SW_VERIFY_COUNTER_FAIL 0x6983 +#define PSCR_SW_NO_REF_DATA 0x6A88 +#define PSCR_SW_FLASH_MEM_ERROR 0x6481 +#define PSCR_SW_FLASH_MEM_ERR2 0x6581 +#define PSCR_SW_WRONG_LENGTH 0x6700 +#define PSCR_SW_UNKNOWN_ICC_ERROR 0x64A0 +#define PSCR_SW_UNKNOWN_PROTOCOL_ERROR 0x64A9 +#define PSCR_SW_NO_PROTOCOL_SELECTED 0x64A5 +#define PSCR_SW_PTS_PROTOCOL_ERROR 0x64AA +#define PSCR_SW_WTX_ERROR 0x64AB +#define PSCR_SW_WTX_ERR2 0x65AB +#define PSCR_SW_INVALID_SOURCE_ADDR 0x6F82 + +// +// Prototypes for access functions ------------------------------------------- +// + + +VOID +PscrFlushInterface( + PREADER_EXTENSION ReaderExtension // context of call + ); + +NTSTATUS +PscrRead( + _In_ PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + _In_ ULONG DataLen, // length of data + _Out_ PULONG pNBytes // number of bytes read + ); + +NTSTATUS +PscrReadDirect( + PREADER_EXTENSION ReaderExtension, // context of call + _Out_writes_bytes_(DataLen) PUCHAR pData, // ptr to data buffer + ULONG DataLen, // length of data + PULONG pNBytes // number of bytes read + ); + +NTSTATUS +PscrWrite( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pData, // ptr to data buffer + ULONG DataLength, // length of data + PULONG pNBytes // number of bytes written + ); + +NTSTATUS +PscrWriteDirect( + PREADER_EXTENSION ReaderExtension, // context of call + PUCHAR pData, // ptr to data buffer + ULONG DataLength, // length of data + PULONG pNBytes // number of bytes written + ); + +UCHAR +PscrCalculateLRC( + PUCHAR pData, // ptr to data buffer + USHORT DataLength // length of data + ); + +NTSTATUS +PscrWait( + PREADER_EXTENSION ReaderExtension, // context of call + UCHAR Mask // mask of requested bits + ); + +#endif // __PSCR_RDWR_H__ + +// ------------------------------- END OF FILE ------------------------------- + + diff --git a/smartcrd/pscr/pscrvers.h b/smartcrd/pscr/pscrvers.h new file mode 100644 index 00000000..0ee8b0a8 --- /dev/null +++ b/smartcrd/pscr/pscrvers.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 1997 - 1999 SCM Microsystems, Inc. + +Module Name: + + PscrVers.h + +Abstract: + + header file for version information + +Author: + + Andreas Straub + +Environment: + + Win 95, Win NT + +Notes: + + The file pscrvers.h was reviewed by LCA in June 2011 and per license is + acceptable for Microsoft use under Dealpoint ID 178449. + +Revision History: + +--*/ +#if !defined( __PSCRVERS_H__ ) +#define __PSCRVERS_H__ + +#define PSCR_VERSION_STR "1.26" +#define PSCR_MAJOR_VERSION 1 +#define PSCR_MINOR_VERSION 26 + +#define PSCR_NAME "PSCR" +#define PSCR_PRODUCT_NAME "PSCR SmartCard Reader" +#define PSCR_VENDOR_NAME "PSCR" +#define PSCR_IFD_TYPE "PCMCIA Reader" +#define PSCR_VXD_NAME "PSCR.VXD" +#define PSCR_DEVICE_NAME "PSCR_0" + +#endif // __PSCRVERS_H__ |
