summaryrefslogtreecommitdiff
path: root/general/pcidrv
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /general/pcidrv
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/pcidrv')
-rw-r--r--general/pcidrv/ReadMe.md186
-rw-r--r--general/pcidrv/kmdf/HW/PCIDRV.vcxproj360
-rw-r--r--general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters75
-rw-r--r--general/pcidrv/kmdf/HW/e100_557.h789
-rw-r--r--general/pcidrv/kmdf/HW/e100_equ.h187
-rw-r--r--general/pcidrv/kmdf/HW/eeprom.c306
-rw-r--r--general/pcidrv/kmdf/HW/isrdpc.c904
-rw-r--r--general/pcidrv/kmdf/HW/localwpp.ini17
-rw-r--r--general/pcidrv/kmdf/HW/macros.h312
-rw-r--r--general/pcidrv/kmdf/HW/nic_def.h800
-rw-r--r--general/pcidrv/kmdf/HW/nic_init.c2378
-rw-r--r--general/pcidrv/kmdf/HW/nic_pm.c1710
-rw-r--r--general/pcidrv/kmdf/HW/nic_recv.c630
-rw-r--r--general/pcidrv/kmdf/HW/nic_req.c1453
-rw-r--r--general/pcidrv/kmdf/HW/nic_send.c838
-rw-r--r--general/pcidrv/kmdf/HW/nuiouser.h105
-rw-r--r--general/pcidrv/kmdf/HW/physet.c1001
-rw-r--r--general/pcidrv/kmdf/HW/precomp.h45
-rw-r--r--general/pcidrv/kmdf/HW/precompsrc.c1
-rw-r--r--general/pcidrv/kmdf/HW/routines.c479
-rw-r--r--general/pcidrv/kmdf/PCIDRV.C1792
-rw-r--r--general/pcidrv/kmdf/PCIDRV.H401
-rw-r--r--general/pcidrv/kmdf/PCIDRV.RC33
-rw-r--r--general/pcidrv/kmdf/PCIDRV.mof19
-rw-r--r--general/pcidrv/kmdf/genpci.inx127
-rw-r--r--general/pcidrv/kmdf/public.h48
-rw-r--r--general/pcidrv/kmdf/trace.h140
-rw-r--r--general/pcidrv/kmdf/wmi.c144
-rw-r--r--general/pcidrv/pcidrv.sln49
-rw-r--r--general/pcidrv/test/myping.c1054
-rw-r--r--general/pcidrv/test/myping.vcxproj201
-rw-r--r--general/pcidrv/test/myping.vcxproj.Filters30
-rw-r--r--general/pcidrv/test/resource.h17
-rw-r--r--general/pcidrv/test/testapp.c1224
-rw-r--r--general/pcidrv/test/testapp.h260
-rw-r--r--general/pcidrv/test/testapp.rc37
36 files changed, 18152 insertions, 0 deletions
diff --git a/general/pcidrv/ReadMe.md b/general/pcidrv/ReadMe.md
new file mode 100644
index 00000000..72898b5b
--- /dev/null
+++ b/general/pcidrv/ReadMe.md
@@ -0,0 +1,186 @@
+PCIDRV - WDF Driver for PCI Device
+==================================
+
+This sample demonstrates how to write a KMDF driver for a PCI device. The sample works with the Intel 82557/82558 based PCI Ethernet Adapter (10/100) and Intel compatibles.
+
+This adapter supports scatter-gather DMA, wake on external event (Wait-Wake), and idle power down. The hardware specification is publicly available, and the source code to interface with the hardware is included in the WDK.
+
+
+Overview
+--------
+
+The following is a list of key KMDF interfaces demonstrated in this sample:
+
+- Handling PnP & Power Events
+
+- Registering Device Interface
+
+- Hardware resource mapping: Port, Memory & Interrupt
+
+- DMA Interfaces
+
+- Parallel default queue for write requests. If the write cannot be satisfied immediately, the request is put into a manual parallel queue.
+
+- Parallel manual queue for Read requests
+
+- Parallelc default queue for IOCTL requests. If the ioctl cannot be satisfied immediately, the request is put into a manual parallel queue.
+
+- Request cancelation
+
+- Handling Interrupt & DPC
+
+- Watchdog Timer DPC to monitor the device state.
+
+- Event Tracing & HEXDUMP
+
+- Reading & Writing to the registry
+
+Note: This sample provides an example of a minimal driver intended for educational purposes. Neither the driver nor its sample test programs are intended for use in a production environment.
+
+As stated earlier, this sample is meant to demonstrate how to write a KMDF driver for a generic PCI device and not for PCI network controllers. For network controllers, you should write a monolithic NDIS miniport driver based on the samples given under the src\\network\\ndis directory.
+
+Note that it is still possible to use a subset of KMDF APIs when writing a NDIS miniport (see src\\network\\ndis\\usbnwifi directory for a sample on how to use KMDF interfaces to talk to USB device in an NDIS miniport).
+
+The sample driver has been tested on the following Intel Ethernet controllers:
+
+<table>
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="left">Device Desc
+Hardware ID</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left"><p>IBM Netfinity 10/100 Ethernet Adapter</p>
+<p>PCI\VEN_8086&amp;DEV_1229&amp;SUBSYS_005C1014&amp;REV_05</p></td>
+<td align="left"><p>Intel(R) PRO/100+ Management Adapter with Alert On LAN</p>
+<p>PCI\VEN_8086&amp;DEV_1229&amp;SUBSYS_000E8086&amp;REV_08</p></td>
+</tr>
+</tbody>
+</table>
+
+Using this sample as a standalone driver
+----------------------------------------
+
+``` {.syntax xml:space="preserve"}
+ ---------------------
+ | |
+ | MYPING | <-- Usermode test application
+ | |
+ ---------------------
+ ^
+ | UserMode
+-------------------------------------------------------------------
+ | KernelMode
+ V
+ ---------------------
+ | |
+ | PCIDRV | <-- Installed as a function driver
+ | |
+ ---------------------
+ ^
+ | <-----Talk to the hardware using I/O resources
+ V
+ ---------------
+ | H/W NIC |
+ ---------------
+ |||||||
+ -------
+```
+
+You can install the driver as a standalone driver of a custom setup class, called Sample Class using GENPCI.INF. The PCI device is not seen as a network controller and as a result no protocol driver is bound to the device. In order to test the read & write path of the driver, you can use the specially developed ping application, called MYPING. This test application crafts the entire Ethernet frame in usermode and sends it to the driver to be transferred on the wire. In this configuration, you can only ping another machine on the same subnet. The application does all the ARP and AARP resolution in the usermode to get the MAC address of the target machine and sends ICMP ECHO requests.
+
+The PCIDRV sample acts as a power policy owner of the device and implements all the wait-wake and idle detection logic.
+
+INSTALLATION
+------------
+
+The driver can be installed as a Net class driver or as a standalone driver (user defined class). The KMDF versions of the INF files are dynamically generated from .INX file. In addition to the driver files, you have to include the WDF coinstaller DLL from the src\\redist\\wdf folder of the WDK.
+
+You can obtain redistributable framework updates by downloading the *wdfcoinstaller.msi* package from [WDK 8 Redistributable Components](http://go.microsoft.com/fwlink/p/?LinkID=226396). This package performs a silent install into the directory of your Windows Driver Kit (WDK) installation. You will see no confirmation that the installation has completed. You can verify that the redistributables have been installed on top of the WDK by ensuring there is a redist\\wdf directory under the root directory of the WDK, %ProgramFiles(x86)%\\Windows Kits\\8.0.
+
+### TESTING
+
+To test standalone driver configuration: You should use the specially developed ping application, called MYPING that comes with the sample. The Ping.exe provided in the system will not work because in this configuration, the test card is not bound to any network protocol - it's not seen as Net device by the system. Currently the test application doesn't have ability to get an IP address from a network DHCP server. As a result, it is better to connect the network device to a private hub and ping another machine connected to that hub. For example, let us say you have a test machine A and another machine B (development box).
+
+- Connect machine A and Machine B to a local hub.
+
+- Assign a static IP address, say 128.0.0.1 to the NIC on machine B.
+
+- Clear the ARP table on machine B by running **Arp -d** on the command line
+
+- Now run Myping.exe. This application enumerates GUID\_DEVINTERFACE\_PCIDRV and displays the name of the devices with an index number. This number will be used in identifying the interface when you invoke ping dialog.
+
+- In the ping dialog specify the following and click okay:
+
+- Device Index: 1 \<- number displayed in the list window
+
+- Source Ip Address: 128.0.0.4 \<- You can make up any valid IP address for test Machine A
+
+- Destination IP Address: 128.0.0.1 \<- IP address of machine B
+
+- Packet Size: 1428 \<- Default max size of ping payload. Minimum value is 32 bytes.
+
+If the machine B has more than one adapter and if the second adapter is connected to the internet (Corporate Network), instead of assigning static IP address to the adapter that's connected to the test machine, you can install Internet Connection Sharing (ICS) on it and get an IP address for ICS. This would let you use the test machine to browse the internet when the sample is installed in the miniport configuration and also in the standalone mode without making up or stealing somebody's IP address. For example, let us say the machine B has two adapters NIC1 and NIC2. NIC1 is connected to the CorpNet and NIC2 is connected to the private hub. Install ICS on NIC2 as described below:
+
+- Select the NIC2 in the Network Connections Applet.
+
+- Click the **Properties** button.
+
+- Go to the Advanced Tab and Check the box "Allow Other network users to connect through this computers internet connection" in the Internet Connection Sharing choice.
+
+- This will assign 192.168.0.1 IP address to NIC2.
+
+- Now on machine B, you can assume 192.168.0.2 as the local IP address and run Myping.exe . Or, you can install the sample in the miniport configuration and browse the internet.
+
+Other menu options of myping applications are:
+
+- Reenumerate All Device: This command lets you terminate active ping threads and close handle to all the device and reenumerate the devices again and display their names with index numbers. This might cause the devices to have new index numbers.
+
+- Cleanup: This command terminates ping threads and closes handles to all the devices.
+
+- Clear Display: Clears the window.
+
+- Verbose: Let you get more debug messages.
+
+- Exit: Terminate the application.
+
+**Note**  You can use this application only on a device installed in the standalone configuration. If you run it on a device that's installed as a miniport, you will get an error message. For such devices, you can use the system provided ping.exe.
+
+RESOURCES
+---------
+
+For the latest release of the Windows Driver Kit, see http://www.microsoft.com/whdc/.
+
+If you have questions on using or adapting this sample for your project, you can either contact Microsoft Technical Support or post your questions in the Microsoft driver development newsgroup.
+
+FILE MANIFEST
+-------------
+
+<table>
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="left">File
+Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left"><p>KMDF</p>
+<p>Contains the driver.</p></td>
+<td align="left"><p>KMDF\HW</p>
+<p>Contains hardware specific code.</p></td>
+</tr>
+</tbody>
+</table>
+
+
diff --git a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj
new file mode 100644
index 00000000..ca2cff13
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj
@@ -0,0 +1,360 @@
+<?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>{2221261F-E1E2-4562-A15D-2EF8BF7D878E}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{EAA7F2DD-6EAB-48CE-80E1-46A17BF21F72}</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">
+ <ClCompile Include="..\pcidrv.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="..\wmi.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="nic_init.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="eeprom.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="nic_recv.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="nic_send.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="routines.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="physet.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="nic_req.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="nic_pm.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="isrdpc.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <Inf Include="..\genpci.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\genpci.inf</CopyOutput>
+ </Inf>
+ <MofComp Include="..\pcidrv.mof">
+ <CreateBinaryMofFile>".\$(IntDir)\pcidrv.bmf"</CreateBinaryMofFile>
+ </MofComp>
+ <OtherWpp Include="..\pcidrv.rc">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ </OtherWpp>
+ <Wmimofck Include=".\$(IntDir)\pcidrv.bmf" />
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>PCIDRV</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>PCIDRV</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>PCIDRV</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>PCIDRV</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="precompsrc.c">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ResourceCompile Include="..\pcidrv.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/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters
new file mode 100644
index 00000000..a15b9d16
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters
@@ -0,0 +1,75 @@
+<?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>{8FC125AF-15BD-4DCD-9D5E-C7FE9A6ACD75}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{938C7F7B-13A2-43D1-A1CF-4B02B581687C}</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>{75E794A5-28E0-464A-A171-8AD7F2A1DEAA}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{EDAC3101-0378-4793-BEA6-FC4E036C130B}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\pcidrv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\wmi.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="eeprom.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="isrdpc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nic_init.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nic_pm.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nic_recv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nic_req.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="nic_send.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="physet.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="precompsrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="routines.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include=".\Debug\\genpci.inf">
+ <Filter>Driver Files</Filter>
+ </FilesToPackage>
+ <Inf Include="..\genpci.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ <MofComp Include="..\pcidrv.mof">
+ <Filter>Driver Files</Filter>
+ </MofComp>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\pcidrv.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/pcidrv/kmdf/HW/e100_557.h b/general/pcidrv/kmdf/HW/e100_557.h
new file mode 100644
index 00000000..fb4075df
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/e100_557.h
@@ -0,0 +1,789 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ e100_557.h (82557.h)
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+#ifndef _E100_557_H
+#define _E100_557_H
+
+//-------------------------------------------------------------------------
+// D100 Stepping Defines
+//-------------------------------------------------------------------------
+#define D100_A_STEP 0 // NEVER SHIPPED
+#define D100_B_STEP 1 // d100 first shipped silicon
+#define D100_C_STEP 2 // d100' (c-step) with vendor/id and hw fix
+#define D101_A_STEP 4 // first silicon of d101
+
+//-------------------------------------------------------------------------
+// E100 Stepping Defines - used in PoMgmt Decisions
+//-------------------------------------------------------------------------
+#define E100_82557_A_STEP 1
+#define E100_82557_B_STEP 2
+#define E100_82557_C_STEP 3
+#define E100_82558_A_STEP 4
+#define E100_82558_B_STEP 5
+#define E100_82559_A_STEP 6
+#define E100_82559_B_STEP 7
+#define E100_82559_C_STEP 8
+#define E100_82559ER_A_STEP 9
+
+//-------------------------------------------------------------------------
+// D100 PORT functions -- lower 4 bits
+//-------------------------------------------------------------------------
+#define PORT_SOFTWARE_RESET 0
+#define PORT_SELFTEST 1
+#define PORT_SELECTIVE_RESET 2
+#define PORT_DUMP 3
+
+
+//-------------------------------------------------------------------------
+// CSR field definitions -- Offsets from CSR base
+//-------------------------------------------------------------------------
+#define SCB_STATUS_LOW_BYTE 0x0
+#define SCB_STATUS_HIGH_BYTE 0x1
+#define SCB_COMMAND_LOW_BYTE 0x2
+#define SCB_COMMAND_HIGH_BYTE 0x3
+#define SCB_GENERAL_POINTER 0x4
+#define CSR_PORT_LOW_WORD 0x8
+#define CSR_PORT_HIGH_WORD 0x0a
+#define CSR_FLASH_CONTROL_REG 0x0c
+#define CSR_EEPROM_CONTROL_REG 0x0e
+#define CSR_MDI_CONTROL_LOW_WORD 0x10
+#define CSR_MDI_CONTROL_HIGH_WORD 0x12
+
+
+//-------------------------------------------------------------------------
+// SCB Status Word bit definitions
+//-------------------------------------------------------------------------
+//- Interrupt status fields
+#define SCB_STATUS_MASK BIT_12_15 // ACK Mask
+#define SCB_STATUS_CX BIT_15 // CU Completed Action Cmd
+#define SCB_STATUS_FR BIT_14 // RU Received A Frame
+#define SCB_STATUS_CNA BIT_13 // CU Became Inactive (IDLE)
+#define SCB_STATUS_RNR BIT_12 // RU Became Not Ready
+#define SCB_STATUS_MDI BIT_11 // MDI read or write done
+#define SCB_STATUS_SWI BIT_10 // Software generated interrupt
+
+//- Interrupt ACK fields
+#define SCB_ACK_MASK (BIT_9 | BIT_12_15 | BIT_8) // ACK Mask
+#define SCB_ALL_INTERRUPT_BITS BIT_8_15 // if all the bits are set, no interrupt to be served
+#define SCB_ACK_CX BIT_15 // CU Completed Action Cmd
+#define SCB_ACK_FR BIT_14 // RU Received A Frame
+#define SCB_ACK_CNA BIT_13 // CU Became Inactive (IDLE)
+#define SCB_ACK_RNR BIT_12 // RU Became Not Ready
+#define SCB_ACK_MDI BIT_11 // MDI read or write done
+#define SCB_ACK_SWI BIT_10 // Software generated interrupt
+#define SCB_ACK_ER BIT_9 // Early Receive interrupt
+#define SCB_ACK_FCP BIT_8 // Flow Control Pause interrupt
+
+//- CUS Fields
+#define SCB_CUS_MASK (BIT_6 | BIT_7) // CUS 2-bit Mask
+#define SCB_CUS_IDLE 0 // CU Idle
+#define SCB_CUS_SUSPEND BIT_6 // CU Suspended
+#define SCB_CUS_ACTIVE BIT_7 // CU Active
+
+//- RUS Fields
+#define SCB_RUS_IDLE 0 // RU Idle
+#define SCB_RUS_MASK BIT_2_5 // RUS 3-bit Mask
+#define SCB_RUS_SUSPEND BIT_2 // RU Suspended
+#define SCB_RUS_NO_RESOURCES BIT_3 // RU Out Of Resources
+#define SCB_RUS_READY BIT_4 // RU Ready
+#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) // RU No More RBDs
+#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) // RU No More RBDs
+#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) // RU Ready, No RBDs
+
+
+//-------------------------------------------------------------------------
+// SCB Command Word bit definitions
+//-------------------------------------------------------------------------
+//- CUC fields
+#define SCB_CUC_MASK BIT_4_6 // CUC 3-bit Mask
+#define SCB_CUC_START BIT_4 // CU Start
+#define SCB_CUC_RESUME BIT_5 // CU Resume
+#define SCB_CUC_DUMP_ADDR BIT_6 // CU Dump Counters Address
+#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) // CU Dump statistics counters
+#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) // Load the CU base
+#define SCB_CUC_DUMP_RST_STAT BIT_4_6 // CU Dump and reset statistics counters
+#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) // CU Static Resume
+
+//- RUC fields
+#define SCB_RUC_MASK BIT_0_2 // RUC 3-bit Mask
+#define SCB_RUC_START BIT_0 // RU Start
+#define SCB_RUC_RESUME BIT_1 // RU Resume
+#define SCB_RUC_ABORT BIT_2 // RU Abort
+#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) // Load RFD Header Data Size
+#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) // Load the RU base
+#define SCB_RUC_RBD_RESUME BIT_0_2 // RBD resume
+
+// Interrupt fields (assuming byte addressing)
+#define SCB_INT_MASK BIT_0 // Mask interrupts
+#define SCB_SOFT_INT BIT_1 // Generate a software interrupt
+
+
+//-------------------------------------------------------------------------
+// EEPROM bit definitions
+//-------------------------------------------------------------------------
+//- EEPROM control register bits
+#define EN_TRNF 0x10 // Enable turnoff
+#define EEDO 0x08 // EEPROM data out
+#define EEDI 0x04 // EEPROM data in (set for writing data)
+#define EECS 0x02 // EEPROM chip select (1=high, 0=low)
+#define EESK 0x01 // EEPROM shift clock (1=high, 0=low)
+
+//- EEPROM opcodes
+#define EEPROM_READ_OPCODE 06
+#define EEPROM_WRITE_OPCODE 05
+#define EEPROM_ERASE_OPCODE 07
+#define EEPROM_EWEN_OPCODE 19 // Erase/write enable
+#define EEPROM_EWDS_OPCODE 16 // Erase/write disable
+
+//- EEPROM data locations
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_FLAGS_WORD_3 3
+#define EEPROM_FLAG_10MC BIT_0
+#define EEPROM_FLAG_100MC BIT_1
+
+//-------------------------------------------------------------------------
+// MDI Control register bit definitions
+//-------------------------------------------------------------------------
+#define MDI_DATA_MASK BIT_0_15 // MDI Data port
+#define MDI_REG_ADDR BIT_16_20 // which MDI register to read/write
+#define MDI_PHY_ADDR BIT_21_25 // which PHY to read/write
+#define MDI_PHY_OPCODE BIT_26_27 // which PHY to read/write
+#define MDI_PHY_READY BIT_28 // PHY is ready for another MDI cycle
+#define MDI_PHY_INT_ENABLE BIT_29 // Assert INT at MDI cycle completion
+
+
+//-------------------------------------------------------------------------
+// MDI Control register opcode definitions
+//-------------------------------------------------------------------------
+#define MDI_WRITE 1 // Phy Write
+#define MDI_READ 2 // Phy read
+
+
+//-------------------------------------------------------------------------
+// D100 Action Commands
+//-------------------------------------------------------------------------
+#define CB_NOP 0
+#define CB_IA_ADDRESS 1
+#define CB_CONFIGURE 2
+#define CB_MULTICAST 3
+#define CB_TRANSMIT 4
+#define CB_LOAD_MICROCODE 5
+#define CB_DUMP 6
+#define CB_DIAGNOSE 7
+
+
+//-------------------------------------------------------------------------
+// Command Block (CB) Field Definitions
+//-------------------------------------------------------------------------
+//- CB Command Word
+#define CB_EL_BIT BIT_15 // CB EL Bit
+#define CB_S_BIT BIT_14 // CB Suspend Bit
+#define CB_I_BIT BIT_13 // CB Interrupt Bit
+#define CB_TX_SF_BIT BIT_3 // TX CB Flexible Mode
+#define CB_CMD_MASK BIT_0_2 // CB 3-bit CMD Mask
+
+//- CB Status Word
+#define CB_STATUS_MASK BIT_12_15 // CB Status Mask (4-bits)
+#define CB_STATUS_COMPLETE BIT_15 // CB Complete Bit
+#define CB_STATUS_OK BIT_13 // CB OK Bit
+#define CB_STATUS_UNDERRUN BIT_12 // CB A Bit
+#define CB_STATUS_FAIL BIT_11 // CB Fail (F) Bit
+
+//misc command bits
+#define CB_TX_EOF_BIT BIT_15 // TX CB/TBD EOF Bit
+
+//-------------------------------------------------------------------------
+// Config CB Parameter Fields
+//-------------------------------------------------------------------------
+#define CB_CFIG_BYTE_COUNT 22 // 22 config bytes
+#define CB_SHORT_CFIG_BYTE_COUNT 8 // 8 config bytes
+
+// byte 0 bit definitions
+#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 // Byte count occupies bit 5-0
+
+// byte 1 bit definitions
+#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 // RxFifo limit mask
+#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 // TxFifo limit mask
+
+// byte 3 bit definitions --
+#define CB_CFIG_B3_MWI_ENABLE BIT_0 // Memory Write Invalidate Enable Bit
+
+// byte 4 bit definitions
+#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 // Rx minimum DMA count mask
+
+// byte 5 bit definitions
+#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 // Tx minimum DMA count mask
+#define CB_CFIG_DMBC_EN BIT_7 // Enable Tx/Rx minimum DMA counts
+
+// byte 6 bit definitions
+#define CB_CFIG_LATE_SCB BIT_0 // Update SCB After New Tx Start
+#define CB_CFIG_TNO_INT BIT_2 // Tx Not OK Interrupt
+#define CB_CFIG_CI_INT BIT_3 // Command Complete Interrupt
+#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 // Save Bad Frames Enabled
+
+// byte 7 bit definitions
+#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 // Discard Short Frames
+#define CB_CFIG_URUN_RETRY BIT_1_2 // Underrun Retry Count
+
+// byte 8 bit definitions
+#define CB_CFIG_503_MII BIT_0 // 503 vs. MII mode
+
+// byte 9 bit definitions -- pre-defined all zeros
+
+// byte 10 bit definitions
+#define CB_CFIG_NO_SRCADR BIT_3 // No Source Address Insertion
+#define CB_CFIG_PREAMBLE_LEN BIT_4_5 // Preamble Length
+#define CB_CFIG_LOOPBACK_MODE BIT_6_7 // Loopback Mode
+
+// byte 11 bit definitions
+#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 // Linear Priority
+
+// byte 12 bit definitions
+#define CB_CFIG_LINEAR_PRI_MODE BIT_0 // Linear Priority mode
+#define CB_CFIG_IFS_MASK BIT_4_7 // CSMA level Interframe Spacing mask
+
+// byte 13 bit definitions -- pre-defined all zeros
+
+// byte 14 bit definitions -- pre-defined 0xf2
+
+// byte 15 bit definitions
+#define CB_CFIG_PROMISCUOUS BIT_0 // Promiscuous Mode Enable
+#define CB_CFIG_BROADCAST_DIS BIT_1 // Broadcast Mode Disable
+#define CB_CFIG_CRS_OR_CDT BIT_7 // CRS Or CDT
+
+// byte 16 bit definitions -- pre-defined all zeros
+
+// byte 17 bit definitions -- pre-defined 0x40
+
+// byte 18 bit definitions
+#define CB_CFIG_STRIPPING BIT_0 // Stripping Disabled
+#define CB_CFIG_PADDING BIT_1 // Padding Disabled
+#define CB_CFIG_CRC_IN_MEM BIT_2 // Transfer CRC To Memory
+
+// byte 19 bit definitions
+#define CB_CFIG_FORCE_FDX BIT_6 // Force Full Duplex
+#define CB_CFIG_FDX_ENABLE BIT_7 // Full Duplex Enabled
+
+// byte 20 bit definitions
+#define CB_CFIG_MULTI_IA BIT_6 // Multiple IA Addr
+
+// byte 21 bit definitions
+#define CB_CFIG_MULTICAST_ALL BIT_3 // Multicast All
+
+
+//-------------------------------------------------------------------------
+// Receive Frame Descriptor Fields
+//-------------------------------------------------------------------------
+
+//- RFD Status Bits
+#define RFD_RECEIVE_COLLISION BIT_0 // Collision detected on Receive
+#define RFD_IA_MATCH BIT_1 // Indv Address Match Bit
+#define RFD_RX_ERR BIT_4 // RX_ERR pin on Phy was set
+#define RFD_FRAME_TOO_SHORT BIT_7 // Receive Frame Short
+#define RFD_DMA_OVERRUN BIT_8 // Receive DMA Overrun
+#define RFD_NO_RESOURCES BIT_9 // No Buffer Space
+#define RFD_ALIGNMENT_ERROR BIT_10 // Alignment Error
+#define RFD_CRC_ERROR BIT_11 // CRC Error
+#define RFD_STATUS_OK BIT_13 // RFD OK Bit
+#define RFD_STATUS_COMPLETE BIT_15 // RFD Complete Bit
+
+//- RFD Command Bits
+#define RFD_EL_BIT BIT_15 // RFD EL Bit
+#define RFD_S_BIT BIT_14 // RFD Suspend Bit
+#define RFD_H_BIT BIT_4 // Header RFD Bit
+#define RFD_SF_BIT BIT_3 // RFD Flexible Mode
+
+//- RFD misc bits
+#define RFD_EOF_BIT BIT_15 // RFD End-Of-Frame Bit
+#define RFD_F_BIT BIT_14 // RFD Buffer Fetch Bit
+#define RFD_ACT_COUNT_MASK BIT_0_13 // RFD Actual Count Mask
+#define RFD_HEADER_SIZE 0x10 // Size of RFD Header (16 bytes)
+
+//-------------------------------------------------------------------------
+// Receive Buffer Descriptor Fields
+//-------------------------------------------------------------------------
+#define RBD_EOF_BIT BIT_15 // RBD End-Of-Frame Bit
+#define RBD_F_BIT BIT_14 // RBD Buffer Fetch Bit
+#define RBD_ACT_COUNT_MASK BIT_0_13 // RBD Actual Count Mask
+
+#define SIZE_FIELD_MASK BIT_0_13 // Size of the associated buffer
+#define RBD_EL_BIT BIT_15 // RBD EL Bit
+
+
+//-------------------------------------------------------------------------
+// Size Of Dump Buffer
+//-------------------------------------------------------------------------
+#define DUMP_BUFFER_SIZE 600 // size of the dump buffer
+
+
+//-------------------------------------------------------------------------
+// Self Test Results
+//-------------------------------------------------------------------------
+#define CB_SELFTEST_FAIL_BIT BIT_12
+#define CB_SELFTEST_DIAG_BIT BIT_5
+#define CB_SELFTEST_REGISTER_BIT BIT_3
+#define CB_SELFTEST_ROM_BIT BIT_2
+
+#define CB_SELFTEST_ERROR_MASK ( \
+ CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \
+ CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT)
+
+
+//-------------------------------------------------------------------------
+// Driver Configuration Default Parameters for the 557
+// Note: If the driver uses any defaults that are different from the chip's
+// defaults, it will be noted below
+//-------------------------------------------------------------------------
+// Byte 0 (byte count) default
+#define CB_557_CFIG_DEFAULT_PARM0 CB_CFIG_BYTE_COUNT
+
+// Byte 1 (fifo limits) default
+#define DEFAULT_TX_FIFO_LIMIT 0x08
+#define DEFAULT_RX_FIFO_LIMIT 0x08
+#define CB_557_CFIG_DEFAULT_PARM1 0x88
+
+// Byte 2 (IFS) default
+#define CB_557_CFIG_DEFAULT_PARM2 0x00
+
+// Byte 3 (reserved) default
+#define CB_557_CFIG_DEFAULT_PARM3 0x00
+
+// Byte 4 (Rx DMA min count) default
+#define CB_557_CFIG_DEFAULT_PARM4 0x00
+
+// Byte 5 (Tx DMA min count, DMA min count enable) default
+#define CB_557_CFIG_DEFAULT_PARM5 0x00
+
+// Byte 6 (Late SCB, TNO int, CI int, Save bad frames) default
+#define CB_557_CFIG_DEFAULT_PARM6 0x32
+
+// Byte 7 (Discard short frames, underrun retry) default
+// note: disc short frames will be enabled
+#define DEFAULT_UNDERRUN_RETRY 0x01
+#define CB_557_CFIG_DEFAULT_PARM7 0x01
+
+// Byte 8 (MII or 503) default
+// note: MII will be the default
+#define CB_557_CFIG_DEFAULT_PARM8 0x01
+
+// Byte 9 - Power management for 82558B, 82559
+#define CB_WAKE_ON_LINK_BYTE9 0x20
+#define CB_WAKE_ON_ARP_PKT_BYTE9 0x40
+
+#define CB_557_CFIG_DEFAULT_PARM9 0
+
+// Byte 10 (scr addr insertion, preamble, loopback) default
+#define CB_557_CFIG_DEFAULT_PARM10 0x2e
+
+// Byte 11 (linear priority) default
+#define CB_557_CFIG_DEFAULT_PARM11 0x00
+
+// Byte 12 (IFS,linear priority mode) default
+#define CB_557_CFIG_DEFAULT_PARM12 0x60
+
+// Byte 13 (reserved) default
+#define CB_557_CFIG_DEFAULT_PARM13 0x00
+
+// Byte 14 (reserved) default
+#define CB_557_CFIG_DEFAULT_PARM14 0xf2
+
+// Byte 15 (promiscuous, broadcast, CRS/CDT) default
+#define CB_557_CFIG_DEFAULT_PARM15 0xea
+
+// Byte 16 (reserved) default
+#define CB_557_CFIG_DEFAULT_PARM16 0x00
+
+// Byte 17 (reserved) default
+#define CB_557_CFIG_DEFAULT_PARM17 0x40
+
+// Byte 18 (Stripping, padding, Rcv CRC in mem) default
+// note: padding will be enabled
+#define CB_557_CFIG_DEFAULT_PARM18 0xf2
+
+// Byte 19 (reserved) default
+// note: full duplex is enabled if FDX# pin is 0
+#define CB_557_CFIG_DEFAULT_PARM19 0x80
+
+// Byte 20 (multi-IA) default
+#define CB_557_CFIG_DEFAULT_PARM20 0x3f
+
+// Byte 21 (multicast all) default
+#define CB_557_CFIG_DEFAULT_PARM21 0x05
+
+
+#pragma pack(1)
+
+//-------------------------------------------------------------------------
+// Ethernet Frame Structure
+//-------------------------------------------------------------------------
+//- Ethernet 6-byte Address
+typedef struct _ETH_ADDRESS_STRUC {
+ UCHAR EthNodeAddress[ETHERNET_ADDRESS_LENGTH];
+} ETH_ADDRESS_STRUC, *PETH_ADDRESS_STRUC;
+
+
+//- Ethernet 14-byte Header
+typedef struct _ETH_HEADER_STRUC {
+ UCHAR Destination[ETHERNET_ADDRESS_LENGTH];
+ UCHAR Source[ETHERNET_ADDRESS_LENGTH];
+ USHORT TypeLength;
+} ETH_HEADER_STRUC, *PETH_HEADER_STRUC;
+
+
+//- Ethernet Buffer (Including Ethernet Header) for Transmits
+typedef struct _ETH_TX_BUFFER_STRUC {
+ ETH_HEADER_STRUC TxMacHeader;
+ UCHAR TxBufferData[(TCB_BUFFER_SIZE - sizeof(ETH_HEADER_STRUC))];
+} ETH_TX_BUFFER_STRUC, *PETH_TX_BUFFER_STRUC;
+
+typedef struct _ETH_RX_BUFFER_STRUC {
+ ETH_HEADER_STRUC RxMacHeader;
+ UCHAR RxBufferData[(RCB_BUFFER_SIZE - sizeof(ETH_HEADER_STRUC))];
+} ETH_RX_BUFFER_STRUC, *PETH_RX_BUFFER_STRUC;
+
+
+
+//-------------------------------------------------------------------------
+// 82557 Data Structures
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+// Self test
+//-------------------------------------------------------------------------
+typedef struct _SELF_TEST_STRUC {
+ ULONG StSignature; // Self Test Signature
+ ULONG StResults; // Self Test Results
+} SELF_TEST_STRUC, *PSELF_TEST_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Control/Status Registers (CSR)
+//-------------------------------------------------------------------------
+typedef struct _CSR_STRUC {
+ USHORT ScbStatus; // SCB Status register
+ UCHAR ScbCommandLow; // SCB Command register (low byte)
+ UCHAR ScbCommandHigh; // SCB Command register (high byte)
+ ULONG ScbGeneralPointer; // SCB General pointer
+ ULONG Port; // PORT register
+ USHORT FlashControl; // Flash Control register
+ USHORT EepromControl; // EEPROM control register
+ ULONG MDIControl; // MDI Control Register
+ ULONG RxDMAByteCount; // Receive DMA Byte count register
+} CSR_STRUC, *PCSR_STRUC;
+
+//-------------------------------------------------------------------------
+// Error Counters
+//-------------------------------------------------------------------------
+typedef struct _ERR_COUNT_STRUC {
+ ULONG XmtGoodFrames; // Good frames transmitted
+ ULONG XmtMaxCollisions; // Fatal frames -- had max collisions
+ ULONG XmtLateCollisions; // Fatal frames -- had a late coll.
+ ULONG XmtUnderruns; // Transmit underruns (fatal or re-transmit)
+ ULONG XmtLostCRS; // Frames transmitted without CRS
+ ULONG XmtDeferred; // Deferred transmits
+ ULONG XmtSingleCollision; // Transmits that had 1 and only 1 coll.
+ ULONG XmtMultCollisions; // Transmits that had multiple coll.
+ ULONG XmtTotalCollisions; // Transmits that had 1+ collisions.
+ ULONG RcvGoodFrames; // Good frames received
+ ULONG RcvCrcErrors; // Aligned frames that had a CRC error
+ ULONG RcvAlignmentErrors; // Receives that had alignment errors
+ ULONG RcvResourceErrors; // Good frame dropped due to lack of resources
+ ULONG RcvOverrunErrors; // Overrun errors - bus was busy
+ ULONG RcvCdtErrors; // Received frames that encountered coll.
+ ULONG RcvShortFrames; // Received frames that were to short
+ ULONG CommandComplete; // A005h indicates cmd completion
+} ERR_COUNT_STRUC, *PERR_COUNT_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Command Block (CB) Generic Header Structure
+//-------------------------------------------------------------------------
+typedef struct _CB_HEADER_STRUC {
+ USHORT CbStatus; // Command Block Status
+ USHORT CbCommand; // Command Block Command
+ ULONG CbLinkPointer; // Link To Next CB
+} CB_HEADER_STRUC, *PCB_HEADER_STRUC;
+
+
+//-------------------------------------------------------------------------
+// NOP Command Block (NOP_CB)
+//-------------------------------------------------------------------------
+typedef struct _NOP_CB_STRUC {
+ CB_HEADER_STRUC NopCBHeader;
+} NOP_CB_STRUC, *PNOP_CB_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Individual Address Command Block (IA_CB)
+//-------------------------------------------------------------------------
+typedef struct _IA_CB_STRUC {
+ CB_HEADER_STRUC IaCBHeader;
+ UCHAR IaAddress[ETHERNET_ADDRESS_LENGTH];
+} IA_CB_STRUC, *PIA_CB_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Configure Command Block (CONFIG_CB)
+//-------------------------------------------------------------------------
+typedef struct _CONFIG_CB_STRUC {
+ CB_HEADER_STRUC ConfigCBHeader;
+ UCHAR ConfigBytes[CB_CFIG_BYTE_COUNT];
+} CONFIG_CB_STRUC, *PCONFIG_CB_STRUC;
+
+
+//-------------------------------------------------------------------------
+// MultiCast Command Block (MULTICAST_CB)
+//-------------------------------------------------------------------------
+typedef struct _MULTICAST_CB_STRUC {
+ CB_HEADER_STRUC McCBHeader;
+ USHORT McCount; // Number of multicast addresses
+ UCHAR McAddress[(ETHERNET_ADDRESS_LENGTH * MAX_MULTICAST_ADDRESSES)];
+} MULTICAST_CB_STRUC, *PMULTICAST_CB_STRUC;
+
+//-------------------------------------------------------------------------
+// WakeUp Filter Command Block (FILTER_CB)
+//-------------------------------------------------------------------------
+typedef struct _FILTER_CB_STRUC {
+ CB_HEADER_STRUC FilterCBHeader;
+ ULONG Pattern[16];
+}FILTER_CB_STRUC , *PFILTER_CB_STRUC ;
+
+//-------------------------------------------------------------------------
+// Dump Command Block (DUMP_CB)
+//-------------------------------------------------------------------------
+typedef struct _DUMP_CB_STRUC {
+ CB_HEADER_STRUC DumpCBHeader;
+ ULONG DumpAreaAddress; // Dump Buffer Area Address
+} DUMP_CB_STRUC, *PDUMP_CB_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Dump Area structure definition
+//-------------------------------------------------------------------------
+typedef struct _DUMP_AREA_STRUC {
+ UCHAR DumpBuffer[DUMP_BUFFER_SIZE];
+} DUMP_AREA_STRUC, *PDUMP_AREA_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Diagnose Command Block (DIAGNOSE_CB)
+//-------------------------------------------------------------------------
+typedef struct _DIAGNOSE_CB_STRUC {
+ CB_HEADER_STRUC DiagCBHeader;
+} DIAGNOSE_CB_STRUC, *PDIAGNOSE_CB_STRUC;
+
+//-------------------------------------------------------------------------
+// Transmit Command Block (TxCB)
+//-------------------------------------------------------------------------
+typedef struct _GENERIC_TxCB {
+ CB_HEADER_STRUC TxCbHeader;
+ ULONG TxCbTbdPointer; // TBD address
+ USHORT TxCbCount; // Data Bytes In TCB past header
+ UCHAR TxCbThreshold; // TX Threshold for FIFO Extender
+ UCHAR TxCbTbdNumber;
+ ETH_TX_BUFFER_STRUC TxCbData;
+ ULONG pad0;
+ ULONG pad1;
+ ULONG pad2;
+ ULONG pad3;
+} TXCB_STRUC, *PTXCB_STRUC;
+
+//-------------------------------------------------------------------------
+// Transmit Buffer Descriptor (TBD)
+//-------------------------------------------------------------------------
+typedef struct _TBD_STRUC {
+ ULONG TbdBufferAddress; // Physical Transmit Buffer Address
+ unsigned TbdCount :14;
+ unsigned :1 ; // always 0
+ unsigned EndOfList:1 ; // EL bit in Tbd
+ unsigned :16; // field that is always 0's in a TBD
+} TBD_STRUC, *PTBD_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Receive Frame Descriptor (RFD)
+//-------------------------------------------------------------------------
+typedef struct _RFD_STRUC {
+ CB_HEADER_STRUC RfdCbHeader;
+ ULONG RfdRbdPointer; // Receive Buffer Descriptor Addr
+ USHORT RfdActualCount; // Number Of Bytes Received
+ USHORT RfdSize; // Number Of Bytes In RFD
+ ETH_RX_BUFFER_STRUC RfdBuffer; // Data buffer in RFD
+} RFD_STRUC, *PRFD_STRUC;
+
+
+//-------------------------------------------------------------------------
+// Receive Buffer Descriptor (RBD)
+//-------------------------------------------------------------------------
+typedef struct _RBD_STRUC {
+ USHORT RbdActualCount; // Number Of Bytes Received
+ USHORT RbdFiller;
+ ULONG RbdLinkAddress; // Link To Next RBD
+ ULONG RbdRcbAddress; // Receive Buffer Address
+ USHORT RbdSize; // Receive Buffer Size
+ USHORT RbdFiller1;
+} RBD_STRUC, *PRBD_STRUC;
+
+#pragma pack()
+
+//-------------------------------------------------------------------------
+// 82557 PCI Register Definitions
+// Refer To The PCI Specification For Detailed Explanations
+//-------------------------------------------------------------------------
+//- Register Offsets
+#define PCI_VENDOR_ID_REGISTER 0x00 // PCI Vendor ID Register
+#define PCI_DEVICE_ID_REGISTER 0x02 // PCI Device ID Register
+#define PCI_CONFIG_ID_REGISTER 0x00 // PCI Configuration ID Register
+#define PCI_COMMAND_REGISTER 0x04 // PCI Command Register
+#define PCI_STATUS_REGISTER 0x06 // PCI Status Register
+#define PCI_REV_ID_REGISTER 0x08 // PCI Revision ID Register
+#define PCI_CLASS_CODE_REGISTER 0x09 // PCI Class Code Register
+#define PCI_CACHE_LINE_REGISTER 0x0C // PCI Cache Line Register
+#define PCI_LATENCY_TIMER 0x0D // PCI Latency Timer Register
+#define PCI_HEADER_TYPE 0x0E // PCI Header Type Register
+#define PCI_BIST_REGISTER 0x0F // PCI Built-In SelfTest Register
+#define PCI_BAR_0_REGISTER 0x10 // PCI Base Address Register 0
+#define PCI_BAR_1_REGISTER 0x14 // PCI Base Address Register 1
+#define PCI_BAR_2_REGISTER 0x18 // PCI Base Address Register 2
+#define PCI_BAR_3_REGISTER 0x1C // PCI Base Address Register 3
+#define PCI_BAR_4_REGISTER 0x20 // PCI Base Address Register 4
+#define PCI_BAR_5_REGISTER 0x24 // PCI Base Address Register 5
+#define PCI_SUBVENDOR_ID_REGISTER 0x2C // PCI SubVendor ID Register
+#define PCI_SUBDEVICE_ID_REGISTER 0x2E // PCI SubDevice ID Register
+#define PCI_EXPANSION_ROM 0x30 // PCI Expansion ROM Base Register
+#define PCI_INTERRUPT_LINE 0x3C // PCI Interrupt Line Register
+#define PCI_INTERRUPT_PIN 0x3D // PCI Interrupt Pin Register
+#define PCI_MIN_GNT_REGISTER 0x3E // PCI Min-Gnt Register
+#define PCI_MAX_LAT_REGISTER 0x3F // PCI Max_Lat Register
+#define PCI_NODE_ADDR_REGISTER 0x40 // PCI Node Address Register
+
+
+//-------------------------------------------------------------------------
+// PHY 100 MDI Register/Bit Definitions
+//-------------------------------------------------------------------------
+// MDI register set
+#define MDI_CONTROL_REG 0x00 // MDI control register
+#define MDI_STATUS_REG 0x01 // MDI Status regiser
+#define PHY_ID_REG_1 0x02 // Phy indentification reg (word 1)
+#define PHY_ID_REG_2 0x03 // Phy indentification reg (word 2)
+#define AUTO_NEG_ADVERTISE_REG 0x04 // Auto-negotiation advertisement
+#define AUTO_NEG_LINK_PARTNER_REG 0x05 // Auto-negotiation link partner ability
+#define AUTO_NEG_EXPANSION_REG 0x06 // Auto-negotiation expansion
+#define AUTO_NEG_NEXT_PAGE_REG 0x07 // Auto-negotiation next page transmit
+#define EXTENDED_REG_0 0x10 // Extended reg 0 (Phy 100 modes)
+#define EXTENDED_REG_1 0x14 // Extended reg 1 (Phy 100 error indications)
+#define NSC_CONG_CONTROL_REG 0x17 // National (TX) congestion control
+#define NSC_SPEED_IND_REG 0x19 // National (TX) speed indication
+#define PHY_EQUALIZER_REG 0x1A // Register for the Phy Equalizer values
+
+// MDI Control register bit definitions
+#define MDI_CR_COLL_TEST_ENABLE BIT_7 // Collision test enable
+#define MDI_CR_FULL_HALF BIT_8 // FDX =1, half duplex =0
+#define MDI_CR_RESTART_AUTO_NEG BIT_9 // Restart auto negotiation
+#define MDI_CR_ISOLATE BIT_10 // Isolate PHY from MII
+#define MDI_CR_POWER_DOWN BIT_11 // Power down
+#define MDI_CR_AUTO_SELECT BIT_12 // Auto speed select enable
+#define MDI_CR_10_100 BIT_13 // 0 = 10Mbs, 1 = 100Mbs
+#define MDI_CR_LOOPBACK BIT_14 // 0 = normal, 1 = loopback
+#define MDI_CR_RESET BIT_15 // 0 = normal, 1 = PHY reset
+
+// MDI Status register bit definitions
+#define MDI_SR_EXT_REG_CAPABLE BIT_0 // Extended register capabilities
+#define MDI_SR_JABBER_DETECT BIT_1 // Jabber detected
+#define MDI_SR_LINK_STATUS BIT_2 // Link Status -- 1 = link
+#define MDI_SR_AUTO_SELECT_CAPABLE BIT_3 // Auto speed select capable
+#define MDI_SR_REMOTE_FAULT_DETECT BIT_4 // Remote fault detect
+#define MDI_SR_AUTO_NEG_COMPLETE BIT_5 // Auto negotiation complete
+#define MDI_SR_10T_HALF_DPX BIT_11 // 10BaseT Half Duplex capable
+#define MDI_SR_10T_FULL_DPX BIT_12 // 10BaseT full duplex capable
+#define MDI_SR_TX_HALF_DPX BIT_13 // TX Half Duplex capable
+#define MDI_SR_TX_FULL_DPX BIT_14 // TX full duplex capable
+#define MDI_SR_T4_CAPABLE BIT_15 // T4 capable
+
+// Auto-Negotiation advertisement register bit definitions
+#define NWAY_AD_SELCTOR_FIELD BIT_0_4 // identifies supported protocol
+#define NWAY_AD_ABILITY BIT_5_12 // technologies that are supported
+#define NWAY_AD_10T_HALF_DPX BIT_5 // 10BaseT Half Duplex capable
+#define NWAY_AD_10T_FULL_DPX BIT_6 // 10BaseT full duplex capable
+#define NWAY_AD_TX_HALF_DPX BIT_7 // TX Half Duplex capable
+#define NWAY_AD_TX_FULL_DPX BIT_8 // TX full duplex capable
+#define NWAY_AD_T4_CAPABLE BIT_9 // T4 capable
+#define NWAY_AD_REMOTE_FAULT BIT_13 // indicates local remote fault
+#define NWAY_AD_RESERVED BIT_14 // reserved
+#define NWAY_AD_NEXT_PAGE BIT_15 // Next page (not supported)
+
+// Auto-Negotiation link partner ability register bit definitions
+#define NWAY_LP_SELCTOR_FIELD BIT_0_4 // identifies supported protocol
+#define NWAY_LP_ABILITY BIT_5_9 // technologies that are supported
+#define NWAY_LP_REMOTE_FAULT BIT_13 // indicates partner remote fault
+#define NWAY_LP_ACKNOWLEDGE BIT_14 // acknowledge
+#define NWAY_LP_NEXT_PAGE BIT_15 // Next page (not supported)
+
+// Auto-Negotiation expansion register bit definitions
+#define NWAY_EX_LP_NWAY BIT_0 // link partner is NWAY
+#define NWAY_EX_PAGE_RECEIVED BIT_1 // link code word received
+#define NWAY_EX_NEXT_PAGE_ABLE BIT_2 // local is next page able
+#define NWAY_EX_LP_NEXT_PAGE_ABLE BIT_3 // partner is next page able
+#define NWAY_EX_PARALLEL_DET_FLT BIT_4 // parallel detection fault
+#define NWAY_EX_RESERVED BIT_5_15 // reserved
+
+
+// PHY 100 Extended Register 0 bit definitions
+#define PHY_100_ER0_FDX_INDIC BIT_0 // 1 = FDX, 0 = half duplex
+#define PHY_100_ER0_SPEED_INDIC BIT_1 // 1 = 100mbs, 0= 10mbs
+#define PHY_100_ER0_WAKE_UP BIT_2 // Wake up DAC
+#define PHY_100_ER0_RESERVED BIT_3_4 // Reserved
+#define PHY_100_ER0_REV_CNTRL BIT_5_7 // Revsion control (A step = 000)
+#define PHY_100_ER0_FORCE_FAIL BIT_8 // Force Fail is enabled
+#define PHY_100_ER0_TEST BIT_9_13 // Revsion control (A step = 000)
+#define PHY_100_ER0_LINKDIS BIT_14 // Link integrity test is disabled
+#define PHY_100_ER0_JABDIS BIT_15 // Jabber function is disabled
+
+
+// PHY 100 Extended Register 1 bit definitions
+#define PHY_100_ER1_RESERVED BIT_0_8 // Reserved
+#define PHY_100_ER1_CH2_DET_ERR BIT_9 // Channel 2 EOF detection error
+#define PHY_100_ER1_MANCH_CODE_ERR BIT_10 // Manchester code error
+#define PHY_100_ER1_EOP_ERR BIT_11 // EOP error
+#define PHY_100_ER1_BAD_CODE_ERR BIT_12 // bad code error
+#define PHY_100_ER1_INV_CODE_ERR BIT_13 // invalid code error
+#define PHY_100_ER1_DC_BAL_ERR BIT_14 // DC balance error
+#define PHY_100_ER1_PAIR_SKEW_ERR BIT_15 // Pair skew error
+
+// PHY TX Register/Bit definitions
+#define PHY_TX_STATUS_CTRL_REG 0x10
+#define PHY_TX_POLARITY_MASK BIT_8 // register 10h bit 8 (the polarity bit)
+#define PHY_TX_NORMAL_POLARITY 0 // register 10h bit 8 =0 (normal polarity)
+
+#define PHY_TX_SPECIAL_CTRL_REG 0x11
+#define AUTO_POLARITY_DISABLE BIT_4 // register 11h bit 4 (0=enable, 1=disable)
+
+#define PHY_TX_REG_18 0x18 // Error counter register
+// National Semiconductor TX phy congestion control register bit definitions
+#define NSC_TX_CONG_TXREADY BIT_10 // Makes TxReady an input
+#define NSC_TX_CONG_ENABLE BIT_8 // Enables congestion control
+#define NSC_TX_CONG_F_CONNECT BIT_5 // Enables congestion control
+
+// National Semiconductor TX phy speed indication register bit definitions
+#define NSC_TX_SPD_INDC_SPEED BIT_6 // 0 = 100mb, 1=10mb
+
+#endif // _E100_557_H
+
diff --git a/general/pcidrv/kmdf/HW/e100_equ.h b/general/pcidrv/kmdf/HW/e100_equ.h
new file mode 100644
index 00000000..c1e0bbde
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/e100_equ.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ e100_equ.h (equates.h)
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+#ifndef _E100_EQU_H
+#define _E100_EQU_H
+
+//-------------------------------------------------------------------------
+// OEM Message Tags
+//-------------------------------------------------------------------------
+#define stringTag 0xFEFA // Length Byte After String
+#define lStringTag 0xFEFB // Length Byte Before String
+#define zStringTag 0xFEFC // Zero-Terminated String Tag
+#define nStringTag 0xFEFD // No Length Byte Or 0-Term
+
+//-------------------------------------------------------------------------
+// Adapter Types Supported
+//-------------------------------------------------------------------------
+#define FLASH32_EISA (0 * 4)
+#define FLASH32_PCI (1 * 4)
+#define D29C_EISA (2 * 4)
+#define D29C_PCI (3 * 4)
+#define D100_PCI (4 * 4)
+
+//-------------------------------------------------------------------------
+// Phy related constants
+//-------------------------------------------------------------------------
+#define PHY_503 0
+#define PHY_100_A 0x000003E0
+#define PHY_100_C 0x035002A8
+#define PHY_TX_ID 0x015002A8
+#define PHY_NSC_TX 0x5c002000
+#define PHY_OTHER 0xFFFF
+
+#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF
+#define PARALLEL_DETECT 0
+#define N_WAY 1
+
+#define RENEGOTIATE_TIME 35 // (3.5 Seconds)
+
+#define CONNECTOR_AUTO 0
+#define CONNECTOR_TPE 1
+#define CONNECTOR_MII 2
+
+//-------------------------------------------------------------------------
+// Ethernet Frame Sizes
+//-------------------------------------------------------------------------
+#define ETHERNET_ADDRESS_LENGTH 6
+#define ETHERNET_HEADER_SIZE 14
+#define MINIMUM_ETHERNET_PACKET_SIZE 60
+#define MAXIMUM_ETHERNET_PACKET_SIZE 1514
+
+#define MAX_MULTICAST_ADDRESSES 32
+#define TCB_BUFFER_SIZE 0XE0 // 224
+#define COALESCE_BUFFER_SIZE 2048
+#define ETH_MAX_COPY_LENGTH 0x80 // 128
+
+// Make receive area 1536 for 16 bit alignment.
+//#define RCB_BUFFER_SIZE MAXIMUM_ETHERNET_PACKET_SIZE
+#define RCB_BUFFER_SIZE 1520 // 0x5F0
+
+//- Area reserved for all Non Transmit command blocks
+#define MAX_NON_TX_CB_AREA 512
+
+//-------------------------------------------------------------------------
+// Ndis/Adapter driver constants
+//-------------------------------------------------------------------------
+#define MAX_PHYS_DESC 16
+#define MAX_RECEIVE_DESCRIPTORS 1024 // 0x400
+#define NUM_RMD 10
+
+//--------------------------------------------------------------------------
+// System wide Equates
+//--------------------------------------------------------------------------
+#define MAX_NUMBER_OF_EISA_SLOTS 15
+#define MAX_NUMBER_OF_PCI_SLOTS 15
+
+//--------------------------------------------------------------------------
+// Equates Added for NDIS 4
+//--------------------------------------------------------------------------
+#define NUM_BYTES_PROTOCOL_RESERVED_SECTION 16
+#define MAX_NUM_ALLOCATED_RFDS 64
+#define MIN_NUM_RFD 4
+#define MAX_ARRAY_SEND_PACKETS 8
+// limit our receive routine to indicating this many at a time
+#define MAX_ARRAY_RECEIVE_PACKETS 16
+#define MAC_RESERVED_SWRFDPTR 0
+#define MAX_PACKETS_TO_ADD 32
+
+//-------------------------------------------------------------------------
+//- Miscellaneous Equates
+//-------------------------------------------------------------------------
+#define CR 0x0D // Carriage Return
+#define LF 0x0A // Line Feed
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#define DRIVER_NULL ((ULONG)0xffffffff)
+#define DRIVER_ZERO 0
+
+//-------------------------------------------------------------------------
+// Bit Mask definitions
+//-------------------------------------------------------------------------
+#define BIT_0 0x0001
+#define BIT_1 0x0002
+#define BIT_2 0x0004
+#define BIT_3 0x0008
+#define BIT_4 0x0010
+#define BIT_5 0x0020
+#define BIT_6 0x0040
+#define BIT_7 0x0080
+#define BIT_8 0x0100
+#define BIT_9 0x0200
+#define BIT_10 0x0400
+#define BIT_11 0x0800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_24 0x01000000
+#define BIT_28 0x10000000
+
+#define BIT_0_2 0x0007
+#define BIT_0_3 0x000F
+#define BIT_0_4 0x001F
+#define BIT_0_5 0x003F
+#define BIT_0_6 0x007F
+#define BIT_0_7 0x00FF
+#define BIT_0_8 0x01FF
+#define BIT_0_13 0x3FFF
+#define BIT_0_15 0xFFFF
+#define BIT_1_2 0x0006
+#define BIT_1_3 0x000E
+#define BIT_2_5 0x003C
+#define BIT_3_4 0x0018
+#define BIT_4_5 0x0030
+#define BIT_4_6 0x0070
+#define BIT_4_7 0x00F0
+#define BIT_5_7 0x00E0
+#define BIT_5_9 0x03E0
+#define BIT_5_12 0x1FE0
+#define BIT_5_15 0xFFE0
+#define BIT_6_7 0x00c0
+#define BIT_7_11 0x0F80
+#define BIT_8_10 0x0700
+#define BIT_9_13 0x3E00
+#define BIT_12_15 0xF000
+#define BIT_8_15 0xFF00
+
+#define BIT_16_20 0x001F0000
+#define BIT_21_25 0x03E00000
+#define BIT_26_27 0x0C000000
+
+// in order to make our custom oids hopefully somewhat unique
+// we will use 0xFF (indicating implementation specific OID)
+// A0 (first byte of non zero intel unique identifier)
+// C9 (second byte of non zero intel unique identifier)
+// XX (the custom OID number - providing 255 possible custom oids)
+#define OID_CUSTOM_DRIVER_SET 0xFFA0C901
+#define OID_CUSTOM_DRIVER_QUERY 0xFFA0C902
+#define OID_CUSTOM_ARRAY 0xFFA0C903
+#define OID_CUSTOM_STRING 0xFFA0C904
+
+#define CMD_BUS_MASTER BIT_2
+
+#endif // _E100_EQU_H
+
diff --git a/general/pcidrv/kmdf/HW/eeprom.c b/general/pcidrv/kmdf/HW/eeprom.c
new file mode 100644
index 00000000..42354f38
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/eeprom.c
@@ -0,0 +1,306 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ eeprom.c
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+#include "precomp.h"
+
+#define EEPROM_MAX_SIZE 256
+
+//*****************************************************************************
+//
+// I/O based Read EEPROM Routines
+//
+//*****************************************************************************
+
+//-----------------------------------------------------------------------------
+// Procedure: EEpromAddressSize
+//
+// Description: determines the number of bits in an address for the eeprom
+// acceptable values are 64, 128, and 256
+//
+// Arguments:
+// Size -- size of the eeprom
+//
+// Returns:
+// bits in an address for that size eeprom
+//-----------------------------------------------------------------------------
+
+USHORT GetEEpromAddressSize(
+ IN USHORT Size)
+{
+ switch (Size)
+ {
+ case 64: return 6;
+ case 128: return 7;
+ case 256: return 8;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: GetEEpromSize
+//
+// Description: This routine determines the size of the EEPROM.
+//
+// Arguments:
+// Reg - EEPROM word to read.
+//
+// Returns:
+// Size of the EEPROM, or zero if TRACE_LEVEL_ERROR.
+//-----------------------------------------------------------------------------
+
+USHORT GetEEpromSize(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ USHORT x, data;
+ USHORT size = 1;
+
+ // select EEPROM, reset bits, set EECS
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~(EEDI | EEDO | EESK);
+ x |= EECS;
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+
+ // write the read opcode
+ ShiftOutBits(FdoData, EEPROM_READ_OPCODE, 3, CSRBaseIoAddress);
+
+ // experiment to discover the size of the eeprom. request register zero
+ // and wait for the eeprom to tell us it has accepted the entire address.
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+ do
+ {
+ size *= 2; // each bit of address doubles eeprom size
+ x |= EEDO; // set bit to detect "dummy zero"
+ x &= ~EEDI; // address consists of all zeros
+
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+ KeStallExecutionProcessor(100);
+ RaiseClock(FdoData, &x, CSRBaseIoAddress);
+ LowerClock(FdoData, &x, CSRBaseIoAddress);
+
+ // check for "dummy zero"
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+ if (size > EEPROM_MAX_SIZE)
+ {
+ size = 0;
+ break;
+ }
+ }
+ while (x & EEDO);
+
+ // Now read the data (16 bits) in from the selected EEPROM word
+ data = ShiftInBits(FdoData, CSRBaseIoAddress);
+
+ EEpromCleanup(FdoData, CSRBaseIoAddress);
+
+ return size;
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: ReadEEprom
+//
+// Description: This routine serially reads one word out of the EEPROM.
+//
+// Arguments:
+// Reg - EEPROM word to read.
+//
+// Returns:
+// Contents of EEPROM word (Reg).
+//-----------------------------------------------------------------------------
+
+USHORT ReadEEprom(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress,
+ IN USHORT Reg,
+ IN USHORT AddressSize)
+{
+ USHORT x;
+ USHORT data;
+
+ // select EEPROM, reset bits, set EECS
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~(EEDI | EEDO | EESK);
+ x |= EECS;
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+
+ // write the read opcode and register number in that order
+ // The opcode is 3bits in length, reg is 6 bits long
+ ShiftOutBits(FdoData, EEPROM_READ_OPCODE, 3, CSRBaseIoAddress);
+ ShiftOutBits(FdoData, Reg, AddressSize, CSRBaseIoAddress);
+
+ // Now read the data (16 bits) in from the selected EEPROM word
+ data = ShiftInBits(FdoData, CSRBaseIoAddress);
+
+ EEpromCleanup(FdoData, CSRBaseIoAddress);
+ return data;
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: ShiftOutBits
+//
+// Description: This routine shifts data bits out to the EEPROM.
+//
+// Arguments:
+// data - data to send to the EEPROM.
+// count - number of data bits to shift out.
+//
+// Returns: (none)
+//-----------------------------------------------------------------------------
+
+VOID ShiftOutBits(
+ IN PFDO_DATA FdoData,
+ IN USHORT data,
+ IN USHORT count,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ USHORT x,mask;
+
+ mask = 0x01 << (count - 1);
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~(EEDO | EEDI);
+
+ do
+ {
+ x &= ~EEDI;
+ if(data & mask)
+ x |= EEDI;
+
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+ KeStallExecutionProcessor(100);
+ RaiseClock(FdoData, &x, CSRBaseIoAddress);
+ LowerClock(FdoData, &x, CSRBaseIoAddress);
+ mask = mask >> 1;
+ } while(mask);
+
+ x &= ~EEDI;
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: ShiftInBits
+//
+// Description: This routine shifts data bits in from the EEPROM.
+//
+// Arguments:
+//
+// Returns:
+// The contents of that particular EEPROM word
+//-----------------------------------------------------------------------------
+
+USHORT ShiftInBits(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ USHORT x,d,i;
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~( EEDO | EEDI);
+ d = 0;
+
+ for(i=0; i<16; i++)
+ {
+ d = d << 1;
+ RaiseClock(FdoData, &x, CSRBaseIoAddress);
+
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~(EEDI);
+ if(x & EEDO)
+ d |= 1;
+
+ LowerClock(FdoData, &x, CSRBaseIoAddress);
+ }
+
+ return d;
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: RaiseClock
+//
+// Description: This routine raises the EEPOM's clock input (EESK)
+//
+// Arguments:
+// x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//-----------------------------------------------------------------------------
+
+VOID RaiseClock(
+ IN PFDO_DATA FdoData,
+ IN OUT USHORT *x,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ *x = *x | EESK;
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x);
+ KeStallExecutionProcessor(100);
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: LowerClock
+//
+// Description: This routine lower's the EEPOM's clock input (EESK)
+//
+// Arguments:
+// x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//-----------------------------------------------------------------------------
+
+VOID LowerClock(
+ IN PFDO_DATA FdoData,
+ IN OUT USHORT *x,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ *x = *x & ~EESK;
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x);
+ KeStallExecutionProcessor(100);
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: EEpromCleanup
+//
+// Description: This routine returns the EEPROM to an idle state
+//
+// Arguments:
+//
+// Returns: (none)
+//-----------------------------------------------------------------------------
+
+VOID EEpromCleanup(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress)
+{
+ USHORT x;
+ x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
+
+ x &= ~(EECS | EEDI);
+ FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
+
+ RaiseClock(FdoData, &x, CSRBaseIoAddress);
+ LowerClock(FdoData, &x, CSRBaseIoAddress);
+}
+
+
diff --git a/general/pcidrv/kmdf/HW/isrdpc.c b/general/pcidrv/kmdf/HW/isrdpc.c
new file mode 100644
index 00000000..ebc2a3a6
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/isrdpc.c
@@ -0,0 +1,904 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ ISRDPC.C
+
+Abstract:
+
+ Contains routine to handle interrupts, interrupt DPCs and WatchDogTimer DPC
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "ISRDPC.tmh"
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, NICEvtDeviceD0ExitPreInterruptsDisabled)
+#endif
+
+
+BOOLEAN
+NICEvtInterruptIsr(
+ IN WDFINTERRUPT Interrupt,
+ IN ULONG MessageID
+ )
+/*++
+Routine Description:
+
+ Interrupt handler for the device.
+
+Arguments:
+
+ Interupt - Address of the framework interrupt object
+ MessageID -
+
+Return Value:
+
+ TRUE if our device is interrupting, FALSE otherwise.
+
+--*/
+{
+ BOOLEAN InterruptRecognized = FALSE;
+ PFDO_DATA FdoData = NULL;
+ USHORT IntStatus;
+
+ UNREFERENCED_PARAMETER( MessageID );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> NICEvtInterruptIsr\n");
+
+ FdoData = FdoGetData(WdfInterruptGetDevice(Interrupt));
+
+ //
+ // We process the interrupt if it's not disabled and it's active
+ //
+ if (!NIC_INTERRUPT_DISABLED(FdoData) && NIC_INTERRUPT_ACTIVE(FdoData))
+ {
+ InterruptRecognized = TRUE;
+
+ //
+ // Disable the interrupt (will be re-enabled in NICEvtInterruptDpc
+ //
+ NICDisableInterrupt(FdoData);
+
+ //
+ // Acknowledge the interrupt(s) and get the interrupt status
+ //
+
+ NIC_ACK_INTERRUPT(FdoData, IntStatus);
+
+ WdfInterruptQueueDpcForIsr( Interrupt );
+
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- NICEvtInterruptIsr\n");
+
+ return InterruptRecognized;
+}
+
+VOID
+NICEvtInterruptDpc(
+ IN WDFINTERRUPT WdfInterrupt,
+ IN WDFOBJECT WdfDevice
+ )
+
+/*++
+
+Routine Description:
+
+ DPC callback for ISR.
+
+Arguments:
+
+ WdfInterrupt - Handle to the framework interrupt object
+
+ WdfDevice - Associated device object.
+
+Return Value:
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> NICEvtInterruptDpc\n");
+
+ fdoData = FdoGetData(WdfDevice);
+
+
+ WdfSpinLockAcquire(fdoData->RcvLock);
+
+ NICHandleRecvInterrupt(fdoData);
+
+
+ WdfSpinLockRelease(fdoData->RcvLock);
+
+ //
+ // Handle send interrupt
+ //
+
+ WdfSpinLockAcquire(fdoData->SendLock);
+
+ NICHandleSendInterrupt(fdoData);
+
+
+ WdfSpinLockRelease(fdoData->SendLock);
+
+ //
+ // Check if any queued Sends need to be reprocessed.
+ //
+ NICCheckForQueuedSends(fdoData);
+
+ //
+ // Start the receive unit if it had stopped
+ //
+
+ WdfSpinLockAcquire(fdoData->RcvLock);
+
+ NICStartRecv(fdoData);
+
+
+ WdfSpinLockRelease(fdoData->RcvLock);
+
+ //
+ // Re-enable the interrupt (disabled in MPIsr)
+ //
+ WdfInterruptSynchronize(
+ WdfInterrupt,
+ NICEnableInterrupt,
+ fdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- NICEvtInterruptDpc\n");
+
+}
+
+NTSTATUS
+NICEvtInterruptEnable(
+ IN WDFINTERRUPT Interrupt,
+ IN WDFDEVICE AssociatedDevice
+ )
+/*++
+
+Routine Description:
+
+ This event is called when the Framework moves the device to D0, and after
+ EvtDeviceD0Entry. The driver should enable its interrupt here.
+
+ This function will be called at the device's assigned interrupt
+ IRQL (DIRQL.)
+
+Arguments:
+
+ Interrupt - Handle to a Framework interrupt object.
+
+ AssociatedDevice - Handle to a Framework device object.
+
+Return Value:
+
+ BOOLEAN - TRUE indicates that the interrupt was successfully enabled.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtInterruptEnable\n");
+
+ fdoData = FdoGetData(AssociatedDevice);
+ NICEnableInterrupt(Interrupt, fdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtInterruptEnable\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NICEvtInterruptDisable(
+ IN WDFINTERRUPT Interrupt,
+ IN WDFDEVICE AssociatedDevice
+ )
+/*++
+
+Routine Description:
+
+ This event is called before the Framework moves the device to D1, D2 or D3
+ and before EvtDeviceD0Exit. The driver should disable its interrupt here.
+
+ This function will be called at the device's assigned interrupt
+ IRQL (DIRQL.)
+
+Arguments:
+
+ Interrupt - Handle to a Framework interrupt object.
+
+ AssociatedDevice - Handle to a Framework device object.
+
+Return Value:
+
+ STATUS_SUCCESS - indicates success.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER(Interrupt);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtInterruptDisable\n");
+
+ fdoData = FdoGetData(AssociatedDevice);
+ NICDisableInterrupt(fdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtInterruptDisable\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NICEvtDeviceD0EntryPostInterruptsEnabled(
+ IN WDFDEVICE Device,
+ IN WDF_POWER_DEVICE_STATE PreviousState
+ )
+/*++
+
+Routine Description:
+
+ This event is called so that driver can do PASSIVE_LEVEL work after
+ the interrupt is connected and enabled. Here we start the watchdog timer.
+ Watch dog timer is used to do the initial link detection during
+ start and then used to make sure the device is not stuck for any reason.
+
+ This function is not marked pageable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+Arguments:
+
+ Interrupt - Handle to a Framework interrupt object.
+
+ AssociatedDevice - Handle to a Framework device object.
+
+Return Value:
+
+ STATUS_SUCCESS - indicates success.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER( PreviousState );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtDeviceD0EntryPostInterruptsEnabled\n");
+
+ fdoData = FdoGetData(Device);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtDeviceD0EntryPostInterruptsEnabled\n");
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS
+NICEvtDeviceD0ExitPreInterruptsDisabled(
+ IN WDFDEVICE Device,
+ IN WDF_POWER_DEVICE_STATE TargetState
+ )
+/*++
+
+Routine Description:
+
+ This event is called so that driver can do PASSIVE_LEVEL work before
+ the interrupt is disconnected and disabled.
+
+Arguments:
+
+ Interrupt - Handle to a Framework interrupt object.
+
+ AssociatedDevice - Handle to a Framework device object.
+
+Return Value:
+
+ STATUS_SUCCESS - indicates success.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER(TargetState);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtDeviceD0ExitPreInterruptsDisabled\n");
+
+ fdoData = FdoGetData(Device);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtDeviceD0ExitPreInterruptsDisabled\n");
+
+ return STATUS_SUCCESS;
+
+}
+
+VOID
+NICStartWatchDogTimer(
+ IN PFDO_DATA FdoData
+ )
+{
+ LARGE_INTEGER dueTime;
+
+ if(!FdoData->CheckForHang){
+
+ //
+ // Set the link detection flag to indicate that NICWatchDogEvtTimerFunc
+ // is first doing link-detection.
+ //
+ MP_SET_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION);
+ FdoData->CheckForHang = FALSE;
+ FdoData->bLinkDetectionWait = FALSE;
+ FdoData->bLookForLink = FALSE;
+ dueTime.QuadPart = NIC_LINK_DETECTION_DELAY;
+
+ } else {
+ dueTime.QuadPart = NIC_CHECK_FOR_HANG_DELAY;
+ }
+
+ WdfTimerStart(FdoData->WatchDogTimer,
+ dueTime.QuadPart
+ );
+
+}
+
+VOID
+NICWatchDogEvtTimerFunc(
+ IN WDFTIMER Timer
+ )
+/*++
+
+Routine Description:
+
+ This DPC is used to do both link detection during hardware init and
+ after that for hardware hang detection.
+
+Arguments:
+
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFDO_DATA FdoData = NULL;
+ LARGE_INTEGER DueTime;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FdoData = FdoGetData(WdfTimerGetParentObject(Timer));
+
+ DueTime.QuadPart = NIC_CHECK_FOR_HANG_DELAY;
+
+
+ if(!FdoData->CheckForHang){
+ //
+ // We are still doing link detection
+ //
+ status = NICLinkDetection(FdoData);
+ if(status == STATUS_PENDING) {
+ // Wait for 100 ms
+ FdoData->bLinkDetectionWait = TRUE;
+ DueTime.QuadPart = NIC_LINK_DETECTION_DELAY;
+ }else {
+ FdoData->CheckForHang = TRUE;
+ }
+ }else {
+ //
+ // Link detection is over, let us check to see
+ // if the hardware is stuck.
+ //
+ if(NICCheckForHang(FdoData)){
+
+ status = NICReset(FdoData);
+ if(!NT_SUCCESS(status)){
+ goto Exit;
+ }
+ }
+ }
+
+ WdfTimerStart(FdoData->WatchDogTimer, // Timer
+ DueTime.QuadPart // DueTime
+ );
+
+ return;
+
+Exit:
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "WatchDogTimer is exiting %x\n", status);
+ return;
+
+}
+
+BOOLEAN
+NICCheckForHang(
+ IN PFDO_DATA FdoData
+ )
+/*++
+
+Routine Description:
+
+ CheckForHang handler is called in the context of a timer DPC.
+ take advantage of this fact when acquiring/releasing spinlocks
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ TRUE This NIC needs a reset
+ FALSE Everything is fine
+
+--*/
+{
+ PMP_TCB pMpTcb;
+
+ //
+ // Just skip this part if the adapter is doing link detection
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION))
+ {
+ return(FALSE);
+ }
+
+ //
+ // any nonrecoverable hardware error?
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_NON_RECOVER_ERROR))
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Non recoverable error - remove\n");
+ return (TRUE);
+ }
+
+ //
+ // hardware failure?
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR))
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "hardware error - reset\n");
+ return(TRUE);
+ }
+
+ //
+ // Is send stuck?
+ //
+
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+
+ if (FdoData->nBusySend > 0)
+ {
+ pMpTcb = FdoData->CurrSendHead;
+ pMpTcb->Count++;
+ if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD)
+ {
+
+ WdfSpinLockRelease(FdoData->SendLock);
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Send is stuck - reset\n");
+ return(TRUE);
+ }
+ }
+
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ //
+ // Update the RFD shrink count
+ //
+ if (FdoData->CurrNumRfd > FdoData->NumRfd)
+ {
+ FdoData->RfdShrinkCount++;
+ }
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ NICIndicateMediaState(FdoData);
+
+ return(FALSE);
+}
+
+NTSTATUS
+NICReset(
+ IN PFDO_DATA FdoData
+ )
+/*++
+
+Routine Description:
+
+ Function to reset the device.
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+
+Return Value:
+
+ NT Status code.
+
+Note:
+ NICReset is called at DPC. Take advantage of this fact
+ when acquiring or releasing spinlocks
+
+--*/
+{
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "---> MPReset\n");
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ do
+ {
+ //
+ // Is this adapter already doing a reset?
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS))
+ {
+ status = STATUS_SUCCESS;
+ goto exit;
+ }
+
+ MP_SET_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS);
+
+ //
+ // Is this adapter doing link detection?
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION))
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Reset is pended...\n");
+ status = STATUS_SUCCESS;
+ goto exit;
+ }
+ //
+ // Is this adapter going to be removed
+ //
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_NON_RECOVER_ERROR))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS))
+ {
+ goto exit;
+ }
+
+ // This is an unrecoverable hardware failure.
+ // We need to tell NDIS to remove this miniport
+ MP_SET_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS);
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS);
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ // TODO: Log an entry into the eventlog
+ WdfDeviceSetFailed(FdoData->WdfDevice, WdfDeviceFailedAttemptRestart);
+
+ TraceEvents(TRACE_LEVEL_FATAL, DBG_DPC, "<--- MPReset, status=%x\n", status);
+
+ return status;
+ }
+
+
+ //
+ // Disable the interrupt and issue a reset to the NIC
+ //
+ NICDisableInterrupt(FdoData);
+ NICIssueSelectiveReset(FdoData);
+
+
+ //
+ // Release all the locks and then acquire back the send lock
+ // we are going to clean up the send queues
+ // which may involve calling Ndis APIs
+ // release all the locks before grabbing the send lock to
+ // avoid deadlocks
+ //
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+
+ //
+ // Free the packets on SendQueueList
+ //
+ NICFreeQueuedSendPackets(FdoData);
+
+ //
+ // Free the packets being actively sent & stopped
+ //
+ NICFreeBusySendPackets(FdoData);
+
+
+ RtlZeroMemory(FdoData->MpTcbMem, FdoData->MpTcbMemSize);
+
+ //
+ // Re-initialize the send structures
+ //
+ NICInitSendBuffers(FdoData);
+
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ //
+ // get all the locks again in the right order
+ //
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ //
+ // Reset the RFD list and re-start RU
+ //
+ NICResetRecv(FdoData);
+ status = NICStartRecv(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ // Are we having failures in a few consecutive resets?
+ if (FdoData->HwErrCount < NIC_HARDWARE_ERROR_THRESHOLD)
+ {
+ // It's not over the threshold yet, let it to continue
+ FdoData->HwErrCount++;
+ }
+ else
+ {
+ // This is an unrecoverable hardware failure.
+ // We need to tell NDIS to remove this miniport
+ MP_SET_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS);
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS);
+
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ // TODO: Log an entry into the eventlog
+ //
+ // Tell the system that the device has failed.
+ //
+ WdfDeviceSetFailed(FdoData->WdfDevice, WdfDeviceFailedAttemptRestart);
+
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_DPC, "<--- MPReset, status=%x\n", status);
+ return(status);
+ }
+
+ break;
+ }
+
+ FdoData->HwErrCount = 0;
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR);
+
+ NICEnableInterrupt(FdoData->WdfInterrupt, FdoData);
+
+ } WHILE (FALSE);
+
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS);
+
+ exit:
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<--- MPReset, status=%x\n", status);
+ return(status);
+}
+
+
+NTSTATUS
+NICLinkDetection(
+ PFDO_DATA FdoData
+ )
+/*++
+
+Routine Description:
+
+ Timer function for postponed link negotiation. Called from
+ the NICWatchDogEvtTimerFunc. After the link detection is over
+ we will complete any pending ioctl or send IRPs.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ NT status
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ MEDIA_STATE CurrMediaState;
+ PNDISPROT_QUERY_OID pQuery = NULL;
+ PNDISPROT_SET_OID pSet = NULL;
+ PVOID DataBuffer;
+ ULONG BytesWritten;
+ NDIS_OID Oid;
+ PVOID InformationBuffer;
+ size_t bufSize;
+ WDFREQUEST request;
+
+ //
+ // Handle the link negotiation.
+ //
+ if (FdoData->bLinkDetectionWait)
+ {
+ status = ScanAndSetupPhy(FdoData);
+ }
+ else
+ {
+ status = PhyDetect(FdoData);
+ }
+
+ if (status == STATUS_PENDING)
+ {
+ return status;
+ }
+
+ //
+ // Reset some variables for link detection
+ //
+ FdoData->bLinkDetectionWait = FALSE;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "NICLinkDetection - negotiation done\n");
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ //
+ // Any OID query request pending?
+ //
+
+ status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
+ IOCTL_NDISPROT_QUERY_OID_VALUE,
+ &request);
+
+ if(NT_SUCCESS(status)) {
+ status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_QUERY_OID), &DataBuffer, &bufSize);
+ if(NT_SUCCESS(status)) {
+
+ pQuery = (PNDISPROT_QUERY_OID)DataBuffer;
+ Oid = pQuery->Oid;
+ InformationBuffer = &pQuery->Data[0];
+ switch(Oid)
+ {
+ case OID_GEN_LINK_SPEED:
+ *((PULONG)InformationBuffer) = FdoData->usLinkSpeed * 10000;
+ BytesWritten = sizeof(ULONG);
+
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ default:
+ ASSERT(Oid == OID_GEN_MEDIA_CONNECT_STATUS);
+
+ CurrMediaState = NICIndicateMediaState(FdoData);
+
+ RtlMoveMemory(InformationBuffer,
+ &CurrMediaState,
+ sizeof(NDIS_MEDIA_STATE));
+
+ BytesWritten = sizeof(NDIS_MEDIA_STATE);
+ }
+
+ WdfRequestCompleteWithInformation(request, status, BytesWritten);
+ }
+ }
+
+ //
+ // Any OID set request pending?
+ //
+ status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
+ IOCTL_NDISPROT_SET_OID_VALUE,
+ &request);
+
+ if(NT_SUCCESS(status)) {
+ ULONG PacketFilter;
+
+ status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_SET_OID), &DataBuffer, &bufSize);
+ if(NT_SUCCESS(status)) {
+
+ pSet = (PNDISPROT_SET_OID)DataBuffer;
+ Oid = pSet->Oid;
+ InformationBuffer = &pSet->Data[0];
+ if (Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ {
+
+ RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ status = NICSetPacketFilter(
+ FdoData,
+ PacketFilter);
+
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ if (status == STATUS_SUCCESS)
+ {
+ FdoData->PacketFilter = PacketFilter;
+ }
+
+ WdfRequestCompleteWithInformation(request, status, 0);
+ }
+ }
+ }
+
+ //
+ // Any read pending?
+ //
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ //
+ // Start the NIC receive unit
+ //
+ status = NICStartRecv(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ MP_SET_HARDWARE_ERROR(FdoData);
+ }
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ //
+ // Send packets which have been queued while link detection was going on.
+ //
+ NICCheckForQueuedSends(FdoData);
+
+ return status;
+}
+
+
diff --git a/general/pcidrv/kmdf/HW/localwpp.ini b/general/pcidrv/kmdf/HW/localwpp.ini
new file mode 100644
index 00000000..c290070a
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/localwpp.ini
@@ -0,0 +1,17 @@
+//
+// This defines how to log a len/buffer pair.
+// This function should be in trace.h
+//
+
+DEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, xstr_t, ItemHEXDump,"s", _HEX_, 0,2);
+
+// DEFINE_CPLX_TYPE(
+// name, // i.e. HEXDUMP // %!HEXDUMP!
+// macro, // i.e. WPP_LOGHEXDUMP // Marshalling macro, defined in trace.h
+// structure, // i.e. xstr_t // Argument type (structure to be created by above macro)
+// item type, // i.e. ItemHEXDump // MOF type that TracePrt can understand
+// format specifier, // i.e. "s" // a format specifier that TracePrt can understand
+// ???? // i.e. _HEX_ // Type signature (becomes a part of function name)
+// ???? // i.e. 0 // Weight (0 is variable data length)
+// ???? // i.e. 2 // Slots used by this entry (optional, 1 default)
+// )
diff --git a/general/pcidrv/kmdf/HW/macros.h b/general/pcidrv/kmdf/HW/macros.h
new file mode 100644
index 00000000..61ed01d6
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/macros.h
@@ -0,0 +1,312 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ macros.h (inlinef.h)
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+__inline BOOLEAN
+WaitScb(
+ IN PFDO_DATA FdoData
+ );
+
+
+//-----------------------------------------------------------------------------
+// Procedure: D100IssueScbCommand
+//
+// Description: This general routine will issue a command to the D100.
+//
+// Arguments:
+// FdoData - ptr to FdoData object instance.
+// ScbCommand - The command that is to be issued
+// WaitForSCB - A boolean value indicating whether or not a wait for SCB
+// must be done before the command is issued to the chip
+//
+// Returns:
+// TRUE if the command was issued to the chip successfully
+// FALSE if the command was not issued to the chip
+//-----------------------------------------------------------------------------
+__inline NTSTATUS
+D100IssueScbCommand(
+ IN PFDO_DATA FdoData,
+ IN UCHAR ScbCommandLow,
+ IN BOOLEAN WaitForScb
+ )
+{
+ if(WaitForScb == TRUE)
+ {
+ if(!WaitScb(FdoData))
+ {
+ return(STATUS_DEVICE_DATA_ERROR);
+ }
+ }
+
+ FdoData->CSRAddress->ScbCommandLow = ScbCommandLow;
+
+ return(STATUS_SUCCESS);
+}
+
+
+__inline NTSTATUS
+MP_GET_STATUS_FROM_FLAGS(
+ IN PFDO_DATA FdoData
+ )
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS))
+ {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+ else if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR))
+ {
+ Status = STATUS_DEVICE_OFF_LINE;
+ }
+ else if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_NO_CABLE))
+ {
+ Status = STATUS_DEVICE_NOT_CONNECTED;
+ }
+
+ return Status;
+}
+
+__inline VOID
+NICDisableInterrupt(
+ IN PFDO_DATA FdoData
+ )
+{
+ FdoData->CSRAddress->ScbCommandHigh = SCB_INT_MASK;
+}
+
+EVT_WDF_INTERRUPT_SYNCHRONIZE NICEnableInterrupt;
+
+__inline BOOLEAN NICEnableInterrupt(
+ IN WDFINTERRUPT WdfInterrupt,
+ IN WDFCONTEXT Context
+ )
+{
+ PFDO_DATA FdoData = (PFDO_DATA)Context;
+
+ UNREFERENCED_PARAMETER(WdfInterrupt);
+
+ FdoData->CSRAddress->ScbCommandHigh = 0;
+
+ return TRUE;
+}
+
+__inline
+BOOLEAN
+IsPoMgmtSupported(
+ IN PFDO_DATA FdoData
+ )
+{
+
+ if (FdoData->RevsionID >= E100_82559_A_STEP
+ /*&& FdoData->RevsionID <= E100_82559_C_STEP*/)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+}
+
+__inline
+USHORT
+NICReadPortUShort (
+ IN USHORT * x
+ )
+{
+ return READ_PORT_USHORT (x);
+}
+__inline
+VOID
+NICWritePortUShort (
+ IN USHORT * x,
+ IN USHORT y
+ )
+{
+ WRITE_PORT_USHORT (x,y);
+}
+
+__inline
+USHORT
+NICReadRegisterUShort (
+ IN USHORT * x
+ )
+{
+ return READ_REGISTER_USHORT (x);
+}
+
+__inline
+VOID
+NICWriteRegisterUShort (
+ IN USHORT * x,
+ IN USHORT y
+ )
+{
+ WRITE_REGISTER_USHORT (x,y);
+}
+
+
+
+// routines.c
+
+BOOLEAN
+MdiRead(
+ IN PFDO_DATA Adapter,
+ IN ULONG RegAddress,
+ IN ULONG PhyAddress,
+ IN BOOLEAN Recoverable,
+ IN OUT PUSHORT DataValue
+ );
+
+VOID
+MdiWrite(
+ IN PFDO_DATA FdoData,
+ IN ULONG RegAddress,
+ IN ULONG PhyAddress,
+ IN USHORT DataValue
+ );
+
+NTSTATUS
+D100IssueScbCommand(
+ IN PFDO_DATA FdoData,
+ IN UCHAR ScbCommandLow,
+ IN BOOLEAN WaitForScb
+ );
+
+MEDIA_STATE
+GetMediaState(
+ IN PFDO_DATA Adapter
+ );
+
+NTSTATUS
+D100SubmitCommandBlockAndWait(
+ IN PFDO_DATA Adapter
+ );
+
+VOID
+NICIssueFullReset(
+ PFDO_DATA Adapter
+ );
+
+VOID
+NICIssueSelectiveReset(
+ PFDO_DATA Adapter
+ );
+
+VOID
+DumpStatsCounters(
+ IN PFDO_DATA Adapter
+ );
+
+
+
+// physet.c
+
+VOID
+ResetPhy(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+PhyDetect(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+ScanAndSetupPhy(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+SelectPhy(
+ IN PFDO_DATA FdoData,
+ IN UINT SelectPhyAddress,
+ IN BOOLEAN WaitAutoNeg
+ );
+
+NTSTATUS
+SetupPhy(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+FindPhySpeedAndDpx(
+ IN PFDO_DATA FdoData,
+ IN UINT PhyId
+ );
+
+
+
+// eeprom.c
+USHORT
+GetEEpromAddressSize(
+ IN USHORT Size
+ );
+
+USHORT
+GetEEpromSize(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
+USHORT
+ReadEEprom(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress,
+ IN USHORT Reg,
+ IN USHORT AddressSize
+ );
+
+VOID
+ShiftOutBits(
+ IN PFDO_DATA FdoData,
+ IN USHORT data,
+ IN USHORT count,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
+USHORT
+ShiftInBits(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
+VOID
+RaiseClock(
+ IN PFDO_DATA FdoData,
+ IN OUT USHORT *x,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
+VOID
+LowerClock(
+ IN PFDO_DATA FdoData,
+ IN OUT USHORT *x,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
+VOID
+EEpromCleanup(
+ IN PFDO_DATA FdoData,
+ IN PUCHAR CSRBaseIoAddress
+ );
+
diff --git a/general/pcidrv/kmdf/HW/nic_def.h b/general/pcidrv/kmdf/HW/nic_def.h
new file mode 100644
index 00000000..6e129be0
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_def.h
@@ -0,0 +1,800 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+
+#ifndef _NIC_DEF_H
+#define _NIC_DEF_H
+
+#if !defined(WIN2K)
+
+#include "xfilter.h" // for ETH_* macros
+
+#else
+
+#define ETH_LENGTH_OF_ADDRESS 6
+
+//
+// ZZZ This is a little-endian specific check.
+//
+#define ETH_IS_MULTICAST(Address) \
+ (BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x01))
+
+//
+// Check whether an address is broadcast.
+//
+#define ETH_IS_BROADCAST(Address) \
+ ((((PUCHAR)(Address))[0] == ((UCHAR)0xff)) && (((PUCHAR)(Address))[1] == ((UCHAR)0xff)))
+
+//
+// This macro is used to copy from one network address to
+// another.
+//
+#define ETH_COPY_NETWORK_ADDRESS(_D, _S) \
+{ \
+ *((ULONG UNALIGNED *)(_D)) = *((ULONG UNALIGNED *)(_S)); \
+ *((USHORT UNALIGNED *)((UCHAR *)(_D)+4)) = *((USHORT UNALIGNED *)((UCHAR *)(_S)+4)); \
+}
+
+#endif
+
+
+
+// packet and header sizes
+#define NIC_MAX_PACKET_SIZE 1514
+#define NIC_MIN_PACKET_SIZE 60
+#define NIC_HEADER_SIZE 14
+
+// multicast list size
+#define NIC_MAX_MCAST_LIST 32
+
+
+// media type, we use ethernet, change if necessary
+#define NIC_MEDIA_TYPE NdisMedium802_3
+
+#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive
+
+// NIC PCI Device and vendor IDs
+#define NIC_PCI_DEVICE_ID 0x1229
+#define NIC_PCI_VENDOR_ID 0x8086
+
+ // IO space length
+#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC)
+
+// PCS config space including the Device Specific part of it/
+#define NIC_PCI_E100_HDR_LENGTH 0xe2
+
+// define some types for convenience
+// TXCB_STRUC, RFD_STRUC and CSR_STRUC are hardware specific structures
+// hardware TCB (Transmit Control Block) structure
+typedef TXCB_STRUC HW_TCB;
+typedef PTXCB_STRUC PHW_TCB;
+
+// hardware RFD (Receive Frame Descriptor) structure
+typedef RFD_STRUC HW_RFD;
+typedef PRFD_STRUC PHW_RFD;
+
+// hardware CSR (Control Status Register) structure
+typedef CSR_STRUC HW_CSR;
+typedef PCSR_STRUC PHW_CSR;
+// change to your company name instead of using Microsoft
+#define NIC_VENDOR_DESC "Microsoft"
+
+// number of TCBs per processor - min, default and max
+#define NIC_MIN_TCBS 1
+#define NIC_DEF_TCBS 32
+#define NIC_MAX_TCBS 64
+
+// max number of physical fragments supported per TCB
+#define NIC_MAX_PHYS_BUF_COUNT 8
+
+// number of RFDs - min, default and max
+#define NIC_MIN_RFDS 4
+#define NIC_DEF_RFDS 20
+#define NIC_MAX_RFDS 1024
+
+// only grow the RFDs up to this number
+#define NIC_MAX_GROW_RFDS 128
+
+// How many intervals before the RFD list is shrinked?
+#define NIC_RFD_SHRINK_THRESHOLD 10
+
+// local data buffer size (to copy send packet data into a local buffer)
+#define NIC_BUFFER_SIZE 1520
+
+// max lookahead size
+#define NIC_MAX_LOOKAHEAD (NIC_MAX_PACKET_SIZE - NIC_HEADER_SIZE)
+
+// max number of send packets the MiniportSendPackets function can accept
+#define NIC_MAX_SEND_PACKETS 10
+
+// supported filters
+#define NIC_SUPPORTED_FILTERS ( \
+ NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+
+// Threshold for a remove
+#define NIC_HARDWARE_ERROR_THRESHOLD 5
+
+// The CheckForHang intervals before we decide the send is stuck
+#define NIC_SEND_HANG_THRESHOLD 5
+
+// NIC specific macros
+#define NIC_RFD_GET_STATUS(_HwRfd) ((_HwRfd)->RfdCbHeader.CbStatus)
+#define NIC_RFD_STATUS_COMPLETED(_Status) ((_Status) & RFD_STATUS_COMPLETE)
+#define NIC_RFD_STATUS_SUCCESS(_Status) ((_Status) & RFD_STATUS_OK)
+#define NIC_RFD_GET_PACKET_SIZE(_HwRfd) (((_HwRfd)->RfdActualCount) & RFD_ACT_COUNT_MASK)
+#define NIC_RFD_VALID_ACTUALCOUNT(_HwRfd) ((((_HwRfd)->RfdActualCount) & (RFD_EOF_BIT | RFD_F_BIT)) == (RFD_EOF_BIT | RFD_F_BIT))
+
+#define ListNext(_pL) (_pL)->Flink
+
+#define ListPrev(_pL) (_pL)->Blink
+
+// Constants for various purposes of KeStallExecutionProcessor
+
+#define NIC_DELAY_POST_RESET 20
+// Wait 5 milliseconds for the self-test to complete
+#define NIC_DELAY_POST_SELF_TEST_MS 5
+
+
+// delay used for link detection to minimize the init time
+// change this value to match your hardware
+#define NIC_LINK_DETECTION_DELAY ((LONGLONG) -MILLISECONDS_TO_100NS * 100) // 100ms
+#define NIC_CHECK_FOR_HANG_DELAY ((LONGLONG) -MILLISECONDS_TO_100NS * 400) // 400ms
+
+// MP_TCB flags
+#define fMP_TCB_IN_USE 0x00000001
+#define fMP_TCB_USE_LOCAL_BUF 0x00000002
+#define fMP_TCB_MULTICAST 0x00000004 // a hardware workaround using multicast
+
+// MP_RFD flags
+#define fMP_RFD_RECV_PEND 0x00000001
+#define fMP_RFD_ALLOC_PEND 0x00000002
+#define fMP_RFD_RECV_READY 0x00000004
+#define fMP_RFD_RESOURCES 0x00000008
+
+// MP_ADAPTER flags
+#define fMP_ADAPTER_SCATTER_GATHER 0x00000001 // obsolete
+#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004
+#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008
+
+#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000
+
+#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000
+#define fMP_ADAPTER_NO_CABLE 0x02000000
+#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000
+#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000
+#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000
+
+#define fMP_ADAPTER_LINK_DETECTION 0x20000000
+
+#define NIC_INTERRUPT_DISABLED(_adapter) \
+ (_adapter->CSRAddress->ScbCommandHigh & SCB_INT_MASK)
+
+#define NIC_INTERRUPT_ACTIVE(_adapter) \
+ (((_adapter->CSRAddress->ScbStatus & SCB_ALL_INTERRUPT_BITS) != SCB_ALL_INTERRUPT_BITS) \
+ && (_adapter->CSRAddress->ScbStatus & SCB_ACK_MASK))
+
+
+#define NIC_ACK_INTERRUPT(_adapter, _value) { \
+ _value = _adapter->CSRAddress->ScbStatus & SCB_ACK_MASK; \
+ _adapter->CSRAddress->ScbStatus = _value; }
+
+#define NIC_IS_RECV_READY(_adapter) \
+ ((_adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) == SCB_RUS_READY)
+
+//-------------------------------------------------------------------------
+// NON_TRANSMIT_CB -- Generic Non-Transmit Command Block
+//-------------------------------------------------------------------------
+typedef struct _NON_TRANSMIT_CB
+{
+ union
+ {
+ MULTICAST_CB_STRUC Multicast;
+ CONFIG_CB_STRUC Config;
+ IA_CB_STRUC Setup;
+ DUMP_CB_STRUC Dump;
+ FILTER_CB_STRUC Filter;
+ } NonTxCb;
+
+} NON_TRANSMIT_CB, *PNON_TRANSMIT_CB;
+
+typedef enum _MEDIA_STATE {
+
+ Connected = 0,
+ Disconnected
+
+} MEDIA_STATE;
+
+#define ALIGN_16 16
+
+//
+// The driver should put the data(after Ethernet header) at 8-bytes boundary
+//
+#define ETH_DATA_ALIGN 8 // the data(after Ethernet header) should be 8-byte aligned
+//
+// Shift HW_RFD 0xA bytes to make Tcp data 8-byte aligned
+// Since the ethernet header is 14 bytes long. If a packet is at 0xA bytes
+// offset, its data(ethernet user data) will be at 8 byte boundary
+//
+#define HWRFD_SHIFT_OFFSET 0xA // Shift HW_RFD 0xA bytes to make Tcp data 8-byte aligned
+
+//
+// The driver has to allocate more data then HW_RFD needs to allow shifting data
+//
+#define MORE_DATA_FOR_ALIGN (ETH_DATA_ALIGN + HWRFD_SHIFT_OFFSET)
+//
+// Get a 8-bytes aligned memory address from a given the memory address.
+// If the given address is not 8-bytes aligned, return the closest bigger memory address
+// which is 8-bytes aligned.
+//
+#define DATA_ALIGN(_Va) ((PVOID)(((ULONG_PTR)(_Va) + (ETH_DATA_ALIGN - 1)) & ~(ETH_DATA_ALIGN - 1)))
+//
+// Get the number of bytes the final address shift from the original address
+//
+#define BYTES_SHIFT(_NewVa, _OrigVa) ((PUCHAR)(_NewVa) - (PUCHAR)(_OrigVa))
+
+#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
+ (BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x02))
+
+
+//--------------------------------------
+// Some utility macros
+//--------------------------------------
+#ifndef min
+#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif
+
+#ifndef max
+#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif
+
+#define MP_ALIGNMEM(_p, _align) (((_align) == 0) ? (_p) : (PUCHAR)(((ULONG_PTR)(_p) + ((_align)-1)) & (~((ULONG_PTR)(_align)-1))))
+#define MP_ALIGNMEM_PHYS(_p, _align) (((_align) == 0) ? (_p) : (((ULONG)(_p) + ((_align)-1)) & (~((ULONG)(_align)-1))))
+#define MP_ALIGNMEM_PA(_p, _align) (((_align) == 0) ? (_p).QuadPart : (((_p).QuadPart + ((_align)-1)) & (~((ULONGLONG)(_align)-1))))
+
+#define GetListHeadEntry(ListHead) ((ListHead)->Flink)
+#define GetListTailEntry(ListHead) ((ListHead)->Blink)
+#define GetListFLink(ListEntry) ((ListEntry)->Flink)
+
+#define IsSListEmpty(ListHead) (((PSINGLE_LIST_ENTRY)ListHead)->Next == NULL)
+
+//--------------------------------------
+// Macros for flag and ref count operations
+//--------------------------------------
+#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F))
+#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F))
+#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0)
+#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0)
+#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F))
+
+#if 0 // Not implemented
+
+//--------------------------------------
+// Coalesce Tx buffer for local data copying
+//--------------------------------------
+typedef struct _MP_TXBUF
+{
+ SINGLE_LIST_ENTRY SList;
+ PMDL Mdl;
+
+ ULONG AllocSize;
+ PVOID AllocVa;
+ PHYSICAL_ADDRESS AllocLa; // Logical Address
+
+ PUCHAR pBuffer;
+ PHYSICAL_ADDRESS BufferLa; // Logical Address
+ ULONG BufferSize;
+
+} MP_TXBUF, *PMP_TXBUF;
+
+#endif
+
+//--------------------------------------
+// TCB (Transmit Control Block)
+//--------------------------------------
+typedef struct _MP_TCB
+{
+ struct _MP_TCB *Next;
+ ULONG Flags;
+ ULONG Count;
+ WDFDMATRANSACTION DmaTransaction;
+
+ PHW_TCB HwTcb; // ptr to HW TCB VA
+ ULONG HwTcbPhys; // ptr to HW TCB PA
+ PHW_TCB PrevHwTcb; // ptr to previous HW TCB VA
+
+ PTBD_STRUC HwTbd; // ptr to first TBD
+ ULONG HwTbdPhys; // ptr to first TBD PA
+
+} MP_TCB, *PMP_TCB;
+
+//--------------------------------------
+// RFD (Receive Frame Descriptor)
+//--------------------------------------
+typedef struct _MP_RFD
+{
+ LIST_ENTRY List;
+ PVOID Buffer; // Pointer to Buffer
+ PMDL Mdl;
+ PHW_RFD HwRfd; // ptr to hardware RFD
+ WDFCOMMONBUFFER WdfCommonBuffer;
+ PHW_RFD OriginalHwRfd; // ptr to shared memory
+ PHYSICAL_ADDRESS HwRfdLa; // logical address of RFD
+ PHYSICAL_ADDRESS OriginalHwRfdLa; // Original physical address allocated by NDIS
+ ULONG HwRfdPhys; // lower part of HwRfdPa
+ BOOLEAN DeleteCommonBuffer; // Indicates if WdfObjectDelete
+ // is to be called when freeing MD_RFD.
+ ULONG Flags;
+ ULONG PacketSize; // total size of receive frame
+ WDFMEMORY LookasideMemoryHdl;
+} MP_RFD, *PMP_RFD;
+
+//--------------------------------------
+// Structure for Power Management Info
+//--------------------------------------
+typedef struct _MP_POWER_MGMT
+{
+
+ // List of Wake Up Patterns
+ LIST_ENTRY PatternList;
+
+ // Current Power state of the adapter
+ UINT PowerState;
+
+ // Is PME_En on this adapter
+ BOOLEAN PME_En;
+
+ // Wake-up capabailities of the adapter
+ BOOLEAN bWakeFromD0;
+ BOOLEAN bWakeFromD1;
+ BOOLEAN bWakeFromD2;
+ BOOLEAN bWakeFromD3Hot;
+ BOOLEAN bWakeFromD3Aux;
+ // Pad
+ BOOLEAN Pad[2];
+
+} MP_POWER_MGMT, *PMP_POWER_MGMT;
+
+
+
+typedef struct _MP_WAKE_PATTERN
+{
+ // Link to the next Pattern
+ LIST_ENTRY linkListEntry;
+
+ // E100 specific signature of the pattern
+ ULONG Signature;
+
+ // Size of this allocation
+ ULONG AllocationSize;
+
+ // Pattern - This contains the NDIS_PM_PACKET_PATTERN
+ UCHAR Pattern[1];
+
+} MP_WAKE_PATTERN , *PMP_WAKE_PATTERN ;
+
+
+//--------------------------------------
+// Macros specific to miniport adapter structure
+//--------------------------------------
+#define MP_TCB_RESOURCES_AVAIABLE(_M) ((_M)->nBusySend < (_M)->NumTcb)
+
+#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK)
+#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK)
+#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK)
+
+#define MP_SET_HARDWARE_ERROR(adapter) MP_SET_FLAG(adapter, fMP_ADAPTER_HARDWARE_ERROR)
+#define MP_SET_NON_RECOVER_ERROR(adapter) MP_SET_FLAG(adapter, fMP_ADAPTER_NON_RECOVER_ERROR)
+
+#define MP_OFFSET(field) ((UINT)FIELD_OFFSET(MP_ADAPTER,field))
+#define MP_SIZE(field) sizeof(((PMP_ADAPTER)0)->field)
+
+
+//--------------------------------------
+// Stall execution and wait with timeout
+//--------------------------------------
+/*++
+ _condition - condition to wait for
+ _timeout_ms - timeout value in milliseconds
+ _result - TRUE if condition becomes true before it times out
+--*/
+#define MP_STALL_AND_WAIT(_condition, _timeout_ms, _result) \
+{ \
+ int counter; \
+ _result = FALSE; \
+ for(counter = _timeout_ms * 50; counter != 0; counter--) \
+ { \
+ if(_condition) \
+ { \
+ _result = TRUE; \
+ break; \
+ } \
+ KeStallExecutionProcessor(20); \
+ } \
+}
+
+__inline VOID MP_STALL_EXECUTION(
+ IN ULONG MsecDelay)
+{
+ // Delay in 100 usec increments
+ MsecDelay *= 10;
+ while (MsecDelay)
+ {
+ KeStallExecutionProcessor(100);
+ MsecDelay--;
+ }
+}
+
+typedef struct _FDO_DATA FDO_DATA, *PFDO_DATA;
+
+
+NTSTATUS
+NICGetDeviceInformation(
+ IN OUT PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICAllocateSoftwareResources(
+ IN OUT PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICMapHWResources(
+ IN OUT PFDO_DATA FdoData,
+ IN WDFCMRESLIST ResourcesRaw,
+ IN WDFCMRESLIST ResourcesTranslated
+ );
+
+NTSTATUS
+NICUnmapHWResources(
+ IN OUT PFDO_DATA FdoData
+ );
+
+
+NTSTATUS
+NICFreeSoftwareResources(
+ IN OUT PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICInitializeAdapter(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICReadAdapterInfo(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICSelfTest(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+HwSoftwareReset(
+ IN PFDO_DATA FdoData
+ );
+
+EVT_WDF_INTERRUPT_ISR NICEvtInterruptIsr;
+EVT_WDF_INTERRUPT_DPC NICEvtInterruptDpc;
+EVT_WDF_INTERRUPT_ENABLE NICEvtInterruptEnable;
+EVT_WDF_INTERRUPT_DISABLE NICEvtInterruptDisable;
+
+EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED NICEvtDeviceD0EntryPostInterruptsEnabled;
+EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED NICEvtDeviceD0ExitPreInterruptsDisabled;
+
+EVT_WDF_IO_QUEUE_IO_WRITE PciDrvEvtIoWrite;
+
+EVT_WDF_PROGRAM_DMA NICEvtProgramDmaFunction;
+
+EVT_WDF_TIMER NICWatchDogEvtTimerFunc;
+
+EVT_WDF_WORKITEM NICAllocRfdWorkItem;
+EVT_WDF_WORKITEM NICFreeRfdWorkItem;
+
+NTSTATUS
+NICAllocAdapterMemory(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICFreeAdapterMemory(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICAllocRfd(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ );
+
+VOID
+NICFreeRfd(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ );
+
+VOID
+NICReturnRFD(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ );
+
+NTSTATUS
+HwConfigure(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+HwSetupIAAddress(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+HwClearAllCounters(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICInitRecvBuffers(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICInitSendBuffers(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICLinkDetection(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICHandleQueryOidRequest(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ WDF_REQUEST_PARAMETERS *Params
+ );
+
+VOID
+NICHandleSetOidRequest(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ WDF_REQUEST_PARAMETERS *Params
+ );
+
+VOID
+NICServiceIndicateStatusIrp(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICGetStatsCounters(
+ IN PFDO_DATA FdoData,
+ IN NDIS_OID Oid,
+ OUT PULONG64 pCounter);
+
+NTSTATUS
+NICSetPacketFilter(
+ IN PFDO_DATA FdoData,
+ IN ULONG PacketFilter);
+
+NTSTATUS
+NICSetMulticastList(
+ IN PFDO_DATA FdoData);
+
+ULONG
+NICGetMediaConnectStatus(
+ IN PFDO_DATA FdoData);
+
+NTSTATUS
+NICWritePacket(
+ IN PFDO_DATA FdoData,
+ IN WDFDMATRANSACTION DmaTransaction,
+ IN PSCATTER_GATHER_LIST SGList
+ );
+
+NTSTATUS
+NICSendPacket(
+ IN PFDO_DATA FdoData,
+ IN PMP_TCB pMpTcb,
+ IN PSCATTER_GATHER_LIST ScatterGather);
+
+NTSTATUS
+NICStartSend(
+ IN PFDO_DATA FdoData,
+ IN PMP_TCB pMpTcb);
+
+_Requires_lock_held_(FdoData->SendLock)
+NTSTATUS
+NICHandleSendInterrupt(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICCheckForQueuedSends(
+ IN PFDO_DATA FdoData
+ );
+
+_IRQL_requires_same_
+_IRQL_requires_(DISPATCH_LEVEL)
+_Requires_lock_held_(FdoData->SendLock)
+VOID
+NICFreeQueuedSendPackets(
+ IN PFDO_DATA FdoData
+ );
+
+_Requires_lock_held_(FdoData->SendLock)
+VOID
+NICFreeBusySendPackets(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICCompleteSendRequest(
+ PFDO_DATA FdoData,
+ WDFREQUEST Request,
+ NTSTATUS Status,
+ ULONG Information
+ );
+
+VOID
+NICShutdown(
+ IN PFDO_DATA FdoData
+ );
+
+_IRQL_requires_same_
+_IRQL_requires_(DISPATCH_LEVEL)
+_Requires_lock_held_(FdoData->RcvLock)
+VOID
+NICHandleRecvInterrupt(
+ IN PFDO_DATA FdoData
+ );
+
+_Requires_lock_held_(FdoData->RcvLock)
+NTSTATUS
+NICStartRecv(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICResetRecv(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICServiceReadIrps(
+ PFDO_DATA FdoData,
+ PMP_RFD *PacketArray,
+ ULONG PacketArrayCount
+ );
+
+BOOLEAN
+NICCheckForHang(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICReset(
+ IN PFDO_DATA FdoData
+ );
+
+MEDIA_STATE
+NICIndicateMediaState(
+ IN PFDO_DATA FdoData
+ );
+
+MEDIA_STATE
+NICGetMediaState(
+ IN PFDO_DATA FdoData
+ );
+
+VOID
+NICExtractPMInfoFromPciSpace(
+ PFDO_DATA FdoData,
+ PUCHAR pPciConfig
+ );
+
+NTSTATUS
+NICSetPower(
+ PFDO_DATA FdoData ,
+ WDF_POWER_DEVICE_STATE PowerState
+ );
+
+NTSTATUS
+MPSetPowerD0(
+ PFDO_DATA FdoData
+ );
+
+NTSTATUS
+MPSetPowerLow(
+ PFDO_DATA FdoData,
+ WDF_POWER_DEVICE_STATE PowerState
+ );
+
+VOID
+NICFillPoMgmtCaps (
+ IN PFDO_DATA FdoData,
+ IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities,
+ IN OUT PNDIS_STATUS pStatus,
+ IN OUT PULONG pulInfoLen
+ );
+
+NTSTATUS
+NICAddWakeUpPattern(
+ IN PFDO_DATA FdoData,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+NTSTATUS
+NICRemoveWakeUpPattern(
+ IN PFDO_DATA FdoData,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+VOID
+NICRemoveAllWakeUpPatterns(
+ PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICConfigureForWakeUp(
+ IN PFDO_DATA FdoData,
+ IN BOOLEAN AddPattern
+ );
+
+NTSTATUS
+NICGetIoctlRequest(
+ IN WDFQUEUE Queue,
+ IN ULONG FunctionCode,
+ OUT WDFREQUEST* Request
+ );
+
+VOID
+NICGetDeviceInfSettings(
+ IN OUT PFDO_DATA FdoData
+ );
+
+NTSTATUS
+NICInitiateDmaTransfer(
+ IN PFDO_DATA FdoData,
+ IN WDFREQUEST Request
+ );
+
+VOID
+NICStartWatchDogTimer(
+ IN PFDO_DATA FdoData
+ );
+
+typedef
+USHORT
+(*PREAD_PORT)(
+ IN USHORT *Register
+ );
+
+typedef
+VOID
+(*PWRITE_PORT)(
+ IN USHORT *Register,
+ IN USHORT Value
+ );
+
+#endif
+
+
diff --git a/general/pcidrv/kmdf/HW/nic_init.c b/general/pcidrv/kmdf/HW/nic_init.c
new file mode 100644
index 00000000..947b1d65
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_init.c
@@ -0,0 +1,2378 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ NIC_INIT.c
+
+Abstract:
+
+ Contains rotuines to do resource allocation and hardware
+ initialization & shutdown.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "nic_init.tmh"
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (PAGE, NICAllocateSoftwareResources)
+#pragma alloc_text (PAGE, NICFreeSoftwareResources)
+#pragma alloc_text (PAGE, NICMapHWResources)
+#pragma alloc_text (PAGE, NICUnmapHWResources)
+#pragma alloc_text (PAGE, NICGetDeviceInformation)
+#pragma alloc_text (PAGE, NICReadAdapterInfo)
+#pragma alloc_text (PAGE, NICAllocAdapterMemory)
+#pragma alloc_text (PAGE, NICFreeAdapterMemory)
+#pragma alloc_text (PAGE, NICInitRecvBuffers)
+#pragma alloc_text (PAGE, NICSelfTest)
+#pragma alloc_text (PAGE, HwClearAllCounters)
+#pragma alloc_text (PAGE, NICAllocRfd)
+#pragma alloc_text (PAGE, NICFreeRfd)
+#pragma alloc_text (PAGE, NICFreeRfdWorkItem)
+#endif
+
+PVOID LocalMmMapIoSpace(
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ SIZE_T NumberOfBytes
+ )
+{
+ typedef
+ PVOID
+ (*PFN_MM_MAP_IO_SPACE_EX) (
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ SIZE_T NumberOfBytes,
+ _In_ ULONG Protect
+ );
+
+ UNICODE_STRING name;
+ PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx;
+
+ RtlInitUnicodeString(&name, L"MmMapIoSpaceEx");
+ pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name);
+
+ if (pMmMapIoSpaceEx != NULL){
+ //
+ // Call WIN10 API if available
+ //
+ return pMmMapIoSpaceEx(PhysicalAddress,
+ NumberOfBytes,
+ PAGE_READWRITE | PAGE_NOCACHE);
+ }
+
+ return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached);
+}
+
+NTSTATUS
+NICAllocateSoftwareResources(
+ IN OUT PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This routine creates two parallel queues and 3 manual queues to hold
+ Read, Write and IOCTL requests. It also creates the interrupt object and
+ DMA object, and performs some additional initialization.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG ioQueueConfig;
+ WDF_DMA_ENABLER_CONFIG dmaConfig;
+ ULONG maximumLength, maxLengthSupported;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ ULONG maxMapRegistersRequired, miniMapRegisters;
+ ULONG mapRegistersAllocated;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "-->NICAllocateSoftwareResources\n");
+
+ PAGED_CODE();
+
+ //
+ // Initialize all the static data first to make sure we don't touch
+ // uninitialized list in the ContextCleanup callback if the
+ // AddDevice fails for any reason.
+ //
+ InitializeListHead(&FdoData->PoMgmt.PatternList);
+ InitializeListHead(&FdoData->RecvList);
+
+ //
+ // This a global lock, to synchonize access to device context.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = FdoData->WdfDevice;
+ status = WdfSpinLockCreate(&attributes,&FdoData->Lock);
+ if(!NT_SUCCESS(status)){
+ return status;
+ }
+
+
+ //
+ // Get the BUS_INTERFACE_STANDARD for our device so that we can
+ // read & write to PCI config space.
+ //
+ status = WdfFdoQueryForInterface(FdoData->WdfDevice,
+ &GUID_BUS_INTERFACE_STANDARD,
+ (PINTERFACE) &FdoData->BusInterface,
+ sizeof(BUS_INTERFACE_STANDARD),
+ 1, // Version
+ NULL); //InterfaceSpecificData
+ if (!NT_SUCCESS (status)){
+ return status;
+ }
+
+ //
+ // First make sure this is our device before doing whole lot
+ // of other things.
+ //
+ status = NICGetDeviceInformation(FdoData);
+ if (!NT_SUCCESS (status)){
+ return status;
+ }
+
+ NICGetDeviceInfSettings(FdoData);
+
+ //
+ // We will create and configure a queue for receiving
+ // write requests. If these requests have to be pended for any
+ // reason, they will be forwarded to a manual queue created after this one.
+ // Framework automatically takes the responsibility of handling
+ // cancellation when the requests are waiting in the queue. This is
+ // a managed queue. So the framework will take care of queueing
+ // incoming requests when the pnp/power state transition takes place.
+ // Since we have configured the queue to dispatch all the specific requests
+ // we care about, we don't need a default queue. A default queue is
+ // used to receive requests that are not preconfigured to go to
+ // a specific queue.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &ioQueueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ ioQueueConfig.EvtIoWrite = PciDrvEvtIoWrite;
+
+ status = WdfIoQueueCreate(
+ FdoData->WdfDevice,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WriteQueue // queue handle
+ );
+
+ if (!NT_SUCCESS (status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed 0x%x\n", status);
+ return status;
+ }
+
+ status = WdfDeviceConfigureRequestDispatching(
+ FdoData->WdfDevice,
+ FdoData->WriteQueue,
+ WdfRequestTypeWrite);
+
+ if(!NT_SUCCESS (status)){
+ ASSERT(NT_SUCCESS(status));
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing write Queue 0x%x\n", status);
+ return status;
+ }
+
+ //
+ // Manual internal queue for write reqeusts. This will be used to queue
+ // the write requests presented to us from the parallel default queue
+ // when we are low in TCB resources or when the device
+ // is busy doing link detection.
+ // Requests can be canceled while waiting in the queue without any
+ // notification to the driver.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &ioQueueConfig,
+ WdfIoQueueDispatchManual
+ );
+
+ status = WdfIoQueueCreate (
+ FdoData->WdfDevice,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->PendingWriteQueue
+ );
+
+ if(!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating manual write Queue 0x%x\n", status);
+ return status;
+ }
+
+
+ //
+ // Manual queue for read requests (WdfRequestTypeRead). We will configure the queue
+ // so that incoming read requests are directly dispatched to this queue. We will
+ // manually remove the requests from the queue and service them in our recv
+ // interrupt handler. WDF_IO_QUEUE_CONFIG_INIT initializes queues to be
+ // auto managed by default.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &ioQueueConfig,
+ WdfIoQueueDispatchManual
+ );
+
+ status = WdfIoQueueCreate (
+ FdoData->WdfDevice,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->PendingReadQueue
+ );
+
+ if(!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating read Queue 0x%x\n", status);
+ return status;
+ }
+
+ status = WdfDeviceConfigureRequestDispatching(
+ FdoData->WdfDevice,
+ FdoData->PendingReadQueue,
+ WdfRequestTypeRead);
+
+ if(!NT_SUCCESS (status)){
+ ASSERT(NT_SUCCESS(status));
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing read Queue 0x%x\n", status);
+ return status;
+ }
+
+
+ //
+ // Parallel queue for device I/O control (WdfRequestTypeDeviceControl) requests.
+ // We will configure the queue so that all the incoming ioctl requests
+ // go directly to this queue. We will try to service the requests immediately.
+ // If we can't, we will forward the request to a manual queue created below
+ // and try to service it from a DPC when the appropriate event happens.
+ //
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &ioQueueConfig,
+ WdfIoQueueDispatchParallel
+ );
+
+ ioQueueConfig.EvtIoDeviceControl = PciDrvEvtIoDeviceControl;
+
+ status = WdfIoQueueCreate (
+ FdoData->WdfDevice,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->IoctlQueue
+ );
+
+ if(!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating ioctl Queue 0x%x\n", status);
+ return status;
+ }
+
+ status = WdfDeviceConfigureRequestDispatching(
+ FdoData->WdfDevice,
+ FdoData->IoctlQueue,
+ WdfRequestTypeDeviceControl);
+
+ if(!NT_SUCCESS (status)){
+ ASSERT(NT_SUCCESS(status));
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing ioctl Queue 0x%x\n", status);
+ return status;
+ }
+
+ //
+ // Manual internal queue for device I/O control requests. This will be used to
+ // queue the ioctl requests presented to us from the parallel ioctl queue
+ // when we cannot handle them immediately. This is a managed queue.
+ // Requests be get canceled while waiting in the queue without any
+ // notification to the driver.
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT(
+ &ioQueueConfig,
+ WdfIoQueueDispatchManual
+ );
+
+ status = WdfIoQueueCreate (
+ FdoData->WdfDevice,
+ &ioQueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->PendingIoctlQueue
+ );
+
+ if(!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "Error Creating manual Ioctl Queue 0x%x\n", status);
+ return status;
+ }
+
+#ifndef PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE
+ {
+ WDF_INTERRUPT_CONFIG interruptConfig;
+
+ //
+ // Create WDFINTERRUPT object.
+ //
+ WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
+ NICEvtInterruptIsr,
+ NICEvtInterruptDpc);
+
+ //
+ // These first two callbacks will be called at DIRQL. Their job is to
+ // enable and disable interrupts.
+ //
+ interruptConfig.EvtInterruptEnable = NICEvtInterruptEnable;
+ interruptConfig.EvtInterruptDisable = NICEvtInterruptDisable;
+
+ status = WdfInterruptCreate(FdoData->WdfDevice,
+ &interruptConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WdfInterrupt);
+
+ if (!NT_SUCCESS (status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "WdfInterruptCreate failed: %!STATUS!\n", status);
+ return status;
+ }
+ }
+#endif
+
+ //
+ // Alignment requirement must be 16-byte for this device. This alignment
+ // value will be inherits by the DMA enabler and used when you allocate
+ // common buffers.
+ //
+ WdfDeviceSetAlignmentRequirement( FdoData->WdfDevice, FILE_OCTA_ALIGNMENT);
+
+ //
+ // Bare minimum number of map registers required to do
+ // a single NIC_MAX_PACKET_SIZE transfer.
+ //
+ miniMapRegisters = BYTES_TO_PAGES(NIC_MAX_PACKET_SIZE) + 1;
+
+ //
+ // Maximum map registers required to do simultaneous transfer
+ // of all TCBs assuming each packet spanning NIC_MAX_PHYS_BUF_COUNT
+ // Buffer can span multiple MDLs.
+ //
+ maxMapRegistersRequired = FdoData->NumTcb * NIC_MAX_PHYS_BUF_COUNT;
+
+ //
+ // The maximum length of buffer for maxMapRegistersRequired number of
+ // map registers would be.
+ //
+ maximumLength = (maxMapRegistersRequired-1) << PAGE_SHIFT;
+
+ //
+ // Create a new DMA Object for Scatter/Gather DMA mode.
+ //
+
+ WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
+ WdfDmaProfileScatterGather,
+ maximumLength );
+
+ status = WdfDmaEnablerCreate( FdoData->WdfDevice,
+ &dmaConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WdfDmaEnabler );
+
+ if (!NT_SUCCESS (status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "WdfDmaEnblerCreate failed: %08X\n", status);
+ return status;
+ }
+
+ maxLengthSupported = (ULONG) WdfDmaEnablerGetFragmentLength(FdoData->WdfDmaEnabler,
+ WdfDmaDirectionReadFromDevice);
+
+ mapRegistersAllocated = BYTES_TO_PAGES(maxLengthSupported) + 1;
+
+ if(mapRegistersAllocated < miniMapRegisters) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "Not enough map registers: Allocated %d, Required %d\n",
+ mapRegistersAllocated, miniMapRegisters);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ return status;
+ }
+
+ //
+ // Adjust our TCB count based on the MapRegisters we got. We will
+ // take the best case scenario where the packet is going to span
+ // no more than 2 pages.
+ //
+ FdoData->NumTcb = mapRegistersAllocated/miniMapRegisters;
+
+ //
+ // Make sure it doesn't exceed NIC_MAX_TCBS.
+ //
+ FdoData->NumTcb = min(FdoData->NumTcb, NIC_MAX_TCBS);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
+ "MapRegisters Allocated %d\n", mapRegistersAllocated);
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
+ "Adjusted TCB count is %d\n", FdoData->NumTcb);
+
+ //
+ // Set the maximum allowable DMA Scatter/Gather list fragmentation size.
+ //
+ WdfDmaEnablerSetMaximumScatterGatherElements( FdoData->WdfDmaEnabler,
+ NIC_MAX_PHYS_BUF_COUNT );
+
+ //
+ // Create a lock to protect all the write-related buffer lists.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = FdoData->WdfDevice;
+ status = WdfSpinLockCreate(&attributes,&FdoData->SendLock);
+ if(!NT_SUCCESS(status)){
+ return status;
+ }
+
+ //
+ // Create a lock to protect all the read-related buffer lists
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = FdoData->WdfDevice;
+ status = WdfSpinLockCreate(&attributes,&FdoData->RcvLock);
+ if(!NT_SUCCESS(status)){
+ return status;
+ }
+
+ status = NICAllocAdapterMemory(FdoData);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // This sets up send buffers. It doesn't actually touch hardware.
+ //
+
+ NICInitSendBuffers(FdoData);
+
+ //
+ // This sets up receive buffers. It doesn't actually touch hardware.
+ //
+
+ status = NICInitRecvBuffers(FdoData);
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- NICAllocateSoftwareResources\n");
+
+ return status;
+}
+
+
+NTSTATUS
+NICFreeSoftwareResources(
+ IN OUT PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Free all the software resources. We shouldn't touch the hardware.
+ This functions is called in the context of EvtDeviceContextCleanup.
+ Most of the resources created in NICAllocateResources such as queues,
+ DMA enabler, SpinLocks, CommonBuffer, are already freed by
+ framework because they are associated with the WDFDEVICE directly
+ or indirectly as child objects.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "-->NICFreeSoftwareResources\n");
+
+ PAGED_CODE();
+
+ NICFreeAdapterMemory(FdoData);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<--NICFreeSoftwareResources\n");
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS
+NICMapHWResources(
+ IN OUT PFDO_DATA FdoData,
+ IN WDFCMRESLIST ResourcesRaw,
+ IN WDFCMRESLIST ResourcesTranslated
+ )
+/*++
+Routine Description:
+
+ Gets the HW resources assigned by the bus driver and:
+ 1) Maps them to system address space.
+ 2) If PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE is defined,
+ it creates a WDFINTERRUPT object.
+
+ Called during EvtDevicePrepareHardware callback.
+
+ Three base address registers are supported by the 8255x:
+ 1) CSR Memory Mapped Base Address Register (BAR 0 at offset 10)
+ 2) CSR I/O Mapped Base Address Register (BAR 1 at offset 14)
+ 3) Flash Memory Mapped Base Address Register (BAR 2 at offset 18)
+
+ The 8255x requires one BAR for I/O mapping and one BAR for memory
+ mapping of these registers anywhere within the 32-bit memory address space.
+ The driver determines which BAR (I/O or Memory) is used to access the
+ Control/Status Registers.
+
+ Just for illustration, this driver maps both memory and I/O registers and
+ shows how to use READ_PORT_xxx or READ_REGISTER_xxx functions to perform
+ I/O in a platform independent basis. On some platforms, the I/O registers
+ can get mapped into memory space and your driver should be able to handle
+ this transparently.
+
+ One BAR is also required to map the accesses to an optional Flash memory.
+ The 82557 implements this register regardless of the presence or absence
+ of a Flash chip on the adapter. The 82558 and 82559 implement this
+ register only if a bit is set in the EEPROM. The size of the space requested
+ by this register is 1Mbyte, and it is always mapped anywhere in the 32-bit
+ memory address space.
+
+ Note: Although the 82558 only supports up to 64 Kbytes of Flash memory
+ and the 82559 only supports 128 Kbytes of Flash memory, the driver
+ requests 1 Mbyte of address space. Software should not access Flash
+ addresses above 64 Kbytes for the 82558 or 128 Kbytes for the 82559
+ because Flash accesses above the limits are aliased to lower addresses.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ ResourcesRaw - Pointer to list of raw resources passed to
+ EvtDevicePrepareHardware callback
+ ResourcesTranslated - Pointer to list of translated resources passed to
+ EvtDevicePrepareHardware callback
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
+ ULONG i;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN bResPort = FALSE;
+ BOOLEAN bResInterrupt = FALSE;
+ BOOLEAN bResMemory = FALSE;
+ ULONG numberOfBARs = 0;
+
+ UNREFERENCED_PARAMETER(ResourcesRaw);
+
+ PAGED_CODE();
+
+ for (i=0; i<WdfCmResourceListGetCount(ResourcesTranslated); i++) {
+
+ descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);
+
+ if(!descriptor){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfResourceCmGetDescriptor");
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ switch (descriptor->Type) {
+
+ case CmResourceTypePort:
+ //
+ // We will increment the BAR count only for valid resources. We will
+ // not count the private device types added by the PCI bus driver.
+ //
+ numberOfBARs++;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "I/O mapped CSR: (%x) Length: (%d)\n",
+ descriptor->u.Port.Start.LowPart,
+ descriptor->u.Port.Length);
+
+ //
+ // The resources are listed in the same order the as
+ // BARs in the config space, so this should be the second one.
+ //
+ if(numberOfBARs != 2) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "I/O mapped CSR is not in the right order\n");
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ return status;
+ }
+
+ //
+ // The port is in I/O space on this machine.
+ // We should use READ_PORT_Xxx, and WRITE_PORT_Xxx routines
+ // to read or write to the port.
+ //
+
+ FdoData->IoBaseAddress = ULongToPtr(descriptor->u.Port.Start.LowPart);
+ FdoData->IoRange = descriptor->u.Port.Length;
+ //
+ // Since all our accesses are USHORT wide, we will create an accessor
+ // table just for these two functions.
+ //
+ FdoData->ReadPort = NICReadPortUShort;
+ FdoData->WritePort = NICWritePortUShort;
+
+ bResPort = TRUE;
+ FdoData->MappedPorts = FALSE;
+ break;
+
+ case CmResourceTypeMemory:
+
+ numberOfBARs++;
+
+ if(numberOfBARs == 1) {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Memory mapped CSR:(%x:%x) Length:(%d)\n",
+ descriptor->u.Memory.Start.LowPart,
+ descriptor->u.Memory.Start.HighPart,
+ descriptor->u.Memory.Length);
+ //
+ // Our CSR memory space should be 0x1000 in size.
+ //
+ ASSERT(descriptor->u.Memory.Length == 0x1000);
+ FdoData->MemPhysAddress = descriptor->u.Memory.Start;
+ FdoData->CSRAddress = LocalMmMapIoSpace(
+ descriptor->u.Memory.Start,
+ NIC_MAP_IOSPACE_LENGTH);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "CSRAddress=%p\n", FdoData->CSRAddress);
+
+ bResMemory = TRUE;
+
+ } else if(numberOfBARs == 2){
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "I/O mapped CSR in Memory Space: (%x) Length: (%d)\n",
+ descriptor->u.Memory.Start.LowPart,
+ descriptor->u.Memory.Length);
+ //
+ // The port is in memory space on this machine.
+ // We should call LocalMmMapIoSpace to map the physical to virtual
+ // address, and also use the READ/WRITE_REGISTER_xxx function
+ // to read or write to the port.
+ //
+
+ FdoData->IoBaseAddress = LocalMmMapIoSpace(
+ descriptor->u.Memory.Start,
+ descriptor->u.Memory.Length);
+
+ FdoData->ReadPort = NICReadRegisterUShort;
+ FdoData->WritePort = NICWriteRegisterUShort;
+ FdoData->MappedPorts = TRUE;
+ bResPort = TRUE;
+
+ } else if(numberOfBARs == 3){
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Flash memory:(%x:%x) Length:(%d)\n",
+ descriptor->u.Memory.Start.LowPart,
+ descriptor->u.Memory.Start.HighPart,
+ descriptor->u.Memory.Length);
+ //
+ // Our flash memory should be 1MB in size. Since we don't
+ // access the memory, let us not bother mapping it.
+ //
+ //ASSERT(descriptor->u.Memory.Length == 0x100000);
+ } else {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "Memory Resources are not in the right order\n");
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ return status;
+ }
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ ASSERT(!bResInterrupt);
+
+#ifdef PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE
+ {
+ WDF_INTERRUPT_CONFIG interruptConfig;
+
+ //
+ // Create WDFINTERRUPT object.
+ //
+ WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
+ NICEvtInterruptIsr,
+ NICEvtInterruptDpc);
+
+ //
+ // These first two callbacks will be called at DIRQL. Their job is to
+ // enable and disable interrupts.
+ //
+ interruptConfig.EvtInterruptEnable = NICEvtInterruptEnable;
+ interruptConfig.EvtInterruptDisable = NICEvtInterruptDisable;
+ interruptConfig.InterruptTranslated = descriptor;
+ interruptConfig.InterruptRaw =
+ WdfCmResourceListGetDescriptor(ResourcesRaw, i);
+
+ status = WdfInterruptCreate(FdoData->WdfDevice,
+ &interruptConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WdfInterrupt);
+
+ if (!NT_SUCCESS (status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "WdfInterruptCreate failed: %!STATUS!\n", status);
+ return status;
+ }
+ }
+#endif
+
+ bResInterrupt = TRUE;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "Interrupt level: 0x%0x, Vector: 0x%0x\n",
+ descriptor->u.Interrupt.Level,
+ descriptor->u.Interrupt.Vector);
+
+ break;
+
+ default:
+ //
+ // This could be device-private type added by the PCI bus driver. We
+ // shouldn't filter this or change the information contained in it.
+ //
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Unhandled resource type (0x%x)\n",
+ descriptor->Type);
+ break;
+ }
+
+ }
+
+ //
+ // Make sure we got all the 3 resources to work with.
+ //
+ if (!(bResPort && bResInterrupt && bResMemory)) {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ return status;
+ }
+
+ //
+ // Read additional info from NIC such as MAC address
+ //
+ status = NICReadAdapterInfo(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ //
+ // Test our adapter hardware
+ //
+ status = NICSelfTest(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ return status;
+
+}
+
+NTSTATUS
+NICUnmapHWResources(
+ IN OUT PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Disconnect the interrupt and unmap all the memory and I/O resources.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ //
+ // Free hardware resources
+ //
+ if (FdoData->CSRAddress)
+ {
+ MmUnmapIoSpace(FdoData->CSRAddress, NIC_MAP_IOSPACE_LENGTH);
+ FdoData->CSRAddress = NULL;
+ }
+
+ if(FdoData->MappedPorts){
+ MmUnmapIoSpace(FdoData->IoBaseAddress, FdoData->IoRange);
+ FdoData->IoBaseAddress = NULL;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+NICGetDeviceInformation(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This function reads the PCI config space and make sure that it's our
+ device and stores the device IDs and power information in the device
+ extension. Should be done in the StartDevice.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) UCHAR buffer[NIC_PCI_E100_HDR_LENGTH ];
+ PPCI_COMMON_CONFIG pPciConfig = (PPCI_COMMON_CONFIG) buffer;
+ USHORT usPciCommand;
+ ULONG bytesRead =0;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "---> NICGetDeviceInformation\n");
+
+ PAGED_CODE();
+
+ RtlZeroMemory(buffer, sizeof(buffer));
+ bytesRead = FdoData->BusInterface.GetBusData(
+ FdoData->BusInterface.Context,
+ PCI_WHICHSPACE_CONFIG, //READ
+ buffer,
+ FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
+ NIC_PCI_E100_HDR_LENGTH);
+
+ if (bytesRead != NIC_PCI_E100_HDR_LENGTH) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "GetBusData (NIC_PCI_E100_HDR_LENGTH) failed =%d\n",
+ bytesRead);
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ //
+ // Is this our device?
+ //
+
+ if (pPciConfig->VendorID != NIC_PCI_VENDOR_ID ||
+ pPciConfig->DeviceID != NIC_PCI_DEVICE_ID)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "VendorID/DeviceID don't match - %x/%x\n",
+ pPciConfig->VendorID, pPciConfig->DeviceID);
+ //return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ }
+
+ //
+ // save TRACE_LEVEL_INFORMATION from config space
+ //
+ FdoData->RevsionID = pPciConfig->RevisionID;
+ FdoData->SubVendorID = pPciConfig->u.type0.SubVendorID;
+ FdoData->SubSystemID = pPciConfig->u.type0.SubSystemID;
+
+ NICExtractPMInfoFromPciSpace (FdoData, (PUCHAR)pPciConfig);
+
+ usPciCommand = pPciConfig->Command;
+
+ if ((usPciCommand & PCI_ENABLE_WRITE_AND_INVALIDATE) && (FdoData->MWIEnable)){
+ FdoData->MWIEnable = TRUE;
+ } else {
+ FdoData->MWIEnable = FALSE;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICGetDeviceInformation\n");
+
+ return status;
+}
+
+NTSTATUS
+NICReadAdapterInfo(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Read the mac addresss from the adapter
+
+Arguments:
+
+ FdoData Pointer to our device context
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ USHORT usValue;
+ int i;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICReadAdapterInfo\n");
+
+ PAGED_CODE();
+
+ FdoData->EepromAddressSize = GetEEpromAddressSize(
+ GetEEpromSize(FdoData, (PUCHAR)FdoData->IoBaseAddress));
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "EepromAddressSize = %d\n",
+ FdoData->EepromAddressSize);
+
+
+ //
+ // Read node address from the EEPROM
+ //
+ for (i=0; i< ETH_LENGTH_OF_ADDRESS; i += 2)
+ {
+ usValue = ReadEEprom(FdoData, (PUCHAR)FdoData->IoBaseAddress,
+ (USHORT)(EEPROM_NODE_ADDRESS_BYTE_0 + (i/2)),
+ FdoData->EepromAddressSize);
+
+ *((PUSHORT)(&FdoData->PermanentAddress[i])) = usValue;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
+ "Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ FdoData->PermanentAddress[0], FdoData->PermanentAddress[1],
+ FdoData->PermanentAddress[2], FdoData->PermanentAddress[3],
+ FdoData->PermanentAddress[4], FdoData->PermanentAddress[5]);
+
+ if (ETH_IS_MULTICAST(FdoData->PermanentAddress) ||
+ ETH_IS_BROADCAST(FdoData->PermanentAddress))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Permanent address is invalid\n");
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+ else
+ {
+ if (!FdoData->bOverrideAddress)
+ {
+ ETH_COPY_NETWORK_ADDRESS(FdoData->CurrentAddress, FdoData->PermanentAddress);
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
+ "Current Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ FdoData->CurrentAddress[0], FdoData->CurrentAddress[1],
+ FdoData->CurrentAddress[2], FdoData->CurrentAddress[3],
+ FdoData->CurrentAddress[4], FdoData->CurrentAddress[5]);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICReadAdapterInfo, status=%x\n",
+ status);
+
+ return status;
+}
+
+
+
+NTSTATUS
+NICAllocAdapterMemory(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Allocate all the memory blocks for send, receive and others
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR pMem;
+ ULONG MemPhys;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICAllocAdapterMemory\n");
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NumTcb=%d\n", FdoData->NumTcb);
+
+ do
+ {
+ //
+ // Send + Misc
+ //
+ //
+ // Allocate MP_TCB's
+ //
+ status = RtlULongMult(FdoData->NumTcb,
+ sizeof(MP_TCB),
+ &FdoData->MpTcbMemSize);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "RtlUlongMult failed 0x%x\n", status);
+ break;
+ }
+
+ pMem = ExAllocatePoolWithTag(NonPagedPool,
+ FdoData->MpTcbMemSize, PCIDRV_POOL_TAG);
+ if (NULL == pMem )
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Failed to allocate MP_TCB's\n");
+ break;
+ }
+
+ RtlZeroMemory(pMem, FdoData->MpTcbMemSize);
+ FdoData->MpTcbMem = pMem;
+
+ // HW_START
+
+ //
+ // Allocate shared memory for send
+ //
+ FdoData->HwSendMemAllocSize = FdoData->NumTcb * (sizeof(TXCB_STRUC) +
+ NIC_MAX_PHYS_BUF_COUNT * sizeof(TBD_STRUC));
+
+ _Analysis_assume_(FdoData->HwSendMemAllocSize > 0);
+ status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler,
+ FdoData->HwSendMemAllocSize,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WdfSendCommonBuffer );
+
+ if (status != STATUS_SUCCESS)
+ {
+ FdoData->HwSendMemAllocSize = 0;
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfCommonBufferCreate(Send) "
+ "failed %08X\n", status );
+ break;
+ }
+
+ FdoData->HwSendMemAllocVa = WdfCommonBufferGetAlignedVirtualAddress(
+ FdoData->WdfSendCommonBuffer);
+
+ FdoData->HwSendMemAllocLa = WdfCommonBufferGetAlignedLogicalAddress(
+ FdoData->WdfSendCommonBuffer);
+
+ RtlZeroMemory(FdoData->HwSendMemAllocVa,
+ FdoData->HwSendMemAllocSize);
+
+ //
+ // Allocate shared memory for other uses
+ //
+ // FIXME-NOTE: The WdfCommonBufferGetAlignedVirtualAddress functions
+ // return device-specified aligned pointers...use them.
+ //
+ FdoData->HwMiscMemAllocSize =
+ sizeof(SELF_TEST_STRUC) + ALIGN_16 +
+ sizeof(DUMP_AREA_STRUC) + ALIGN_16 +
+ sizeof(NON_TRANSMIT_CB) + ALIGN_16 +
+ sizeof(ERR_COUNT_STRUC) + ALIGN_16;
+
+ //
+ // Allocate the shared memory for the command block data structures.
+ //
+ status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler,
+ FdoData->HwMiscMemAllocSize,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &FdoData->WdfMiscCommonBuffer );
+
+ if (status != STATUS_SUCCESS)
+ {
+ FdoData->HwMiscMemAllocSize = 0;
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfCommonBufferCreate(Misc) "
+ "failed %08X\n", status );
+ break;
+ }
+
+ FdoData->HwMiscMemAllocVa = WdfCommonBufferGetAlignedVirtualAddress(
+ FdoData->WdfMiscCommonBuffer);
+
+ FdoData->HwMiscMemAllocLa = WdfCommonBufferGetAlignedLogicalAddress(
+ FdoData->WdfMiscCommonBuffer);
+
+ RtlZeroMemory(FdoData->HwMiscMemAllocVa,
+ FdoData->HwMiscMemAllocSize);
+
+ pMem = FdoData->HwMiscMemAllocVa;
+ MemPhys = FdoData->HwMiscMemAllocLa.LowPart ;
+
+ FdoData->SelfTest = (PSELF_TEST_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
+ FdoData->SelfTestPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
+ pMem = (PUCHAR)FdoData->SelfTest + sizeof(SELF_TEST_STRUC);
+ MemPhys = FdoData->SelfTestPhys + sizeof(SELF_TEST_STRUC);
+
+ FdoData->NonTxCmdBlock = (PNON_TRANSMIT_CB)MP_ALIGNMEM(pMem, ALIGN_16);
+ FdoData->NonTxCmdBlockPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
+ pMem = (PUCHAR)FdoData->NonTxCmdBlock + sizeof(NON_TRANSMIT_CB);
+ MemPhys = FdoData->NonTxCmdBlockPhys + sizeof(NON_TRANSMIT_CB);
+
+ FdoData->DumpSpace = (PDUMP_AREA_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
+ FdoData->DumpSpacePhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
+ pMem = (PUCHAR)FdoData->DumpSpace + sizeof(DUMP_AREA_STRUC);
+ MemPhys = FdoData->DumpSpacePhys + sizeof(DUMP_AREA_STRUC);
+
+ FdoData->StatsCounters = (PERR_COUNT_STRUC)MP_ALIGNMEM(pMem, ALIGN_16);
+ FdoData->StatsCounterPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16);
+
+ // HW_END
+
+ //
+ // Recv
+ //
+
+ // set the max number of RFDs
+ // disable the RFD grow/shrink scheme if user specifies a NumRfd value
+ // larger than NIC_MAX_GROW_RFDS
+ FdoData->MaxNumRfd = max(FdoData->NumRfd, NIC_MAX_GROW_RFDS);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NumRfd = %d\n", FdoData->NumRfd);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "MaxNumRfd = %d\n", FdoData->MaxNumRfd);
+
+ //
+ // The driver should allocate more data than sizeof(RFD_STRUC) to allow the
+ // driver to align the data(after ethernet header) at 8 byte boundary
+ //
+ FdoData->HwRfdSize = sizeof(RFD_STRUC) + MORE_DATA_FOR_ALIGN;
+
+ status = STATUS_SUCCESS;
+
+ } WHILE( FALSE );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "<-- NICAllocAdapterMemory, status=%x\n", status);
+
+ return status;
+
+}
+
+VOID
+NICFreeAdapterMemory(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Free all the resources and MP_ADAPTER data block
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_RFD pMpRfd;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICFreeAdapterMemory\n");
+
+ PAGED_CODE();
+
+ // No active and waiting sends
+ ASSERT(FdoData->nBusySend == 0);
+ ASSERT(FdoData->nWaitSend == 0);
+
+ ASSERT(FdoData->nReadyRecv == FdoData->CurrNumRfd);
+
+ while (!IsListEmpty(&FdoData->RecvList))
+ {
+ pMpRfd = (PMP_RFD)RemoveHeadList(&FdoData->RecvList);
+
+ pMpRfd->DeleteCommonBuffer = FALSE;
+
+ NICFreeRfd(FdoData, pMpRfd);
+ }
+
+ FdoData->WdfSendCommonBuffer = NULL;
+ FdoData->HwSendMemAllocVa = NULL;
+
+ FdoData->WdfMiscCommonBuffer = NULL;
+ FdoData->HwMiscMemAllocVa = NULL;
+ FdoData->SelfTest = NULL;
+ FdoData->StatsCounters = NULL;
+ FdoData->NonTxCmdBlock = NULL;
+ FdoData->DumpSpace = NULL;
+
+ // Free the memory for MP_TCB structures
+ if (FdoData->MpTcbMem)
+ {
+ ExFreePoolWithTag(FdoData->MpTcbMem, PCIDRV_POOL_TAG);
+ FdoData->MpTcbMem = NULL;
+ }
+
+ //Free all the wake up patterns on this adapter
+ NICRemoveAllWakeUpPatterns(FdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICFreeAdapterMemory\n");
+}
+
+
+
+VOID
+NICInitSendBuffers(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Initialize send data structures. Can be called at DISPATCH_LEVEL.
+
+Arguments:
+
+ FdoData - Pointer to our adapter context
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_TCB pMpTcb;
+ PHW_TCB pHwTcb;
+ ULONG HwTcbPhys;
+ ULONG TcbCount;
+
+ PTBD_STRUC pHwTbd;
+ ULONG HwTbdPhys;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitSendBuffers\n");
+
+ FdoData->TransmitIdle = TRUE;
+ FdoData->ResumeWait = TRUE;
+
+ // Setup the initial pointers to the SW and HW TCB data space
+ pMpTcb = (PMP_TCB) FdoData->MpTcbMem;
+ pHwTcb = (PHW_TCB) FdoData->HwSendMemAllocVa;
+ HwTcbPhys = FdoData->HwSendMemAllocLa.LowPart;
+
+ // Setup the initial pointers to the TBD data space.
+ // TBDs are located immediately following the TCBs
+ pHwTbd = (PTBD_STRUC) (FdoData->HwSendMemAllocVa +
+ (sizeof(TXCB_STRUC) * FdoData->NumTcb));
+ HwTbdPhys = HwTcbPhys + (sizeof(TXCB_STRUC) * FdoData->NumTcb);
+
+ _Analysis_assume_(FdoData->HwSendMemAllocSize >= (FdoData->NumTcb * sizeof(HW_TCB)));
+ _Analysis_assume_(FdoData->MpTcbMemSize >= (FdoData->NumTcb * sizeof(MP_TCB)));
+
+ // Go through and set up each TCB
+ for (TcbCount = 0; TcbCount < FdoData->NumTcb; TcbCount++)
+ {
+ pMpTcb->HwTcb = pHwTcb; // save ptr to HW TCB
+ pMpTcb->HwTcbPhys = HwTcbPhys; // save HW TCB physical address
+ pMpTcb->HwTbd = pHwTbd; // save ptr to TBD array
+ pMpTcb->HwTbdPhys = HwTbdPhys; // save TBD array physical address
+
+ if (TcbCount){
+ pMpTcb->PrevHwTcb = pHwTcb - 1;
+ }
+ else {
+ pMpTcb->PrevHwTcb = (PHW_TCB)((PUCHAR)FdoData->HwSendMemAllocVa +
+ ((FdoData->NumTcb - 1) * sizeof(HW_TCB)));
+ }
+ pHwTcb->TxCbHeader.CbStatus = 0; // clear the status
+ pHwTcb->TxCbHeader.CbCommand = CB_EL_BIT | CB_TX_SF_BIT | CB_TRANSMIT;
+
+
+ // Set the link pointer in HW TCB to the next TCB in the chain.
+ // If this is the last TCB in the chain, then set it to the first TCB.
+ if (TcbCount < FdoData->NumTcb - 1)
+ {
+ pMpTcb->Next = pMpTcb + 1;
+ pHwTcb->TxCbHeader.CbLinkPointer = HwTcbPhys + sizeof(HW_TCB);
+ }
+ else
+ {
+ pMpTcb->Next = (PMP_TCB) FdoData->MpTcbMem;
+ pHwTcb->TxCbHeader.CbLinkPointer =
+ FdoData->HwSendMemAllocLa.LowPart;
+ }
+
+ pHwTcb->TxCbThreshold = (UCHAR) FdoData->AiThreshold;
+ pHwTcb->TxCbTbdPointer = HwTbdPhys;
+
+ pMpTcb++;
+ pHwTcb++;
+ HwTcbPhys += sizeof(TXCB_STRUC);
+ pHwTbd = (PTBD_STRUC)((PUCHAR)pHwTbd + sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT);
+ HwTbdPhys += sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT;
+ }
+
+ // set the TCB head/tail indexes
+ // head is the olded one to free, tail is the next one to use
+ FdoData->CurrSendHead = (PMP_TCB) FdoData->MpTcbMem;
+ FdoData->CurrSendTail = (PMP_TCB) FdoData->MpTcbMem;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitSendBuffers\n");
+}
+
+NTSTATUS
+NICInitRecvBuffers(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Initialize receive data structures
+
+Arguments:
+
+ FdoData - Pointer to our adapter context
+
+Return Value:
+
+--*/
+{
+ NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
+ PMP_RFD pMpRfd;
+ ULONG RfdCount;
+ WDFMEMORY memoryHdl;
+ PDRIVER_CONTEXT driverContext = GetDriverContext(WdfGetDriver());
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitRecvBuffers\n");
+
+ PAGED_CODE();
+
+ // Setup each RFD
+ for (RfdCount = 0; RfdCount < FdoData->NumRfd; RfdCount++)
+ {
+ status = WdfMemoryCreateFromLookaside(
+ driverContext->RecvLookaside,
+ &memoryHdl
+ );
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Failed to get lookaside buffer\n");
+ continue;
+ }
+ pMpRfd = WdfMemoryGetBuffer(memoryHdl, NULL);
+ if (!pMpRfd)
+ {
+ //ErrorValue = ERRLOG_OUT_OF_LOOKASIDE_MEMORY;
+ continue;
+ }
+ pMpRfd->LookasideMemoryHdl = memoryHdl;
+ //
+ // Allocate the shared memory for this RFD.
+ //
+ _Analysis_assume_(FdoData->HwRfdSize > 0);
+ status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler,
+ FdoData->HwRfdSize,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &pMpRfd->WdfCommonBuffer );
+
+ if (status != STATUS_SUCCESS)
+ {
+ pMpRfd->WdfCommonBuffer = NULL;
+ WdfObjectDelete(pMpRfd->LookasideMemoryHdl);
+ continue;
+ }
+
+ pMpRfd->OriginalHwRfd =
+ WdfCommonBufferGetAlignedVirtualAddress(pMpRfd->WdfCommonBuffer);
+
+ pMpRfd->OriginalHwRfdLa =
+ WdfCommonBufferGetAlignedLogicalAddress(pMpRfd->WdfCommonBuffer);
+
+ //
+ // Get a 8-byts aligned memory from the original HwRfd
+ //
+ pMpRfd->HwRfd = (PHW_RFD)DATA_ALIGN(pMpRfd->OriginalHwRfd);
+
+ //
+ // Now HwRfd is already 8-bytes aligned, and the size of HwPfd
+ // header(not data part) is a multiple of 8,
+ // If we shift HwRfd 0xA bytes up, the Ethernet header size
+ // is 14 bytes long, then the data will be at
+ // 8 byte boundary.
+ //
+ pMpRfd->HwRfd = (PHW_RFD)((PUCHAR)(pMpRfd->HwRfd) + HWRFD_SHIFT_OFFSET);
+
+ //
+ // Update physical address accordingly
+ //
+ pMpRfd->HwRfdLa.QuadPart = pMpRfd->OriginalHwRfdLa.QuadPart +
+ BYTES_SHIFT(pMpRfd->HwRfd, pMpRfd->OriginalHwRfd);
+
+ status = NICAllocRfd(FdoData, pMpRfd);
+ if (!NT_SUCCESS(status))
+ {
+ WdfObjectDelete(pMpRfd->LookasideMemoryHdl);
+ continue;
+ }
+ //
+ // Add this RFD to the RecvList
+ //
+ FdoData->CurrNumRfd++;
+ NICReturnRFD(FdoData, pMpRfd);
+ }
+
+ if (FdoData->CurrNumRfd > NIC_MIN_RFDS)
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // FdoData->CurrNumRfd < NIC_MIN_RFDs
+ //
+ if (status != STATUS_SUCCESS)
+ {
+ // TODO: Log an entry into the eventlog
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitRecvBuffers, status=%x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+NICAllocRfd(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ )
+/*++
+Routine Description:
+
+ Allocate NDIS_PACKET and NDIS_BUFFER associated with a RFD.
+ Can be called at DISPATCH_LEVEL.
+
+Arguments:
+
+ FdoData Pointer to our adapter
+ pMpRfd pointer to a RFD
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PHW_RFD pHwRfd;
+
+ UNREFERENCED_PARAMETER(FdoData);
+
+ PAGED_CODE();
+
+ do{
+ pHwRfd = pMpRfd->HwRfd;
+ pMpRfd->HwRfdPhys = pMpRfd->HwRfdLa.LowPart;
+
+ pMpRfd->Flags = 0;
+
+ pMpRfd->Mdl = IoAllocateMdl((PVOID)&pHwRfd->RfdBuffer.RxMacHeader,
+ NIC_MAX_PACKET_SIZE,
+ FALSE,
+ FALSE,
+ NULL);
+ if (!pMpRfd->Mdl)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ MmBuildMdlForNonPagedPool(pMpRfd->Mdl);
+
+ pMpRfd->Buffer = &pHwRfd->RfdBuffer.RxMacHeader;
+
+ // Init each RFD header
+ pHwRfd->RfdRbdPointer = DRIVER_NULL;
+ pHwRfd->RfdSize = NIC_MAX_PACKET_SIZE;
+
+ } WHILE (FALSE);
+
+
+ if (!NT_SUCCESS(status))
+ {
+ if (pMpRfd->WdfCommonBuffer)
+ {
+ //
+ // Free HwRfd, we need to free the original memory
+ // pointed by OriginalHwRfd.
+ //
+ WdfObjectDelete( pMpRfd->WdfCommonBuffer );
+
+ pMpRfd->WdfCommonBuffer = NULL;
+ pMpRfd->HwRfd = NULL;
+ pMpRfd->OriginalHwRfd = NULL;
+
+ pMpRfd->DeleteCommonBuffer = TRUE;
+ }
+ }
+
+ return status;
+
+}
+
+VOID
+NICFreeRfd(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ )
+/*++
+Routine Description:
+
+ Free a RFD.
+ Can be called at DISPATCH_LEVEL.
+
+Arguments:
+
+ FdoData Pointer to our adapter
+ pMpRfd Pointer to a RFD
+
+Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER(FdoData);
+ PAGED_CODE();
+
+ ASSERT(pMpRfd->HwRfd);
+ ASSERT(pMpRfd->Mdl);
+
+ IoFreeMdl(pMpRfd->Mdl);
+
+ //
+ // Free HwRfd, we need to free the original memory pointed
+ // by OriginalHwRfd.
+ //
+ if (pMpRfd->DeleteCommonBuffer == TRUE) {
+
+ WdfObjectDelete( pMpRfd->WdfCommonBuffer );
+ }
+
+ pMpRfd->WdfCommonBuffer = NULL;
+ pMpRfd->HwRfd = NULL;
+ pMpRfd->OriginalHwRfd = NULL;
+
+ WdfObjectDelete(pMpRfd->LookasideMemoryHdl);
+}
+
+VOID
+NICAllocRfdWorkItem(
+ IN WDFWORKITEM WorkItem
+)
+/*++
+
+Routine Description:
+
+ Worker routine to allocate memory for RFD at PASSIVE_LEVEL.
+
+Arguments:
+
+ WorkItem - Handle to framework item object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFDO_DATA FdoData;
+ //KIRQL oldIrql;
+ PMP_RFD TempMpRfd;
+ NTSTATUS status;
+ PWORKER_ITEM_CONTEXT item;
+ WDFMEMORY tempMpRfdMemHdl;
+ PDRIVER_CONTEXT driverContext = GetDriverContext(WdfGetDriver());
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICAllocRfdWorkItem\n");
+
+ item = GetWorkItemContext(WorkItem);
+ FdoData = item->FdoData;
+
+ status = WdfMemoryCreateFromLookaside(driverContext->RecvLookaside, &tempMpRfdMemHdl);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Failed to get lookaside buffer\n");
+ return ;
+ }
+ TempMpRfd = WdfMemoryGetBuffer(tempMpRfdMemHdl, NULL);
+ if (TempMpRfd)
+ {
+ TempMpRfd->LookasideMemoryHdl = tempMpRfdMemHdl;
+ //
+ // Allocate the shared memory for this RFD.
+ //
+ _Analysis_assume_(FdoData->HwRfdSize > 0);
+ status = WdfCommonBufferCreate(FdoData->WdfDmaEnabler,
+ FdoData->HwRfdSize,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &TempMpRfd->WdfCommonBuffer);
+
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
+ "WdfCommonBufferCreate failed %X\n", status);
+ WdfObjectDelete(TempMpRfd->LookasideMemoryHdl);
+ goto Exit;
+ }
+
+ TempMpRfd->OriginalHwRfd =
+ WdfCommonBufferGetAlignedVirtualAddress(
+ TempMpRfd->WdfCommonBuffer);
+
+ TempMpRfd->OriginalHwRfdLa =
+ WdfCommonBufferGetAlignedLogicalAddress(
+ TempMpRfd->WdfCommonBuffer);
+
+ //
+ // First get a HwRfd at 8 byte boundary from OriginalHwRfd
+ //
+ TempMpRfd->HwRfd = (PHW_RFD)DATA_ALIGN(TempMpRfd->OriginalHwRfd);
+ //
+ // Then shift HwRfd so that the data(after ethernet header) is at 8 bytes boundary
+ //
+ TempMpRfd->HwRfd = (PHW_RFD)((PUCHAR)TempMpRfd->HwRfd + HWRFD_SHIFT_OFFSET);
+ //
+ // Update physical address as well
+ //
+ TempMpRfd->HwRfdLa.QuadPart = TempMpRfd->OriginalHwRfdLa.QuadPart +
+ BYTES_SHIFT(TempMpRfd->HwRfd, TempMpRfd->OriginalHwRfd);
+
+ status = NICAllocRfd(FdoData, TempMpRfd);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // NICAllocRfd frees common buffer when it returns an TRACE_LEVEL_ERROR.
+ // So, let us not worry about freeing that here.
+ //
+ WdfObjectDelete(TempMpRfd->LookasideMemoryHdl);
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Recv: NICAllocRfd failed %x\n", status);
+ goto Exit;
+ }
+
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ //
+ // Add this RFD to the RecvList
+ //
+ FdoData->CurrNumRfd++;
+ NICReturnRFD(FdoData, TempMpRfd);
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ ASSERT(FdoData->CurrNumRfd <= FdoData->MaxNumRfd);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
+ "CurrNumRfd=%d\n", FdoData->CurrNumRfd);
+
+ }
+
+Exit:
+ FdoData->AllocNewRfd = FALSE;
+
+ WdfObjectDelete(WorkItem);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICAllocRfdWorkItem\n");
+
+ return;
+}
+
+VOID
+NICFreeRfdWorkItem(
+ IN WDFWORKITEM WorkItem
+)
+/*++
+
+Routine Description:
+
+ Worker routine to RFD memory at PASSIVE_LEVEL.
+
+Arguments:
+
+ WorkItem - Handle to framework item object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFDO_DATA fdoData;
+ PMP_RFD pMpRfd;
+ PWORKER_ITEM_CONTEXT item;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICFreeRfdWorkItem\n");
+
+ PAGED_CODE();
+
+ item = GetWorkItemContext(WorkItem);
+ fdoData = item->FdoData;
+ pMpRfd = (PMP_RFD)item->Argument1;
+
+ NICFreeRfd(fdoData, pMpRfd);
+
+ WdfObjectDelete(WorkItem);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICFreeRfdWorkItem\n");
+
+ return;
+}
+
+
+
+NTSTATUS
+NICSelfTest(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Perform a NIC self-test
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ NT status code
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG SelfTestCommandCode;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICSelfTest\n");
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "SelfTest=%p, SelfTestPhys=%x\n",
+ FdoData->SelfTest, FdoData->SelfTestPhys);
+
+ //
+ // Issue a software reset to the adapter
+ //
+ HwSoftwareReset(FdoData);
+
+ //
+ // Execute The PORT Self Test Command On The 82558.
+ //
+ ASSERT(FdoData->SelfTestPhys != 0);
+ SelfTestCommandCode = FdoData->SelfTestPhys;
+
+ //
+ // Setup SELF TEST Command Code in D3 - D0
+ //
+ SelfTestCommandCode |= PORT_SELFTEST;
+
+ //
+ // Initialize the self-test signature and results DWORDS
+ //
+ FdoData->SelfTest->StSignature = 0;
+ FdoData->SelfTest->StResults = 0xffffffff;
+
+ //
+ // Do the port command
+ //
+ FdoData->CSRAddress->Port = SelfTestCommandCode;
+
+ MP_STALL_EXECUTION(NIC_DELAY_POST_SELF_TEST_MS);
+
+ //
+ // if The First Self Test DWORD Still Zero, We've timed out. If the second
+ // DWORD is not zero then we have an TRACE_LEVEL_ERROR.
+ //
+ if ((FdoData->SelfTest->StSignature == 0) || (FdoData->SelfTest->StResults != 0))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "StSignature=%x, StResults=%x\n",
+ FdoData->SelfTest->StSignature, FdoData->SelfTest->StResults);
+
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICSelfTest, status=%x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+NICInitializeAdapter(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Initialize the adapter and set up everything
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ NT Status Code
+
+--*/
+{
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitializeAdapter\n");
+
+ do
+ {
+
+ // set up our link indication variable
+ // it doesn't matter what this is right now because it will be
+ // set correctly if link fails
+ FdoData->MediaState = Connected;
+
+ // Issue a software reset to the D100
+ HwSoftwareReset(FdoData);
+
+ // Load the CU BASE (set to 0, because we use linear mode)
+ FdoData->CSRAddress->ScbGeneralPointer = 0;
+ status = D100IssueScbCommand(FdoData, SCB_CUC_LOAD_BASE, FALSE);
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Wait for the SCB command word to clear before we set the general pointer
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ // Load the RU BASE (set to 0, because we use linear mode)
+ FdoData->CSRAddress->ScbGeneralPointer = 0;
+ status = D100IssueScbCommand(FdoData, SCB_RUC_LOAD_BASE, FALSE);
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Configure the adapter
+ status = HwConfigure(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ status = HwSetupIAAddress(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Clear the internal counters
+ HwClearAllCounters(FdoData);
+
+
+ } WHILE (FALSE);
+
+ if (status != STATUS_SUCCESS)
+ {
+ // TODO: Log an entry into the eventlog
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitializeAdapter, Status=%x\n", status);
+
+ return status;
+}
+
+VOID
+NICShutdown(
+ IN PFDO_DATA FdoData)
+/*++
+
+Routine Description:
+
+ Shutdown the device
+
+Arguments:
+
+ FdoData - Pointer to our adapter
+
+Return Value:
+
+ None
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "---> NICShutdown\n");
+
+ if(FdoData->CSRAddress) {
+ //
+ // Disable interrupt and issue a full reset
+ //
+ NICDisableInterrupt(FdoData);
+ NICIssueFullReset(FdoData);
+ //
+ // Reset the PHY chip. We do this so that after a warm boot, the PHY will
+ // be in a known state, with auto-negotiation enabled.
+ //
+ ResetPhy(FdoData);
+ }
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<--- NICShutdown\n");
+}
+
+VOID
+HwSoftwareReset(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Issue a software reset to the hardware
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ None
+
+--*/
+{
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwSoftwareReset\n");
+
+ // Issue a PORT command with a data word of 0
+ FdoData->CSRAddress->Port = PORT_SOFTWARE_RESET;
+
+ // wait after the port reset command
+ KeStallExecutionProcessor(NIC_DELAY_POST_RESET);
+
+ // Mask off our interrupt line -- its unmasked after reset
+ NICDisableInterrupt(FdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- HwSoftwareReset\n");
+}
+
+
+
+NTSTATUS
+HwConfigure(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Configure the hardware
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ NT Status
+
+
+--*/
+{
+ NTSTATUS status;
+ PCB_HEADER_STRUC NonTxCmdBlockHdr =
+ (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock;
+ UINT i;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwConfigure\n");
+
+ //
+ // Init the packet filter to nothing.
+ //
+ FdoData->OldPacketFilter = FdoData->PacketFilter;
+ FdoData->PacketFilter = 0;
+
+ //
+ // Store the current setting for BROADCAST/PROMISCUOS modes
+ FdoData->OldParameterField = CB_557_CFIG_DEFAULT_PARM15;
+
+ // Setup the non-transmit command block header for the configure command.
+ NonTxCmdBlockHdr->CbStatus = 0;
+ NonTxCmdBlockHdr->CbCommand = CB_CONFIGURE;
+ NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
+
+ // Fill in the configure command data.
+
+ // First fill in the static (end user can't change) config bytes
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = CB_557_CFIG_DEFAULT_PARM21;
+
+ // Now fill in the rest of the configuration bytes (the bytes that contain
+ // user configurable parameters).
+
+ // Set the Tx and Rx Fifo limits
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] =
+ (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo);
+
+ if (FdoData->MWIEnable)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE;
+ }
+
+ // Set the Tx and Rx DMA maximum byte count fields.
+ if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount))
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
+ FdoData->AiRxDmaCount;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
+ (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN);
+ }
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
+ CB_557_CFIG_DEFAULT_PARM4;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
+ CB_557_CFIG_DEFAULT_PARM5;
+ }
+
+
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] =
+ (UCHAR) ((CB_557_CFIG_DEFAULT_PARM7 & (~CB_CFIG_URUN_RETRY)) |
+ (FdoData->AiUnderrunRetry << 1)
+ );
+
+ // Setup for MII or 503 operation. The CRS+CDT bit should only be set
+ // when operating in 503 mode.
+ if (FdoData->PhyAddress == 32)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
+ (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII));
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
+ (CB_557_CFIG_DEFAULT_PARM15 | CB_CFIG_CRS_OR_CDT);
+ }
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
+ (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII);
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
+ ((CB_557_CFIG_DEFAULT_PARM15 & (~CB_CFIG_CRS_OR_CDT)) | CB_CFIG_BROADCAST_DIS);
+ }
+
+
+ // Setup Full duplex stuff
+
+ // If forced to half duplex
+ if (FdoData->AiForceDpx == 1)
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ (CB_557_CFIG_DEFAULT_PARM19 &
+ (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE)));
+
+ // If forced to full duplex
+ else if (FdoData->AiForceDpx == 2)
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
+
+ // If auto-duplex
+ else
+ {
+ // We must force full duplex on if we are using PHY 0, and we are
+ // supposed to run in FDX mode. We do this because the D100 has only
+ // one FDX# input pin, and that pin will be connected to PHY 1.
+ if ((FdoData->PhyAddress == 0) && (FdoData->usDuplexMode == 2))
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
+ else
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ CB_557_CFIG_DEFAULT_PARM19;
+ }
+
+
+ // display the config TRACE_LEVEL_INFORMATION to the debugger
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Issuing Configure command\n");
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Config Block at virt addr %p phys address %x\n",
+ &NonTxCmdBlockHdr->CbStatus, FdoData->NonTxCmdBlockPhys);
+
+ for (i=0; i < CB_CFIG_BYTE_COUNT; i++)
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Config byte %x = %.2x\n",
+ i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]);
+
+ // Wait for the SCB command word to clear before we set the general pointer
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ }
+ else
+ {
+ ASSERT(FdoData->CSRAddress->ScbCommandLow == 0);
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
+
+ // Submit the configure command to the chip, and wait for it to complete.
+ status = D100SubmitCommandBlockAndWait(FdoData);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS,
+ "<-- HwConfigure, Status=%x\n", status);
+
+ return status;
+}
+
+
+NTSTATUS
+HwSetupIAAddress(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Set up the individual MAC address
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ NT Status code
+
+--*/
+{
+ NTSTATUS status;
+ UINT i;
+ PCB_HEADER_STRUC NonTxCmdBlockHdr =
+ (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwSetupIAAddress\n");
+
+ // Individual Address Setup
+ NonTxCmdBlockHdr->CbStatus = 0;
+ NonTxCmdBlockHdr->CbCommand = CB_IA_ADDRESS;
+ NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
+
+ // Copy in the station's individual address
+ for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++)
+ FdoData->NonTxCmdBlock->NonTxCb.Setup.IaAddress[i] = FdoData->CurrentAddress[i];
+
+ // Update the command list pointer. We don't need to do a WaitSCB here
+ // because this command is either issued immediately after a reset, or
+ // after another command that runs in polled mode. This guarantees that
+ // the low byte of the SCB command word will be clear. The only commands
+ // that don't run in polled mode are transmit and RU-start commands.
+ ASSERT(FdoData->CSRAddress->ScbCommandLow == 0);
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
+
+ // Submit the IA configure command to the chip, and wait for it to complete.
+ status = D100SubmitCommandBlockAndWait(FdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- HwSetupIAAddress, Status=%x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+HwClearAllCounters(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This routine will clear the hardware TRACE_LEVEL_ERROR statistic counters
+
+Arguments:
+
+ FdoData Pointer to our adapter
+
+Return Value:
+
+ NT Status code
+
+
+--*/
+{
+ NTSTATUS status;
+ BOOLEAN bResult;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwClearAllCounters\n");
+
+ PAGED_CODE();
+
+ do
+ {
+ // Load the dump counters pointer. Since this command is generated only
+ // after the IA setup has complete, we don't need to wait for the SCB
+ // command word to clear
+ ASSERT(FdoData->CSRAddress->ScbCommandLow == 0);
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->StatsCounterPhys;
+
+ // Issue the load dump counters address command
+ status = D100IssueScbCommand(FdoData, SCB_CUC_DUMP_ADDR, FALSE);
+ if (status != STATUS_SUCCESS)
+ break;
+
+ // Now dump and reset all of the statistics
+ status = D100IssueScbCommand(FdoData, SCB_CUC_DUMP_RST_STAT, TRUE);
+ if (status != STATUS_SUCCESS)
+ break;
+
+ // Now wait for the dump/reset to complete, timeout value 2 secs
+ MP_STALL_AND_WAIT(FdoData->StatsCounters->CommandComplete == 0xA007, 2000, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(FdoData);
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ // init packet counts
+ FdoData->GoodTransmits = 0;
+ FdoData->GoodReceives = 0;
+
+ // init transmit error counts
+ FdoData->TxAbortExcessCollisions = 0;
+ FdoData->TxLateCollisions = 0;
+ FdoData->TxDmaUnderrun = 0;
+ FdoData->TxLostCRS = 0;
+ FdoData->TxOKButDeferred = 0;
+ FdoData->OneRetry = 0;
+ FdoData->MoreThanOneRetry = 0;
+ FdoData->TotalRetries = 0;
+
+ // init receive error counts
+ FdoData->RcvCrcErrors = 0;
+ FdoData->RcvAlignmentErrors = 0;
+ FdoData->RcvResourceErrors = 0;
+ FdoData->RcvDmaOverrunErrors = 0;
+ FdoData->RcvCdtFrames = 0;
+ FdoData->RcvRuntErrors = 0;
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS,
+ "<-- HwClearAllCounters, Status=%x\n", status);
+
+ return status;
+}
+
+VOID
+NICGetDeviceInfSettings(
+ IN OUT PFDO_DATA FdoData
+ )
+{
+
+ //
+ // Number of ReceiveFrameDescriptors
+ //
+ if(!PciDrvReadRegistryValue(FdoData,
+ L"NumRfd",
+ &FdoData->NumRfd)){
+ FdoData->NumRfd = 32;
+ }
+
+ FdoData->NumRfd = min(FdoData->NumRfd, NIC_MAX_RFDS);
+ FdoData->NumRfd = max(FdoData->NumRfd, 1);
+
+ //
+ // Number of Transmit Control Blocks
+ //
+ if(!PciDrvReadRegistryValue(FdoData,
+ L"NumTcb",
+ &FdoData->NumTcb)){
+ FdoData->NumTcb = NIC_DEF_TCBS;
+
+ }
+
+ FdoData->NumTcb = min(FdoData->NumTcb, NIC_MAX_TCBS);
+ FdoData->NumTcb = max(FdoData->NumTcb, 1);
+
+ //
+ // Max number of buffers required for coalescing fragmented packet.
+ // Not implemented in this sample
+ //
+ if(!PciDrvReadRegistryValue(FdoData,
+ L"NumCoalesce",
+ &FdoData->NumBuffers)){
+ FdoData->NumBuffers = 8;
+ }
+
+ FdoData->NumBuffers = min(FdoData->NumBuffers, 32);
+ FdoData->NumBuffers = max(FdoData->NumBuffers, 1);
+
+ //
+ // Get the Link Speed & Duplex.
+ //
+ if(!PciDrvReadRegistryValue(FdoData,
+ L"SpeedDuplex",
+ &FdoData->SpeedDuplex)){
+ FdoData->SpeedDuplex = 0;
+ }
+ FdoData->SpeedDuplex = min(FdoData->SpeedDuplex, 4);
+ FdoData->SpeedDuplex = max(FdoData->SpeedDuplex, 0);
+ //
+ // Decode SpeedDuplex
+ // Value 0 means Auto detect
+ // Value 1 means 10Mb-Half-Duplex
+ // Value 2 means 10Mb-Full-Duplex
+ // Value 3 means 100Mb-Half-Duplex
+ // Value 4 means 100Mb-Full-Duplex
+ //
+ switch(FdoData->SpeedDuplex)
+ {
+ case 1:
+ FdoData->AiTempSpeed = 10; FdoData->AiForceDpx = 1;
+ break;
+
+ case 2:
+ FdoData->AiTempSpeed = 10; FdoData->AiForceDpx = 2;
+ break;
+
+ case 3:
+ FdoData->AiTempSpeed = 100; FdoData->AiForceDpx = 1;
+ break;
+
+ case 4:
+ FdoData->AiTempSpeed = 100; FdoData->AiForceDpx = 2;
+ break;
+ }
+
+ //
+ // Rest of these values are currently not configured thru INF.
+ //
+ FdoData->PhyAddress = 0xFF;
+ FdoData->Connector = 0;
+ FdoData->AiTxFifo = DEFAULT_TX_FIFO_LIMIT;
+ FdoData->AiRxFifo = DEFAULT_RX_FIFO_LIMIT;
+ FdoData->AiTxDmaCount = 0;
+ FdoData->AiRxDmaCount = 0;
+ FdoData->AiUnderrunRetry = DEFAULT_UNDERRUN_RETRY;
+ FdoData->AiThreshold = 200;
+ FdoData->MWIEnable = 1;
+ FdoData->Congest = 0;
+
+ return;
+ }
+
+
diff --git a/general/pcidrv/kmdf/HW/nic_pm.c b/general/pcidrv/kmdf/HW/nic_pm.c
new file mode 100644
index 00000000..7bdd3b99
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_pm.c
@@ -0,0 +1,1710 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "nic_pm.tmh"
+#endif
+
+
+// Things to note:
+// PME_ena bit should be active before the 82558 is set into low power mode
+// Default for WOL should generate wake up event after a HW Reset
+
+// Fixed Packet Filtering
+// Need to verify that the micro code is loaded and Micro Machine is active
+// Clock signal is active on PCI clock
+
+
+// Address Matching
+// Need to enable IAMatch_Wake_En bit and the MCMatch_Wake_En bit is set
+
+// ARP Wakeup
+// Need to set BRCST DISABL bet to 0 (broadcast enable)
+// To handle VLAN set the VLAN_ARP bit
+// IP address needs to be configured with 16 least significant bits
+// Set the IP Address in the IP_Address configuration word.
+
+// Fixed WakeUp Filters:
+// There are 3ight different fixed WakeUp Filters
+// ( Unicast, Multicast, Arp. etc).
+
+
+// Link Status Event
+// Set Link_Status_Wakeup Enable bit.
+
+// Flexible filtering:
+// Supports: ARP packets, Directed, Magic Packet and Link Event
+
+// Flexible Filtering Overview:
+// driver should program micro-code before setting card into low power
+// Incoming packets are compared against the loadable microcode. If PME is
+// is enabled then, the system is woken up.
+
+
+// Segments are defined in book - but not implemented here.
+
+// WakeUp Packet -that causes the machine to wake up will be stored
+// in the Micro Machine temporary storage area so that the driver can read it.
+
+
+// Software Work:
+// Power Down:
+// OS requests the driver to go to a low power state
+// SW sets CU and RU to idle by issuing a Selective Reset to the device
+// 3rd portion .- Wake Up Segments defintion
+// The above three segments are loaded as on chain. The last CB must have
+// its EL bit set.
+// Device can now be powered down.
+// Software driver completes OS request
+// OS then physically switches the Device to low power state
+//
+
+// Power Up:
+// OS powers up the Device
+// driver should NOT initialize the Device. It should NOT issue a Self Test
+// Driver Initiates a PORT DUMP command
+// Device dumps its internal registers including the wakeup frame storage area
+// SW reads the PME register
+// SW reads the WakeUp Frame Data, analyzes it and acts accordingly
+// SW restores its cvonfiguration and and resumes normal operation.
+//
+
+//
+// Power Management definitions from the Intel Handbook
+//
+
+//
+// Definitions from Table 4.2, Pg 4.9
+// of the 10/100 Mbit Ethernet Family Software Technical
+// Reference Manual
+//
+
+#define PMC_Offset 0xDE
+#define E100_PMC_WAKE_FROM_D0 0x1
+#define E100_PMC_WAKE_FROM_D1 0x2
+#define E100_PMC_WAKE_FROM_D2 0x4
+#define E100_PMC_WAKE_FROM_D3HOT 0x8
+#define E100_PMC_WAKE_FROM_D3_AUX 0x10
+
+//
+// Load Programmable filter definintions.
+// Taken from C-19 from the Software Reference Manual.
+// It has examples too. The opcode used for load is 0x80000
+//
+
+#define BIT_15_13 0xA000
+
+#define CB_LOAD_PROG_FILTER BIT_3
+#define CU_LOAD_PROG_FILTER_EL BIT_7
+#define CU_SUCCEED_LOAD_PROG_FILTER BIT_15_13
+#define CB_FILTER_EL BIT_7
+#define CB_FILTER_PREDEFINED_FIX BIT_6
+#define CB_FILTER_ARP_WAKEUP BIT_3
+#define CB_FILTER_IA_WAKEUP BIT_1
+
+#define CU_SCB_NULL ((UINT)-1)
+
+
+#pragma pack( push, enter_include1, 1 )
+
+//
+// Define the PM Capabilities register in the device
+// portion of the PCI config space
+//
+typedef struct _MP_PM_CAP_REG {
+
+ #pragma warning(disable:4214) // bit field types other than int warning
+
+ USHORT UnInteresting:11;
+ USHORT PME_Support:5;
+
+ #pragma warning(default:4214)
+
+} MP_PM_CAP_REG;
+
+
+//
+// Define the PM Control/Status Register
+//
+typedef struct _MP_PMCSR {
+
+ #pragma warning(disable:4214) // bit field types other than int warning
+
+ USHORT PowerState:2; // Power State;
+ USHORT Res:2; // reserved
+ USHORT DynData:1; // Ignored
+ USHORT Res1:3; // Reserved
+ USHORT PME_En:1; // Enable device to set the PME Event;
+ USHORT DataSel:4; // Unused
+ USHORT DataScale:2; // Data Scale - Unused
+ USHORT PME_Status:1; // PME Status - Sticky bit;
+
+ #pragma warning(default:4214)
+
+} MP_PMCSR ;
+
+typedef struct _MP_PM_PCI_SPACE {
+
+ UCHAR Stuff[PMC_Offset];
+
+ // PM capabilites
+
+ MP_PM_CAP_REG PMCaps;
+
+ // PM Control Status Register
+
+ MP_PMCSR PMCSR;
+
+
+} MP_PM_PCI_SPACE , *PMP_PM_PCI_SPACE ;
+
+
+//
+// This is the Programmable Filter Command Structure
+//
+typedef struct _MP_PROG_FILTER_COMM_STRUCT
+{
+ // CB Status Word
+ USHORT CBStatus;
+
+ // CB Command Word
+ USHORT CBCommand;
+
+ //Next CB PTR == ffff ffff
+ ULONG NextCBPTR;
+
+ //Programmable Filters
+ ULONG FilterData[16];
+
+
+} MP_PROG_FILTER_COMM_STRUCT,*PMP_PROG_FILTER_COMM_STRUCT;
+
+typedef struct _MP_PMDR
+{
+ #pragma warning(disable:4214) // bit field types other than int warning
+
+ // Status of the PME bit
+ UCHAR PMEStatus:1;
+
+ // Is the TCO busy
+ UCHAR TCORequest:1;
+
+ // Force TCO indication
+ UCHAR TCOForce:1;
+
+ // Is the TCO Ready
+ UCHAR TCOReady:1;
+
+ // Reserved
+ UCHAR Reserved:1;
+
+ // Has an InterestingPacket been received
+ UCHAR InterestingPacket:1;
+
+ // Has a Magic Packet been received
+ UCHAR MagicPacket:1;
+
+ // Has the Link Status been changed
+ UCHAR LinkStatus:1;
+
+ #pragma warning(default:4214)
+
+} MP_PMDR , *PMP_PMDR;
+
+//-------------------------------------------------------------------------
+// Structure used to set up a programmable filter.
+// This is overlayed over the Control/Status Register (CSR)
+//-------------------------------------------------------------------------
+typedef struct _CSR_FILTER_STRUC {
+
+ // Status- used to verify if the load prog filter command
+ // has been accepted .set to 0xa000
+ USHORT ScbStatus; // SCB Status register
+
+ // Set to an opcode of 0x8
+ //
+ UCHAR ScbCommandLow; // SCB Command register (low byte)
+
+ // 80. Low + High gives the required opcode 0x80080000
+ UCHAR ScbCommandHigh; // SCB Command register (high byte)
+
+ // Set to NULL ff ff ff ff
+ ULONG NextPointer; // SCB General pointer
+
+ // Set to a hardcoded filter, Arp + IA Match, + IP address
+
+ union
+ {
+ ULONG u32;
+
+ struct {
+ UCHAR IPAddress[2];
+ UCHAR Reserved;
+ UCHAR Set;
+
+ }PreDefined;
+
+ }Programmable; // Wake UP Filter union
+
+} CSR_FILTER_STRUC, *PCSR_FILTER_STRUC;
+
+#pragma pack( pop, enter_include1 )
+
+#define MP_CLEAR_PMDR(pPMDR) (*pPMDR) = ((*pPMDR) | 0xe0); // clear the 3 uppermost bits in the PMDR
+
+
+//-------------------------------------------------------------------------
+// L O C A L P R O T O T Y P E S
+//-------------------------------------------------------------------------
+
+__inline
+NTSTATUS
+MPIssueScbPoMgmtCommand(
+ IN PFDO_DATA Adapter,
+ IN PCSR_FILTER_STRUC pFilter,
+ IN BOOLEAN WaitForScb
+ );
+
+
+VOID
+MPCreateProgrammableFilter (
+ IN PMP_WAKE_PATTERN pMpWakePattern ,
+ IN PUCHAR pFilter,
+ IN OUT PULONG pNext
+ );
+
+
+
+//-------------------------------------------------------------------------
+// P O W E R M G M T F U N C T I O N S
+//-------------------------------------------------------------------------
+
+PUCHAR
+HwReadPowerPMDR(
+ IN PFDO_DATA Adapter
+ )
+/*++
+Routine Description:
+
+ This routine will read Hardware's PM registers
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+ STATUS_SUCCESS
+ NTSTATUS_HARD_ERRORS
+
+--*/
+{
+ UCHAR PMDR =0;
+ PUCHAR pPMDR = NULL;
+
+#define CSR_SIZE sizeof (*Adapter->CSRAddress)
+
+
+
+ ASSERT (CSR_SIZE == 0x18);
+
+ pPMDR = 0x18 + (PUCHAR)Adapter->CSRAddress ;
+
+ PMDR = *pPMDR;
+
+ return pPMDR;
+
+}
+
+
+NTSTATUS
+MpClearPME_En (
+ IN PFDO_DATA FdoData,
+ IN MP_PMCSR PMCSR
+ )
+{
+ NTSTATUS status;
+ UINT ulResult;
+
+ PMCSR.PME_En = 0;
+
+ ulResult = FdoData->BusInterface.SetBusData(
+ FdoData->BusInterface.Context,
+ PCI_WHICHSPACE_CONFIG,
+ (PVOID)&PMCSR,
+ FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
+ sizeof(PMCSR));
+
+ ASSERT (ulResult == sizeof(PMCSR));
+ if (ulResult == sizeof(PMCSR)) {
+ status = STATUS_SUCCESS;
+
+ } else {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return status;
+}
+
+
+
+VOID
+MPSetPowerLowPrivate(
+ WDFINTERRUPT WdfInterrupt,
+ PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ The section follows the steps mentioned in
+ Section C.2.6.2 of the Reference Manual.
+
+
+Arguments:
+
+ Adapter Pointer to our adapter
+
+Return Value:
+
+--*/
+{
+ CSR_FILTER_STRUC Filter;
+ USHORT IntStatus;
+ MP_PMCSR PMCSR = {0};
+ ULONG ulResult;
+
+ UNREFERENCED_PARAMETER( WdfInterrupt );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "-->MPSetPowerLowPrivate\n");
+ RtlZeroMemory (&Filter, sizeof (Filter));
+
+ //
+ // Before issue the command to low power state, we should ack all the
+ // pending interrupts, then set the adapter's power to low state.
+ //
+ NIC_ACK_INTERRUPT(FdoData, IntStatus);
+
+ //
+ // If the driver should wake up the machine
+ //
+ if (FdoData->AllowWakeArming)
+ {
+ //
+ // Send the WakeUp Pattern to the nic
+ MPIssueScbPoMgmtCommand(FdoData, &Filter, TRUE);
+
+
+ //
+ // Section C.2.6.2 - The driver needs to wait for the CU to idle
+ // The above function already waits for the CU to idle
+ //
+ ASSERT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_IDLE);
+ }
+ else
+ {
+
+ ulResult = FdoData->BusInterface.GetBusData(
+ FdoData->BusInterface.Context,
+ PCI_WHICHSPACE_CONFIG,
+ (PVOID)&PMCSR,
+ FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
+ sizeof(PMCSR));
+
+ if(ulResult != sizeof(PMCSR)){
+ ASSERT(ulResult == sizeof(PMCSR));
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "GetBusData for PMCSR failed\n");
+ return;
+ }
+ if (PMCSR.PME_En == 1)
+ {
+ //
+ // PME is enabled. Clear the PME_En bit.
+ // So that it is not asserted
+ //
+ MpClearPME_En (FdoData,PMCSR);
+
+ }
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<--MPSetPowerLowPrivate\n");
+
+}
+
+NTSTATUS
+MPSetPowerD0Private (
+ IN PFDO_DATA FdoData
+ )
+{
+ PUCHAR pPMDR;
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "-->MPSetPowerD0Private\n");
+
+ // Dump the packet if necessary
+ //Cause of Wake Up
+
+ pPMDR = HwReadPowerPMDR(FdoData);
+
+ status = NICInitializeAdapter(FdoData);
+
+ // Clear the PMDR
+ MP_CLEAR_PMDR(pPMDR);
+
+ NICIssueSelectiveReset(FdoData);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<--MPSetPowerD0Private\n");
+
+ return status;
+}
+
+
+VOID
+HwSetWakeUpConfigure(
+ IN PFDO_DATA FdoData,
+ PUCHAR pPoMgmtConfigType,
+ UINT WakeUpParameter
+ )
+{
+ UNREFERENCED_PARAMETER( WakeUpParameter );
+
+ if (IsPoMgmtSupported( FdoData) == TRUE)
+ {
+ (*pPoMgmtConfigType)= ((*pPoMgmtConfigType) |
+ CB_WAKE_ON_LINK_BYTE9 |
+ CB_WAKE_ON_ARP_PKT_BYTE9 );
+ }
+}
+
+NTSTATUS
+MPSetUpFilterCB(
+ IN PFDO_DATA FdoData
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock;
+ PFILTER_CB_STRUC pFilterCb = (PFILTER_CB_STRUC)NonTxCmdBlockHdr;
+ ULONG Curr = 0;
+ ULONG Next = 0;
+ PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPSetUpFilterCB\n");
+
+ RtlZeroMemory (pFilterCb, sizeof(*pFilterCb));
+
+ // Individual Address Setup
+ NonTxCmdBlockHdr->CbStatus = 0;
+ NonTxCmdBlockHdr->CbCommand = CB_EL_BIT | CB_LOAD_PROG_FILTER;
+ NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
+
+ // go through each filter in the list.
+
+ while (pPatternEntry != (&FdoData->PoMgmt.PatternList))
+ {
+ PMP_WAKE_PATTERN pWakeUpPattern = NULL;
+ //PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;;
+
+ // initialize local variables
+ pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry);
+
+ // increment the iterator
+ pPatternEntry = ListNext (pPatternEntry);
+
+ // Update the Curr Array Pointer
+ Curr = Next;
+
+ // Create the Programmable filter for this device.
+ MPCreateProgrammableFilter (pWakeUpPattern , (PUCHAR)&pFilterCb->Pattern[Curr], &Next);
+
+ if (Next >=16)
+ {
+ break;
+ }
+
+ }
+
+ {
+ // Set the EL bit on the last pattern
+ PUCHAR pLastPattern = (PUCHAR) &pFilterCb->Pattern[Curr];
+
+ // Get to bit 31
+ pLastPattern[3] |= CB_FILTER_EL ;
+
+
+ }
+
+ ASSERT(FdoData->CSRAddress->ScbCommandLow == 0);
+
+ // Wait for the CU to Idle before giving it this command
+ if(!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPSetUpFilterCB\n");
+
+ return status;
+
+
+}
+
+NTSTATUS
+MPIssueScbPoMgmtCommand(
+ IN PFDO_DATA FdoData,
+ IN PCSR_FILTER_STRUC pNewFilter,
+ IN BOOLEAN WaitForScb
+ )
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ UNREFERENCED_PARAMETER( pNewFilter );
+ UNREFERENCED_PARAMETER( WaitForScb );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,
+ "--> MPIssueScbPoMgmtCommand\n");
+
+ do
+ {
+ // Set up SCB to issue this command
+
+ status = MPSetUpFilterCB(FdoData);
+
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Submit the configure command to the chip, and wait for
+ // it to complete.
+
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
+
+ status = D100SubmitCommandBlockAndWait(FdoData);
+
+ if(status != STATUS_SUCCESS)
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,
+ "<-- MPIssueScbPoMgmtCommand %x\n", status);
+
+ return status;
+}
+
+
+
+NTSTATUS
+MPCalculateE100PatternForFilter (
+ IN PUCHAR pFrame,
+ IN ULONG FrameLength,
+ IN PUCHAR pMask,
+ IN ULONG MaskLength,
+ OUT PULONG pSignature
+ )
+/*++
+Routine Description:
+
+ This function outputs the E100 specific Pattern Signature
+ used to wake up the machine.
+
+ Section C.2.4 - CRC word calculation of a Flexible Filer
+
+
+Arguments:
+
+ pFrame - Pattern Set by the protocols
+ FrameLength - Length of the Pattern
+ pMask - Mask set by the Protocols
+ MaskLength - Length of the Mask
+ pSignature - caller allocated return structure
+
+Return Value:
+ Returns Success
+ Failure - if the Pattern is greater than 129 bytes
+
+--*/
+{
+
+ const ULONG Coefficients = 0x04c11db7;
+ ULONG Signature = 0;
+ ULONG n = 0;
+ ULONG i= 0;
+ PUCHAR pCurrentMaskByte = pMask - 1; // init to -1
+ ULONG MaskOffset = 0;
+ ULONG BitOffsetInMask = 0;
+ ULONG MaskBit = 0;
+ ULONG ShiftBy = 0;
+ UCHAR FrameByte = 0;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPCalculateE100PatternForFilter\n");
+
+ *pSignature = 0;
+
+ do
+ {
+ if (FrameLength > 128)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ // The E100 driver can only accept 3 DWORDS of Mask in a single pattern
+ if (MaskLength > (3*sizeof(ULONG)))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ for (n=i=0;(n<128) && (n < FrameLength); ++n)
+ {
+
+ // The first half deals with the question -
+ // Is the nth Frame byte to be included in the Filter
+ //
+
+ BitOffsetInMask = (n % 8);
+
+ if (BitOffsetInMask == 0)
+ {
+ //
+ // We need to move to a new byte.
+ // [0] for 0th byte, [1] for 8th byte, [2] for 16th byte, etc.
+ //
+ MaskOffset = n/8; // This is the new byte we need to go
+
+ //
+ //
+ if (MaskOffset == MaskLength)
+ {
+ break;
+ }
+
+ pCurrentMaskByte ++;
+ ASSERT (*pCurrentMaskByte == pMask[n/8]);
+ }
+
+
+ // Now look at the actual bit in the mask
+ MaskBit = 1 << BitOffsetInMask ;
+
+ // If the current Mask Bit is set in the Mask then
+ // we need to use it in the CRC calculation, otherwise we ignore it
+
+ if (! (MaskBit & pCurrentMaskByte[0]))
+ {
+ continue;
+ }
+
+ // We are suppossed to take in the current byte as part of the CRC calculation
+ // Initialize the variables
+ FrameByte = pFrame[n];
+ ShiftBy = (i % 3 ) * 8;
+
+ ASSERT (ShiftBy!= 24); // Bit 24 is never used
+
+ if (Signature & 0x80000000)
+ {
+ Signature = ((Signature << 1) ^ ( FrameByte << ShiftBy) ^ Coefficients);
+ }
+ else
+ {
+ Signature = ((Signature << 1 ) ^ (FrameByte << ShiftBy));
+ }
+ ++i;
+
+ }
+
+ // Clear bits 22-31
+ Signature &= 0x00ffffff;
+
+ // Update the result
+ *pSignature = Signature;
+
+ // We have succeeded
+ status = STATUS_SUCCESS;
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPCalculateE100PatternForFilter\n");
+
+ return status;
+}
+
+
+VOID
+MPCreateProgrammableFilter (
+ IN PMP_WAKE_PATTERN pMpWakePattern ,
+ IN PUCHAR pFilter,
+ IN OUT PULONG pNext
+ )
+/*++
+Routine Description:
+
+ This function outputs the E100 specific Pattern Signature
+ used to wake up the machine.
+
+ Section C.2.4 - Load Programmable Filter page C.20
+
+
+Arguments:
+
+ pMpWakePattern - Filter will be created for this pattern,
+ pFilter - Filter will be stored here,
+ pNext - Used for validation . This Ulong will also be incremented by the size
+ of the filter (in ulongs)
+
+Return Value:
+
+--*/
+{
+ PUCHAR pCurrentByte = pFilter;
+ ULONG NumBytesWritten = 0;
+ PULONG pCurrentUlong = (PULONG)pFilter;
+ PNDIS_PM_PACKET_PATTERN pNdisPattern = (PNDIS_PM_PACKET_PATTERN)(&pMpWakePattern->Pattern[0]);
+ ULONG LengthOfFilter = 0;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPCreateProgrammableFilter\n");
+
+ // Is there enough room for this pattern
+ //
+ {
+ // Length in DWORDS
+ LengthOfFilter = pNdisPattern->MaskSize /4;
+
+ if (pNdisPattern->MaskSize % 4 != 0)
+ {
+ LengthOfFilter++;
+ }
+
+ // Increment LengthOfFilter to account for the 1st DWORD
+ LengthOfFilter++;
+
+ // We are only allowed 16 DWORDS in a filter
+ if (*pNext + LengthOfFilter >= 16)
+ {
+ // Failure - early exit
+ return;
+ }
+
+ }
+ // Clear the Predefined bit; already cleared in the previous function.
+ // first , initialize -
+ *pCurrentUlong = 0;
+
+ // Mask Length goes into Bits 27-29 of the 1st DWORD. MaskSize is measured in DWORDs
+ {
+ ULONG dwMaskSize = pNdisPattern->MaskSize /4;
+ ULONG dwMLen = 0;
+
+
+ // If there is a remainder a remainder then increment
+ if (pNdisPattern->MaskSize % 4 != 0)
+ {
+ dwMaskSize++;
+ }
+
+
+ //
+ // If we fail this assertion, it means our
+ // MaskSize is greater than 16 bytes.
+ // This filter should have been failed upfront at the time of the request
+ //
+
+ ASSERT (0 < dwMaskSize && dwMaskSize < 5);
+ //
+ // In the Spec, 0 - Single DWORD maske, 001 - 2 DWORD mask,
+ // 011 - 3 DWORD mask, 111 - 4 Dword Mask.
+ //
+
+ if (dwMaskSize == 1) dwMLen = 0;
+ if (dwMaskSize == 2) dwMLen = 1;
+ if (dwMaskSize == 3) dwMLen = 3;
+ if (dwMaskSize == 4) dwMLen = 7;
+
+ // Adjust the Mlen, so it is in the correct position
+
+ dwMLen = (dwMLen << 3);
+
+
+
+ if (dwMLen != 0)
+ {
+ ASSERT (dwMLen <= 0x38 && dwMLen >= 0x08);
+ }
+
+ // These go into bits 27,28,29 (bits 3,4 and 5 of the 4th byte)
+ pCurrentByte[3] |= dwMLen ;
+
+
+ }
+
+ // Add the signature to bits 0-23 of the 1st DWORD
+ {
+ PUCHAR pSignature = (PUCHAR)&pMpWakePattern->Signature;
+
+
+ // Bits 0-23 are also the 1st three bytes of the DWORD
+ pCurrentByte[0] = pSignature[0];
+ pCurrentByte[1] = pSignature[1];
+ pCurrentByte[2] = pSignature[2];
+
+ }
+
+
+ // Lets move to the next DWORD. Init variables
+ pCurrentByte += 4 ;
+ NumBytesWritten = 4;
+ pCurrentUlong = (PULONG)pCurrentByte;
+
+ // We Copy in the Mask over here
+ {
+ // The Mask is at the end of the pattern
+
+ PUCHAR pMask = (PUCHAR)pNdisPattern + sizeof(*pNdisPattern);
+
+ //Dump (pMask,pNdisPattern->MaskSize, 0,1);
+
+ RtlMoveMemory (pCurrentByte, pMask, pNdisPattern->MaskSize);
+
+ NumBytesWritten += pNdisPattern->MaskSize;
+
+ }
+
+
+ // Update the output value
+ {
+ ULONG NumUlongs = (NumBytesWritten /4);
+
+ if ((NumBytesWritten %4) != 0)
+ {
+ NumUlongs ++;
+ }
+
+ ASSERT (NumUlongs == LengthOfFilter);
+
+ *pNext = *pNext + NumUlongs;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPCreateProgrammableFilter\n");
+
+ return;
+}
+
+NTSTATUS
+MPSetPowerD0(
+ PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This routine is called when the adapter receives a SetPower
+ to D0.
+
+Arguments:
+
+ Adapter Pointer to the adapter structure
+ PowerState NewPowerState
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ //KIRQL oldIrql;
+
+ //
+ // MPSetPowerD0Private Initializes the adapte, issues a selective reset.
+ //
+ MPSetPowerD0Private (FdoData);
+ ASSERT(FdoData->DevicePowerState == PowerDeviceD0);
+ //
+ // Set up the packet filter
+ //
+
+ WdfSpinLockAcquire(FdoData->Lock);
+ status = NICSetPacketFilter(
+ FdoData,
+ FdoData->OldPacketFilter);
+ //
+ // If Set Packet Filter succeeds, restore the old packet filter
+ //
+ if (status == STATUS_SUCCESS)
+ {
+ FdoData->PacketFilter = FdoData->OldPacketFilter;
+ }
+
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ //
+ // Set up the multicast list address
+ //
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ status = NICSetMulticastList(FdoData);
+
+ NICStartRecv(FdoData);
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ return status;
+}
+
+NTSTATUS
+MPSetPowerLow(
+ PFDO_DATA FdoData,
+ WDF_POWER_DEVICE_STATE PowerState
+ )
+/*++
+Routine Description:
+
+ This routine is called when the FdoData receives a SetPower
+ to a PowerState > D0
+
+Arguments:
+
+ FdoData Pointer to the FdoData structure
+ PowerState NewPowerState
+
+Return Value:
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ STATUS_DEVICE_DATA_ERROR
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER( PowerState );
+
+ //
+ // Stop sending packets. Create a new flag and make it part
+ // of the Send Fail Mask. TODO: Does something need to happen here?
+ //
+
+ //
+ // Stop hardware from receiving packets - Set the RU to idle.
+ // TODO: Does something need to happen here?
+ //
+
+ //
+ // Check the current status of the receive unit
+ //
+ if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
+ {
+ //
+ // Issue an RU abort. Since an interrupt will be issued, the
+ // RU will be started by the DPC.
+ //
+ status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE);
+ }
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ //
+ // MPSetPowerLowPrivate first disables the interrupt, acknowledges all the pending
+ // interrupts and sets FdoData->DevicePowerState to the given low power state
+ // then starts Hardware specific part of the transition to low power state
+ // Setting up wake-up patterns, filters, wake-up events etc
+ //
+ // Interrupt is disabled and disconnected before entering D0Exit, so no need to
+ // sychronize.
+ //
+
+ MPSetPowerLowPrivate(NULL, FdoData);
+
+ return STATUS_SUCCESS;
+}
+
+BOOLEAN
+MPAreTwoPatternsEqual(
+ IN PNDIS_PM_PACKET_PATTERN pNdisPattern1,
+ IN PNDIS_PM_PACKET_PATTERN pNdisPattern2
+ )
+/*++
+Routine Description:
+
+ This routine will compare two wake up patterns to see if they are equal
+
+Arguments:
+
+ pNdisPattern1 - Pattern1
+ pNdisPattern2 - Pattern 2
+
+
+Return Value:
+
+ True - if patterns are equal
+ False - Otherwise
+--*/
+{
+ BOOLEAN bEqual = FALSE;
+
+ // Local variables used later in the compare section of this function
+ PUCHAR pMask1, pMask2;
+ PUCHAR pPattern1, pPattern2;
+ UINT MaskSize, PatternSize;
+
+ do
+ {
+
+ bEqual = (BOOLEAN)(pNdisPattern1->Priority == pNdisPattern2->Priority);
+
+ if (bEqual == FALSE)
+ {
+ break;
+ }
+
+ bEqual = (BOOLEAN)(pNdisPattern1->MaskSize == pNdisPattern2->MaskSize);
+ if (bEqual == FALSE)
+ {
+ break;
+ }
+
+ //
+ // Verify the Mask
+ //
+ MaskSize = pNdisPattern1->MaskSize ;
+ pMask1 = (PUCHAR) pNdisPattern1 + sizeof (NDIS_PM_PACKET_PATTERN);
+ pMask2 = (PUCHAR) pNdisPattern2 + sizeof (NDIS_PM_PACKET_PATTERN);
+
+ bEqual = (BOOLEAN)RtlEqualMemory (pMask1, pMask2, MaskSize);
+
+ if (bEqual == FALSE)
+ {
+ break;
+ }
+
+ //
+ // Verify the Pattern
+ //
+ bEqual = (BOOLEAN)(pNdisPattern1->PatternSize == pNdisPattern2->PatternSize);
+
+ if (bEqual == FALSE)
+ {
+ break;
+ }
+
+ PatternSize = pNdisPattern2->PatternSize;
+ pPattern1 = (PUCHAR) pNdisPattern1 + pNdisPattern1->PatternOffset;
+ pPattern2 = (PUCHAR) pNdisPattern2 + pNdisPattern2->PatternOffset;
+
+ bEqual = (BOOLEAN)RtlEqualMemory (pPattern1, pPattern2, PatternSize );
+
+ if (bEqual == FALSE)
+ {
+ break;
+ }
+
+ } WHILE (FALSE);
+
+ return bEqual;
+}
+
+VOID
+NICExtractPMInfoFromPciSpace(
+ PFDO_DATA FdoData,
+ PUCHAR pPciConfig
+ )
+/*++
+Routine Description:
+
+ Looks at the PM information in the
+ device specific section of the PCI Config space.
+
+ Interprets the register values and stores it
+ in the adapter structure
+
+ Definitions from Table 4.2 & 4.3, Pg 4-9 & 4-10
+ of the 10/100 Mbit Ethernet Family Software Technical
+ Reference Manual
+
+
+Arguments:
+
+ Adapter Pointer to our adapter
+ pPciConfig Pointer to Common Pci Space
+
+Return Value:
+
+--*/
+{
+ PMP_PM_PCI_SPACE pPmPciConfig = (PMP_PM_PCI_SPACE )pPciConfig;
+ MP_PMCSR PMCSR;
+
+ //
+ // First interpret the PM Capabities register
+ //
+ {
+ MP_PM_CAP_REG PmCaps;
+
+ PmCaps = pPmPciConfig->PMCaps;
+
+ if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D0)
+ {
+ FdoData->PoMgmt.bWakeFromD0 = TRUE;
+ }
+
+ if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D1)
+ {
+ FdoData->PoMgmt.bWakeFromD1 = TRUE;
+ }
+
+ if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D2)
+ {
+ FdoData->PoMgmt.bWakeFromD2 = TRUE;
+ }
+
+ if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3HOT)
+ {
+ FdoData->PoMgmt.bWakeFromD3Hot = TRUE;
+ }
+
+ if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3_AUX)
+ {
+ FdoData->PoMgmt.bWakeFromD3Aux = TRUE;
+ }
+
+ }
+
+ //
+ // Interpret the PM Control/Status Register
+ //
+ {
+ PMCSR = pPmPciConfig->PMCSR;
+
+ if (PMCSR.PME_En == 1)
+ {
+ //
+ // PME is enabled. Clear the PME_En bit.
+ // So that it is not asserted
+ //
+ MpClearPME_En (FdoData,PMCSR);
+
+ }
+
+ }
+
+}
+
+
+NTSTATUS
+NICSetPower(
+ PFDO_DATA FdoData ,
+ WDF_POWER_DEVICE_STATE PowerState
+ )
+/*++
+Routine Description:
+
+ This routine is called when the FdoData receives a SetPower
+ request. It redirects the call to an appropriate routine to
+ Set the New PowerState
+
+Arguments:
+
+ FdoData Pointer to the FdoData structure
+ PowerState NewPowerState
+
+Return Value:
+
+ NTSTATUS Code
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if(IsPoMgmtSupported(FdoData)){
+
+ if (PowerState == PowerDeviceD0)
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering fully on state\n");
+ MPSetPowerD0 (FdoData);
+ }
+ else
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering a deeper sleep state\n");
+ status = MPSetPowerLow (FdoData, PowerState);
+ }
+ }
+
+ return status;
+}
+
+
+
+NTSTATUS
+NICAddWakeUpPattern(
+ IN PFDO_DATA FdoData,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+Routine Description:
+
+ This routine will allocate a local memory structure, copy the pattern,
+ insert the pattern into a linked list and return success
+
+ We are gauranteed that we wll get only one request at a time, so this is implemented
+ without locks.
+
+Arguments:
+
+ FdoData FdoData structure
+ InformationBuffer Wake up Pattern
+ InformationBufferLength Wake Up Pattern Length
+
+Return Value:
+
+ STATUS_Success - if successful.
+ STATUS_UNSUCCESSFUL - if memory allocation fails.
+
+--*/
+{
+
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ PMP_WAKE_PATTERN pWakeUpPattern = NULL;
+ ULONG AllocationLength = 0;
+ PNDIS_PM_PACKET_PATTERN pPmPattern = NULL;
+ ULONG Signature = 0;
+ ULONG CopyLength = 0;
+ ULONG safeAddResult;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICAddWakeUpPattern\n");
+
+ do
+ {
+
+ if(!FdoData->AllowWakeArming) {
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ pPmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
+
+ if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
+ break;
+ }
+
+ //
+ // safeAddResult = pPmPattern->PatternOffset + pPmPattern->PatternSize
+ //
+ status = RtlULongAdd(
+ pPmPattern->PatternOffset,
+ pPmPattern->PatternSize,
+ &safeAddResult) ;
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+ if (InformationBufferLength < safeAddResult)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ *BytesNeeded = safeAddResult;
+ break;
+ }
+
+ *BytesRead = safeAddResult;
+
+
+ //
+ // Calculate the e100 signature
+ //
+ status = MPCalculateE100PatternForFilter (
+ (PUCHAR)pPmPattern+ pPmPattern->PatternOffset,
+ pPmPattern->PatternSize,
+ (PUCHAR)pPmPattern +sizeof(NDIS_PM_PACKET_PATTERN),
+ pPmPattern->MaskSize,
+ &Signature );
+
+ if ( status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ CopyLength = safeAddResult;
+
+ //
+ // Allocate the memory to hold the WakeUp Pattern
+ //
+ // AllocationLength = sizeof (MP_WAKE_PATTERN) + CopyLength;
+ //
+ status = RtlULongAdd(
+ sizeof(MP_WAKE_PATTERN),
+ CopyLength,
+ &AllocationLength);
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+ pWakeUpPattern = ExAllocatePoolWithTag(NonPagedPool, AllocationLength, PCIDRV_POOL_TAG);
+
+ if (!pWakeUpPattern)
+ {
+ break;
+ }
+
+ //
+ // Initialize pWakeUpPattern
+ //
+ RtlZeroMemory (pWakeUpPattern, AllocationLength);
+
+ pWakeUpPattern->AllocationSize = AllocationLength;
+
+ pWakeUpPattern->Signature = Signature;
+
+ //
+ // Copy the pattern into local memory
+ //
+ RtlMoveMemory (&pWakeUpPattern->Pattern[0], InformationBuffer, CopyLength);
+
+ ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
+
+ //
+ // Insert the pattern into the list
+ //
+ /* ExInterlockedInsertHeadList (&FdoData->PoMgmt.PatternList,
+ &pWakeUpPattern->linkListEntry,
+ &FdoData->Lock);
+ */
+
+ WdfSpinLockAcquire(FdoData->Lock);
+ InsertHeadList(&FdoData->PoMgmt.PatternList,&pWakeUpPattern->linkListEntry );
+ WdfSpinLockRelease(FdoData->Lock);
+
+
+ status = STATUS_SUCCESS;
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICAddWakeUpPattern\n");
+
+ return status;
+}
+
+NTSTATUS
+NICRemoveWakeUpPattern(
+ IN PFDO_DATA FdoData,
+ IN PVOID InformationBuffer,
+ IN UINT InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+Routine Description:
+
+ This routine will walk the list of wake up pattern and attempt to match the wake up pattern.
+ If it finds a copy , it will remove that WakeUpPattern
+
+Arguments:
+
+ FdoData FdoData structure
+ InformationBuffer Wake up Pattern
+ InformationBufferLength Wake Up Pattern Length
+
+Return Value:
+
+ Success - if successful.
+ STATUS_UNSUCCESSFUL - if memory allocation fails.
+
+--*/
+{
+
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ PNDIS_PM_PACKET_PATTERN pReqPattern = (PNDIS_PM_PACKET_PATTERN)InformationBuffer;
+ PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICRemoveWakeUpPattern\n");
+
+ do
+ {
+ if(!FdoData->AllowWakeArming) {
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
+ break;
+ }
+ if (InformationBufferLength < pReqPattern->PatternOffset + pReqPattern->PatternSize)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ *BytesNeeded = pReqPattern->PatternOffset + pReqPattern->PatternSize;
+ break;
+ }
+
+ *BytesRead = pReqPattern->PatternOffset + pReqPattern->PatternSize;
+
+ while (pPatternEntry != (&FdoData->PoMgmt.PatternList))
+ {
+ BOOLEAN bIsThisThePattern = FALSE;
+ PMP_WAKE_PATTERN pWakeUpPattern = NULL;
+ PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;;
+
+ //
+ // initialize local variables
+ //
+ pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry);
+
+ pCurrPattern = (PNDIS_PM_PACKET_PATTERN)&pWakeUpPattern->Pattern[0];
+
+ //
+ // increment the iterator
+ //
+ pPatternEntry = ListNext (pPatternEntry);
+
+ //
+ // Begin Check : Is (pCurrPattern == pReqPattern)
+ //
+ bIsThisThePattern = MPAreTwoPatternsEqual(pReqPattern, pCurrPattern);
+
+
+ if (bIsThisThePattern == TRUE)
+ {
+ //
+ // we have a match - remove the entry
+ //
+ RemoveEntryList (&pWakeUpPattern->linkListEntry);
+
+ //
+ // Free the entry
+ //
+ ExFreePoolWithTag(pWakeUpPattern, PCIDRV_POOL_TAG);
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ }
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICRemoveWakeUpPattern\n");
+
+ return status;
+}
+
+
+
+VOID
+NICRemoveAllWakeUpPatterns(
+ PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This routine will walk the list of wake up pattern and free it
+
+Arguments:
+
+ FdoData FdoData structure
+
+Return Value:
+
+ Success - if successful.
+
+--*/
+{
+
+ PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICRemoveAllWakeUpPatterns\n");
+
+ while (pPatternEntry != (&FdoData->PoMgmt.PatternList))
+ {
+ PMP_WAKE_PATTERN pWakeUpPattern = NULL;
+
+ //
+ // initialize local variables
+ //
+ pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN,linkListEntry);
+
+ //
+ // increment the iterator
+ //
+ pPatternEntry = ListNext (pPatternEntry);
+
+ //
+ // Remove the entry from the list
+ //
+ RemoveEntryList (&pWakeUpPattern->linkListEntry);
+
+ //
+ // Free the memory
+ //
+ ExFreePoolWithTag(pWakeUpPattern, PCIDRV_POOL_TAG);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICRemoveAllWakeUpPatterns\n");
+
+}
+
+
+NTSTATUS
+NICConfigureForWakeUp(
+ IN PFDO_DATA FdoData,
+ IN BOOLEAN AddPattern
+ )
+/*++
+Routine Description:
+
+
+Arguments:
+
+ FdoData FdoData structure
+
+Return Value:
+
+ Success - if successful.
+
+--*/
+{
+#define MAX_WAKEUP_PATTERN_LENGTH 128
+
+ UCHAR Buffer[sizeof(NDIS_PM_PACKET_PATTERN) +
+ MAX_WAKEUP_PATTERN_LENGTH];
+ PCHAR patternBuffer, nextMask, nextPattern;
+ ULONG maskLen;
+ PNDIS_PM_PACKET_PATTERN ndisPattern;
+ ULONG bufLen;
+ NTSTATUS status;
+ ULONG unUsed;
+ CHAR wakePattern[]={0xff,0xff,0xff,0xff,0xff,0xff}; //broadcast address
+
+ patternBuffer = (PCHAR)&Buffer[0];
+
+ ndisPattern = (PNDIS_PM_PACKET_PATTERN)patternBuffer;
+ RtlZeroMemory(ndisPattern, sizeof(NDIS_PM_PACKET_PATTERN));
+
+
+ ndisPattern->PatternSize = sizeof(wakePattern);
+
+ maskLen = (ndisPattern->PatternSize-1)/8 + 1;
+
+ nextMask = (PCHAR)patternBuffer + sizeof(NDIS_PM_PACKET_PATTERN);
+
+ nextPattern = nextMask + maskLen;
+
+ *nextMask = 0x3f;
+
+ ndisPattern->MaskSize = maskLen;
+ ndisPattern->PatternOffset = (ULONG) ((ULONG_PTR) nextPattern - (ULONG_PTR) patternBuffer);
+
+ bufLen = sizeof(NDIS_PM_PACKET_PATTERN) + maskLen + ndisPattern->PatternSize;
+
+ RtlCopyMemory(nextPattern, FdoData->CurrentAddress, ETHERNET_ADDRESS_LENGTH);
+
+ if(AddPattern){
+ status = NICAddWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICAddWakeupPattern failed %x\n", status);
+ }
+ }else{
+ status = NICRemoveWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICRemoveWakeUpPattern failed %x\n", status);
+ }
+ }
+
+ return status;
+}
+
+#if 0
+NTSTATUS
+NICConfigureForWakeUp(
+ IN PFDO_DATA FdoData,
+ IN BOOLEAN AddPattern
+ )
+{
+#define MAX_WAKEUP_PATTERN_LENGTH 128
+#define ETHER_IP_ICMP_HEADER_SIZE 14+20+8
+
+ UCHAR Buffer[sizeof(NDIS_PM_PACKET_PATTERN) +
+ MAX_WAKEUP_PATTERN_LENGTH];
+ PCHAR patternBuffer, nextMask, nextPattern;
+ ULONG maskLen;
+ PNDIS_PM_PACKET_PATTERN ndisPattern;
+ ULONG bufLen;
+ NTSTATUS status;
+ ULONG unUsed;
+ CHAR pingPattern[]={'a','b','c','d','e','f','g','h'};
+
+ patternBuffer = (PCHAR)&Buffer[0];
+
+ ndisPattern = (PNDIS_PM_PACKET_PATTERN)patternBuffer;
+ RtlZeroMemory(ndisPattern, sizeof(NDIS_PM_PACKET_PATTERN));
+
+
+ ndisPattern->PatternSize = ETHER_IP_ICMP_HEADER_SIZE + sizeof(pingPattern);
+
+ maskLen = (ndisPattern->PatternSize-1)/8 + 1;
+
+ nextMask = (PCHAR)patternBuffer + sizeof(NDIS_PM_PACKET_PATTERN);
+
+ nextPattern = nextMask + maskLen;
+
+ *nextMask = 0x0;nextMask++;
+ *nextMask = 0x0;nextMask++;
+ *nextMask = 0x0;nextMask++;
+ *nextMask = 0x0;nextMask++;
+ *nextMask = 0x0;nextMask++;
+ *nextMask = 0x3f;nextMask++;
+ *nextMask = 0x0C;
+
+ ndisPattern->MaskSize = maskLen;
+ ndisPattern->PatternOffset = (ULONG) ((ULONG_PTR) nextPattern - (ULONG_PTR) patternBuffer);
+
+ bufLen = sizeof(NDIS_PM_PACKET_PATTERN) + maskLen + ndisPattern->PatternSize;
+
+ RtlZeroMemory(nextPattern, ETHER_IP_ICMP_HEADER_SIZE);
+ nextPattern += ETHER_IP_ICMP_HEADER_SIZE;
+
+ RtlCopyMemory(nextPattern, pingPattern, sizeof(pingPattern));
+
+ if(AddPattern){
+ status = MPAddWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "MpAddWakeupPattern failed %x\n", status);
+ }
+ }else{
+ status = MPRemoveWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "MPRemoveWakeUpPattern failed %x\n", status);
+ }
+ }
+
+ return status;
+}
+
+#endif
+
+
diff --git a/general/pcidrv/kmdf/HW/nic_recv.c b/general/pcidrv/kmdf/HW/nic_recv.c
new file mode 100644
index 00000000..41cc0ec7
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_recv.c
@@ -0,0 +1,630 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+ NIC_RECV.C
+
+Abstract:
+ This module contains miniport receive routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "nic_recv.tmh"
+#endif
+
+
+_IRQL_requires_same_
+_IRQL_requires_(DISPATCH_LEVEL)
+_Requires_lock_held_(FdoData->RcvLock)
+VOID
+NICHandleRecvInterrupt(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Interrupt handler for receive processing. Put the received packets
+ into an array and call NICServiceReadIrps. If we run low on
+ RFDs, allocate another one.
+
+ Assumption: This function is called with the Rcv SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_RFD pMpRfd = NULL;
+ PHW_RFD pHwRfd = NULL;
+
+ PMP_RFD PacketArray[NIC_DEF_RFDS];
+ PMP_RFD PacketFreeArray[NIC_DEF_RFDS];
+ UINT PacketArrayCount;
+ UINT PacketFreeCount;
+ UINT Index;
+ UINT LoopIndex = 0;
+ UINT LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1; // avoid staying here too long
+
+ BOOLEAN bContinue = TRUE;
+ BOOLEAN bAllocNewRfd = FALSE;
+ USHORT PacketStatus;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICHandleRecvInterrupt\n");
+
+ ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);
+
+ while (LoopIndex++ < LoopCount && bContinue)
+ {
+ PacketArrayCount = 0;
+ PacketFreeCount = 0;
+
+ //
+ // Process up to the array size RFD's
+ //
+ while (PacketArrayCount < NIC_DEF_RFDS)
+ {
+ if (IsListEmpty(&FdoData->RecvList))
+ {
+ ASSERT(FdoData->nReadyRecv == 0);
+ bContinue = FALSE;
+ break;
+ }
+
+ //
+ // Get the next MP_RFD to process
+ //
+ pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
+
+ //
+ // Get the associated HW_RFD
+ //
+ pHwRfd = pMpRfd->HwRfd;
+
+ //
+ // Is this packet completed?
+ //
+ PacketStatus = NIC_RFD_GET_STATUS(pHwRfd);
+ if (!NIC_RFD_STATUS_COMPLETED(PacketStatus))
+ {
+ bContinue = FALSE;
+ break;
+ }
+
+ //
+ // HW specific - check if actual count field has been updated
+ //
+ if (!NIC_RFD_VALID_ACTUALCOUNT(pHwRfd))
+ {
+ bContinue = FALSE;
+ break;
+ }
+
+
+ //
+ // Remove the RFD from the head of the List
+ //
+ RemoveEntryList((PLIST_ENTRY)pMpRfd);
+ FdoData->nReadyRecv--;
+
+ ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY));
+ MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY);
+
+ //
+ // A good packet? drop it if not.
+ //
+ if (!NIC_RFD_STATUS_SUCCESS(PacketStatus))
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_READ,
+ "Receive failure = %x\n", PacketStatus);
+ NICReturnRFD(FdoData, pMpRfd);
+ continue;
+ }
+
+ //
+ // Do not receive any packets until a filter has been set
+ //
+ if (!FdoData->PacketFilter)
+ {
+ NICReturnRFD(FdoData, pMpRfd);
+ continue;
+ }
+
+ //
+ // Do not receive any packets until we are at D0
+ //
+ if (FdoData->DevicePowerState != PowerDeviceD0)
+ {
+ NICReturnRFD(FdoData, pMpRfd);
+ continue;
+ }
+
+ pMpRfd->PacketSize = NIC_RFD_GET_PACKET_SIZE(pHwRfd);
+
+ KeFlushIoBuffers(pMpRfd->Mdl, TRUE, TRUE);
+
+ //
+ // set the status on the packet, either resources or success
+ //
+ if (FdoData->nReadyRecv >= MIN_NUM_RFD)
+ {
+ MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
+
+ }
+ else
+ {
+ MP_SET_FLAG(pMpRfd, fMP_RFD_RESOURCES);
+
+ _Analysis_assume_(PacketFreeCount <= PacketArrayCount);
+ PacketFreeArray[PacketFreeCount] = pMpRfd;
+ PacketFreeCount++;
+
+ //
+ // Reset the RFD shrink count - don't attempt to shrink RFD
+ //
+ FdoData->RfdShrinkCount = 0;
+
+ //
+ // Remember to allocate a new RFD later
+ //
+ bAllocNewRfd = TRUE;
+ }
+
+ PacketArray[PacketArrayCount] = pMpRfd;
+ PacketArrayCount++;
+ }
+
+ //
+ // if we didn't process any receives, just return from here
+ //
+ if (PacketArrayCount == 0)
+ {
+ break;
+ }
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockAcquire(FdoData->Lock);
+ //
+ // if we have a Recv interrupt and have reported a media disconnect status
+ // time to indicate the new status
+ //
+
+ if (Disconnected == FdoData->MediaState)
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_READ, "Media state changed to Connected\n");
+
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE);
+
+ FdoData->MediaState = Connected;
+
+
+ WdfSpinLockRelease(FdoData->Lock);
+ //
+ // Indicate the media event
+ //
+ NICServiceIndicateStatusIrp(FdoData);
+ }
+
+ else
+ {
+
+ WdfSpinLockRelease(FdoData->Lock);
+ }
+
+
+ NICServiceReadIrps(
+ FdoData,
+ PacketArray,
+ PacketArrayCount);
+
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ //
+ // Return all the RFDs to the pool.
+ //
+ for (Index = 0; Index < PacketFreeCount; Index++)
+ {
+
+ //
+ // Get the MP_RFD saved in this packet, in NICAllocRfd
+ //
+ pMpRfd = PacketFreeArray[Index];
+
+ ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES));
+ MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES);
+
+ NICReturnRFD(FdoData, pMpRfd);
+ }
+
+ }
+
+ //
+ // If we ran low on RFD's, we need to allocate a new RFD
+ //
+ if (bAllocNewRfd)
+ {
+ //
+ // Allocate one more RFD only if it doesn't exceed the max RFD limit
+ //
+ if (FdoData->CurrNumRfd < FdoData->MaxNumRfd
+ && !FdoData->AllocNewRfd)
+ {
+ NTSTATUS status;
+
+ FdoData->AllocNewRfd = TRUE;
+
+ //
+ // Since we are running at DISPATCH_LEVEL, we will queue a workitem
+ // to allocate RFD memory at PASSIVE_LEVEL. Note that
+ // AllocateCommonBuffer and FreeCommonBuffer can be called only at
+ // PASSIVE_LEVEL.
+ //
+ status = PciDrvQueuePassiveLevelCallback(FdoData,
+ NICAllocRfdWorkItem,
+ NULL, NULL);
+ if(!NT_SUCCESS(status)){
+ FdoData->AllocNewRfd = FALSE;
+ }
+ }
+ }
+
+ ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICHandleRecvInterrupt\n");
+}
+
+VOID
+NICReturnRFD(
+ IN PFDO_DATA FdoData,
+ IN PMP_RFD pMpRfd
+ )
+/*++
+Routine Description:
+
+ Recycle a RFD and put it back onto the receive list
+
+ Assumption: This function is called with the Rcv SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ pMpRfd Pointer to the RFD
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_RFD pLastMpRfd;
+ PHW_RFD pHwRfd = pMpRfd->HwRfd;
+
+ ASSERT(pMpRfd->Flags == 0);
+ MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_READY);
+
+ //
+ // HW_SPECIFIC_START
+ //
+ pHwRfd->RfdCbHeader.CbStatus = 0;
+ pHwRfd->RfdActualCount = 0;
+ pHwRfd->RfdCbHeader.CbCommand = (RFD_EL_BIT);
+ pHwRfd->RfdCbHeader.CbLinkPointer = DRIVER_NULL;
+
+ //
+ // Append this RFD to the RFD chain
+ if (!IsListEmpty(&FdoData->RecvList))
+ {
+ pLastMpRfd = (PMP_RFD)GetListTailEntry(&FdoData->RecvList);
+
+ // Link it onto the end of the chain dynamically
+ pHwRfd = pLastMpRfd->HwRfd;
+ pHwRfd->RfdCbHeader.CbLinkPointer = pMpRfd->HwRfdPhys;
+ pHwRfd->RfdCbHeader.CbCommand = 0;
+ }
+
+ //
+ // HW_SPECIFIC_END
+ //
+
+ //
+ // The processing on this RFD is done, so put it back on the tail of
+ // our list
+ //
+ InsertTailList(&FdoData->RecvList, (PLIST_ENTRY)pMpRfd);
+ FdoData->nReadyRecv++;
+ ASSERT(FdoData->nReadyRecv <= FdoData->CurrNumRfd);
+}
+
+_Requires_lock_held_(FdoData->RcvLock)
+NTSTATUS
+NICStartRecv(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Start the receive unit if it's not in a ready state
+
+ Assumption: This function is called with the Rcv SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ NT Status code
+
+--*/
+{
+ PMP_RFD pMpRfd;
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICStartRecv\n");
+
+ //
+ // If the receiver is ready, then don't try to restart.
+ //
+ if (NIC_IS_RECV_READY(FdoData))
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Receive unit already active\n");
+ return STATUS_SUCCESS;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Re-start receive unit...\n");
+ ASSERT(!IsListEmpty(&FdoData->RecvList));
+
+ //
+ // Get the MP_RFD head
+ //
+ pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
+
+ //
+ // If more packets are received, clean up RFD chain again
+ //
+ if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd))
+ {
+ NICHandleRecvInterrupt(FdoData);
+ ASSERT(!IsListEmpty(&FdoData->RecvList));
+
+ //
+ // Get the new MP_RFD head
+ //
+ pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
+ }
+
+ //
+ // Wait for the SCB to clear before we set the general pointer
+ //
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ goto exit;
+ }
+
+ if (FdoData->DevicePowerState > PowerDeviceD0)
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ goto exit;
+ }
+ //
+ // Set the SCB General Pointer to point the current Rfd
+ //
+ FdoData->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys;
+
+ //
+ // Issue the SCB RU start command
+ //
+ status = D100IssueScbCommand(FdoData, SCB_RUC_START, FALSE);
+ if (status == STATUS_SUCCESS)
+ {
+ // wait for the command to be accepted
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ }
+ }
+
+ exit:
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICStartRecv, Status=%x\n", status);
+ return status;
+}
+
+
+
+VOID
+NICResetRecv(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Reset the receive list
+
+ Assumption: This function is called with the Rcv SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_RFD pMpRfd;
+ PHW_RFD pHwRfd;
+ ULONG RfdCount;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> NICResetRecv\n");
+
+ ASSERT(!IsListEmpty(&FdoData->RecvList));
+
+ //
+ // Get the MP_RFD head
+ //
+ pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
+ for (RfdCount = 0; RfdCount < FdoData->nReadyRecv; RfdCount++)
+ {
+ pHwRfd = pMpRfd->HwRfd;
+ pHwRfd->RfdCbHeader.CbStatus = 0;
+
+ pMpRfd = (PMP_RFD)GetListFLink(&pMpRfd->List);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- NICResetRecv\n");
+}
+
+
+VOID
+NICServiceReadIrps(
+ PFDO_DATA FdoData,
+ PMP_RFD *PacketArray,
+ ULONG PacketArrayCount
+ )
+/*++
+Routine Description:
+
+ Copy the data from the recv buffers to pending read IRP buffers
+ and complete the IRP. When used as network driver, copy operation
+ can be avoided by devising a private interface between us and the
+ NDIS-WDM filter and have the NDIS-WDM edge to indicate our buffers
+ directly to NDIS.
+
+ Called at DISPATCH_LEVEL. Take advantage of that fact while
+ acquiring spinlocks.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_RFD pMpRfd = NULL;
+ ULONG index;
+ NTSTATUS status;
+ PVOID buffer;
+ WDFREQUEST request;
+ size_t bufLength=0;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> NICServiceReadIrps\n");
+
+
+ for(index=0; index < PacketArrayCount; index++)
+ {
+ pMpRfd = PacketArray[index];
+ ASSERT(pMpRfd);
+
+ status = WdfIoQueueRetrieveNextRequest( FdoData->PendingReadQueue,
+ &request );
+
+ if(NT_SUCCESS(status)){
+
+ WDF_REQUEST_PARAMETERS params;
+ ULONG length = 0;
+
+ WDF_REQUEST_PARAMETERS_INIT(&params);
+
+ WdfRequestGetParameters(
+ request,
+ &params
+ );
+
+ ASSERT(status == STATUS_SUCCESS);
+
+ bufLength = params.Parameters.Read.Length;
+
+ status = WdfRequestRetrieveOutputBuffer(request,
+ bufLength,
+ &buffer,
+ &bufLength);
+ if(NT_SUCCESS(status) ) {
+
+ length = min((ULONG)bufLength, pMpRfd->PacketSize);
+
+ RtlCopyMemory(buffer, pMpRfd->Buffer, length);
+
+ Hexdump((TRACE_LEVEL_VERBOSE, DBG_READ,
+ "Received Packet Data: %!HEXDUMP!\n",
+ log_xstr(buffer, (USHORT)length)));
+ FdoData->BytesReceived += length;
+ }
+
+ WdfRequestCompleteWithInformation(request, status, length);
+ }else {
+ ASSERTMSG("WdfIoQueueRetrieveNextRequest failed",
+ (status == STATUS_NO_MORE_ENTRIES ||
+ status == STATUS_WDF_PAUSED));
+ }
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_PEND));
+ MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
+
+
+ if (FdoData->RfdShrinkCount < NIC_RFD_SHRINK_THRESHOLD)
+ {
+ NICReturnRFD(FdoData, pMpRfd);
+ }
+ else
+ {
+ ASSERT(FdoData->CurrNumRfd > FdoData->NumRfd);
+ status = PciDrvQueuePassiveLevelCallback(FdoData,
+ NICFreeRfdWorkItem, (PVOID)pMpRfd,
+ NULL);
+ if(NT_SUCCESS(status)){
+
+ FdoData->RfdShrinkCount = 0;
+ FdoData->CurrNumRfd--;
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Shrink... CurrNumRfd = %d\n",
+ FdoData->CurrNumRfd);
+ } else {
+ //
+ // We couldn't queue a workitem to free memory, so let us
+ // put that back in the main pool and try again next time.
+ //
+ NICReturnRFD(FdoData, pMpRfd);
+ }
+ }
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ }// end of loop
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- NICServiceReadIrps\n");
+
+ return;
+
+}
+
+
+
+
diff --git a/general/pcidrv/kmdf/HW/nic_req.c b/general/pcidrv/kmdf/HW/nic_req.c
new file mode 100644
index 00000000..2621ee9f
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_req.c
@@ -0,0 +1,1453 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+ mp_req.c
+
+Abstract:
+ This module handle NDIS OID ioctls. This module is not required
+ if the upper edge is not NDIS.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "nic_req.tmh"
+#endif
+
+//
+// Following status values are copied from NDIS.H
+//
+#define NDIS_STATUS_MEDIA_CONNECT 0x4001000BL
+#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000CL
+
+
+PCHAR DbgGetOidName(ULONG oid);
+
+
+VOID
+NICHandleQueryOidRequest(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ WDF_REQUEST_PARAMETERS *Params
+ )
+/*++
+
+Routine Description:
+
+ Query an arbitrary OID value from the miniport.
+
+Arguments:
+
+ Queue - Default queue handle
+ Request - IOCTL request handle
+ Params - pointer to params structure for the request. This is
+ equivalent to the IRP stack location pointer.
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PNDISPROT_QUERY_OID pQuery = NULL;
+ NDIS_OID Oid = 0;
+ ULONG ulInfo = 0;
+ ULONG64 ul64Info = 0;
+ PVOID pInfo = (PVOID) &ulInfo;
+ ULONG ulInfoLen = sizeof(ulInfo);
+ PVOID InformationBuffer = NULL;
+ ULONG InformationBufferLength = 0;
+ MEDIA_STATE CurrMediaState;
+ PVOID DataBuffer;
+ size_t BufferLength;
+ NDIS_PNP_CAPABILITIES Power_Management_Capabilities;
+ PFDO_DATA FdoData = NULL;
+
+
+ UNREFERENCED_PARAMETER( Params );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
+ "--> HandleQueryOIDRequest \n");
+
+ FdoData = FdoGetData(WdfIoQueueGetDevice(Queue));
+
+ //
+ // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer &
+ // WdfRequestRetrieveInputBuffer return the same buffer pointer.
+ // So make sure you read all the information you need from
+ // the buffer before you write to it.
+ //
+ status = WdfRequestRetrieveOutputBuffer(Request,
+ sizeof(NDISPROT_QUERY_OID),
+ &DataBuffer,
+ &BufferLength);
+ if( !NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
+ "WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ do {
+
+ pQuery = (PNDISPROT_QUERY_OID)DataBuffer;
+ Oid = pQuery->Oid;
+ if(OID_GEN_LINK_SPEED != Oid) { // To avoid flood of trace messages
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "\t%s\n",
+ DbgGetOidName(Oid));
+ }
+ InformationBuffer = &pQuery->Data[0];
+ InformationBufferLength = (ULONG)BufferLength -
+ FIELD_OFFSET(NDISPROT_QUERY_OID, Data);
+
+ switch(Oid)
+ {
+
+ case OID_GEN_LINK_SPEED:
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+
+ if (InformationBufferLength < sizeof(ULONG))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION))
+ {
+ status = WdfRequestForwardToIoQueue(Request,
+ FdoData->PendingIoctlQueue);
+
+ WdfSpinLockRelease(FdoData->Lock);
+ if(NT_SUCCESS(status)) {
+ goto End;
+ }
+ break;
+ }
+ else
+ {
+
+ WdfSpinLockRelease(FdoData->Lock);
+ if (Oid == OID_GEN_LINK_SPEED)
+ {
+ ulInfo = FdoData->usLinkSpeed * 10000;
+ } else {
+
+ CurrMediaState = NICIndicateMediaState(FdoData);
+ ulInfo = CurrMediaState;
+ }
+ }
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ if (InformationBufferLength < ETH_LENGTH_OF_ADDRESS)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ pInfo = FdoData->PermanentAddress;
+ ulInfoLen = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ if (InformationBufferLength < ETH_LENGTH_OF_ADDRESS)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ pInfo = FdoData->CurrentAddress;
+ ulInfoLen = ETH_LENGTH_OF_ADDRESS;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ if (InformationBufferLength < sizeof(ULONG))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ ulInfo = NIC_MAX_MCAST_LIST;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ case OID_GEN_RCV_OK:
+ case OID_GEN_XMIT_ERROR:
+ case OID_GEN_RCV_ERROR:
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_GEN_RCV_CRC_ERROR:
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ case OID_802_3_XMIT_DEFERRED:
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_RCV_OVERRUN:
+ case OID_802_3_XMIT_UNDERRUN:
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+
+ if (InformationBufferLength < sizeof(ULONG))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ ulInfoLen = sizeof(ul64Info);
+ status = NICGetStatsCounters(FdoData, Oid, &ul64Info);
+ if (status == STATUS_SUCCESS)
+ {
+ ulInfoLen = min(InformationBufferLength, ulInfoLen);
+ pInfo = &ul64Info;
+ }
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ //
+ // This query is sent during init to get the PNP capabilities of the device.
+ //
+ NICFillPoMgmtCaps (FdoData,
+ &Power_Management_Capabilities,
+ (PNDIS_STATUS) &status,
+ &ulInfoLen);
+ if (status == STATUS_SUCCESS &&
+ ulInfoLen <= InformationBufferLength)
+ {
+ pInfo = (PVOID) &Power_Management_Capabilities;
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ pInfo = NULL;
+ }
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ //
+ // NDIS sends the query when it receives Query-DIRP.
+ // As a power policy owner, NDIS generates query-DIRP when it
+ // receives query-SIRP from the system.
+ // NDIS will forward the D-IRP to lower stack only if we answer this query
+ // successfully.
+ //
+ status = STATUS_SUCCESS;
+ break;
+
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ } WHILE (FALSE);
+
+ if (status == STATUS_SUCCESS)
+ {
+ RtlMoveMemory(InformationBuffer, pInfo, ulInfoLen);
+ }
+ //
+ // Adjust the size to include the structure.
+ //
+ ulInfoLen += FIELD_OFFSET(NDISPROT_QUERY_OID, Data);
+ WdfRequestCompleteWithInformation(Request, status, ulInfoLen);
+
+End:
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
+ "<--HandleQueryOIDRequest: Status %x\n",
+ status);
+
+ return;
+
+}
+
+VOID
+NICHandleSetOidRequest(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ WDF_REQUEST_PARAMETERS *Params
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to handle set OID request sent in the ioctl buffer.
+ If the device is busy, we will forward the request into a queue and complete
+ it later in the DPC.
+
+Arguments:
+
+ Queue - Default queue handle
+ Request - IOCTL request handle
+ Params - pointer to params structure for the request. This is
+ equivalent to the IRP stack location pointer.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PNDISPROT_SET_OID pSet;
+ NDIS_OID Oid;
+ ULONG PacketFilter;
+ PVOID InformationBuffer = NULL;
+ ULONG InformationBufferLength = 0;
+ PVOID DataBuffer;
+ size_t BufferLength;
+ ULONG unUsed;
+ WDF_POWER_DEVICE_STATE newDeviceState;
+ WDF_POWER_DEVICE_STATE oldDeviceState;
+ PFDO_DATA FdoData = NULL;
+
+ UNREFERENCED_PARAMETER( Params );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
+ "--> HandleSetOIDRequest\n");
+
+ FdoData = FdoGetData(WdfIoQueueGetDevice(Queue));
+
+ //
+ // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer &
+ // WdfRequestRetrieveInputBuffer return the same buffer pointer.
+ // So make sure you read all the information you need from
+ // the buffer before you write to it.
+ //
+ status = WdfRequestRetrieveInputBuffer(Request,
+ sizeof(NDISPROT_SET_OID),
+ &DataBuffer,
+ &BufferLength);
+ if( !NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
+ "WdfRequestRetrieveInputBuffer failed 0x%x\n",
+ status);
+ WdfRequestComplete(Request, status);
+ return;
+ }
+
+ Oid = 0;
+
+ do {
+
+ if (BufferLength < sizeof(NDISPROT_SET_OID))
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ pSet = (PNDISPROT_SET_OID)DataBuffer;
+ Oid = pSet->Oid;
+ InformationBuffer = &pSet->Data[0];
+ InformationBufferLength =
+ (ULONG)BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "\t%s\n",
+ DbgGetOidName(Oid));
+
+ switch(Oid)
+ {
+
+ case OID_802_3_MULTICAST_LIST:
+ //
+ // Verify the length
+ //
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0)
+ {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ break;
+
+ }
+
+ //
+ // Save the number of MC list size
+ //
+ FdoData->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
+ ASSERT(FdoData->MCAddressCount <= NIC_MAX_MCAST_LIST);
+
+ //
+ // Save the MC list
+ //
+ RtlMoveMemory(
+ FdoData->MCList,
+ InformationBuffer,
+ InformationBufferLength);
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ status = NICSetMulticastList(FdoData);
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ //
+ // Verify the Length
+ //
+ if (InformationBufferLength != sizeof(ULONG))
+ {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ break;
+ }
+
+ RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+ //
+ // any bits not supported?
+ //
+ if (PacketFilter & ~NIC_SUPPORTED_FILTERS)
+ {
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // any filtering changes?
+ //
+ if (PacketFilter == FdoData->PacketFilter)
+ {
+ break;
+ }
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ WdfSpinLockAcquire(FdoData->RcvLock);
+
+ if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION))
+ {
+
+ status = WdfRequestForwardToIoQueue(Request,
+ FdoData->PendingIoctlQueue);
+ WdfSpinLockRelease(FdoData->RcvLock);
+ WdfSpinLockRelease(FdoData->Lock);
+
+ if(NT_SUCCESS(status)) {
+ goto End;
+ }
+
+ break;
+ }
+
+ status = NICSetPacketFilter(
+ FdoData,
+ PacketFilter);
+
+
+ WdfSpinLockRelease(FdoData->RcvLock);
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ if (status == STATUS_SUCCESS)
+ {
+ FdoData->PacketFilter = PacketFilter;
+ }
+
+ break;
+
+ case OID_PNP_SET_POWER:
+
+ //
+ // NDIS sends this query when it receives Set D-IRP. As a power policy
+ // owner, it requests a set D-IRP when it recieves a set S-IRP from the system.
+ //
+ if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE ))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ newDeviceState = *(PDEVICE_POWER_STATE UNALIGNED)InformationBuffer;
+ oldDeviceState = FdoData->DevicePowerState;
+ FdoData->DevicePowerState = newDeviceState;
+ //
+ // Set the power state - Cannot fail this request.
+ //
+ status = NICSetPower(FdoData, newDeviceState );
+
+ if (status != STATUS_SUCCESS)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "SET Power: Hardware error !!!\n");
+ break;
+ }
+
+ status = STATUS_SUCCESS;
+ break;
+
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ //
+ // call a function that would program the adapter's wake
+ // up pattern, return success
+ //
+
+ status = NICAddWakeUpPattern(FdoData,
+ InformationBuffer,
+ InformationBufferLength,
+ &unUsed,
+ &unUsed);
+ break;
+
+
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+
+ //
+ // call a function that would remove the adapter's wake
+ // up pattern, return success
+ //
+
+ status = NICRemoveWakeUpPattern(FdoData,
+ InformationBuffer,
+ InformationBufferLength,
+ &unUsed,
+ &unUsed);
+
+ break;
+
+ case OID_PNP_ENABLE_WAKE_UP:
+ //
+ // call a function that would enable wake up on the adapter
+ // return success
+ //
+ if (IsPoMgmtSupported(FdoData))
+ {
+ ULONG WakeUpEnable;
+ RtlMoveMemory(&WakeUpEnable, InformationBuffer,sizeof(ULONG));
+ //
+ // The WakeUpEable can only be 0, or NDIS_PNP_WAKE_UP_PATTERN_MATCH since the driver only
+ // supports wake up pattern match
+ //
+ if ((WakeUpEnable != 0)
+ && ((WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH) != NDIS_PNP_WAKE_UP_PATTERN_MATCH ))
+ {
+ status = STATUS_NOT_SUPPORTED;
+ FdoData->AllowWakeArming = FALSE;
+ break;
+ }
+ //
+ // When the driver goes to low power state, it would check WakeUpEnable to decide
+ // which wake up methed it should use to wake up the machine. If WakeUpEnable is 0,
+ // no wake up method is enabled.
+ //
+ FdoData->AllowWakeArming = TRUE;
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_NOT_SUPPORTED;
+ }
+
+ break;
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+ } WHILE (FALSE);
+
+ WdfRequestCompleteWithInformation(Request, status, 0);
+
+End:
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
+ "<-- HandleSetOIDRequest %x\n", status);
+
+ return;
+}
+
+
+VOID
+NICServiceIndicateStatusIrp(
+ IN PFDO_DATA FdoData
+ )
+/*++
+
+Routine Description:
+
+ We process the IRP based on the input arguments and complete
+ the IRP. If the IRP was cancelled for some reason we will let
+ the cancel routine do the IRP completion.
+
+Arguments:
+
+ Cancel - Should the IRP be cancelled right away.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PNDISPROT_INDICATE_STATUS pIndicateStatus = NULL;
+ NTSTATUS status;
+ ULONG bytes = 0;
+ size_t bufLength;
+ WDFREQUEST request;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "-->ndisServiceIndicateStatusIrp\n");
+
+ status = NICGetIoctlRequest(FdoData->PendingIoctlQueue,
+ IOCTL_NDISPROT_INDICATE_STATUS,
+ &request);
+
+ if(!NT_SUCCESS(status)) {
+ return;
+ }
+
+ //
+ // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer &
+ // WdfRequestRetrieveInputBuffer return the same buffer pointer.
+ // So make sure you read all the information you need from
+ // the buffer before you write to it.
+ //
+ status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_INDICATE_STATUS), &pIndicateStatus, &bufLength);
+ if( !NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
+ WdfRequestComplete(request, status);
+ return;
+ }
+
+ //
+ // Check to see whether the buffer is large enough.
+ //
+
+
+ if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_NO_CABLE)){
+ pIndicateStatus->IndicatedStatus = NDIS_STATUS_MEDIA_DISCONNECT;
+ } else {
+ pIndicateStatus->IndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
+ }
+
+ pIndicateStatus->StatusBufferLength = 0;
+ pIndicateStatus->StatusBufferOffset = 0;
+ status = STATUS_SUCCESS;
+ bytes = sizeof(NDISPROT_INDICATE_STATUS);
+ WdfRequestCompleteWithInformation(request, status, bytes);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<--ndisServiceIndicateStatusIrp\n");
+ return;
+}
+
+NTSTATUS
+NICGetIoctlRequest(
+ IN WDFQUEUE Queue,
+ IN ULONG FunctionCode,
+ OUT WDFREQUEST* Request
+ )
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ WDF_REQUEST_PARAMETERS params;
+ WDFREQUEST tagRequest;
+ WDFREQUEST prevTagRequest;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICGetIoctlRequest\n");
+
+ WDF_REQUEST_PARAMETERS_INIT(&params);
+
+ *Request = NULL;
+ prevTagRequest = tagRequest = NULL;
+
+ do {
+
+ WDF_REQUEST_PARAMETERS_INIT(&params);
+ status = WdfIoQueueFindRequest(Queue,
+ prevTagRequest,
+ NULL,
+ &params,
+ &tagRequest);
+
+ //
+ // WdfIoQueueFindRequest takes an extra reference on the returned tagRequest to
+ // prevent the memory from being freed. However, the tagRequest still
+ // in the queue and can be cancelled or removed by another thread and
+ // completed.
+ //
+ if(prevTagRequest) {
+ WdfObjectDereference(prevTagRequest);
+ }
+
+ if(status == STATUS_NO_MORE_ENTRIES) {
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ if(status == STATUS_NOT_FOUND) {
+ //
+ // It seems like prevTagRequest disappeared from the
+ // queue for some reason - either it got cancelled, got
+ // dispatched to the driver. There might be other requests
+ // that match our criteria so let us restart the search.
+ //
+ prevTagRequest = tagRequest = NULL;
+ continue;
+ }
+
+ if( !NT_SUCCESS(status)) {
+ //
+ // Something bad happened.
+ //
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
+ "WdfIoQueueFindRequest failed %!STATUS!\n", status);
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ if(FunctionCode == params.Parameters.DeviceIoControl.IoControlCode){
+
+ status = WdfIoQueueRetrieveFoundRequest(
+ Queue,
+ tagRequest, // TagRequest
+ Request
+ );
+
+ WdfObjectDereference(tagRequest);
+
+ if(status == STATUS_NOT_FOUND) {
+ //
+ // It seems like the tagrequest disappeared from the
+ // queue for some reason - either it got cancelled, got
+ // dispatched to the driver. There might be other requests
+ // that match our criteria so let us restart the search.
+ //
+ prevTagRequest = tagRequest = NULL;
+ continue;
+ }
+
+ if( !NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
+ "WdfIoQueueRetrieveNextRequest failed %!STATUS!\n", status);
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ //
+ // We got a request. Drop the extra reference taken by peek request before
+ // returning the call.
+ //
+ ASSERT(*Request == tagRequest);
+ status = STATUS_SUCCESS;
+ break;
+
+ }else {
+ //
+ // This is not the request we need. We will drop the reference
+ // on the tagrequest after we looking for the next request.
+ //
+ prevTagRequest = tagRequest;
+ continue;
+ }
+
+ } WHILE (TRUE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICGetIoctlRequest\n");
+
+ return status;
+
+}
+
+MEDIA_STATE
+NICIndicateMediaState(
+ IN PFDO_DATA FdoData
+ )
+{
+ MEDIA_STATE CurrMediaState;
+
+
+ WdfSpinLockAcquire(FdoData->Lock);
+
+ CurrMediaState = GetMediaState(FdoData);
+
+ if (CurrMediaState != FdoData->MediaState)
+ {
+ TraceEvents(TRACE_LEVEL_WARNING, DBG_IOCTLS, "Media state changed to %s\n",
+ ((CurrMediaState == Connected)?
+ "Connected": "Disconnected"));
+
+ FdoData->MediaState = CurrMediaState;
+
+ if (CurrMediaState == Connected)
+ {
+ MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE);
+ }
+ else
+ {
+ MP_SET_FLAG(FdoData, fMP_ADAPTER_NO_CABLE);
+ }
+
+
+ WdfSpinLockRelease(FdoData->Lock);
+
+ // Indicate the media event
+ NICServiceIndicateStatusIrp(FdoData);
+ }
+ else
+ {
+
+ WdfSpinLockRelease(FdoData->Lock);
+ }
+
+ return CurrMediaState;
+}
+
+
+NTSTATUS
+NICGetStatsCounters(
+ IN PFDO_DATA FdoData,
+ IN NDIS_OID Oid,
+ OUT PULONG64 pCounter
+ )
+/*++
+Routine Description:
+
+ Get the value for a statistics OID
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ Oid Self-explanatory
+ pCounter Pointer to receive the value
+
+Return Value:
+
+ NT Status code
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICGetStatsCounters\n");
+
+ *pCounter = 0;
+
+ DumpStatsCounters(FdoData);
+
+ switch(Oid)
+ {
+ case OID_GEN_XMIT_OK:
+ *pCounter = FdoData->GoodTransmits;
+ break;
+
+ case OID_GEN_RCV_OK:
+ *pCounter = FdoData->GoodReceives;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ *pCounter = FdoData->TxAbortExcessCollisions +
+ FdoData->TxDmaUnderrun +
+ FdoData->TxLostCRS +
+ FdoData->TxLateCollisions;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ *pCounter = FdoData->RcvCrcErrors +
+ FdoData->RcvAlignmentErrors +
+ FdoData->RcvResourceErrors +
+ FdoData->RcvDmaOverrunErrors +
+ FdoData->RcvRuntErrors;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ *pCounter = FdoData->RcvResourceErrors;
+ break;
+
+ case OID_GEN_RCV_CRC_ERROR:
+ *pCounter = FdoData->RcvCrcErrors;
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ *pCounter = FdoData->nWaitSend;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ *pCounter = FdoData->RcvAlignmentErrors;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ *pCounter = FdoData->OneRetry;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ *pCounter = FdoData->MoreThanOneRetry;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+ *pCounter = FdoData->TxOKButDeferred;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ *pCounter = FdoData->TxAbortExcessCollisions;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+ *pCounter = FdoData->RcvDmaOverrunErrors;
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+ *pCounter = FdoData->TxDmaUnderrun;
+ break;
+
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ *pCounter = FdoData->TxLostCRS;
+ break;
+
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ *pCounter = FdoData->TxLostCRS;
+ break;
+
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ *pCounter = FdoData->TxLateCollisions;
+ break;
+
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICGetStatsCounters\n");
+
+ return(status);
+}
+
+NTSTATUS NICSetPacketFilter(
+ IN PFDO_DATA FdoData,
+ IN ULONG PacketFilter
+ )
+/*++
+Routine Description:
+
+ This routine will set up the FdoData so that it accepts packets
+ that match the specified packet filter. The only filter bits
+ that can truly be toggled are for broadcast and promiscuous
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ PacketFilter The new packet filter
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UCHAR NewParameterField;
+ UINT i;
+ BOOLEAN bResult;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICSetPacketFilter, PacketFilter=%08x\n", PacketFilter);
+
+ //
+ // Need to enable or disable broadcast and promiscuous support depending
+ // on the new filter
+ //
+ NewParameterField = CB_557_CFIG_DEFAULT_PARM15;
+
+ if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
+ {
+ NewParameterField &= ~CB_CFIG_BROADCAST_DIS;
+ }
+ else
+ {
+ NewParameterField |= CB_CFIG_BROADCAST_DIS;
+ }
+
+ if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
+ {
+ NewParameterField |= CB_CFIG_PROMISCUOUS;
+ }
+ else
+ {
+ NewParameterField &= ~CB_CFIG_PROMISCUOUS;
+ }
+
+ do
+ {
+ if ((FdoData->OldParameterField == NewParameterField ) &&
+ !(PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST))
+ {
+ break;
+ }
+
+ //
+ // Only need to do something to the HW if the filter bits have changed.
+ //
+ FdoData->OldParameterField = NewParameterField;
+ ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_CONFIGURE;
+ ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0;
+ ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbLinkPointer = DRIVER_NULL;
+
+ //
+ // First fill in the static (end user can't change) config bytes
+ //
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20;
+
+ //
+ // Set the Tx underrun retries
+ //
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] =
+ (UCHAR) (CB_557_CFIG_DEFAULT_PARM7 | (FdoData->AiUnderrunRetry << 1));
+
+ //
+ // Set the Tx and Rx Fifo limits
+ //
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] =
+ (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo);
+
+ //
+ // set the MWI enable bit if needed
+ //
+ if (FdoData->MWIEnable)
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE;
+
+ //
+ // Set the Tx and Rx DMA maximum byte count fields.
+ //
+ if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount))
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
+ FdoData->AiRxDmaCount;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
+ (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN);
+ }
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] =
+ CB_557_CFIG_DEFAULT_PARM4;
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] =
+ CB_557_CFIG_DEFAULT_PARM5;
+ }
+
+ //
+ // Setup for MII or 503 operation. The CRS+CDT bit should only be
+ // set when operating in 503 mode.
+ //
+ if (FdoData->PhyAddress == 32)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
+ (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII));
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
+ (UCHAR) (NewParameterField | CB_CFIG_CRS_OR_CDT);
+ }
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] =
+ (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII);
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] =
+ (UCHAR) (NewParameterField & (~CB_CFIG_CRS_OR_CDT));
+ }
+
+ //
+ // Setup Full duplex stuff
+ //
+
+ //
+ // If forced to half duplex
+ //
+ if (FdoData->AiForceDpx == 1)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ (CB_557_CFIG_DEFAULT_PARM19 &
+ (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE)));
+ }
+ //
+ // If forced to full duplex
+ //
+ else if (FdoData->AiForceDpx == 2)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX);
+ }
+ //
+ // If auto-duplex
+ //
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] =
+ CB_557_CFIG_DEFAULT_PARM19;
+ }
+
+ //
+ // if multicast all is being turned on, set the bit
+ //
+ if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] =
+ (CB_557_CFIG_DEFAULT_PARM21 | CB_CFIG_MULTICAST_ALL);
+ }
+ else
+ {
+ FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] =
+ CB_557_CFIG_DEFAULT_PARM21;
+ }
+
+
+ //
+ // Wait for the SCB to clear before we check the CU status.
+ //
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ //
+ // If we have issued any transmits, then the CU will either be active,
+ // or in the suspended state. If the CU is active, then we wait for
+ // it to be suspended.
+ //
+ if (FdoData->TransmitIdle == FALSE)
+ {
+ //
+ // Wait for suspended state
+ //
+ MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(FdoData);
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ //
+ // Check the current status of the receive unit
+ //
+ if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
+ {
+ // Issue an RU abort. Since an interrupt will be issued, the
+ // RU will be started by the DPC.
+ status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE);
+ if (status != STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ break;
+ }
+
+ //
+ // Restore the transmit software flags. After the multicast
+ // command is issued, the command unit will be idle, because the
+ // EL bit will be set in the multicast commmand block.
+ //
+ FdoData->TransmitIdle = TRUE;
+ FdoData->ResumeWait = TRUE;
+ }
+
+ //
+ // Display config information
+ //
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Re-Issuing Configure command for filter change\n");
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Config Block at virt addr %p, phys address %x\n",
+ &((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus, FdoData->NonTxCmdBlockPhys);
+
+ for (i = 0; i < CB_CFIG_BYTE_COUNT; i++)
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, " Config byte %x = %.2x\n",
+ i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]);
+
+ //
+ // Submit the configure command to the chip, and wait for it to complete.
+ //
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
+ status = D100SubmitCommandBlockAndWait(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ status = STATUS_DEVICE_NOT_READY;
+ }
+
+ } WHILE (FALSE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICSetPacketFilter, Status=%x\n", status);
+
+ return(status);
+}
+
+NTSTATUS
+NICSetMulticastList(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ This routine will set up the FdoData for a specified multicast address list
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ PUCHAR McAddress;
+ UINT i, j;
+ BOOLEAN bResult;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICSetMulticastList\n");
+
+ //
+ // Setup the command block for the multicast command.
+ //
+ for (i = 0; i < FdoData->MCAddressCount; i++)
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "MC(%d) = %02x-%02x-%02x-%02x-%02x-%02x\n",
+ i,
+ FdoData->MCList[i][0],
+ FdoData->MCList[i][1],
+ FdoData->MCList[i][2],
+ FdoData->MCList[i][3],
+ FdoData->MCList[i][4],
+ FdoData->MCList[i][5]);
+
+ McAddress = &FdoData->NonTxCmdBlock->NonTxCb.Multicast.McAddress[i*ETHERNET_ADDRESS_LENGTH];
+
+ for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++)
+ *(McAddress++) = FdoData->MCList[i][j];
+ }
+
+ FdoData->NonTxCmdBlock->NonTxCb.Multicast.McCount =
+ (USHORT)(FdoData->MCAddressCount * ETH_LENGTH_OF_ADDRESS);
+ ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0;
+ ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_MULTICAST;
+
+ //
+ // Wait for the SCB to clear before we check the CU status.
+ //
+ if (!WaitScb(FdoData))
+ {
+ status = STATUS_DEVICE_DATA_ERROR;
+ goto exit;
+ }
+
+ //
+ // If we have issued any transmits, then the CU will either be active, or
+ // in the suspended state. If the CU is active, then we wait for it to be
+ // suspended.
+ //
+ if (FdoData->TransmitIdle == FALSE)
+ {
+ //
+ // Wait for suspended state
+ //
+ MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(FdoData);
+ status = STATUS_DEVICE_DATA_ERROR;
+ }
+
+ //
+ // Restore the transmit software flags. After the multicast command is
+ // issued, the command unit will be idle, because the EL bit will be
+ // set in the multicast commmand block.
+ //
+ FdoData->TransmitIdle = TRUE;
+ FdoData->ResumeWait = TRUE;
+ }
+
+ //
+ // Update the command list pointer.
+ //
+ FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys;
+
+ //
+ // Submit the multicast command to the FdoData and wait for it to complete.
+ //
+ status = D100SubmitCommandBlockAndWait(FdoData);
+ if (status != STATUS_SUCCESS)
+ {
+ status = STATUS_DEVICE_NOT_READY;
+ }
+
+ exit:
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICSetMulticastList, Status=%x\n", status);
+
+ return(status);
+
+}
+
+
+VOID
+NICFillPoMgmtCaps (
+ IN PFDO_DATA FdoData,
+ IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities,
+ IN OUT PNDIS_STATUS pStatus,
+ IN OUT PULONG pulInfoLen
+ )
+/*++
+Routine Description:
+
+ Fills in the Power Managment structure depending the capabilities of
+ the software driver and the card.
+
+ Currently this is only supported on 82559 Version of the driver
+
+Arguments:
+
+ FdoData Pointer to the FdoData structure
+ pPower_Management_Capabilities - Power management struct as defined in the DDK,
+ pStatus Status to be returned by the request,
+ pulInfoLen Length of the pPowerManagmentCapabilites
+
+Return Value:
+
+ Success or failure depending on the type of card
+--*/
+
+{
+
+ BOOLEAN bIsPoMgmtSupported;
+
+ bIsPoMgmtSupported = IsPoMgmtSupported(FdoData);
+
+ if (bIsPoMgmtSupported == TRUE)
+ {
+ pPower_Management_Capabilities->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
+ pPower_Management_Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPower_Management_Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3;
+ pPower_Management_Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ *pulInfoLen = sizeof (*pPower_Management_Capabilities);
+ *pStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ RtlZeroMemory (pPower_Management_Capabilities, sizeof(*pPower_Management_Capabilities));
+ *pStatus = STATUS_NOT_SUPPORTED;
+ *pulInfoLen = 0;
+
+ }
+}
+
+PCHAR
+DbgGetOidName(ULONG oid)
+{
+ PCHAR oidName;
+
+ switch (oid){
+
+ #undef MAKECASE
+ #define MAKECASE(oidx) case oidx: oidName = #oidx; break;
+
+ MAKECASE(OID_GEN_SUPPORTED_LIST)
+ MAKECASE(OID_GEN_HARDWARE_STATUS)
+ MAKECASE(OID_GEN_MEDIA_SUPPORTED)
+ MAKECASE(OID_GEN_MEDIA_IN_USE)
+ MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+ MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+ MAKECASE(OID_GEN_LINK_SPEED)
+ MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+ MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+ MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+ MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+ MAKECASE(OID_GEN_VENDOR_ID)
+ MAKECASE(OID_GEN_VENDOR_DESCRIPTION)
+ MAKECASE(OID_GEN_CURRENT_PACKET_FILTER)
+ MAKECASE(OID_GEN_CURRENT_LOOKAHEAD)
+ MAKECASE(OID_GEN_DRIVER_VERSION)
+ MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+ MAKECASE(OID_GEN_PROTOCOL_OPTIONS)
+ MAKECASE(OID_GEN_MAC_OPTIONS)
+ MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS)
+ MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+ MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION)
+ MAKECASE(OID_GEN_SUPPORTED_GUIDS)
+ MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+ MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+ MAKECASE(OID_GEN_MEDIA_CAPABILITIES)
+ MAKECASE(OID_GEN_PHYSICAL_MEDIUM)
+ MAKECASE(OID_GEN_XMIT_OK)
+ MAKECASE(OID_GEN_RCV_OK)
+ MAKECASE(OID_GEN_XMIT_ERROR)
+ MAKECASE(OID_GEN_RCV_ERROR)
+ MAKECASE(OID_GEN_RCV_NO_BUFFER)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_RCV)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_RCV_CRC_ERROR)
+ MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+ MAKECASE(OID_GEN_GET_TIME_CAPS)
+ MAKECASE(OID_GEN_GET_NETCARD_TIME)
+ MAKECASE(OID_GEN_NETCARD_LOAD)
+ MAKECASE(OID_GEN_DEVICE_PROFILE)
+ MAKECASE(OID_GEN_INIT_TIME_MS)
+ MAKECASE(OID_GEN_RESET_COUNTS)
+ MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS)
+ MAKECASE(OID_PNP_CAPABILITIES)
+ MAKECASE(OID_PNP_SET_POWER)
+ MAKECASE(OID_PNP_QUERY_POWER)
+ MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_ENABLE_WAKE_UP)
+ MAKECASE(OID_802_3_PERMANENT_ADDRESS)
+ MAKECASE(OID_802_3_CURRENT_ADDRESS)
+ MAKECASE(OID_802_3_MULTICAST_LIST)
+ MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE)
+ MAKECASE(OID_802_3_MAC_OPTIONS)
+ MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+ MAKECASE(OID_802_3_XMIT_ONE_COLLISION)
+ MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS)
+ MAKECASE(OID_802_3_XMIT_DEFERRED)
+ MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS)
+ MAKECASE(OID_802_3_RCV_OVERRUN)
+ MAKECASE(OID_802_3_XMIT_UNDERRUN)
+ MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+ MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+ MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS)
+
+ default:
+ oidName = "<** UNKNOWN OID **>";
+ break;
+ }
+
+ return oidName;
+}
+
+
diff --git a/general/pcidrv/kmdf/HW/nic_send.c b/general/pcidrv/kmdf/HW/nic_send.c
new file mode 100644
index 00000000..dafabed1
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nic_send.c
@@ -0,0 +1,838 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+ nic_send.c
+
+Abstract:
+ This module contains routines to write packets.
+
+Environment:
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "nic_send.tmh"
+#endif
+
+_IRQL_requires_same_
+_IRQL_requires_(DISPATCH_LEVEL)
+_Requires_lock_held_(FdoData->SendLock)
+__inline
+VOID
+MP_FREE_SEND_PACKET(
+ IN PFDO_DATA FdoData,
+ IN PMP_TCB pMpTcb,
+ IN NTSTATUS Status
+ )
+/*++
+Routine Description:
+
+ Recycle a MP_TCB and complete the packet if necessary
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ pMpTcb Pointer to MP_TCB
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ WDFREQUEST request;
+ WDFDMATRANSACTION dmaTransaction;
+ size_t length;
+
+ ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
+
+ dmaTransaction = pMpTcb->DmaTransaction;
+ pMpTcb->DmaTransaction = NULL;
+
+ MP_CLEAR_FLAGS(pMpTcb);
+
+ FdoData->CurrSendHead = FdoData->CurrSendHead->Next;
+ FdoData->nBusySend--;
+
+ request = WdfDmaTransactionGetRequest(dmaTransaction);
+ length = WdfDmaTransactionGetBytesTransferred(dmaTransaction);
+
+ WdfObjectDelete( dmaTransaction );
+
+ if (request)
+ {
+ WdfSpinLockRelease(FdoData->SendLock);
+ WdfRequestCompleteWithInformation(request, Status, length);
+ FdoData->BytesTransmitted += length;
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+ }
+}
+
+VOID
+PciDrvEvtIoWrite(
+ IN WDFQUEUE Queue,
+ IN WDFREQUEST Request,
+ IN size_t Length
+ )
+/*++
+
+Routine Description:
+
+ Called by the framework as soon as it receive a write IRP.
+ If the device is not ready, fail the request. Otherwise
+ get scatter-gather list for this request and send the
+ packet to the hardware for DMA.
+
+Arguments:
+
+ Queue - Handle to the framework queue object that is associated
+ with the I/O request.
+ Request - Handle to a framework request object.
+
+ Length - Length of the IO operation
+ The default property of the queue is to not dispatch
+ zero lenght read & write requests to the driver and
+ complete is with status success. So we will never get
+ a zero length request.
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ PFDO_DATA FdoData;
+ WDFDEVICE hDevice;
+ PMDL mdl = NULL;
+
+ UNREFERENCED_PARAMETER(Length);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> PciDrvEvtIoWrite Request %p\n", Request);
+
+ hDevice = WdfIoQueueGetDevice(Queue);
+ FdoData = FdoGetData(hDevice);
+
+ status = WdfRequestRetrieveInputWdmMdl(Request, &mdl);
+ if (!NT_SUCCESS(status))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfRequestRetrieveInputWdmMdl failed %x\n", status);
+ WdfRequestCompleteWithInformation(Request, status, 0);
+
+ } else {
+
+ status = NICInitiateDmaTransfer(FdoData, Request);
+ if(!NT_SUCCESS(status)) {
+
+ WdfRequestCompleteWithInformation(Request, status, 0);
+ }
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- PciDrvEvtIoWrite %X\n", status);
+
+ return;
+}
+
+NTSTATUS
+NICInitiateDmaTransfer(
+ IN PFDO_DATA FdoData,
+ IN WDFREQUEST Request
+ )
+{
+ WDFDMATRANSACTION dmaTransaction;
+ NTSTATUS status;
+ BOOLEAN bCreated = FALSE;
+
+ do {
+ //
+ // Create a new DmaTransaction.
+ //
+ status = WdfDmaTransactionCreate( FdoData->WdfDmaEnabler,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &dmaTransaction );
+
+ if(!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfDmaTransactionCreate failed %X\n", status);
+ break;
+ }
+
+ bCreated = TRUE;
+ //
+ // Initialize the new DmaTransaction.
+ //
+
+ status = WdfDmaTransactionInitializeUsingRequest(
+ dmaTransaction,
+ Request,
+ NICEvtProgramDmaFunction,
+ WdfDmaDirectionWriteToDevice );
+
+ if(!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfDmaTransactionInitalizeUsingRequest failed %X\n",
+ status);
+ break;
+ }
+
+ //
+ // Execute this DmaTransaction.
+ //
+ status = WdfDmaTransactionExecute( dmaTransaction,
+ dmaTransaction );
+
+ if(!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "WdfDmaTransactionExecute failed %X\n", status);
+ break;
+ }
+
+ } WHILE (FALSE);
+
+ if(!NT_SUCCESS(status)){
+
+ if(bCreated) {
+ WdfObjectDelete( dmaTransaction );
+
+ }
+ }
+
+ return status;
+}
+
+
+BOOLEAN
+NICEvtProgramDmaFunction(
+ IN WDFDMATRANSACTION Transaction,
+ IN WDFDEVICE Device,
+ IN PVOID Context,
+ IN WDF_DMA_DIRECTION Direction,
+ IN PSCATTER_GATHER_LIST ScatterGather
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PFDO_DATA fdoData;
+ WDFREQUEST request;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER( Context );
+ UNREFERENCED_PARAMETER( Direction );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICEvtProgramDmaFunction\n");
+
+ fdoData = FdoGetData(Device);
+ request = WdfDmaTransactionGetRequest(Transaction);
+
+
+ WdfSpinLockAcquire(fdoData->SendLock);
+
+ //
+ // If tcb or link is not available, queue the request
+ //
+ if (!MP_TCB_RESOURCES_AVAIABLE(fdoData) ||
+ MP_TEST_FLAG(fdoData, fMP_ADAPTER_LINK_DETECTION))
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "Resource is not available: queue Request %p\n", request);
+
+ //
+ // Must abort the transaction before deleting.
+ //
+ (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
+ ASSERT(NT_SUCCESS(status));
+ WdfObjectDelete( Transaction );
+
+ //
+ // Queue the request for later processing.
+ //
+ status = WdfRequestForwardToIoQueue(request,
+ fdoData->PendingWriteQueue);
+
+ if(!NT_SUCCESS(status)) {
+ ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE);
+ WdfSpinLockRelease(fdoData->SendLock);
+ WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0);
+ return FALSE;
+ }
+ fdoData->nWaitSend++;
+
+ } else {
+
+ status = NICWritePacket(fdoData, Transaction, ScatterGather);
+
+ if(!NT_SUCCESS(status)){
+
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "<-- NICEvtProgramDmaFunction returning %!STATUS!\n",
+ status);
+ //
+ // Must abort the transaction before deleting.
+ //
+ (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
+ ASSERT(NT_SUCCESS(status));
+ WdfObjectDelete( Transaction );
+
+ WdfSpinLockRelease(fdoData->SendLock);
+ WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0);
+ return FALSE;
+ }
+ }
+
+
+ WdfSpinLockRelease(fdoData->SendLock);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- NICEvtProgramDmaFunction\n");
+
+ return TRUE;
+}
+
+
+NTSTATUS
+NICWritePacket(
+ IN PFDO_DATA FdoData,
+ IN WDFDMATRANSACTION DmaTransaction,
+ IN PSCATTER_GATHER_LIST SGList
+ )
+/*++
+Routine Description:
+
+ Do the work to send a packet
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+--*/
+{
+ PMP_TCB pMpTcb = NULL;
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICWritePacket: SGList %p\n", SGList);
+
+ //
+ // Initialize the Transfer Control Block.
+ //
+ pMpTcb = FdoData->CurrSendTail;
+ ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));
+
+ pMpTcb->DmaTransaction = DmaTransaction;
+
+ MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);
+
+ //
+ // Call the send handler, it only needs to deal with the ScatterGather list
+ //
+ status = NICSendPacket(FdoData, pMpTcb, SGList);
+ if(!NT_SUCCESS(status)){
+ MP_CLEAR_FLAG(pMpTcb, fMP_TCB_IN_USE);
+ return status;
+ }
+
+ FdoData->nBusySend++;
+ ASSERT(FdoData->nBusySend <= FdoData->NumTcb);
+
+ FdoData->CurrSendTail = FdoData->CurrSendTail->Next;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICWritePacket\n");
+
+ return status;
+}
+
+NTSTATUS
+NICSendPacket(
+ IN PFDO_DATA FdoData,
+ IN PMP_TCB pMpTcb,
+ IN PSCATTER_GATHER_LIST ScatterGather
+ )
+/*++
+Routine Description:
+
+ NIC specific send handler
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ pMpTcb Pointer to MP_TCB
+ ScatterGather The pointer to the frag list to be filled
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NTSTATUS status;
+ ULONG index;
+ UCHAR TbdCount = 0;
+
+ PHW_TCB pHwTcb = pMpTcb->HwTcb;
+ PTBD_STRUC pHwTbd = pMpTcb->HwTbd;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICSendPacket\n");
+
+ for (index = 0; index < ScatterGather->NumberOfElements; index++)
+ {
+ if (ScatterGather->Elements[index].Length)
+ {
+ pHwTbd->TbdBufferAddress =
+ ScatterGather->Elements[index].Address.LowPart;
+
+ pHwTbd->TbdCount = ScatterGather->Elements[index].Length;
+
+ pHwTbd++;
+ TbdCount++;
+ }
+ }
+
+ pHwTcb->TxCbHeader.CbStatus = 0;
+ pHwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT;
+
+ pHwTcb->TxCbTbdPointer = pMpTcb->HwTbdPhys;
+ pHwTcb->TxCbTbdNumber = TbdCount;
+ pHwTcb->TxCbCount = 0;
+ pHwTcb->TxCbThreshold = (UCHAR) FdoData->AiThreshold;
+
+
+ status = NICStartSend(FdoData, pMpTcb);
+
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "NICStartSend returned error %x\n", status);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICSendPacket\n");
+
+ return status;
+}
+
+NTSTATUS
+NICStartSend(
+ IN PFDO_DATA FdoData,
+ IN PMP_TCB pMpTcb
+ )
+/*++
+Routine Description:
+
+ Issue a send command to the NIC
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+ pMpTcb Pointer to MP_TCB
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NTSTATUS status;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICStartSend\n");
+
+ //
+ // If the transmit unit is idle (very first transmit) then we must
+ // setup the general pointer and issue a full CU-start
+ //
+ if (FdoData->TransmitIdle)
+ {
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "CU is idle -- First TCB added to Active List\n");
+
+ //
+ // Wait for the SCB to clear before we set the general pointer
+ //
+ if (!WaitScb(FdoData))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "NICStartSend -- WaitScb returned error\n");
+ status = STATUS_DEVICE_DATA_ERROR;
+ goto exit;
+ }
+
+ //
+ // Don't try to start the transmitter if the command unit is not
+ // idle ((not idle) == (Cu-Suspended or Cu-Active)).
+ //
+ if ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "FdoData = %p, CU Not IDLE\n", FdoData);
+ MP_SET_HARDWARE_ERROR(FdoData);
+ KeStallExecutionProcessor(25);
+ }
+
+ FdoData->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys;
+
+ status = D100IssueScbCommand(FdoData, SCB_CUC_START, FALSE);
+
+ FdoData->TransmitIdle = FALSE;
+ FdoData->ResumeWait = TRUE;
+ }
+ else
+ {
+ //
+ // If the command unit has already been started, then append this
+ // TCB onto the end of the transmit chain, and issue a CU-Resume.
+ //
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "adding TCB to Active chain\n");
+
+ //
+ // Clear the suspend bit on the previous packet.
+ //
+ pMpTcb->PrevHwTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;
+
+ //
+ // Issue a CU-Resume command to the device. We only need to do a
+ // WaitScb if the last command was NOT a RESUME.
+ //
+ status = D100IssueScbCommand(FdoData,
+ SCB_CUC_RESUME,
+ FdoData->ResumeWait);
+ }
+
+ exit:
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICStartSend\n");
+
+ return status;
+}
+
+_Requires_lock_held_(FdoData->SendLock)
+NTSTATUS
+NICHandleSendInterrupt(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Interrupt handler for sending processing. Re-claim the send resources,
+ complete sends and get more to send from the send wait queue.
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PMP_TCB pMpTcb;
+
+#if DBG
+ ULONG i;
+#endif
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICHandleSendInterrupt\n");
+
+ //
+ // Any packets being sent? Any packet waiting in the send queue?
+ //
+ if (FdoData->nBusySend == 0)
+ {
+ ASSERT(FdoData->CurrSendHead == FdoData->CurrSendTail);
+ return status;
+ }
+
+ //
+ // Check the first TCB on the send list
+ //
+ while (FdoData->nBusySend > 0)
+ {
+
+#if DBG
+ pMpTcb = FdoData->CurrSendHead;
+ for (i = 0; i < FdoData->nBusySend; i++)
+ {
+ pMpTcb = pMpTcb->Next;
+ }
+
+ if (pMpTcb != FdoData->CurrSendTail)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "nBusySend= %d\n", FdoData->nBusySend);
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "CurrSendhead= %p\n", FdoData->CurrSendHead);
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
+ "CurrSendTail= %p\n", FdoData->CurrSendTail);
+ ASSERT(FALSE);
+ }
+#endif
+
+ pMpTcb = FdoData->CurrSendHead;
+
+ //
+ // Is this TCB completed?
+ //
+ if (pMpTcb->HwTcb->TxCbHeader.CbStatus & CB_STATUS_COMPLETE)
+ {
+ //
+ // Check if this is a multicast hw workaround packet
+ //
+ if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
+ {
+ BOOLEAN transactionComplete;
+
+ ASSERT(pMpTcb->DmaTransaction);
+
+ //
+ // Indicate this DMA operation has completed:
+ // This may drive the transfer on the next packet if
+ // there is still data to be transfered in the DmaTransaction.
+ //
+ transactionComplete =
+ WdfDmaTransactionDmaCompleted( pMpTcb->DmaTransaction,
+ &status );
+
+ if(transactionComplete == TRUE) {
+
+ ASSERT(status == STATUS_SUCCESS);
+ MP_FREE_SEND_PACKET(FdoData, pMpTcb, status);
+
+ } else {
+ //
+ // NOTE: For this ethernet driver this should never
+ // be returned as the packets are <= 1514 bytes.
+ // It is included to show the complete DmaTransaction
+ // coding pattern.
+ //
+ ASSERT(!"STATUS_MORE_PROCESSING_REQUIRED");
+ }
+
+ }
+ else
+ {
+
+ // Multicast workaround would be here (???)
+
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- NICHandleSendInterrupt\n");
+ return status;
+}
+
+VOID
+NICCheckForQueuedSends(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+--*/
+{
+ WDFREQUEST request;
+ WDFDMATRANSACTION dmaTransaction;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER( dmaTransaction );
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICCheckForQueuedSends\n");
+
+ //
+ // If we queued any transmits because we didn't have any TCBs earlier,
+ // dequeue and send those packets now, as long as we have free TCBs.
+ //
+ while (MP_TCB_RESOURCES_AVAIABLE(FdoData))
+ {
+ status = WdfIoQueueRetrieveNextRequest(
+ FdoData->PendingWriteQueue,
+ &request
+ );
+
+ if(!NT_SUCCESS(status) ) {
+ if(STATUS_NO_MORE_ENTRIES != status) {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "WdfIoQueueRetrieveNextRequest failed %X\n", status);
+ }
+ break;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "\t processing Request %p \n", request);
+
+ status = NICInitiateDmaTransfer(FdoData, request);
+ if(!NT_SUCCESS(status)) {
+ WdfRequestCompleteWithInformation(request, status, 0);
+ }
+
+ FdoData->nWaitSend--;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- NICCheckForQueuedSends\n");
+}
+
+_Requires_lock_held_(FdoData->SendLock)
+VOID
+NICFreeBusySendPackets(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Free and complete the stopped active sends
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ PMP_TCB pMpTcb;
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICFreeBusySendPackets\n");
+
+ //
+ // Any packets being sent? Check the first TCB on the send list
+ //
+ while (FdoData->nBusySend > 0)
+ {
+ pMpTcb = FdoData->CurrSendHead;
+
+ //
+ // Is this TCB completed?
+ //
+ if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
+ {
+ MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_SUCCESS);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- NICFreeBusySendPackets\n");
+}
+
+
+_IRQL_requires_same_
+_IRQL_requires_(DISPATCH_LEVEL)
+_Requires_lock_held_(FdoData->SendLock)
+VOID
+NICFreeQueuedSendPackets(
+ IN PFDO_DATA FdoData
+ )
+/*++
+Routine Description:
+
+ Free and complete the pended sends on SendQueueHead
+
+ Assumption: This function is called with the Send SPINLOCK held.
+
+Arguments:
+
+ FdoData Pointer to our FdoData
+
+Return Value:
+
+ None
+
+--*/
+{
+ WDFREQUEST request;
+ NTSTATUS status = MP_GET_STATUS_FROM_FLAGS(FdoData);
+
+ if (STATUS_UNSUCCESSFUL == status) {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "MP_GET_STATUS_FROM_FLAGS failed %x\n", status);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "--> NICFreeQueuedSendPackets\n");
+
+ do {
+ status = WdfIoQueueRetrieveNextRequest(
+ FdoData->PendingWriteQueue,
+ &request
+ );
+
+ if(!NT_SUCCESS(status) ) {
+ if(STATUS_NO_MORE_ENTRIES != status){
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "WdfIoQueueRetrieveNextRequest failed %x\n", status);
+ }
+ break;
+ }
+
+ FdoData->nWaitSend--;
+
+ WdfSpinLockRelease(FdoData->SendLock);
+
+ WdfRequestCompleteWithInformation(request, status, 0);
+
+ WdfSpinLockAcquire(FdoData->SendLock);
+
+ } WHILE (TRUE);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
+ "<-- NICFreeQueuedSendPackets\n");
+
+}
+
+
diff --git a/general/pcidrv/kmdf/HW/nuiouser.h b/general/pcidrv/kmdf/HW/nuiouser.h
new file mode 100644
index 00000000..c33861ae
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/nuiouser.h
@@ -0,0 +1,105 @@
+/*++
+
+Copyright (c) 2000 Microsoft Corporation
+
+Module Name:
+
+ nuiouser.h
+
+Abstract:
+
+ Constants and types to access the NDISPROT driver.
+ Users must also include ntddndis.h
+
+Environment:
+
+ User/Kernel mode.
+
+--*/
+
+#ifndef __NUIOUSER__H
+#define __NUIOUSER__H
+
+
+#define FSCTL_NDISPROT_BASE FILE_DEVICE_NETWORK
+
+#define _NDISPROT_CTL_CODE(_Function, _Method, _Access) \
+ CTL_CODE(FSCTL_NDISPROT_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISPROT_OPEN_DEVICE \
+ _NDISPROT_CTL_CODE(0x200, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_QUERY_OID_VALUE \
+ _NDISPROT_CTL_CODE(0x201, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_SET_OID_VALUE \
+ _NDISPROT_CTL_CODE(0x205, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_QUERY_BINDING \
+ _NDISPROT_CTL_CODE(0x203, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_BIND_WAIT \
+ _NDISPROT_CTL_CODE(0x204, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISPROT_INDICATE_STATUS \
+ _NDISPROT_CTL_CODE(0x206, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+
+
+//
+// Structure to go with IOCTL_NDISPROT_QUERY_OID_VALUE.
+// The Data part is of variable length, determined by
+// the input buffer length passed to DeviceIoControl.
+//
+typedef struct _NDISPROT_QUERY_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+
+} NDISPROT_QUERY_OID, *PNDISPROT_QUERY_OID;
+
+//
+// Structure to go with IOCTL_NDISPROT_SET_OID_VALUE.
+// The Data part is of variable length, determined
+// by the input buffer length passed to DeviceIoControl.
+//
+typedef struct _NDISPROT_SET_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+
+} NDISPROT_SET_OID, *PNDISPROT_SET_OID;
+
+
+//
+// Structure to go with IOCTL_NDISPROT_QUERY_BINDING.
+// The input parameter is BindingIndex, which is the
+// index into the list of bindings active at the driver.
+// On successful completion, we get back a device name
+// and a device descriptor (friendly name).
+//
+typedef struct _NDISPROT_QUERY_BINDING
+{
+ ULONG BindingIndex; // 0-based binding number
+ ULONG DeviceNameOffset; // from start of this struct
+ ULONG DeviceNameLength; // in bytes
+ ULONG DeviceDescrOffset; // from start of this struct
+ ULONG DeviceDescrLength; // in bytes
+
+} NDISPROT_QUERY_BINDING, *PNDISPROT_QUERY_BINDING;
+
+//
+// Structure to go with IOCTL_NDISPROT_INDICATE_STATUS.
+// NDISPROT copies the status indicated by the NIC and
+// also the data indicated in the StatusBuffer.
+//
+typedef struct _NDISPROT_INDICATE_STATUS
+{
+ ULONG IndicatedStatus; // NDIS_STATUS
+ ULONG StatusBufferOffset; // from start of this struct
+ ULONG StatusBufferLength; // in bytes
+} NDISPROT_INDICATE_STATUS, *PNDISPROT_INDICATE_STATUS;
+
+#endif // __NUIOUSER__H
+
+
diff --git a/general/pcidrv/kmdf/HW/physet.c b/general/pcidrv/kmdf/HW/physet.c
new file mode 100644
index 00000000..94132fec
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/physet.c
@@ -0,0 +1,1001 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ physet.c
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+//#pragma TRACE_LEVEL_WARNING (disable: 4514)
+
+//-----------------------------------------------------------------------------
+// Procedure: PhyDetect
+//
+// Description: This routine will detect what phy we are using, set the line
+// speed, FDX or HDX, and configure the phy if necessary.
+//
+// The following combinations are supported:
+// - TX or T4 PHY alone at PHY address 1
+// - T4 or TX PHY at address 1 and MII PHY at address 0
+// - 82503 alone (10Base-T mode, no full duplex support)
+// - 82503 and MII PHY (TX or T4) at address 0
+//
+// The sequence / priority of detection is as follows:
+// If there is a PHY Address override use that address.
+// else scan based on the 'Connector' setting.
+// Switch Connector
+// 0 = AutoScan
+// 1 = Onboard TPE only
+// 2 = MII connector only
+//
+// Each of the above cases is explained below.
+//
+// AutoScan means:
+// Look for link on addresses 1, 0, 2..31 (in that order). Use the first
+// address found that has link.
+// If link is not found then use the first valid PHY found in the same scan
+// order 1,0,2..31. NOTE: this means that NO LINK or Multi-link cases will
+// default to the onboard PHY (address 1).
+//
+// Onboard TPE only:
+// Phy address is set to 1 (No Scanning).
+//
+// MII connector only means:
+// Look for link on addresses 0, 2..31 (again in that order, Note address 1 is
+// NOT scanned). Use the first address found that has link.
+// If link is not found then use the first valid Phy found in the same scan
+// order 0, 2..31.
+// In the AutoScan case above we should always find a valid PHY at address 1,
+// there is no such guarantee here, so, If NO Phy is found then the driver
+// should default to address 0 and continue to load. Note: External
+// transceivers should be at address 0 but our early Nitro3 testing found
+// transceivers at several non-zero addresses (6,10,14).
+//
+//
+// NWAY
+// Additionally auto-negotiation capable (NWAY) and parallel
+// detection PHYs are supported. The flow-chart is described in
+// the 82557 software writer's manual.
+//
+// NOTE: 1. All PHY MDI registers are read in polled mode.
+// 2. The routines assume that the 82557 has been RESET and we have
+// obtained the virtual memory address of the CSR.
+// 3. PhyDetect will not RESET the PHY.
+// 4. If FORCEFDX is set, SPEED should also be set. The driver will
+// check the values for inconsistency with the detected PHY
+// technology.
+// 5. PHY 1 (the PHY on the adapter) MUST be at address 1.
+// 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface
+// is detected.
+//
+//
+// Arguments:
+// FdoData - ptr to FdoData object instance
+//
+// Result:
+// Returns:
+// STATUS_SUCCESS
+// NDIS_STATUS_FAILURE
+//-----------------------------------------------------------------------------
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "physet.tmh"
+#endif
+
+NTSTATUS PhyDetect(
+ IN PFDO_DATA FdoData
+ )
+{
+#if DBG
+ USHORT MdiControlReg;
+ USHORT MdiStatusReg;
+#endif
+
+ //
+ // Check for a phy address over-ride of 32 which indicates a 503
+ //
+ if (FdoData->PhyAddress == 32)
+ {
+ //
+ // 503 interface over-ride
+ //
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " 503 serial component over-ride\n");
+
+ FdoData->PhyAddress = 32;
+
+ //
+ // Record the current speed and duplex. We will be in half duplex
+ // mode unless the user used the force full duplex over-ride.
+ //
+ FdoData->usLinkSpeed = 10;
+ FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx;
+ if (!FdoData->usDuplexMode)
+ {
+ FdoData->usDuplexMode = 1;
+ }
+
+ return(STATUS_SUCCESS);
+ }
+
+ //
+ // Check for other phy address over-rides.
+ // If the Phy Address is between 0-31 then there is an over-ride.
+ // Or the connector was set to 1
+ //
+ if ((FdoData->PhyAddress < 32) || (FdoData->Connector == CONNECTOR_TPE))
+ {
+
+ //
+ // User Override nothing to do but setup Phy and leave
+ //
+ if ((FdoData->PhyAddress > 32) && (FdoData->Connector == CONNECTOR_TPE))
+ {
+ FdoData->PhyAddress = 1; // Connector was forced
+
+ // Isolate all other PHYs and unisolate this one
+ SelectPhy(FdoData, FdoData->PhyAddress, FALSE);
+
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
+ " Phy address Override to address %d\n", FdoData->PhyAddress);
+
+#if DBG
+ //
+ // Read the MDI control register at override address.
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // Read the status register at override address.
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ //
+ // Read the status register again because of sticky bits
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // check if we found a valid phy
+ //
+ if (!((MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0))))
+ {
+ //
+ // we have a valid phy1
+ //
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Over-ride address %d has a valid Phy.\n", FdoData->PhyAddress);
+
+ //
+ // Read the status register again
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // If there is a valid link then use this Phy.
+ //
+ if (MdiStatusReg & MDI_SR_LINK_STATUS)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Phy at address %d has link\n", FdoData->PhyAddress);
+ }
+
+ }
+ else
+ {
+ //
+ // no PHY at over-ride address
+ //
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Over-ride address %d has no Phy!!!!\n", FdoData->PhyAddress);
+ }
+#endif
+ return(SetupPhy(FdoData));
+ }
+ else // Need to scan - No address over-ride and Connector is AUTO or MII
+ {
+ FdoData->CurrentScanPhyIndex = 0;
+ FdoData->LinkDetectionWaitCount = 0;
+ FdoData->FoundPhyAt = 0xff;
+ FdoData->bLookForLink = TRUE;
+
+ return(ScanAndSetupPhy(FdoData));
+
+ } // End else scan
+
+
+}
+
+NTSTATUS ScanAndSetupPhy(
+ IN PFDO_DATA FdoData
+ )
+{
+ USHORT MdiControlReg = 0;
+ USHORT MdiStatusReg = 0;
+
+ if (FdoData->bLinkDetectionWait)
+ {
+ goto NEGOTIATION_WAIT;
+ }
+
+ SCAN_PHY_START:
+
+ //
+ // For each PhyAddress 0 - 31
+ //
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Index=%d, bLookForLink=%d\n",
+ FdoData->CurrentScanPhyIndex, FdoData->bLookForLink);
+
+ if (FdoData->bLookForLink)
+ {
+ //
+ // Phy Addresses must be tested in the order 1,0,2..31.
+ //
+ switch(FdoData->CurrentScanPhyIndex)
+ {
+ case 0:
+ FdoData->PhyAddress = 1;
+ break;
+
+ case 1:
+ FdoData->PhyAddress = 0;
+ break;
+
+ default:
+ FdoData->PhyAddress = FdoData->CurrentScanPhyIndex;
+ break;
+ }
+
+ //
+ // Skip OnBoard for MII only case
+ //
+ if ((FdoData->PhyAddress == 1)&&(FdoData->Connector == CONNECTOR_MII))
+ {
+ goto SCAN_PHY_NEXT;
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Scanning Phy address %d for link\n", FdoData->PhyAddress);
+
+ //
+ // Read the MDI control register
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // Read the status register
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ // Sticky Bits
+ }
+ else
+ {
+ //
+ // Not looking for link
+ //
+ if (FdoData->FoundPhyAt < 32)
+ {
+ FdoData->PhyAddress = FdoData->FoundPhyAt;
+ }
+ else if (FdoData->Connector == CONNECTOR_MII)
+ {
+ //
+ // No valid PHYs were found last time so just default
+ //
+ FdoData->PhyAddress = 0; // Default for MII
+ }
+ else
+ {
+ //
+ // assume a 503 interface
+ //
+ FdoData->PhyAddress = 32;
+
+ //
+ // Record the current speed and duplex. We will be in half duplex
+ // mode unless the user used the force full duplex over-ride.
+ //
+ FdoData->usLinkSpeed = 10;
+ FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx;
+ if (!FdoData->usDuplexMode)
+ {
+ FdoData->usDuplexMode = 1;
+ }
+
+ return(STATUS_SUCCESS);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " No Links Found!!\n");
+ }
+
+ //
+ // check if we found a valid phy or on !LookForLink pass
+ //
+ if (!( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0)))
+ || (!FdoData->bLookForLink))
+ {
+
+ //
+ // Valid phy or Not looking for Link
+ //
+
+#if DBG
+ if (!( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0))))
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Found a Phy at address %d\n", FdoData->PhyAddress);
+ }
+#endif
+ //
+ // Store highest priority phy found for NO link case
+ //
+ if (FdoData->CurrentScanPhyIndex < FdoData->FoundPhyAt && FdoData->FoundPhyAt != 1)
+ {
+ // this phy is higher priority
+ FdoData->FoundPhyAt = (UCHAR) FdoData->PhyAddress;
+ }
+
+ //
+ // Select Phy before checking link status
+ // NOTE: may take up to 3.5 Sec if LookForLink == TRUE
+ //SelectPhy(FdoData, FdoData->PhyAddress, (BOOLEAN)LookForLink);
+ //
+ SelectPhy(FdoData, FdoData->PhyAddress, FALSE);
+
+ NEGOTIATION_WAIT:
+
+ //
+ // wait for auto-negotiation to complete (up to 3.5 seconds)
+ //
+ if (FdoData->LinkDetectionWaitCount++ < RENEGOTIATE_TIME)
+ {
+ // Read the status register twice because of sticky bits
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ if (!(MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE))
+ {
+ return STATUS_PENDING;
+ }
+ }
+ else
+ {
+ FdoData->LinkDetectionWaitCount = 0;
+ }
+
+ //
+ // Read the MDI control register
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // Read the status register
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // If there is a valid link or we alreadry tried once then use this Phy.
+ //
+ if ((MdiStatusReg & MDI_SR_LINK_STATUS) || (!FdoData->bLookForLink))
+ {
+#if DBG
+ if (MdiStatusReg & MDI_SR_LINK_STATUS)
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Using Phy at address %d with link\n", FdoData->PhyAddress);
+ }
+ else
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Using Phy at address %d WITHOUT link!!!\n", FdoData->PhyAddress);
+ }
+#endif
+
+ return(SetupPhy(FdoData)); // Exit with Link Path
+ }
+ } // End if valid PHY
+
+ SCAN_PHY_NEXT:
+
+ FdoData->CurrentScanPhyIndex++;
+ if (FdoData->CurrentScanPhyIndex >= 32)
+ {
+ FdoData->bLookForLink = FALSE;
+ }
+
+ goto SCAN_PHY_START;
+}
+
+
+//***************************************************************************
+//
+// Name: SelectPhy
+//
+// Description: This routine will Isolate all Phy addresses on the MII
+// Bus except for the one address to be 'selected'. This
+// Phy address will be un-isolated and auto-negotiation will
+// be enabled, started, and completed. The Phy will NOT be
+// reset and the speed will NOT be set to any value (that is
+// done in SetupPhy).
+//
+// Arguments: SelectPhyAddress - PhyAddress to select
+// WaitAutoNeg - Flag TRUE = Wait for Auto Negociation to complete.
+// FALSE = don't wait. Good for 'No Link' case.
+//
+// Returns: Nothing
+//
+// Modification log:
+// Date Who Description
+// -------- --- --------------------------------------------------------
+//***************************************************************************
+VOID SelectPhy(
+ IN PFDO_DATA FdoData,
+ IN UINT SelectPhyAddress,
+ IN BOOLEAN WaitAutoNeg
+ )
+{
+ UCHAR i;
+ USHORT MdiControlReg = 0;
+ USHORT MdiStatusReg = 0;
+
+ //
+ // Isolate all other phys and unisolate the one to query
+ //
+ for (i = 0; i < 32; i++)
+ {
+ if (i != SelectPhyAddress)
+ {
+ // isolate this phy
+ MdiWrite(FdoData, MDI_CONTROL_REG, i, MDI_CR_ISOLATE);
+ // wait 100 microseconds for the phy to isolate.
+ KeStallExecutionProcessor(100);
+ }
+ }
+
+ // unisolate the phy to query
+
+ //
+ // Read the MDI control register
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, SelectPhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // Set/Clear bit unisolate this phy
+ //
+ MdiControlReg &= ~MDI_CR_ISOLATE; // Clear the Isolate Bit
+
+ //
+ // issue the command to unisolate this Phy
+ //
+ MdiWrite(FdoData, MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg);
+
+ //
+ // sticky bits on link
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // if we have link, don't mess with the phy
+ //
+ if (MdiStatusReg & MDI_SR_LINK_STATUS)
+ return;
+
+ //
+ // Read the MDI control register
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, SelectPhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // set Restart auto-negotiation
+ //
+ MdiControlReg |= MDI_CR_AUTO_SELECT; // Set Auto Neg Enable
+ MdiControlReg |= MDI_CR_RESTART_AUTO_NEG; // Restart Auto Neg
+
+ //
+ // restart the auto-negotion process
+ //
+ MdiWrite(FdoData, MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg);
+
+ //
+ // wait 200 microseconds for the phy to unisolate.
+ //
+ KeStallExecutionProcessor(200);
+
+ if (WaitAutoNeg)
+ {
+ //
+ // wait for auto-negotiation to complete (up to 3.5 seconds)
+ //
+ for (i = RENEGOTIATE_TIME; i != 0; i--)
+ {
+ // Read the status register twice because of sticky bits
+ MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg);
+
+ if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)
+ break;
+
+ MP_STALL_EXECUTION(100);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: SetupPhy
+//
+// Description: This routine will setup phy 1 or phy 0 so that it is configured
+// to match a speed and duplex over-ride option. If speed or
+// duplex mode is not explicitly specified in the registry, the
+// driver will skip the speed and duplex over-ride code, and
+// assume the FdoData is automatically setting the line speed, and
+// the duplex mode. At the end of this routine, any truly Phy
+// specific code will be executed (each Phy has its own quirks,
+// and some require that certain special bits are set).
+//
+// NOTE: The driver assumes that SPEED and FORCEFDX are specified at the
+// same time. If FORCEDPX is set without speed being set, the driver
+// will encouter a fatal error and log a message into the event viewer.
+//
+// Arguments:
+// FdoData - ptr to FdoData object instance
+//
+// Result:
+// Returns:
+// STATUS_SUCCESS
+// NDIS_STATUS_FAILURE
+//-----------------------------------------------------------------------------
+
+NTSTATUS SetupPhy(
+ IN PFDO_DATA FdoData)
+{
+ USHORT MdiControlReg = 0;
+ USHORT MdiStatusReg = 0;
+ USHORT MdiIdLowReg = 0;
+ USHORT MdiIdHighReg = 0;
+ USHORT MdiMiscReg = 0;
+ UINT PhyId;
+ BOOLEAN ForcePhySetting = FALSE;
+
+ //
+ // If we are NOT forcing a setting for line speed or full duplex, then
+ // we won't force a link setting, and we'll jump down to the phy
+ // specific code.
+ //
+ if (((FdoData->AiTempSpeed) || (FdoData->AiForceDpx)))
+ {
+
+ //
+ // Find out what kind of technology this Phy is capable of.
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // Read the MDI control register at our phy
+ //
+ MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg);
+
+ //
+ // Now check the validity of our forced option. If the force option is
+ // valid, then force the setting. If the force option is not valid,
+ // we'll set a flag indicating that we should error out.
+ //
+
+ //
+ // If speed is forced to 10mb
+ //
+ if (FdoData->AiTempSpeed == 10)
+ {
+ // If half duplex is forced
+ if (FdoData->AiForceDpx == 1)
+ {
+ if (MdiStatusReg & MDI_SR_10T_HALF_DPX)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb 1/2 duplex\n");
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ }
+ }
+
+ // If full duplex is forced
+ else if (FdoData->AiForceDpx == 2)
+ {
+ if (MdiStatusReg & MDI_SR_10T_FULL_DPX)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb full duplex\n");
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT);
+ MdiControlReg |= MDI_CR_FULL_HALF;
+ ForcePhySetting = TRUE;
+ }
+ }
+
+ // If auto duplex (we actually set phy to 1/2)
+ else
+ {
+ if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb auto duplex\n");
+ MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ FdoData->AiForceDpx = 1;
+ }
+ }
+ }
+
+ //
+ // If speed is forced to 100mb
+ //
+ else if (FdoData->AiTempSpeed == 100)
+ {
+ // If half duplex is forced
+ if (FdoData->AiForceDpx == 1)
+ {
+ if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb half duplex\n");
+ MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ MdiControlReg |= MDI_CR_10_100;
+ ForcePhySetting = TRUE;
+ }
+ }
+
+ // If full duplex is forced
+ else if (FdoData->AiForceDpx == 2)
+ {
+ if (MdiStatusReg & MDI_SR_TX_FULL_DPX)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb full duplex\n");
+ MdiControlReg &= ~MDI_CR_AUTO_SELECT;
+ MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF);
+ ForcePhySetting = TRUE;
+ }
+ }
+
+ // If auto duplex (we set phy to 1/2)
+ else
+ {
+ if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb auto duplex\n");
+ MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF);
+ MdiControlReg |= MDI_CR_10_100;
+ ForcePhySetting = TRUE;
+ FdoData->AiForceDpx = 1;
+ }
+ }
+ }
+
+ if (ForcePhySetting == FALSE)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Can't force speed=%d, duplex=%d\n",FdoData->AiTempSpeed, FdoData->AiForceDpx);
+
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ //
+ // Write the MDI control register with our new Phy configuration
+ //
+ MdiWrite(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, MdiControlReg);
+
+ //
+ // wait 100 milliseconds for auto-negotiation to complete
+ //
+ MP_STALL_EXECUTION(100);
+
+ }
+
+ //
+ // Find out specifically what Phy this is. We do this because for certain
+ // phys there are specific bits that must be set so that the phy and the
+ // 82557 work together properly.
+ //
+ MdiRead(FdoData, PHY_ID_REG_1, FdoData->PhyAddress, FALSE, &MdiIdLowReg);
+ MdiRead(FdoData, PHY_ID_REG_2, FdoData->PhyAddress, FALSE, &MdiIdHighReg);
+
+ PhyId = ((UINT) MdiIdLowReg | ((UINT) MdiIdHighReg << 16));
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Phy ID is %x\n", PhyId);
+
+ //
+ // And out the revsion field of the Phy ID so that we'll be able to detect
+ // future revs of the same Phy.
+ //
+ PhyId &= PHY_MODEL_REV_ID_MASK;
+
+ //
+ // Handle the National TX
+ //
+ if (PhyId == PHY_NSC_TX)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Found a NSC TX Phy\n");
+
+ MdiRead(FdoData, NSC_CONG_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiMiscReg);
+
+ MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT);
+
+ //
+ // If we are configured to do congestion control, then enable the
+ // congestion control bit in the National Phy
+ //
+ if (FdoData->Congest)
+ MdiMiscReg |= NSC_TX_CONG_ENABLE;
+ else
+ MdiMiscReg &= ~NSC_TX_CONG_ENABLE;
+
+ MdiWrite(FdoData, NSC_CONG_CONTROL_REG, FdoData->PhyAddress, MdiMiscReg);
+ }
+
+ FindPhySpeedAndDpx(FdoData, PhyId);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Current Speed=%d, Current Duplex=%d\n",FdoData->usLinkSpeed, FdoData->usDuplexMode);
+
+ return(STATUS_SUCCESS);
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: FindPhySpeedAndDpx
+//
+// Description: This routine will figure out what line speed and duplex mode
+// the PHY is currently using.
+//
+// Arguments:
+// FdoData - ptr to FdoData object instance
+// PhyId - The ID of the PHY in question.
+//
+// Returns:
+// NOTHING
+//-----------------------------------------------------------------------------
+
+VOID FindPhySpeedAndDpx(
+ IN PFDO_DATA FdoData,
+ IN UINT PhyId
+ )
+{
+ USHORT MdiStatusReg = 0;
+ USHORT MdiMiscReg = 0;
+ USHORT MdiOwnAdReg = 0;
+ USHORT MdiLinkPartnerAdReg = 0;
+
+ //
+ // If there was a speed and/or duplex override, then set our current
+ // value accordingly
+ //
+ FdoData->usLinkSpeed = FdoData->AiTempSpeed;
+ FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx;
+
+ //
+ // If speed and duplex were forced, then we know our current settings, so
+ // we'll just return. Otherwise, we'll need to figure out what NWAY set
+ // us to.
+ //
+ if (FdoData->usLinkSpeed && FdoData->usDuplexMode)
+ {
+ return;
+ }
+
+ //
+ // If we didn't have a valid link, then we'll assume that our current
+ // speed is 10mb half-duplex.
+ //
+
+ //
+ // Read the status register twice because of sticky bits
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // If there wasn't a valid link then use default speed & duplex
+ //
+ if (!(MdiStatusReg & MDI_SR_LINK_STATUS))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Link Not found for speed detection!!! Using defaults.\n");
+
+ FdoData->usLinkSpeed = 10;
+ FdoData->usDuplexMode = 1;
+
+ return;
+ }
+
+ //
+ // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits
+ // 1 and 0 of extended register 0, to get the current speed and duplex
+ // settings.
+ //
+ if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx for an Intel PHY\n");
+
+ //
+ // Read extended register 0
+ //
+ MdiRead(FdoData, EXTENDED_REG_0, FdoData->PhyAddress, FALSE, &MdiMiscReg);
+
+ //
+ // Get current speed setting
+ //
+ if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC)
+ {
+ FdoData->usLinkSpeed = 100;
+ }
+ else
+ {
+ FdoData->usLinkSpeed = 10;
+ }
+
+ //
+ //
+ // Get current duplex setting -- if bit is set then FDX is enabled
+ //
+ if (MdiMiscReg & PHY_100_ER0_FDX_INDIC)
+ {
+ FdoData->usDuplexMode = 2;
+ }
+ else
+ {
+ FdoData->usDuplexMode = 1;
+ }
+
+ return;
+ }
+
+ //
+ // Read our link partner's advertisement register
+ //
+ MdiRead(FdoData,
+ AUTO_NEG_LINK_PARTNER_REG,
+ FdoData->PhyAddress,
+ FALSE,
+ &MdiLinkPartnerAdReg);
+ //
+ // See if Auto-Negotiation was complete (bit 5, reg 1)
+ //
+ MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg);
+
+ //
+ // If a True NWAY connection was made, then we can detect speed/duplex by
+ // ANDing our FdoData's advertised abilities with our link partner's
+ // advertised ablilities, and then assuming that the highest common
+ // denominator was chosed by NWAY.
+ //
+ if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) &&
+ (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx from NWAY connection\n");
+
+ //
+ // Read our advertisement register
+ //
+ MdiRead(FdoData, AUTO_NEG_ADVERTISE_REG, FdoData->PhyAddress, FALSE, &MdiOwnAdReg);
+
+ //
+ // AND the two advertisement registers together, and get rid of any
+ // extraneous bits.
+ //
+ MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY);
+
+ //
+ // Get speed setting
+ //
+ if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE))
+ {
+ FdoData->usLinkSpeed = 100;
+ }
+ else
+ {
+ FdoData->usLinkSpeed = 10;
+ }
+
+ //
+ // Get duplex setting -- use priority resolution algorithm
+ //
+ if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE))
+ {
+ FdoData->usDuplexMode = 1;
+ return;
+ }
+ else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX))
+ {
+ FdoData->usDuplexMode = 2;
+ return;
+ }
+ else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX))
+ {
+ FdoData->usDuplexMode = 1;
+ return;
+ }
+ else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX))
+ {
+ FdoData->usDuplexMode = 2;
+ return;
+ }
+ else
+ {
+ FdoData->usDuplexMode = 1;
+ return;
+ }
+ }
+
+ //
+ // If we are connected to a non-NWAY repeater or hub, and the line
+ // speed was determined automatically by parallel detection, then we have
+ // no way of knowing exactly what speed the PHY is set to unless that PHY
+ // has a propietary register which indicates speed in this situation. The
+ // NSC TX PHY does have such a register. Also, since NWAY didn't establish
+ // the connection, the duplex setting should HALF duplex.
+ //
+ FdoData->usDuplexMode = 1;
+
+ if (PhyId == PHY_NSC_TX)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx from non-NWAY NSC connection\n");
+
+ //
+ // Read register 25 to get the SPEED_10 bit
+ //
+ MdiRead(FdoData, NSC_SPEED_IND_REG, FdoData->PhyAddress, FALSE, &MdiMiscReg);
+
+ //
+ // If bit 6 was set then we're at 10mb
+ //
+ if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED)
+ {
+ FdoData->usLinkSpeed = 10;
+ }
+ else
+ {
+ FdoData->usLinkSpeed = 100;
+ }
+ }
+ //
+ // If we don't know what line speed we are set at, then we'll default to
+ // 10mbs
+ //
+ else
+ {
+ FdoData->usLinkSpeed = 10;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: ResetPhy
+//
+// Description: This routine will reset the PHY that the FdoData is currently
+// configured to use.
+//
+// Arguments:
+// FdoData - ptr to FdoData object instance
+//
+// Returns:
+// NOTHING
+//-----------------------------------------------------------------------------
+
+VOID ResetPhy(
+ IN PFDO_DATA FdoData
+ )
+{
+ USHORT MdiControlReg;
+
+ //
+ // Reset the Phy, enable auto-negotiation, and restart auto-negotiation.
+ //
+ MdiControlReg = (MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | MDI_CR_RESET);
+
+ //
+ // Write the MDI control register with our new Phy configuration
+ //
+ MdiWrite(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, MdiControlReg);
+}
+
diff --git a/general/pcidrv/kmdf/HW/precomp.h b/general/pcidrv/kmdf/HW/precomp.h
new file mode 100644
index 00000000..851ce1f1
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/precomp.h
@@ -0,0 +1,45 @@
+//
+// precomp.h for pcidrv driver
+//
+#define WIN9X_COMPAT_SPINLOCK
+#include <ntddk.h>
+#include <wdf.h>
+
+typedef unsigned int UINT;
+typedef unsigned int *PUINT;
+
+#include <initguid.h> // required for GUID definitions
+#include <wdmguid.h> // required for WMILIB_CONTEXT
+#include <wmistr.h>
+#include <wmilib.h>
+#include <ntintsafe.h>
+
+
+//
+// Disable warnings that prevent our driver from compiling with /W4 MSC_WARNING_LEVEL
+//
+// Disable warning C4214: nonstandard extension used : bit field types other than int
+// Disable warning C4201: nonstandard extension used : nameless struct/union
+// Disable warning C4115: named type definition in parentheses
+//
+#pragma warning(disable:4214)
+#pragma warning(disable:4201)
+#pragma warning(disable:4115)
+
+#include "ntddndis.h" // for OIDs
+
+#pragma warning(default:4214)
+#pragma warning(default:4201)
+#pragma warning(default:4115)
+
+#include "nuiouser.h" // for ioctls recevied from ndisedge
+#include "public.h"
+
+#include "e100_equ.h"
+#include "e100_557.h"
+#include "trace.h"
+#include "nic_def.h"
+#include "pcidrv.h"
+#include "macros.h"
+
+
diff --git a/general/pcidrv/kmdf/HW/precompsrc.c b/general/pcidrv/kmdf/HW/precompsrc.c
new file mode 100644
index 00000000..5944cf51
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/precompsrc.c
@@ -0,0 +1 @@
+#include "precomp.h" \ No newline at end of file
diff --git a/general/pcidrv/kmdf/HW/routines.c b/general/pcidrv/kmdf/HW/routines.c
new file mode 100644
index 00000000..d6908ea5
--- /dev/null
+++ b/general/pcidrv/kmdf/HW/routines.c
@@ -0,0 +1,479 @@
+/****************************************************************************
+** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
+** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
+** HTTP://WWW.INTEL.COM/ **
+** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
+** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
+****************************************************************************/
+
+/****************************************************************************
+Module Name:
+ routines.c
+
+This driver runs on the following hardware:
+ - 82558 based PCI 10/100Mb ethernet adapters
+ (aka Intel EtherExpress(TM) PRO Adapters)
+
+Environment:
+ Kernel Mode - Or whatever is the equivalent on WinNT
+
+*****************************************************************************/
+
+//#pragma TRACE_LEVEL_WARNING (disable: 4514 4706)
+
+//-----------------------------------------------------------------------------
+// Procedure: MdiWrite
+//
+// Description: This routine will write a value to the specified MII register
+// of an external MDI compliant device (e.g. PHY 100). The
+// command will execute in polled mode.
+//
+// Arguments:
+// Adapter - ptr to Adapter object instance
+// RegAddress - The MII register that we are writing to
+// PhyAddress - The MDI address of the Phy component.
+// DataValue - The value that we are writing to the MII register.
+//
+// Returns:
+// NOTHING
+//-----------------------------------------------------------------------------
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "routines.tmh"
+#endif
+
+//-----------------------------------------------------------------------------
+// Procedure: WaitScb
+//
+// Description: This routine checks to see if the D100 has accepted a command.
+// It does so by checking the command field in the SCB, which will
+// be zeroed by the D100 upon accepting a command. The loop waits
+// for up to 600 milliseconds for command acceptance.
+//
+// Arguments:
+// Adapter - ptr to Adapter object instance
+//
+// Returns:
+// TRUE if the SCB cleared within 600 milliseconds.
+// FALSE if it didn't clear within 600 milliseconds
+//-----------------------------------------------------------------------------
+__inline BOOLEAN
+WaitScb(
+ IN PFDO_DATA FdoData
+ )
+{
+ BOOLEAN bResult;
+
+ HW_CSR volatile *pCSRAddress = FdoData->CSRAddress;
+
+ MP_STALL_AND_WAIT(pCSRAddress->ScbCommandLow == 0, 600, bResult);
+ if(!bResult)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "WaitScb failed, ScbCommandLow=%x\n", pCSRAddress->ScbCommandLow);
+ if(pCSRAddress->ScbCommandLow != 0x80)
+ {
+ //ASSERT(FALSE);
+ }
+ MP_SET_HARDWARE_ERROR(FdoData);
+ }
+
+ return bResult;
+}
+
+
+VOID
+MdiWrite(
+ IN PFDO_DATA Adapter,
+ IN ULONG RegAddress,
+ IN ULONG PhyAddress,
+ IN USHORT DataValue
+ )
+{
+ BOOLEAN bResult;
+
+ // Issue the write command to the MDI control register.
+ Adapter->CSRAddress->MDIControl = (((ULONG) DataValue) |
+ (RegAddress << 16) |
+ (PhyAddress << 21) |
+ (MDI_WRITE << 26));
+
+ // wait 20usec before checking status
+ KeStallExecutionProcessor (20);
+
+ // wait 2 seconds for the mdi write to complete
+ MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult);
+
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: MdiRead
+//
+// Description: This routine will read a value from the specified MII register
+// of an external MDI compliant device (e.g. PHY 100), and return
+// it to the calling routine. The command will execute in polled
+// mode.
+//
+// Arguments:
+// Adapter - ptr to Adapter object instance
+// RegAddress - The MII register that we are reading from
+// PhyAddress - The MDI address of the Phy component.
+// Recoverable - Whether the hardware TRACE_LEVEL_ERROR(if any)if recoverable or not
+//
+// Results:
+// DataValue - The value that we read from the MII register.
+//
+// Returns:
+// None
+//-----------------------------------------------------------------------------
+BOOLEAN
+MdiRead(
+ IN PFDO_DATA Adapter,
+ IN ULONG RegAddress,
+ IN ULONG PhyAddress,
+ IN BOOLEAN Recoverable,
+ IN OUT PUSHORT DataValue
+ )
+{
+ BOOLEAN bResult;
+
+ // Issue the read command to the MDI control register.
+ Adapter->CSRAddress->MDIControl = ((RegAddress << 16) |
+ (PhyAddress << 21) |
+ (MDI_READ << 26));
+
+ // wait 20usec before checking status
+ KeStallExecutionProcessor (20);
+
+ // Wait up to 2 seconds for the mdi read to complete
+ MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult);
+ if (!bResult)
+ {
+ if (!Recoverable)
+ {
+ MP_SET_NON_RECOVER_ERROR(Adapter);
+ }
+ MP_SET_HARDWARE_ERROR(Adapter);
+ return bResult;
+ }
+
+ *DataValue = (USHORT) Adapter->CSRAddress->MDIControl;
+ return bResult;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: DumpStatsCounters
+//
+// Description: This routine will dump and reset the 82557's internal
+// Statistics counters. The current stats dump values will be
+// added to the "Adapter's" overall statistics.
+// Arguments:
+// Adapter - ptr to Adapter object instance
+//
+// Returns:
+// NOTHING
+//-----------------------------------------------------------------------------
+VOID
+DumpStatsCounters(
+ IN PFDO_DATA Adapter
+ )
+{
+ BOOLEAN bResult;
+ //KIRQL oldIrql;
+
+ // The query is for a driver statistic, so we need to first
+ // update our statistics in software.
+
+ // clear the dump counters complete DWORD
+ Adapter->StatsCounters->CommandComplete = 0;
+
+
+ WdfSpinLockAcquire(Adapter->Lock);
+
+ // Dump and reset the hardware's statistic counters
+ D100IssueScbCommand(Adapter, SCB_CUC_DUMP_RST_STAT, TRUE);
+
+ // Restore the resume transmit software flag. After the dump counters
+ // command is issued, we should do a WaitSCB before issuing the next send.
+ Adapter->ResumeWait = TRUE;
+
+
+ WdfSpinLockRelease(Adapter->Lock);
+
+ // wait up to 2 seconds for the dump/reset to complete
+ MP_STALL_AND_WAIT(Adapter->StatsCounters->CommandComplete == 0xA007, 2000, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ return;
+ }
+
+ // Output the debug counters to the debug terminal.
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Good Transmits %d\n", Adapter->StatsCounters->XmtGoodFrames);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Good Receives %d\n", Adapter->StatsCounters->RcvGoodFrames);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Max Collisions %d\n", Adapter->StatsCounters->XmtMaxCollisions);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Late Collisions %d\n", Adapter->StatsCounters->XmtLateCollisions);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmit Underruns %d\n", Adapter->StatsCounters->XmtUnderruns);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmit Lost CRS %d\n", Adapter->StatsCounters->XmtLostCRS);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmits Deferred %d\n", Adapter->StatsCounters->XmtDeferred);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "One Collision xmits %d\n", Adapter->StatsCounters->XmtSingleCollision);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Mult Collision xmits %d\n", Adapter->StatsCounters->XmtMultCollisions);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Total Collisions %d\n", Adapter->StatsCounters->XmtTotalCollisions);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive CRC errors %d\n", Adapter->StatsCounters->RcvCrcErrors);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive Alignment errors %d\n", Adapter->StatsCounters->RcvAlignmentErrors);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive no resources %d\n", Adapter->StatsCounters->RcvResourceErrors);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive overrun errors %d\n", Adapter->StatsCounters->RcvOverrunErrors);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive CDT errors %d\n", Adapter->StatsCounters->RcvCdtErrors);
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive short frames %d\n", Adapter->StatsCounters->RcvShortFrames);
+
+ // update packet counts
+ Adapter->GoodTransmits += Adapter->StatsCounters->XmtGoodFrames;
+ Adapter->GoodReceives += Adapter->StatsCounters->RcvGoodFrames;
+
+ // update transmit TRACE_LEVEL_ERROR counts
+ Adapter->TxAbortExcessCollisions += Adapter->StatsCounters->XmtMaxCollisions;
+ Adapter->TxLateCollisions += Adapter->StatsCounters->XmtLateCollisions;
+ Adapter->TxDmaUnderrun += Adapter->StatsCounters->XmtUnderruns;
+ Adapter->TxLostCRS += Adapter->StatsCounters->XmtLostCRS;
+ Adapter->TxOKButDeferred += Adapter->StatsCounters->XmtDeferred;
+ Adapter->OneRetry += Adapter->StatsCounters->XmtSingleCollision;
+ Adapter->MoreThanOneRetry += Adapter->StatsCounters->XmtMultCollisions;
+ Adapter->TotalRetries += Adapter->StatsCounters->XmtTotalCollisions;
+
+ // update receive TRACE_LEVEL_ERROR counts
+ Adapter->RcvCrcErrors += Adapter->StatsCounters->RcvCrcErrors;
+ Adapter->RcvAlignmentErrors += Adapter->StatsCounters->RcvAlignmentErrors;
+ Adapter->RcvResourceErrors += Adapter->StatsCounters->RcvResourceErrors;
+ Adapter->RcvDmaOverrunErrors += Adapter->StatsCounters->RcvOverrunErrors;
+ Adapter->RcvCdtFrames += Adapter->StatsCounters->RcvCdtErrors;
+ Adapter->RcvRuntErrors += Adapter->StatsCounters->RcvShortFrames;
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: NICIssueSelectiveReset
+//
+// Description: This routine will issue a selective reset, forcing the adapter
+// the CU and RU back into their idle states. The receive unit
+// will then be re-enabled if it was previously enabled, because
+// an RNR interrupt will be generated when we abort the RU.
+//
+// Arguments:
+// Adapter - ptr to Adapter object instance
+//
+// Returns:
+// NOTHING
+//-----------------------------------------------------------------------------
+
+VOID
+NICIssueSelectiveReset(
+ PFDO_DATA Adapter
+ )
+{
+ NTSTATUS status;
+ BOOLEAN bResult;
+
+ // Wait for the SCB to clear before we check the CU status.
+ if (!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HARDWARE_ERROR))
+ {
+ WaitScb(Adapter);
+ }
+
+ // If we have issued any transmits, then the CU will either be active, or
+ // in the suspended state. If the CU is active, then we wait for it to be
+ // suspended. If the the CU is suspended, then we need to put the CU back
+ // into the idle state by issuing a selective reset.
+ if (Adapter->TransmitIdle == FALSE)
+ {
+ // Wait up to 2 seconds for suspended state
+ MP_STALL_AND_WAIT((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 2000, bResult)
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ }
+
+ // Check the current status of the receive unit
+ if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
+ {
+ // Issue an RU abort. Since an interrupt will be issued, the
+ // RU will be started by the DPC.
+ status = D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE);
+ }
+
+ // Issue a selective reset.
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "CU suspended. ScbStatus=%04x Issue selective reset\n", Adapter->CSRAddress->ScbStatus);
+ Adapter->CSRAddress->Port = PORT_SELECTIVE_RESET;
+
+ // Wait after a port sel-reset command
+ KeStallExecutionProcessor (NIC_DELAY_POST_RESET);
+
+ // wait up to 2 ms for port command to complete
+ MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult)
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ }
+
+ // disable interrupts after issuing reset, because the int
+ // line gets raised when reset completes.
+ NICDisableInterrupt(Adapter);
+
+ // Restore the transmit software flags.
+ Adapter->TransmitIdle = TRUE;
+ Adapter->ResumeWait = TRUE;
+ }
+}
+
+VOID
+NICIssueFullReset(
+ PFDO_DATA Adapter
+ )
+{
+ BOOLEAN bResult;
+
+ NICIssueSelectiveReset(Adapter);
+
+ Adapter->CSRAddress->Port = PORT_SOFTWARE_RESET;
+
+ // wait up to 2 ms for port command to complete
+ MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ return;
+ }
+
+ NICDisableInterrupt(Adapter);
+}
+
+
+//-----------------------------------------------------------------------------
+// Procedure: D100SubmitCommandBlockAndWait
+//
+// Description: This routine will submit a command block to be executed, and
+// then it will wait for that command block to be executed. Since
+// board ints will be disabled, we will ack the interrupt in
+// this routine.
+//
+// Arguments:
+// Adapter - ptr to Adapter object instance
+//
+// Returns:
+// NDIS_STATUS_SUCCESS
+// STATUS_DEVICE_DATA_ERROR
+//-----------------------------------------------------------------------------
+
+NTSTATUS
+D100SubmitCommandBlockAndWait(
+ IN PFDO_DATA Adapter
+ )
+{
+ NTSTATUS status;
+ BOOLEAN bResult;
+
+ // Points to the Non Tx Command Block.
+ NON_TRANSMIT_CB volatile *CommandBlock = Adapter->NonTxCmdBlock;
+
+ // Set the Command Block to be the last command block
+ CommandBlock->NonTxCb.Config.ConfigCBHeader.CbCommand |= CB_EL_BIT;
+
+ // Clear the status of the command block
+ CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus = 0;
+
+#if DBG
+ // Don't try to start the CU if the command unit is active.
+ if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Scb %p ScbStatus %04x\n", Adapter->CSRAddress, Adapter->CSRAddress->ScbStatus);
+ ASSERT(FALSE);
+ MP_SET_HARDWARE_ERROR(Adapter);
+ return(STATUS_DEVICE_DATA_ERROR);
+ }
+#endif
+
+ // Start the command unit.
+ D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);
+
+ // Wait for the SCB to clear, indicating the completion of the command.
+ if (!WaitScb(Adapter))
+ {
+ return(STATUS_DEVICE_DATA_ERROR);
+ }
+
+ // Wait for some status, timeout value 3 secs
+ MP_STALL_AND_WAIT(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_COMPLETE, 3000, bResult);
+ if (!bResult)
+ {
+ MP_SET_HARDWARE_ERROR(Adapter);
+ return(STATUS_DEVICE_DATA_ERROR);
+ }
+
+ // Ack any interrupts
+ if (Adapter->CSRAddress->ScbStatus & SCB_ACK_MASK)
+ {
+ // Ack all pending interrupts now
+ Adapter->CSRAddress->ScbStatus &= SCB_ACK_MASK;
+ }
+
+ // Check the status of the command, and if the command failed return FALSE,
+ // otherwise return TRUE.
+ if (!(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_OK))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Command failed\n");
+ MP_SET_HARDWARE_ERROR(Adapter);
+ status = STATUS_DEVICE_DATA_ERROR;
+ }
+ else
+ status = STATUS_SUCCESS;
+
+ return(status);
+}
+
+//-----------------------------------------------------------------------------
+// Procedure: GetConnectionStatus
+//
+// Description: This function returns the connection status that is
+// a required indication for PC 97 specification from MS
+// the value we are looking for is if there is link to the
+// wire or not.
+//
+// Arguments: IN Adapter structure pointer
+//
+// Returns: NdisMediaStateConnected
+// NdisMediaStateDisconnected
+//-----------------------------------------------------------------------------
+MEDIA_STATE
+GetMediaState(
+ IN PFDO_DATA Adapter
+ )
+{
+ USHORT MdiStatusReg = 0;
+ BOOLEAN bResult1;
+ BOOLEAN bResult2;
+
+
+ // Read the status register at phy 1
+ bResult1 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg);
+ bResult2 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg);
+
+ // if there is hardware failure, or let the state remains the same
+ if (!bResult1 || !bResult2)
+ {
+ return Adapter->MediaState;
+ }
+ if (MdiStatusReg & MDI_SR_LINK_STATUS)
+ return(Connected);
+ else
+ return(Disconnected);
+
+}
+
diff --git a/general/pcidrv/kmdf/PCIDRV.C b/general/pcidrv/kmdf/PCIDRV.C
new file mode 100644
index 00000000..41a71b3c
--- /dev/null
+++ b/general/pcidrv/kmdf/PCIDRV.C
@@ -0,0 +1,1792 @@
+
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ PciDrv.c
+
+Abstract:
+
+ This is a generic WDM sample driver for Intel 82557/82558
+ based PCI Ethernet Adapter (10/100) and Intel compatibles.
+ The WDM interface in this sample is based on the Toaster function
+ driver, and all the code to access the hardware is taken from
+ the E100BEX NDIS miniport sample from the DDK and converted to
+ use WDM interfaces instead of NDIS functions.
+
+ This driver can be installed as a standalone driver (genpci.inf)
+ for the Intel PCI device. Please read the PCIDRV.HTM file for
+ more information.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+//
+// The trace message header (.tmh) file must be included in a source file
+// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS
+// macro (defined in toaster.h). During the compilation, WPP scans the source
+// files for DoTraceMessage() calls and builds a .tmh file which stores a unique
+// data GUID for each message, the text resource string for each message,
+// and the data types of the variables passed in for each message. This file
+// is automatically generated and used during post-processing.
+//
+#include "pcidrv.tmh"
+#endif
+
+//
+// Global debug error level
+//
+#if !defined(EVENT_TRACING)
+ULONG DebugLevel = TRACE_LEVEL_INFORMATION;
+ULONG DebugFlag = 0x2f;//0x46;//0x4FF; //0x00000006;
+#else
+ULONG DebugLevel; // wouldn't be used to control the TRACE_LEVEL_VERBOSE
+ULONG DebugFlag;
+#endif
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text (INIT, DriverEntry)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceAdd)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceContextCleanup)
+#pragma alloc_text (PAGE, PciDrvEvtDevicePrepareHardware)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceReleaseHardware)
+#pragma alloc_text (PAGE, PciDrvReadRegistryValue)
+#pragma alloc_text (PAGE, PciDrvWriteRegistryValue)
+#pragma alloc_text (PAGE, PciDrvEvtDriverContextCleanup)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceSelfManagedIoCleanup)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceSelfManagedIoSuspend)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeArmS0)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeTriggeredS0)
+#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeArmSx)
+#pragma alloc_text (PAGE, PciDrvSetPowerPolicy)
+#pragma alloc_text (PAGE, PciDrvReadFdoRegistryKeyValue)
+#endif
+
+
+#define PARAMATER_NAME_LEN 80
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path,
+ to driver-specific key in the registry.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ WDF_DRIVER_CONFIG config;
+ WDF_OBJECT_ATTRIBUTES attrib;
+ WDFDRIVER driver;
+ PDRIVER_CONTEXT driverContext;
+
+ //
+ // Initialize WPP Tracing
+ //
+ WPP_INIT_TRACING( DriverObject, RegistryPath );
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "PCIDRV Sample - Driver Framework Edition \n");
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, DRIVER_CONTEXT);
+
+ //
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ //
+ attrib.EvtCleanupCallback = PciDrvEvtDriverContextCleanup;
+
+ //
+ // Initialize the Driver Config structure..
+ //
+ WDF_DRIVER_CONFIG_INIT(&config, PciDrvEvtDeviceAdd);
+
+ //
+ // Create a WDFDRIVER object.
+ //
+ status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ &attrib,
+ &config,
+ &driver);
+
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "WdfDriverCreate failed with status %!STATUS!\n", status);
+ //
+ // Cleanup tracing here because DriverContextCleanup will not be called
+ // as we have failed to create WDFDRIVER object itself.
+ // Please note that if your return failure from DriverEntry after the
+ // WDFDRIVER object is created successfully, you don't have to
+ // call WPP cleanup because in those cases DriverContextCleanup
+ // will be executed when the framework deletes the DriverObject.
+ //
+ WPP_CLEANUP(DriverObject);
+ return status;
+ }
+
+ driverContext = GetDriverContext(driver);
+
+ //
+ // Create a driver wide lookside list used for allocating memory for the
+ // MP_RFD structure for all device instances (if there are multiple present).
+ //
+ status = WdfLookasideListCreate(WDF_NO_OBJECT_ATTRIBUTES, // LookAsideAttributes
+ sizeof(MP_RFD),
+ NonPagedPool,
+ WDF_NO_OBJECT_ATTRIBUTES, // MemoryAttributes
+ PCIDRV_POOL_TAG,
+ &driverContext->RecvLookaside
+ );
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
+ "Couldn't allocate lookaside list status %!STATUS!\n", status);
+ return status;
+ }
+
+ return status;
+
+}
+
+NTSTATUS
+PciDrvEvtDeviceAdd(
+ IN WDFDRIVER Driver,
+ IN PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager.
+
+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 = STATUS_SUCCESS;
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks;
+ WDF_OBJECT_ATTRIBUTES fdoAttributes;
+ WDFDEVICE device;
+ PFDO_DATA fdoData = NULL;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "-->PciDrvEvtDeviceAdd routine. Driver: 0x%p\n", Driver);
+
+ //
+ // I/O type is Buffered by default. If required to use something else,
+ // call WdfDeviceInitSetIoType with the appropriate type.
+ //
+ WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
+
+ //
+ // Zero out the PnpPowerCallbacks structure.
+ //
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+
+ //
+ // Set Callbacks for any of the functions we are interested in.
+ // If no callback is set, Framework will take the default action
+ // by itself. This sample provides many of the possible callbacks,
+ // mostly because it's a fairly complex sample that drives full-featured
+ // hardware. Drivers derived from this sample will often be able to
+ // provide only some of these.
+ //
+
+ //
+ // These callback is invoked to tear down all the driver-managed state
+ // that is set up in this function. Many times, this callback won't do
+ // much of anything, since many of the things that are set up here will
+ // have their lifetimes automatically managed by the Framework.
+ //
+
+
+ //
+ // These two callbacks set up and tear down hardware state,
+ // specifically that which only has to be done once.
+ //
+
+ pnpPowerCallbacks.EvtDevicePrepareHardware = PciDrvEvtDevicePrepareHardware;
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = PciDrvEvtDeviceReleaseHardware;
+
+ //
+ // These two callbacks set up and tear down hardware state that must be
+ // done every time the device moves in and out of the D0-working state.
+ //
+
+ pnpPowerCallbacks.EvtDeviceD0Entry = PciDrvEvtDeviceD0Entry;
+ pnpPowerCallbacks.EvtDeviceD0Exit = PciDrvEvtDeviceD0Exit;
+
+ //
+ // These next two callbacks are for doing work at PASSIVE_LEVEL (low IRQL)
+ // after all the interrupts are connected and before they are disconnected.
+ //
+ // Some drivers need to do device initialization and tear-down while the
+ // interrupt is connected. (This is a problem for these devices, since
+ // it opens them up to taking interrupts before they are actually ready
+ // to handle them, or to taking them after they have torn down too much
+ // to be able to handle them.) While this hardware design pattern is to
+ // be discouraged, it is possible to handle it by doing device init and
+ // tear down in these routines rather than in EvtDeviceD0Entry and
+ // EvtDeviceD0Exit.
+ //
+ // In this sample these callbacks don't do anything.
+ //
+
+ pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = NICEvtDeviceD0EntryPostInterruptsEnabled;
+ pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = NICEvtDeviceD0ExitPreInterruptsDisabled;
+
+ //
+ // This next group of five callbacks allow a driver to become involved in
+ // starting and stopping operations within a driver as the driver moves
+ // through various PnP/Power states. These functions are not necessary
+ // if the Framework is managing all the device's queues and there is no
+ // activity going on that isn't queue-based. This sample provides these
+ // callbacks because it uses watchdog timer to monitor whether the device
+ // is working or not and it needs to start and stop the timer when the device
+ // is started or removed. It cannot start and stop the timers in the D0Entry
+ // and D0Exit callbacks because if the device is surprise-removed, D0Exit
+ // will not be called.
+ //
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = PciDrvEvtDeviceSelfManagedIoInit;
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = PciDrvEvtDeviceSelfManagedIoCleanup;
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = PciDrvEvtDeviceSelfManagedIoSuspend;
+ pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = PciDrvEvtDeviceSelfManagedIoRestart;
+
+ //
+ // Register the PnP and power callbacks. Power policy related callbacks will be registered
+ // later.
+ //
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ //
+ // Init the power policy callbacks
+ //
+ WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks);
+
+ //
+ // This group of three callbacks allows this sample driver to manage
+ // arming the device for wake from the S0 state. Networking devices can
+ // optionally be put into a low-power state when there is no networking
+ // cable plugged into them. This sample implements this feature.
+ //
+ powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = PciDrvEvtDeviceWakeArmS0;
+ powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = PciDrvEvtDeviceWakeDisarmS0;
+ powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = PciDrvEvtDeviceWakeTriggeredS0;
+
+ //
+ // This group of three callbacks allows the device to be armed for wake
+ // from Sx (S1, S2, S3 or S4.) Networking devices can optionally be put
+ // into a state where a packet sent to them will cause the device's wake
+ // signal to be triggered, which causes the machine to wake, moving back
+ // into the S0 state.
+ //
+
+ powerPolicyCallbacks.EvtDeviceArmWakeFromSx = PciDrvEvtDeviceWakeArmSx;
+ powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = PciDrvEvtDeviceWakeDisarmSx;
+ powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = PciDrvEvtDeviceWakeTriggeredSx;
+
+ //
+ // Register the power policy callbacks.
+ //
+ WdfDeviceInitSetPowerPolicyEventCallbacks(DeviceInit, &powerPolicyCallbacks);
+
+ // Since we are the function driver, we are now the power policy owner
+ // for the device according to the default framework rule. We will register
+ // our power policy callbacks after finding the wakeup capability of the device.
+
+ //
+ // Specify the context type and size for the device we are about to create.
+ //
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA);
+
+ //
+ // ContextCleanup will be called by the framework when it deletes the device.
+ // So you can defer freeing any resources allocated to Cleanup callback in the
+ // event AddDevice returns any error after the device is created.
+ //
+ fdoAttributes.EvtCleanupCallback = PciDrvEvtDeviceContextCleanup;
+
+ status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device);
+
+ if ( !NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceInitialize failed %!STATUS!\n", status);
+ return status;
+ }
+
+ //
+ // Device creation is complete.
+ // Get the DeviceExtension and initialize it.
+ //
+ fdoData = FdoGetData(device);
+ fdoData->WdfDevice = device;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "PDO(0x%p) FDO(0x%p), Lower(0x%p) DevExt (0x%p)\n",
+ WdfDeviceWdmGetPhysicalDevice (device),
+ WdfDeviceWdmGetDeviceObject (device),
+ WdfDeviceWdmGetAttachedDevice(device),
+ fdoData);
+
+ //
+ // Initialize the device extension and allocate all the software resources
+ //
+ status = NICAllocateSoftwareResources(fdoData);
+ if (!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "NICAllocateSoftwareResources failed: %!STATUS!\n",
+ status);
+ return status;
+ }
+
+ //
+ // If our device supports wait-wake then we will set our power-policy and
+ // update S0-Idle policy.
+ //
+ if (IsPoMgmtSupported(fdoData)) {
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "Device has wait-wake capability\n");
+ status = PciDrvSetPowerPolicy(fdoData);
+ if (!NT_SUCCESS (status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "PciDrvSetPowerPolicy failed %!STATUS!\n", status);
+ return status;
+ }
+ }
+
+ //
+ // Tell the Framework that this device will need an interface so that
+ // application can interact with it.
+ //
+ status = WdfDeviceCreateDeviceInterface(
+ device,
+ (LPGUID) &GUID_DEVINTERFACE_PCIDRV,
+ NULL
+ );
+
+ if (!NT_SUCCESS (status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status);
+ return status;
+ }
+
+ status = PciDrvWmiRegistration(device);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PciDrvEvtDeviceAdd \n");
+
+ return status;
+}
+
+VOID
+PciDrvEvtDeviceContextCleanup (
+ WDFOBJECT Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceContextCleanup event callback cleans up anything done in
+ EvtDeviceAdd, except those things that are automatically cleaned
+ up by the Framework.
+
+ In the case of this sample, everything is automatically handled. In a
+ driver derived from this sample, it's quite likely that this function could
+ be deleted.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+
+ PAGED_CODE();
+
+ fdoData = FdoGetData((WDFDEVICE)Device);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceContextCleanup\n");
+
+ NICFreeSoftwareResources(fdoData);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceContextCleanup\n");
+
+}
+
+NTSTATUS
+PciDrvEvtDevicePrepareHardware (
+ WDFDEVICE Device,
+ WDFCMRESLIST Resources,
+ WDFCMRESLIST ResourcesTranslated
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceStart 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
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PFDO_DATA fdoData = NULL;
+
+ UNREFERENCED_PARAMETER(Resources);
+ UNREFERENCED_PARAMETER(ResourcesTranslated);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDevicePrepareHardware\n");
+
+ fdoData = FdoGetData(Device);
+
+ status = NICMapHWResources(fdoData, Resources, ResourcesTranslated);
+ if (!NT_SUCCESS (status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "NICMapHWResources failed: %!STATUS!\n", status);
+ return status;
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDevicePrepareHardware\n");
+
+ return status;
+
+}
+
+NTSTATUS
+PciDrvEvtDeviceReleaseHardware(
+ IN WDFDEVICE Device,
+ IN WDFCMRESLIST ResourcesTranslated
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceReleaseHardware is called by the framework whenever the PnP manager
+ is revoking ownership of our resources. This may be in response to either
+ IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before
+ passing down the IRP to the lower driver.
+
+ In this callback, do anything necessary to free those resources.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+ 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:
+
+ NTSTATUS - Failures will be logged, but not acted on.
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+
+ UNREFERENCED_PARAMETER(ResourcesTranslated);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceReleaseHardware\n");
+
+ fdoData = FdoGetData(Device);
+
+ //
+ // Unmap any I/O ports. Disconnecting from the interrupt will be done
+ // automatically by the framework.
+ //
+ NICUnmapHWResources(fdoData);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceReleaseHardware\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+PciDrvEvtDeviceD0Entry(
+ 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 is not marked pageable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+ This function runs at PASSIVE_LEVEL, even though it is 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
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,
+ "-->PciDrvEvtDeviceD0Entry - coming from %s\n",
+ DbgDevicePowerString(PreviousState));
+
+ fdoData = FdoGetData(Device);
+
+ ASSERT(PowerDeviceD0 != PreviousState);
+
+ fdoData->DevicePowerState = PowerDeviceD0;
+
+ if(IsPoMgmtSupported(fdoData)){
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,
+ "Entering fully on state\n");
+ MPSetPowerD0 (fdoData);
+ }
+
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--PciDrvEvtDeviceD0Entry\n");
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+PciDrvEvtDeviceD0Exit(
+ 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.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER,
+ "-->PciDrvEvtDeviceD0Exit - moving to %s\n",
+ DbgDevicePowerString(TargetState));
+
+ fdoData = FdoGetData(Device);
+
+ fdoData->DevicePowerState = TargetState;
+
+ switch (TargetState) {
+ case WdfPowerDeviceD1:
+ case WdfPowerDeviceD2:
+ case WdfPowerDeviceD3:
+
+ if(IsPoMgmtSupported(fdoData)){
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER,
+ "Entering a deeper sleep state\n");
+ MPSetPowerLow (fdoData, TargetState);
+ }
+ 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.
+ //
+ 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.
+ //
+ NICShutdown(fdoData);
+ break;
+
+ default:
+ break;
+ }
+
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--PciDrvEvtDeviceD0Exit\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+PciDrvEvtDeviceSelfManagedIoInit(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ PciDrvEvtDeviceSelfManagedIoInit is called by the Framework when the device
+ enters the D0 state. Its job is to start any I/O-related actions that the
+ Framework isn't managing. This might include releasing queues that are not
+ power-managed, that is, the Framework is not automatically holding and releasing
+ them across PnP/Power transitions. (The default behavior for WDFQUEUE is
+ auto-managed, so most queues don't need to be dealt with here.) This might
+ also include setting up non-queue-based actions.
+
+ If you allow the Framework to manage most or all of your queues, then when
+ you build a driver from this sample, you can probably delete this function.
+
+ In this driver, the SelfManagedIo callbacks are used to implement a watchdog timer.
+
+ This function is not marked pagable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - Failures will result in the device stack being torn down.
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+ WDF_TIMER_CONFIG wdfTimerConfig;
+ NTSTATUS status;
+ WDF_OBJECT_ATTRIBUTES timerAttributes;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceSelfManagedIoInit\n");
+
+ fdoData = FdoGetData(Device);
+ //
+ // To minimize init-time, create a timer DPC to do link detection.
+ // This DPC will also be used to check for hardware hang.
+ //
+ WDF_TIMER_CONFIG_INIT(&wdfTimerConfig, NICWatchDogEvtTimerFunc);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+ timerAttributes.ParentObject = fdoData->WdfDevice;
+
+ status = WdfTimerCreate(
+ &wdfTimerConfig,
+ &timerAttributes,
+ &fdoData->WatchDogTimer
+ );
+
+ if(!NT_SUCCESS(status) ) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "Error: WdfTimerCreate create failed 0x%x\n", status);
+ return status;
+ }
+
+ NICStartWatchDogTimer(fdoData);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceSelfManagedIoInit\n");
+
+ return status;
+}
+
+NTSTATUS
+PciDrvEvtDeviceSelfManagedIoSuspend(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceSelfManagedIoSuspend is called by the Framework before the device
+ leaves the D0 state. Its job is to stop any I/O-related actions that the
+ Framework isn't managing, and which cannot be handled when the device
+ hardware isn't available. In general, this means reversing anything that
+ was done in EvtDeviceSelfManagedIoStart.
+
+ If you allow the Framework to manage most or all of your queues, then when
+ you build a driver from this sample, you can probably delete this function.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - Failures will result in the device stack being torn down.
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceSelfManagedIoSuspend\n");
+
+ fdoData = FdoGetData(Device);
+
+ //
+ // Stop the watchdog timer and wait for DPC to run to completion if
+ // it's already fired.
+ //
+ WdfTimerStop(fdoData->WatchDogTimer, TRUE);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceSelfManagedIoSuspend\n");
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+PciDrvEvtDeviceSelfManagedIoRestart(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceSelfManagedIoRestart is called by the Framework before the device
+ is restarted for one of the following reasons:
+ a) the PnP resources were rebalanced (framework received
+ query-stop and stop IRPS )
+ b) the device resumed from a low power state to D0.
+
+ This function is not marked pagable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ NTSTATUS - Failure will cause the device stack to be torn down.
+
+--*/
+{
+ PFDO_DATA fdoData;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceSelfManagedIoRestart\n");
+
+ fdoData = FdoGetData(Device);
+
+ //
+ // Restart the watchdog timer.
+ //
+ NICStartWatchDogTimer(fdoData);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceSelfManagedIoRestart\n");
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+PciDrvEvtDeviceSelfManagedIoCleanup(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceSelfManagedIoCleanup is called by the Framework when the device is
+ being torn down, either in response to the WDM IRP_MN_REMOVE_DEVICE
+ It will be called only once. Its job is to stop all outstanding I/O in the driver
+ that the Framework is not managing.
+
+Arguments:
+
+ Device - Handle to a framework device object.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFDO_DATA fdoData = NULL;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceSelfManagedIoCleanup\n");
+
+ fdoData = FdoGetData(Device);
+
+ if(fdoData->WatchDogTimer) {
+ WdfObjectDelete(fdoData->WatchDogTimer);
+ }
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceSelfManagedIoCleanup\n");
+}
+
+
+VOID
+PciDrvEvtIoDeviceControl(
+ 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
+
+--*/
+{
+ NTSTATUS status= STATUS_SUCCESS;
+ PFDO_DATA fdoData = NULL;
+ WDFDEVICE hDevice;
+ WDF_REQUEST_PARAMETERS params;
+
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
+ "PciDrvEvtIoDeviceControl called %p\n", Request);
+
+ hDevice = WdfIoQueueGetDevice(Queue);
+ fdoData = FdoGetData(hDevice);
+
+ WDF_REQUEST_PARAMETERS_INIT(&params);
+
+ WdfRequestGetParameters(
+ Request,
+ &params
+ );
+
+ switch (IoControlCode)
+ {
+ case IOCTL_NDISPROT_QUERY_OID_VALUE:
+
+ ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);
+
+ NICHandleQueryOidRequest(
+ Queue,
+ Request,
+ &params
+ );
+ break;
+
+ case IOCTL_NDISPROT_SET_OID_VALUE:
+
+ ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);
+
+ NICHandleSetOidRequest(
+ Queue,
+ Request,
+ &params
+ );
+
+ break;
+
+ case IOCTL_NDISPROT_INDICATE_STATUS:
+
+ status = WdfRequestForwardToIoQueue(Request,
+ fdoData->PendingIoctlQueue);
+ if(!NT_SUCCESS(status)){
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
+ "WdfRequestForwardToIoQueue failed 0x%x\n", status);
+ WdfRequestComplete(Request, status);
+ break;
+ }
+
+ break;
+
+ default:
+ ASSERTMSG(FALSE, "Invalid IOCTL request\n");
+ WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
+ break;
+ }
+
+ return;
+}
+
+NTSTATUS
+PciDrvEvtDeviceWakeArmS0(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeArmS0 is called when the Framework arms the device for
+ wake in the S0 state. If there is any device-specific initialization
+ that needs to be done to arm internal wake signals, or to route internal
+ interrupt signals to the wake logic, it should be done here. The device
+ will be moved out of the D0 state soon after this callback is invoked.
+
+ In this sample, wake from S0 involves waking on packet arrival, as does
+ wake from Sx. A more common NIC implementation might wake on cable
+ insertion.
+
+ This function is pageable and it will run at PASSIVE_LEVEL.
+
+Arguments:
+
+ Device - Handle to a Framework device object.
+
+Return Value:
+
+ NTSTATUS - Failure will result in the device remaining in the D0 state.
+
+--*/
+{
+ NTSTATUS status;
+ PFDO_DATA fdoData;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeArmS0\n");
+
+ fdoData = FdoGetData(Device);
+
+ //
+ // Add pattern before sending wait-wake
+ //
+ status = NICConfigureForWakeUp(fdoData, TRUE);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeArmS0 %x\n", status);
+
+ return status;
+}
+
+NTSTATUS
+PciDrvEvtDeviceWakeArmSx(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeArmSx is called when the Framework arms the device for
+ wake from the S1, S2, S3 or S4 states. If there is any device-specific
+ initialization that needs to be done to arm internal wake signals, or to
+ route internal interrupt signals to the wake logic, it should be done here.
+ The device will be moved out of the D0 state soon after this callback is
+ invoked.
+
+ In this sample, wake from Sx involves arming for wake on packet arrival.
+ Cable insertion should not be enabled, as nobody would want their machine
+ to wake up simply because they plugged the cable in.
+
+ This function runs at PASSIVE_LEVEL. Whether it is pageable or not depends
+ on whether the device has set DO_POWER_PAGABLE.
+
+Arguments:
+
+ Device - Handle to a Framework device object.
+
+Return Value:
+
+ NTSTATUS - Failure will result in the device not being armed for wake
+ while the system is in Sx.
+
+--*/
+{
+ NTSTATUS status;
+ PFDO_DATA fdoData;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeArmSx\n");
+
+ fdoData = FdoGetData(Device);
+ //
+ // Add pattern before sending wait-wake
+ //
+ status = NICConfigureForWakeUp(fdoData, TRUE);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeArmSx %x\n", status);
+
+ return status;
+}
+
+VOID
+PciDrvEvtDeviceWakeDisarmS0(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeDisarmS0 reverses anything done in EvtDeviceWakeArmS0.
+
+ This function is not marked pageable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+Arguments:
+
+ Device - Handle to a Framework device object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ NTSTATUS status;
+ PFDO_DATA fdoData;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeDisarmS0\n");
+
+ fdoData = FdoGetData(Device);
+ status = NICConfigureForWakeUp(fdoData, FALSE);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeDisarmS0 %x\n", status);
+
+ return ;
+}
+
+VOID
+PciDrvEvtDeviceWakeDisarmSx(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeDisarmSx reverses anything done in EvtDeviceWakeArmSx.
+
+ This function is not marked pageable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+ This function runs at PASSIVE_LEVEL, even though it is 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.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ NTSTATUS status;
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeDisarmSx\n");
+
+ fdoData = FdoGetData(Device);
+ status = NICConfigureForWakeUp(fdoData, FALSE);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeDisarmSx %x\n", status);
+
+ return;
+}
+
+VOID
+PciDrvEvtDeviceWakeTriggeredS0(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeTriggeredS0 will be called whenever the device triggers its
+ wake signal after being armed for wake from S0.
+
+ This function is pageable and runs at PASSIVE_LEVEL.
+
+Arguments:
+
+ Device - Handle to a Framework device object.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Device);
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeTriggeredS0\n");
+
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeTriggeredS0\n");
+}
+
+VOID
+PciDrvEvtDeviceWakeTriggeredSx(
+ IN WDFDEVICE Device
+ )
+/*++
+
+Routine Description:
+
+ EvtDeviceWakeTriggeredSx will be called whenever the device triggers its
+ wake signal after being armed for wake from Sx.
+
+ This function is not marked pageable because this function is in the
+ device power up path. When a function is marked pagable and the code
+ section is paged out, it will generate a page fault which could impact
+ the fast resume behavior because the client driver will have to wait
+ until the system drivers can service this page fault.
+
+ This function runs at PASSIVE_LEVEL, even though it is 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.
+
+Return Value:
+
+ VOID
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Device);
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvEvtDeviceWakeTriggeredSx");
+
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvEvtDeviceWakeTriggeredSx");
+
+ return;
+}
+
+
+NTSTATUS
+PciDrvQueuePassiveLevelCallback(
+ IN PFDO_DATA FdoData,
+ IN PFN_WDF_WORKITEM CallbackFunction,
+ IN PVOID Context1,
+ IN PVOID Context2
+ )
+/*++
+ Routine Description:
+
+ This routine is used to queue workitems so that the callback
+ functions can be executed at PASSIVE_LEVEL in the conext of
+ a system thread.
+
+Arguments:
+
+ FdoData - pointer to a device extenion.
+
+ CallbackFunction - Function to invoke when at PASSIVE_LEVEL.
+
+ Context1 & 2 - Meaning of the context values depends on the
+ callback function.
+
+Return Value:
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PWORKER_ITEM_CONTEXT context;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDF_WORKITEM_CONFIG workitemConfig;
+ WDFWORKITEM hWorkItem;
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, WORKER_ITEM_CONTEXT);
+
+ attributes.ParentObject = FdoData->WdfDevice;
+
+ WDF_WORKITEM_CONFIG_INIT(&workitemConfig, CallbackFunction);
+
+ status = WdfWorkItemCreate( &workitemConfig,
+ &attributes,
+ &hWorkItem);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ context = GetWorkItemContext(hWorkItem);
+
+ context->FdoData = FdoData;
+ context->Argument1 = Context1;
+ context->Argument2 = Context2;
+
+ //
+ // Execute this work item.
+ //
+ WdfWorkItemEnqueue(hWorkItem);
+
+ return STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+PciDrvReadRegistryValue(
+ _In_ PFDO_DATA FdoData,
+ _In_ PWSTR Name,
+ _Out_ PULONG Value
+ )
+/*++
+
+Routine Description:
+
+ Can be used to read any REG_DWORD registry value stored
+ under Device Parameter.
+
+Arguments:
+
+ FdoData - pointer to the device extension
+ Name - Name of the registry value
+ Value -
+
+
+Return Value:
+
+ TRUE if successful
+ FALSE if not present/error in reading registry
+
+--*/
+{
+ WDFKEY hKey = NULL;
+ NTSTATUS status;
+ BOOLEAN retValue = FALSE;
+ UNICODE_STRING valueName;
+
+
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "-->PciDrvReadRegistryValue \n");
+
+ *Value = 0;
+
+ status = WdfDeviceOpenRegistryKey(FdoData->WdfDevice,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &hKey);
+
+ if (NT_SUCCESS (status)) {
+
+ RtlInitUnicodeString(&valueName,Name);
+
+ status = WdfRegistryQueryULong( hKey,
+ &valueName,
+ Value );
+
+ if (NT_SUCCESS (status)) {
+ retValue = TRUE;
+ }
+
+ WdfRegistryClose(hKey);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "<--PciDrvReadRegistryValue %ws %d \n", Name, *Value);
+
+ return retValue;
+}
+
+BOOLEAN
+PciDrvWriteRegistryValue(
+ _In_ PFDO_DATA FdoData,
+ _In_ PWSTR Name,
+ _In_ ULONG Value
+ )
+/*++
+
+Routine Description:
+
+ Can be used to write any REG_DWORD registry value stored
+ under Device Parameter.
+
+Arguments:
+
+
+Return Value:
+
+ TRUE - if write is successful
+ FALSE - otherwise
+
+--*/
+{
+ WDFKEY hKey = NULL;
+ NTSTATUS status;
+ BOOLEAN retValue = FALSE;
+ UNICODE_STRING valueName;
+
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
+ "Entered PciDrvWriteRegistryValue\n");
+
+ //
+ // write the value out to the registry
+ //
+ status = WdfDeviceOpenRegistryKey(FdoData->WdfDevice,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &hKey);
+
+ if (NT_SUCCESS (status)) {
+
+ RtlInitUnicodeString(&valueName,Name);
+
+ status = WdfRegistryAssignULong (hKey,
+ &valueName,
+ Value );
+
+ if (NT_SUCCESS (status)) {
+ retValue = TRUE;
+ }
+
+ WdfRegistryClose(hKey);
+ }
+
+ return retValue;
+
+}
+
+#define PARAMATER_NAME_LEN 80
+
+BOOLEAN
+PciDrvReadFdoRegistryKeyValue(
+ _In_ PWDFDEVICE_INIT DeviceInit,
+ _In_ PWSTR Name,
+ _Out_ PULONG Value
+ )
+/*++
+
+Routine Description:
+
+ Can be used to read any REG_DWORD registry value stored
+ under Device Parameter.
+
+Arguments:
+
+ FdoData - pointer to the device extension
+ Name - Name of the registry value
+ Value -
+
+
+Return Value:
+
+ TRUE if successful
+ FALSE if not present/error in reading registry
+
+--*/
+{
+ WDFKEY hKey = NULL;
+ NTSTATUS status;
+ BOOLEAN retValue = FALSE;
+ UNICODE_STRING valueName;
+
+ PAGED_CODE();
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP,
+ "-->PciDrvReadFdoRegistryKeyValue\n");
+
+ *Value = 0;
+
+ status = WdfFdoInitOpenRegistryKey(DeviceInit,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &hKey);
+
+ if (NT_SUCCESS (status)) {
+
+ RtlInitUnicodeString(&valueName,Name);
+
+ status = WdfRegistryQueryULong (hKey,
+ &valueName,
+ Value);
+
+ if (NT_SUCCESS (status)) {
+ retValue = TRUE;
+ }
+
+ WdfRegistryClose(hKey);
+ }
+
+ TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP,
+ "<--PciDrvReadFdoRegistryKeyValue %ws %d \n",
+ Name, *Value);
+
+ return retValue;
+}
+
+VOID
+PciDrvEvtDriverContextCleanup(
+ IN WDFOBJECT Driver
+ )
+/*++
+Routine Description:
+
+ Free all the resources allocated in DriverEntry.
+
+Arguments:
+
+ Driver - handle to a WDF Driver object.
+
+Return Value:
+
+ VOID.
+
+--*/
+{
+ PDRIVER_CONTEXT driverContext;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
+ "--> PciDrvEvtDriverContextCleanup\n");
+ PAGED_CODE ();
+
+ driverContext = GetDriverContext((WDFDRIVER)Driver);
+
+ if (driverContext->RecvLookaside) {
+ WdfObjectDelete(driverContext->RecvLookaside);
+ }
+ //
+ // Stop WPP Tracing
+ //
+ WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver ) );
+
+}
+
+NTSTATUS
+PciDrvSetPowerPolicy(
+ IN PFDO_DATA FdoData
+ )
+{
+ WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
+ WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "--> PciDrvSetPowerPolicy\n");
+
+ PAGED_CODE();
+
+ //
+ // Init the idle policy structure.
+ //
+ WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCanWakeFromS0);
+ idleSettings.IdleTimeout = 10000; // 10-sec
+
+ status = WdfDeviceAssignS0IdleSettings(FdoData->WdfDevice, &idleSettings);
+ if ( !NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status);
+ return status;
+ }
+
+ //
+ // Init wait-wake policy structure.
+ //
+ WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
+
+ status = WdfDeviceAssignSxWakeSettings(FdoData->WdfDevice, &wakeSettings);
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceAssignSxWakeSettings failed %x\n", status);
+ return status;
+ }
+
+
+ //
+ // Functions that program wakeup patterns on the device
+ // check this variable to see whether the NDIS edge has enabled
+ // wakeup on this device. If there is no ndis edge, this variable and all
+ // the checks can be removed because framework as a power policy owner
+ // it knows when to call the driver to arm/disarm for wakeup.
+ //
+ FdoData->AllowWakeArming = TRUE;
+
+ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
+ "<-- PciDrvSetPowerPolicy\n");
+
+ return status;
+}
+
+PCHAR
+DbgDevicePowerString(
+ IN WDF_POWER_DEVICE_STATE Type
+ )
+/*++
+
+Updated Routine Description:
+ DbgDevicePowerString does not change in this stage of the function driver.
+
+--*/
+{
+ switch (Type)
+ {
+ case WdfPowerDeviceInvalid:
+ return "WdfPowerDeviceInvalid";
+ case WdfPowerDeviceD0:
+ return "WdfPowerDeviceD0";
+ case WdfPowerDeviceD1:
+ return "WdfPowerDeviceD1";
+ case WdfPowerDeviceD2:
+ return "WdfPowerDeviceD2";
+ case WdfPowerDeviceD3:
+ return "WdfPowerDeviceD3";
+ case WdfPowerDeviceD3Final:
+ return "WdfPowerDeviceD3Final";
+ case WdfPowerDevicePrepareForHibernation:
+ return "WdfPowerDevicePrepareForHibernation";
+ case WdfPowerDeviceMaximum:
+ return "WdfPowerDeviceMaximum";
+ default:
+ return "UnKnown Device Power State";
+ }
+}
+
+
+#if !defined(EVENT_TRACING)
+
+VOID
+TraceEvents (
+ IN ULONG TraceEventsLevel,
+ IN ULONG TraceEventsFlag,
+ IN PCCHAR DebugMessage,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Debug print for the sample driver.
+
+Arguments:
+
+ TraceEventsLevel - print level between 0 and 3, with 3 the most verbose
+
+Return Value:
+
+ None.
+
+ --*/
+ {
+#if DBG
+#define TEMP_BUFFER_SIZE 512
+ va_list list;
+ CHAR debugMessageBuffer[TEMP_BUFFER_SIZE];
+ NTSTATUS status;
+
+ va_start(list, DebugMessage);
+
+ if (DebugMessage) {
+
+ //
+ // Using new safe string functions instead of _vsnprintf.
+ // This function takes care of NULL terminating if the message
+ // is longer than the buffer.
+ //
+ status = RtlStringCbVPrintfA( debugMessageBuffer,
+ sizeof(debugMessageBuffer),
+ DebugMessage,
+ list );
+ if(!NT_SUCCESS(status)) {
+
+ DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed %x\n",
+ status);
+ return;
+ }
+ if (TraceEventsLevel <= TRACE_LEVEL_INFORMATION ||
+ (TraceEventsLevel <= DebugLevel &&
+ ((TraceEventsFlag & DebugFlag) == TraceEventsFlag))) {
+ DbgPrint(debugMessageBuffer);
+ }
+ }
+ va_end(list);
+
+ return;
+#else
+ UNREFERENCED_PARAMETER(TraceEventsLevel);
+ UNREFERENCED_PARAMETER(TraceEventsFlag);
+ UNREFERENCED_PARAMETER(DebugMessage);
+#endif
+}
+
+#endif
+
diff --git a/general/pcidrv/kmdf/PCIDRV.H b/general/pcidrv/kmdf/PCIDRV.H
new file mode 100644
index 00000000..db42bd39
--- /dev/null
+++ b/general/pcidrv/kmdf/PCIDRV.H
@@ -0,0 +1,401 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ PciDrv.h
+
+Abstract:
+
+ Header file for the PCIDRV driver modules.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#if !defined(_PCIDRV_H_)
+#define _PCIDRV_H_
+
+//
+// Let us use newly introduced (.NET DDK) safe string function to avoid
+// security issues related buffer overrun.
+// The advantages of the RtlStrsafe functions include:
+// 1) The size of the destination buffer is always provided to the
+// function to ensure that the function does not write past the end of
+// the buffer.
+// 2) Buffers are guaranteed to be null-terminated, even if the
+// operation truncates the intended result.
+//
+
+//
+// In this driver we are using a safe version vsnprintf, which is
+// RtlStringCbVPrintfA. To use strsafe function on 9x, ME, and Win2K Oses, we
+// have to define NTSTRSAFE_LIB before including this header file and explicitly
+// link to ntstrsafe.lib. If your driver is just target for XP and above, there is
+// no define NTSTRSAFE_LIB and link to the lib.
+//
+#define NTSTRSAFE_LIB
+#include <ntstrsafe.h>
+
+//-----------------------------------------------------------------------------
+// 4127 -- Conditional Expression is Constant warning
+//-----------------------------------------------------------------------------
+#define WHILE(constant) \
+__pragma(warning(suppress: 4127)) while(constant)
+
+#define _DRIVER_NAME_ "PCIDRV"
+
+#define PCIDRV_POOL_TAG (ULONG) 'DICP'
+#define PCIDRV_FDO_INSTANCE_SIGNATURE (ULONG) 'odFT'
+
+#define MILLISECONDS_TO_100NS (10000)
+#define SECOND_TO_MILLISEC (1000)
+#define SECOND_TO_100NS (SECOND_TO_MILLISEC * MILLISECONDS_TO_100NS)
+
+//
+// Bit Flag Macros
+//
+
+#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit))
+#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit))
+#define TEST_FLAG(Flags, Bit) (((Flags) & (Bit)) != 0)
+
+//
+// The driver context contains global data to the whole driver.
+//
+typedef struct _DRIVER_CONTEXT {
+ //
+ // The assumption here is that there is nothing device specific in the lookaside list
+ // and hence the same list can be used to do allocations for multiple devices.
+ //
+ WDFLOOKASIDE RecvLookaside;
+
+} DRIVER_CONTEXT, * PDRIVER_CONTEXT;
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DRIVER_CONTEXT, GetDriverContext)
+
+
+
+//
+// Connector Types
+//
+
+typedef struct _PCIDRV_WMI_STD_DATA {
+
+ //
+ // Current Mac Address of the NIC
+ //
+
+ UINT64 MacAddress;
+
+} PCIDRV_WMI_STD_DATA, * PPCIDRV_WMI_STD_DATA;
+
+
+//
+// General purpose workitem context used in dispatching work to
+// system worker thread to be executed at PASSIVE_LEVEL.
+//
+typedef struct _WORKER_ITEM_CONTEXT {
+ PFDO_DATA FdoData;
+ PVOID Argument1;
+ PVOID Argument2;
+} WORKER_ITEM_CONTEXT, *PWORKER_ITEM_CONTEXT;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKER_ITEM_CONTEXT, GetWorkItemContext)
+
+//
+// The device extension for the device object
+//
+typedef struct _FDO_DATA
+{
+ ULONG Signature; // must be PCIDRV_FDO_INSTANCE_SIGNATURE
+ // beneath this device object.
+ WDFDEVICE WdfDevice;
+
+ // Power Management
+ MP_POWER_MGMT PoMgmt;
+ WDF_POWER_DEVICE_STATE DevicePowerState; // Current power state of the device(D0 - D3)
+
+ // Wait-Wake
+ BOOLEAN AllowWakeArming;
+
+ // Idle Detection
+ //BOOLEAN IdleDetectionEnabled;
+ PCIDRV_WMI_STD_DATA StdDeviceData;
+
+ // Following fields are specific to the hardware
+ // Configuration
+ ULONG Flags;
+ UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS];
+ UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS];
+ BOOLEAN bOverrideAddress;
+ USHORT AiTxFifo; // TX FIFO Threshold
+ USHORT AiRxFifo; // RX FIFO Threshold
+ UCHAR AiTxDmaCount; // Tx dma count
+ UCHAR AiRxDmaCount; // Rx dma count
+ UCHAR AiUnderrunRetry; // The underrun retry mechanism
+ UCHAR AiForceDpx; // duplex setting
+ USHORT AiTempSpeed; // 'Speed', user over-ride of line speed
+ USHORT AiThreshold; // 'Threshold', Transmit Threshold
+ BOOLEAN MWIEnable; // Memory Write Invalidate bit in the PCI command word
+ UCHAR Congest; // Enables congestion control
+ ULONG SpeedDuplex; // New reg value for speed/duplex
+
+
+ // IDs
+ UCHAR RevsionID;
+ USHORT SubVendorID;
+ USHORT SubSystemID;
+
+ // HW Resources
+ ULONG CacheFillSize;
+ PULONG IoBaseAddress;
+ ULONG IoRange;
+ PHYSICAL_ADDRESS MemPhysAddress;
+
+ WDFINTERRUPT WdfInterrupt;
+
+ BOOLEAN MappedPorts;
+ PHW_CSR CSRAddress;
+ BUS_INTERFACE_STANDARD BusInterface;
+ PREAD_PORT ReadPort;
+ PWRITE_PORT WritePort;
+ WDFDMAENABLER WdfDmaEnabler;
+
+ // Media Link State
+ UCHAR CurrentScanPhyIndex;
+ UCHAR LinkDetectionWaitCount;
+ UCHAR FoundPhyAt;
+ USHORT EepromAddressSize;
+ MEDIA_STATE MediaState;
+
+ // SEND
+ PMP_TCB CurrSendHead;
+ PMP_TCB CurrSendTail;
+ ULONG nBusySend;
+ LONG nWaitSend;
+ LONG nCancelSend;
+ WDFQUEUE WriteQueue;
+ WDFQUEUE PendingWriteQueue;
+ SINGLE_LIST_ENTRY SendBufList;
+ WDFSPINLOCK SendLock;
+
+ ULONG NumTcb; // Total number of TCBs
+ LONG RegNumTcb; // 'NumTcb'
+ ULONG NumBuffers;
+
+
+ _Field_size_(MpTcbMemSize) PUCHAR MpTcbMem;
+ ULONG MpTcbMemSize;
+
+ WDFCOMMONBUFFER WdfSendCommonBuffer;
+
+ _Field_size_(HwSendMemAllocSize) PUCHAR HwSendMemAllocVa;
+ ULONG HwSendMemAllocSize;
+ PHYSICAL_ADDRESS HwSendMemAllocLa; // Logical Address
+
+ // command unit status flags
+ BOOLEAN TransmitIdle;
+ BOOLEAN ResumeWait;
+
+ // RECV
+ LIST_ENTRY RecvList;
+ ULONG nReadyRecv;
+ LONG RefCount;
+
+ ULONG NumRfd;
+ ULONG CurrNumRfd;
+ ULONG MaxNumRfd;
+ ULONG HwRfdSize;
+ LONG RfdShrinkCount;
+
+ WDFQUEUE PendingReadQueue;
+ WDFSPINLOCK RcvLock;
+
+ BOOLEAN AllocNewRfd;
+
+ // spin locks for protecting misc variables
+ WDFSPINLOCK Lock;
+
+ // Packet Filter and look ahead size.
+ ULONG PacketFilter;
+ ULONG OldPacketFilter;
+ ULONG ulLookAhead;
+ USHORT usLinkSpeed;
+ USHORT usDuplexMode;
+
+ // multicast list
+ UINT MCAddressCount;
+ UCHAR MCList[NIC_MAX_MCAST_LIST][ETH_LENGTH_OF_ADDRESS];
+
+ WDFCOMMONBUFFER WdfMiscCommonBuffer;
+ _Field_size_(HwMiscMemAllocSize) PUCHAR HwMiscMemAllocVa;
+ ULONG HwMiscMemAllocSize;
+ PHYSICAL_ADDRESS HwMiscMemAllocLa; // Logical Address
+
+ PSELF_TEST_STRUC SelfTest; // 82558 SelfTest
+ ULONG SelfTestPhys;
+ BOOLEAN SelfTested;
+
+ PNON_TRANSMIT_CB NonTxCmdBlock; // 82558 (non transmit) Command Block
+ ULONG NonTxCmdBlockPhys;
+
+ PDUMP_AREA_STRUC DumpSpace; // 82558 dump buffer area
+ ULONG DumpSpacePhys;
+
+ PERR_COUNT_STRUC StatsCounters;
+ ULONG StatsCounterPhys;
+
+ UINT PhyAddress; // Address of the phy component
+ UCHAR Connector; // 0=Auto, 1=TPE, 2=MII
+
+ UCHAR OldParameterField;
+
+ ULONG HwErrCount;
+
+ // WatchDog timer related fields
+ WDFTIMER WatchDogTimer;
+ BOOLEAN bLinkDetectionWait;
+ BOOLEAN bLookForLink;
+ BOOLEAN CheckForHang;
+
+ // For handling IOCTLs - required if the upper edge is NDIS
+ WDFQUEUE IoctlQueue;
+ WDFQUEUE PendingIoctlQueue;
+
+ // Packet counts
+ ULONG64 GoodTransmits;
+ ULONG64 GoodReceives;
+ ULONG NumTxSinceLastAdjust;
+
+ // Count of transmit errors
+ ULONG TxAbortExcessCollisions;
+ ULONG TxLateCollisions;
+ ULONG TxDmaUnderrun;
+ ULONG TxLostCRS;
+ ULONG TxOKButDeferred;
+ ULONG OneRetry;
+ ULONG MoreThanOneRetry;
+ ULONG TotalRetries;
+
+ // Count of receive errors
+ ULONG RcvCrcErrors;
+ ULONG RcvAlignmentErrors;
+ ULONG RcvResourceErrors;
+ ULONG RcvDmaOverrunErrors;
+ ULONG RcvCdtFrames;
+ ULONG RcvRuntErrors;
+
+ // Count of bytes received & transmitted
+ ULONG64 BytesReceived;
+ ULONG64 BytesTransmitted;
+} FDO_DATA, *PFDO_DATA;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, FdoGetData)
+
+#define CLRMASK(x, mask) ((x) &= ~(mask));
+#define SETMASK(x, mask) ((x) |= (mask));
+
+
+//
+// Function prototypes
+//
+DRIVER_INITIALIZE DriverEntry;
+
+EVT_WDF_DRIVER_DEVICE_ADD PciDrvEvtDeviceAdd;
+
+EVT_WDF_OBJECT_CONTEXT_CLEANUP PciDrvEvtDriverContextCleanup;
+EVT_WDF_DEVICE_CONTEXT_CLEANUP PciDrvEvtDeviceContextCleanup;
+
+EVT_WDF_DEVICE_D0_ENTRY PciDrvEvtDeviceD0Entry;
+EVT_WDF_DEVICE_D0_EXIT PciDrvEvtDeviceD0Exit;
+EVT_WDF_DEVICE_PREPARE_HARDWARE PciDrvEvtDevicePrepareHardware;
+EVT_WDF_DEVICE_RELEASE_HARDWARE PciDrvEvtDeviceReleaseHardware;
+
+EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP PciDrvEvtDeviceSelfManagedIoCleanup;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT PciDrvEvtDeviceSelfManagedIoInit;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND PciDrvEvtDeviceSelfManagedIoSuspend;
+EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART PciDrvEvtDeviceSelfManagedIoRestart;
+
+EVT_WDF_DEVICE_ARM_WAKE_FROM_S0 PciDrvEvtDeviceWakeArmS0;
+EVT_WDF_DEVICE_ARM_WAKE_FROM_SX PciDrvEvtDeviceWakeArmSx;
+EVT_WDF_DEVICE_DISARM_WAKE_FROM_S0 PciDrvEvtDeviceWakeDisarmS0;
+EVT_WDF_DEVICE_DISARM_WAKE_FROM_SX PciDrvEvtDeviceWakeDisarmSx;
+EVT_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED PciDrvEvtDeviceWakeTriggeredS0;
+EVT_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED PciDrvEvtDeviceWakeTriggeredSx;
+
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PciDrvEvtIoDeviceControl;
+
+NTSTATUS
+PciDrvReturnResources (
+ IN OUT PFDO_DATA FdoData
+ );
+
+NTSTATUS
+PciDrvSetPowerPolicy(
+ IN PFDO_DATA FdoData
+ );
+
+NTSTATUS
+PciDrvQueuePassiveLevelCallback(
+ IN PFDO_DATA FdoData,
+ IN PFN_WDF_WORKITEM CallbackFunction,
+ IN PVOID Context1,
+ IN PVOID Context2
+ );
+
+BOOLEAN
+PciDrvReadRegistryValue(
+ _In_ PFDO_DATA FdoData,
+ _In_ PWSTR Name,
+ _Out_ PULONG Value
+ );
+
+BOOLEAN
+PciDrvWriteRegistryValue(
+ _In_ PFDO_DATA FdoData,
+ _In_ PWSTR Name,
+ _In_ ULONG Value
+ );
+
+
+NTSTATUS
+PciDrvWmiRegistration(
+ WDFDEVICE hDevice
+);
+
+PCHAR
+DbgDevicePowerString(
+ IN WDF_POWER_DEVICE_STATE Type
+ );
+
+
+BOOLEAN
+PciDrvReadFdoRegistryKeyValue(
+ _In_ PWDFDEVICE_INIT DeviceInit,
+ _In_ PWSTR Name,
+ _Out_ PULONG Value
+ );
+
+#if defined(WIN2K)
+
+NTKERNELAPI
+VOID
+ExFreePoolWithTag(
+ _In_ PVOID P,
+ _In_ ULONG Tag
+ );
+
+#endif
+
+#endif // _PCIDRV_H_
+
+
diff --git a/general/pcidrv/kmdf/PCIDRV.RC b/general/pcidrv/kmdf/PCIDRV.RC
new file mode 100644
index 00000000..dd01a93c
--- /dev/null
+++ b/general/pcidrv/kmdf/PCIDRV.RC
@@ -0,0 +1,33 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "WDM Driver for Intel 8255x Ethernet Adapters"
+#define VER_INTERNALNAME_STR "PCIDRV.sys"
+#define VER_ORIGINALFILENAME_STR "PCIDRV.sys"
+
+#define VER_FILEVERSION 1,00,00,0000
+#define VER_FILEVERSION_STR "1.00.00.0000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION VER_FILEVERSION
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
+
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2003 Microsoft Corporation"
+#ifdef VER_COMPANYNAME_STR
+
+#undef VER_COMPANYNAME_STR
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#endif
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft Sample Driver for PCI Device"
+
+#include "common.ver"
+
+
+
diff --git a/general/pcidrv/kmdf/PCIDRV.mof b/general/pcidrv/kmdf/PCIDRV.mof
new file mode 100644
index 00000000..283b6fb7
--- /dev/null
+++ b/general/pcidrv/kmdf/PCIDRV.mof
@@ -0,0 +1,19 @@
+#PRAGMA AUTORECOVER
+
+[Dynamic, Provider("WMIProv"),
+ WMI,
+ Description("PCIDRV Device Information"),
+ guid("{20E35E40-7179-4f89-A28C-12ED5A3CAAA5}"),
+ locale("MS\\0x409")]
+class PciDeviceInformation
+{
+ [key, read]
+ string InstanceName;
+ [read] boolean Active;
+
+ [WmiDataId(1),
+ read,
+ write,
+ Description("Current Mac Address of the NIC.")]
+ uint64 MacAddress;
+}; \ No newline at end of file
diff --git a/general/pcidrv/kmdf/genpci.inx b/general/pcidrv/kmdf/genpci.inx
new file mode 100644
index 00000000..b1f30a6c
--- /dev/null
+++ b/general/pcidrv/kmdf/genpci.inx
@@ -0,0 +1,127 @@
+;/*++
+;
+;Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+; PURPOSE.
+;
+;Module Name:
+;
+; GenPCI.INF
+;
+;Abstract:
+; INF file for a generic PCI device.
+;
+;--*/
+
+[Version]
+Signature = "$WINDOWS NT$"
+Class = Sample
+ClassGuid = {78A1C341-4539-11d3-B88D-00C04FAD5171}
+Provider = %MSFT%
+DriverVer = 03/20/2003,5.00.3788
+CatalogFile = KmdfSamples.cat
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+;-------------------------------------------------------------------------
+; Class Section
+;-------------------------------------------------------------------------
+[ClassInstall32]
+Addreg = SampleClassReg
+
+[SampleClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens
+HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin.
+
+;-------------------------------------------------------------------------
+; Device Install Section
+;-------------------------------------------------------------------------
+[ControlFlags]
+ExcludeFromSelect = *
+
+[Manufacturer]
+%MSFT%=MSFT,NT$ARCH$
+
+[SourceDisksFiles]
+pcidrv.sys = 1
+
+[SourceDisksNames]
+1=%DISK_NAME%,
+
+; For Win2K
+[MSFT]
+; DisplayName Section DeviceId
+; ----------- ------- --------
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1229
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_103D
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1031
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1038
+
+; For XP and later
+[MSFT.NT$ARCH$]
+; DisplayName Section DeviceId
+; ----------- ------- --------
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1229
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_103D
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1031
+%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1038
+
+[GenPCI_Inst.NT]
+CopyFiles = GenPCI.CopyFiles
+
+
+[GenPCI.CopyFiles]
+pcidrv.sys
+
+
+[GenPCI_Inst.NT.Services]
+AddService = GenPCI,0x00000002,GenPCI_Service
+
+[GenPCI_Service]
+DisplayName = %GenPCI.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\pcidrv.sys
+
+;-------------------------------------------------------------------------
+; WDF Coinstaller installation
+;-------------------------------------------------------------------------
+[DestinationDirs]
+CoInstaller_CopyFiles = 11
+
+[GenPCI_Inst.NT.CoInstallers]
+AddReg = CoInstaller_AddReg
+CopyFiles = CoInstaller_CopyFiles
+
+[CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[SourceDisksFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1 ; make sure the number matches with SourceDisksNames
+
+[CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[GenPCI_Inst.NT.Wdf]
+KmdfService = GenPCI, GenPCI_wdfsect
+
+[GenPCI_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+;------------------------------------------------------------------------------
+; String Definitions
+;------------------------------------------------------------------------------
+
+[Strings]
+MSFT = "Microsoft"
+ClassName = "Sample Device"
+GenPCI.SVCDESC = "Sample WDF PCI Driver Service for Intel 8255x Ethernet Controller"
+GenPCI.DRVDESC = "Sample WDF PCI Driver for Intel 8255x Ethernet Controller"
+DISK_NAME = "GenPCI Sample Install Disk"
diff --git a/general/pcidrv/kmdf/public.h b/general/pcidrv/kmdf/public.h
new file mode 100644
index 00000000..70a2087f
--- /dev/null
+++ b/general/pcidrv/kmdf/public.h
@@ -0,0 +1,48 @@
+/*++
+ Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ public.h
+
+Abstract:
+
+ This module contains the common declarations shared by driver
+ and user applications.
+
+Environment:
+
+ user and kernel
+
+--*/
+
+//
+// Define an Interface Guid for toaster device class.
+// This GUID is used to register (IoRegisterDeviceInterface)
+// an instance of an interface so that user application
+// can control the toaster device.
+//
+
+DEFINE_GUID (GUID_DEVINTERFACE_PCIDRV,
+ 0xb74cfec2, 0x9366, 0x454a, 0xba, 0x71, 0x7c, 0x27, 0xb5, 0x14, 0x70, 0xa4);
+// {B74CFEC2-9366-454a-BA71-7C27B51470A4}
+
+//
+// Define a WMI GUID to get toaster device info.
+//
+
+DEFINE_GUID (PCIDRV_WMI_STD_DATA_GUID,
+ 0x20e35e40, 0x7179, 0x4f89, 0xa2, 0x8c, 0x12, 0xed, 0x5a, 0x3c, 0xaa, 0xa5);
+
+// {20E35E40-7179-4f89-A28C-12ED5A3CAAA5}
+
+//
+// GUID definition are required to be outside of header inclusion pragma to avoid
+// error during precompiled headers.
+//
+
diff --git a/general/pcidrv/kmdf/trace.h b/general/pcidrv/kmdf/trace.h
new file mode 100644
index 00000000..2c041319
--- /dev/null
+++ b/general/pcidrv/kmdf/trace.h
@@ -0,0 +1,140 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ TRACE.h
+
+Abstract:
+
+ Header file for the debug tracing related function defintions and macros.
+ HEXDUMP is not defined by default. So we have to provide a localwpp.ini file
+ that defines type.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <evntrace.h> // For TRACE_LEVEL definitions
+
+#if !defined(EVENT_TRACING)
+
+//
+// TODO: These defines are missing in evntrace.h
+// in some DDK build environments (XP).
+//
+#if !defined(TRACE_LEVEL_NONE)
+ #define TRACE_LEVEL_NONE 0
+ #define TRACE_LEVEL_CRITICAL 1
+ #define TRACE_LEVEL_FATAL 1
+ #define TRACE_LEVEL_ERROR 2
+ #define TRACE_LEVEL_WARNING 3
+ #define TRACE_LEVEL_INFORMATION 4
+ #define TRACE_LEVEL_VERBOSE 5
+ #define TRACE_LEVEL_RESERVED6 6
+ #define TRACE_LEVEL_RESERVED7 7
+ #define TRACE_LEVEL_RESERVED8 8
+ #define TRACE_LEVEL_RESERVED9 9
+#endif
+
+
+//
+// Define Debug Flags
+//
+#define DBG_INIT 0x00000001
+#define DBG_PNP 0x00000002
+#define DBG_POWER 0x00000004
+#define DBG_WMI 0x00000008
+#define DBG_CREATE_CLOSE 0x00000010
+#define DBG_IOCTLS 0x00000020
+#define DBG_WRITE 0x00000040
+#define DBG_READ 0x00000080
+#define DBG_DPC 0x00000100
+#define DBG_INTERRUPT 0x00000200
+#define DBG_LOCKS 0x00000400
+#define DBG_QUEUEING 0x00000800
+#define DBG_HW_ACCESS 0x00001000
+
+VOID
+TraceEvents (
+ IN ULONG DebugPrintLevel,
+ IN ULONG DebugPrintFlag,
+ IN PCCHAR DebugMessage,
+ ...
+ );
+
+#define Hexdump(x) // Used for HEXDUMP in case tracing is enabled
+#define WPP_INIT_TRACING(DriverObject, RegistryPath)
+#define WPP_CLEANUP(DriverObject)
+
+#else
+//
+// If software tracing is defined in the sources file..
+// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver.
+// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID ***
+// WPP_DEFINE_BIT allows setting debug bit masks to selectively print.
+// The names defined in the WPP_DEFINE_BIT call define the actual names
+// that are used to control the level of tracing for the control guid
+// specified.
+//
+// Name of the logger is PciDrv and the guid is
+// {BC6C9364-FC67-42c5-ACF7-ABED3B12ECC6}
+// (0xbc6c9364, 0xfc67, 0x42c5, 0xac, 0xf7, 0xab, 0xed, 0x3b, 0x12, 0xec, 0xc6);
+//
+
+#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(PciDrvTraceGuid,(bc6c9364,fc67,42c5,acf7,abed3b12ecc6), \
+ WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \
+ WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \
+ WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \
+ WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \
+ WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \
+ WPP_DEFINE_BIT(DBG_IOCTLS) /* bit 5 = 0x00000020 */ \
+ WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \
+ WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \
+ WPP_DEFINE_BIT(DBG_DPC) /* bit 8 = 0x00000100 */ \
+ WPP_DEFINE_BIT(DBG_INTERRUPT) /* bit 9 = 0x00000200 */ \
+ WPP_DEFINE_BIT(DBG_LOCKS) /* bit 10 = 0x00000400 */ \
+ WPP_DEFINE_BIT(DBG_QUEUEING) /* bit 11 = 0x00000800 */ \
+ WPP_DEFINE_BIT(DBG_HW_ACCESS) /* bit 12 = 0x00001000 */ \
+ /* You can have up to 32 defines. If you want more than that,\
+ you have to provide another trace control GUID */\
+ )
+
+
+#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+#pragma warning(disable:4204) // C4204 nonstandard extension used : non-constant aggregate initializer
+
+//
+// Define the 'xstr' structure for logging buffer and length pairs
+// and the 'log_xstr' function which returns it to create one in-place.
+// this enables logging of complex data types.
+//
+typedef struct xstr { char * _buf; short _len; } xstr_t;
+__inline xstr_t log_xstr(void * p, short l) { xstr_t xs = {(char*)p,l}; return xs; }
+
+#pragma warning(default:4204)
+
+//
+// Define the macro required for a hexdump use as:
+//
+// DebugTraceEx((LEVEL, FLAG,"%!HEXDUMP!\n", log_xstr(buffersize,(char *)buffer) ));
+//
+//
+#define WPP_LOGHEXDUMP(x) WPP_LOGPAIR(2, &((x)._len)) WPP_LOGPAIR((x)._len, (x)._buf)
+
+#endif
+
+
diff --git a/general/pcidrv/kmdf/wmi.c b/general/pcidrv/kmdf/wmi.c
new file mode 100644
index 00000000..a0c5eba5
--- /dev/null
+++ b/general/pcidrv/kmdf/wmi.c
@@ -0,0 +1,144 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ WMI.C
+
+Abstract:
+
+ This module handle all the WMI Irps.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#include "precomp.h"
+
+#if defined(EVENT_TRACING)
+#include "wmi.tmh"
+#endif
+
+
+#define MOFRESOURCENAME L"PciDrvWMI"
+
+EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiDeviceInfoQueryInstance;
+
+EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiDeviceInfoSetInstance;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, PciDrvWmiRegistration)
+#pragma alloc_text(PAGE, EvtWmiDeviceInfoQueryInstance)
+#pragma alloc_text(PAGE, EvtWmiDeviceInfoSetInstance)
+#endif
+
+NTSTATUS
+PciDrvWmiRegistration(
+ WDFDEVICE Device
+ )
+/*++
+Routine Description
+
+ Registers with WMI as a data provider for this
+ instance of the device
+
+--*/
+{
+ WDF_WMI_PROVIDER_CONFIG providerConfig;
+ WDF_WMI_INSTANCE_CONFIG instanceConfig;
+ NTSTATUS status;
+ DECLARE_CONST_UNICODE_STRING(mofRsrcName, MOFRESOURCENAME);
+
+ PAGED_CODE();
+
+ status = WdfDeviceAssignMofResourceName(Device, &mofRsrcName);
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfDeviceAssignMofResourceName failed 0x%x", status);
+ return status;
+ }
+
+ WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &PCIDRV_WMI_STD_DATA_GUID);
+ providerConfig.MinInstanceBufferSize = sizeof(PCIDRV_WMI_STD_DATA);
+
+ WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig);
+ instanceConfig.Register = TRUE;
+ instanceConfig.EvtWmiInstanceQueryInstance = EvtWmiDeviceInfoQueryInstance;
+ instanceConfig.EvtWmiInstanceSetInstance = EvtWmiDeviceInfoSetInstance;
+
+ //
+ // No need to get the newly creawted handle because we just reference data
+ // from our device extension directly.
+ //
+ status = WdfWmiInstanceCreate(Device,
+ &instanceConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ WDF_NO_HANDLE);
+ if (!NT_SUCCESS(status)) {
+ TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
+ "WdfWmiInstanceCreate failed 0x%x", status);
+ return status;
+ }
+
+ return status;
+}
+
+NTSTATUS
+EvtWmiDeviceInfoQueryInstance(
+ _In_ WDFWMIINSTANCE WmiInstance,
+ _In_ ULONG OutBufferSize,
+ _Out_writes_bytes_to_(OutBufferSize, *BufferUsed) PVOID OutBuffer,
+ _Out_ PULONG BufferUsed
+ )
+{
+ PFDO_DATA fdoData;
+
+ PAGED_CODE();
+
+ fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));
+
+ *BufferUsed = sizeof(fdoData->CurrentAddress);
+
+ if (OutBufferSize < sizeof(fdoData->CurrentAddress)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ RtlZeroMemory(OutBuffer, OutBufferSize);
+ RtlCopyMemory(OutBuffer, fdoData->CurrentAddress, sizeof(fdoData->CurrentAddress));
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+EvtWmiDeviceInfoSetInstance(
+ _In_ WDFWMIINSTANCE WmiInstance,
+ _In_ ULONG InBufferSize,
+ _In_reads_bytes_(InBufferSize) PVOID InBuffer
+ )
+{
+ PFDO_DATA fdoData;
+
+ UNREFERENCED_PARAMETER(InBufferSize);
+
+ PAGED_CODE();
+
+ fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance));
+
+ if (InBufferSize < sizeof(fdoData->CurrentAddress)) {
+ return STATUS_WMI_SET_FAILURE;
+ }
+
+ RtlCopyMemory(fdoData->CurrentAddress, InBuffer, sizeof(fdoData->CurrentAddress));
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/general/pcidrv/pcidrv.sln b/general/pcidrv/pcidrv.sln
new file mode 100644
index 00000000..e6607b8a
--- /dev/null
+++ b/general/pcidrv/pcidrv.sln
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{EFA400EA-F405-4FB2-AC59-22D52ED1C479}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HW", "HW", "{8CBB3334-12D6-42CE-BD7A-A6F00E08FE45}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf", "Kmdf", "{A8847B95-FC0F-4553-9D94-354FE3C0A56E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "myping", "test\myping.vcxproj", "{AAB2FA59-187D-45F7-A84F-09C7089848B3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PCIDRV", "kmdf\HW\PCIDRV.vcxproj", "{2221261F-E1E2-4562-A15D-2EF8BF7D878E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.Build.0 = Debug|Win32
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.ActiveCfg = Release|Win32
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.Build.0 = Release|Win32
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.ActiveCfg = Debug|x64
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.Build.0 = Debug|x64
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.ActiveCfg = Release|x64
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.Build.0 = Release|x64
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.Build.0 = Debug|Win32
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.ActiveCfg = Release|Win32
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.Build.0 = Release|Win32
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.ActiveCfg = Debug|x64
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.Build.0 = Debug|x64
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.ActiveCfg = Release|x64
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {AAB2FA59-187D-45F7-A84F-09C7089848B3} = {EFA400EA-F405-4FB2-AC59-22D52ED1C479}
+ {2221261F-E1E2-4562-A15D-2EF8BF7D878E} = {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45}
+ {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45} = {A8847B95-FC0F-4553-9D94-354FE3C0A56E}
+ EndGlobalSection
+EndGlobal
diff --git a/general/pcidrv/test/myping.c b/general/pcidrv/test/myping.c
new file mode 100644
index 00000000..b0c2d22c
--- /dev/null
+++ b/general/pcidrv/test/myping.c
@@ -0,0 +1,1054 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ MYPING.C
+
+Abstract:
+
+
+
+Environment:
+
+ usermode console application
+
+--*/
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
+
+#include "testapp.h"
+#include "nuiouser.h"
+#include <intsafe.h>
+
+#define MAX_HEADER_SIZE (sizeof(ETH_HEADER) + sizeof(IpHeader) + sizeof(IcmpHeader))
+#define MAX_ECHO_PAY_LOAD (ETH_MAX_PACKET_SIZE - MAX_HEADER_SIZE)
+
+
+#define ETH_HEADER_SIZE 14
+#define ETH_MAX_DATA_SIZE 1500
+#define ETH_MAX_PACKET_SIZE ETH_HEADER_SIZE + ETH_MAX_DATA_SIZE
+#define ETH_MIN_PACKET_SIZE 60
+
+#define ARP_ETYPE_ARP 0x806
+#define IP_PROT_TYPE 0x800
+#define ARP_REQUEST 1
+#define ARP_RESPONSE 2
+#define ARP_HW_ENET 1
+
+#define PROTOCOL_ICMP 1
+
+// ICMP types and codes
+#define ICMPV4_ECHO_REQUEST_TYPE 8
+#define ICMPV4_ECHO_REQUEST_CODE 0
+#define ICMPV4_ECHO_REPLY_TYPE 0
+#define ICMPV4_ECHO_REPLY_CODE 0
+#define ICMPV4_MINIMUM_HEADER 8
+
+#define DEFAULT_DATA_SIZE 32 // default data size
+
+#define DEFAULT_SEND_COUNT 32767 // number of ICMP requests to send
+
+#define DEFAULT_RECV_TIMEOUT 6000 // six second
+
+#define DEFAULT_TTL 128
+
+#define IP_ADDR_LEN 4
+
+#include <pshpack1.h>
+
+// ========================================================================
+// The IP header
+//
+
+typedef struct iphdr {
+ unsigned char verlen;
+ unsigned char tos; // Type of service
+ unsigned short total_len; // total length of the packet
+ unsigned short ident; // unique identifier
+ unsigned short frag_and_flags; // flags
+ unsigned char ttl; // time to live
+ unsigned char proto; // protocol (TCP, UDP etc)
+ unsigned char checksumHigh;
+ unsigned char checksumLow;
+ unsigned int sourceIP; // source ip address
+ unsigned int destIP; // destination ip address
+
+} IpHeader;
+
+// ========================================================================
+// ICMP header
+//
+
+typedef struct _ihdr {
+ BYTE i_type;
+ BYTE i_code; /* type sub code */
+ USHORT i_cksum;
+ USHORT i_id;
+ USHORT i_seq;
+ ULONG timestamp; /* non standard, reserve space for time */
+} IcmpHeader;
+
+typedef struct _ETH_HEADER
+{
+ UCHAR DstAddr[MAC_ADDR_LEN];
+ UCHAR SrcAddr[MAC_ADDR_LEN];
+ USHORT EthType;
+} ETH_HEADER, *PETH_HEADER;
+
+// Structure of an ARP header.
+typedef struct _ARP_BODY {
+ USHORT hw; // Hardware address space. = 00 01
+ USHORT pro; // Protocol address space. = 08 00
+ UCHAR hlen; // Hardware address length. = 06
+ UCHAR plen; // Protocol address length. = 04
+ USHORT opcode; // Opcode.
+ UCHAR SenderHwAddr[MAC_ADDR_LEN]; // Source HW address.
+ UINT SenderIpAddr; // Source protocol address.
+ UCHAR DestHwAddr[MAC_ADDR_LEN]; // Destination HW address.
+ UINT DestIPAddr; // Destination protocol address.
+} _ARP_BODY, *PARP_BODY;
+
+#include <poppack.h>
+
+//
+// For Read operation.
+//
+typedef struct _RCB {
+ OVERLAPPED Overlapped;
+ char Buffer[ETH_MAX_PACKET_SIZE];
+ PDEVICE_INFO DeviceInfo;
+}RCB, *PRCB;
+
+//
+// For Write operation.
+//
+typedef struct _TCB {
+ OVERLAPPED Overlapped;
+ char *Buffer; // packet length is user specified.
+ ULONG BufferLength;
+ PDEVICE_INFO DeviceInfo;
+
+}TCB, *PTCB;
+
+unsigned short PacketId;
+
+VOID
+PostNextRead(
+ RCB *pRCB
+ );
+
+
+//
+// Function: SetIcmpSequence
+//
+// Description:
+// This routine sets the sequence number of the ICMP request packet.
+//
+VOID
+SetIcmpSequence(
+ _At_((IcmpHeader*)buf, _Out_writes_bytes_all_(bufSize)) char *buf,
+ _In_ _In_range_(==, sizeof(IcmpHeader)) ULONG bufSize
+ )
+{
+ ULONG sequence=0;
+ IcmpHeader *icmpv4=NULL;
+
+ #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above")
+ sequence = GetTickCount();
+
+ icmpv4 = (IcmpHeader *)buf;
+
+ icmpv4->i_seq = (USHORT)sequence;
+}
+
+//
+// Using _Inexpressible_ to suppress prefast warning 2014 : "Potential overflow
+// using expression at icmp_hdr->i_code"
+//
+VOID
+InitIcmpHeader(
+ _Out_writes_bytes_(_Inexpressible_(bufSize + datasize)) char *buf,
+ ULONG bufSize,
+ int datasize)
+{
+ IcmpHeader *icmp_hdr=NULL;
+ char *datapart=NULL;
+
+ icmp_hdr = (IcmpHeader *)buf;
+ icmp_hdr->i_type = ICMPV4_ECHO_REQUEST_TYPE; // request an ICMP echo
+ icmp_hdr->i_code = ICMPV4_ECHO_REQUEST_CODE;
+ icmp_hdr->i_id = htons((USHORT)PacketId++);
+ icmp_hdr->i_cksum = 0;
+ icmp_hdr->i_seq = 0;
+ #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above")
+ icmp_hdr->timestamp= htonl(GetTickCount());
+
+ datapart = buf + sizeof(IcmpHeader);
+ //
+ // Place some junk in the buffer.
+ //
+ memset(datapart, 'X', datasize);
+}
+
+VOID
+ComputeIPChecksum (
+ IpHeader *pIPHeader
+ )
+//////////////////////////////////////////////////////////////////////////////
+{
+ ULONG Checksum;
+ PUCHAR NextChar;
+
+ pIPHeader->checksumHigh = pIPHeader->checksumLow = 0;
+ Checksum = 0;
+ for ( NextChar = (PUCHAR) pIPHeader
+ ; (NextChar - (PUCHAR) pIPHeader) <= (sizeof(IpHeader) - 2)
+ ; NextChar += 2)
+ {
+ Checksum += ((ULONG) (NextChar[0]) << 8) + (ULONG) (NextChar[1]);
+ }
+
+ Checksum = (Checksum >> 16) + (Checksum & 0xffff);
+ Checksum += (Checksum >> 16);
+ Checksum = ~Checksum;
+
+ pIPHeader->checksumHigh = (UCHAR) ((Checksum >> 8) & 0xff);
+ pIPHeader->checksumLow = (UCHAR) (Checksum & 0xff);
+}
+
+//
+// Function: checksum
+//
+// Description:
+// This function calculates the 16-bit one's complement sum
+// of the supplied buffer (ICMP) header.
+//
+USHORT
+checksum(
+ USHORT *buffer,
+ int size
+ )
+{
+ unsigned long cksum=0;
+
+ while (size > 1)
+ {
+ cksum += *buffer++;
+ size -= sizeof(USHORT);
+ }
+ if (size)
+ {
+ cksum += *(UCHAR*)buffer;
+ }
+ cksum = (cksum >> 16) + (cksum & 0xffff);
+ cksum += (cksum >>16);
+ return (USHORT)(~cksum);
+}
+
+
+VOID
+ComputeIcmpChecksum(
+ _At_((IcmpHeader*) buf, _Inout_updates_bytes_all_(bufSize)) char *buf,
+ _In_ _In_range_(==, sizeof(IcmpHeader)) ULONG bufSize,
+ int packetlen
+ )
+{
+ IcmpHeader *icmpv4;
+
+ icmpv4 = (IcmpHeader *)buf;
+ icmpv4->i_cksum = 0;
+ icmpv4->i_cksum = checksum((USHORT *)buf, packetlen);
+}
+
+void
+InitEtherHeader(
+ PDEVICE_INFO DeviceInfo,
+ PETH_HEADER pEthHeader
+ )
+{
+
+ pEthHeader->EthType = htons(IP_PROT_TYPE);
+ memcpy(pEthHeader->DstAddr, DeviceInfo->TargetMacAddr, MAC_ADDR_LEN);
+ memcpy(pEthHeader->SrcAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN);
+
+
+}
+
+BOOL
+InitIpHeader(
+ PDEVICE_INFO DeviceInfo,
+ IpHeader *pIpHeader,
+ unsigned short IpLength)
+{
+ pIpHeader->verlen = 0x45;
+ pIpHeader->tos = 0; //Normal service
+ pIpHeader->total_len = htons(IpLength);
+ pIpHeader->ident = htons(0xABBA);
+ pIpHeader->frag_and_flags = 0;
+ pIpHeader->ttl = DEFAULT_TTL;
+ pIpHeader->proto = PROTOCOL_ICMP;
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ pIpHeader->sourceIP = inet_addr(DeviceInfo->SourceIp);
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ pIpHeader->destIP = inet_addr(DeviceInfo->DestIp);
+
+ return TRUE;
+}
+VOID WriteComplete(DWORD dwError, DWORD dwBytesTransferred, LPOVERLAPPED pOvl)
+{
+ TCB* pTCB = (TCB *)pOvl;
+
+ if (dwError) {
+ if(dwError == ERROR_DEVICE_NOT_CONNECTED) {
+ Display(TEXT("WriteComplete: Device not connected"));
+ }
+ else {
+ Display(TEXT("WriteComplete: Error %x"), dwError);
+
+ }
+ }
+
+ DisplayV(TEXT("Write Complete: %x"), dwBytesTransferred);
+ HeapFree (GetProcessHeap(), 0, pTCB->Buffer);
+ HeapFree (GetProcessHeap(), 0, pTCB);
+}
+
+VOID WriteCompleteArp(DWORD dwError, DWORD dwBytesTransferred, LPOVERLAPPED pOvl)
+{
+ if (dwError) {
+ if(dwError == ERROR_DEVICE_NOT_CONNECTED) {
+ Display(TEXT("WriteCompleteArp: Device not connected"));
+ }
+ else {
+ Display(TEXT("WriteCompleteArp: Error %x"), dwError);
+
+ }
+ }
+
+ DisplayV(TEXT("Write Complete ARP: %x"), dwBytesTransferred);
+}
+
+VOID
+ReadMacAddrComplete(
+ DWORD dwError,
+ DWORD dwBytesTransferred,
+ LPOVERLAPPED pOvl
+ )
+{
+ if (ERROR_OPERATION_ABORTED != dwError)
+ {
+ RCB* pRCB = (RCB *)pOvl;
+
+ char *Buffer = pRCB->Buffer;
+ PETH_HEADER ethHeader = (PETH_HEADER) Buffer;
+ PARP_BODY pBody;
+
+ PDEVICE_INFO deviceInfo = pRCB->DeviceInfo;
+ WCHAR unicodeIpAddr[MAX_LEN];
+ char *ipAddr;
+
+ DisplayV(TEXT("ReadMacAddrComplete: %x"), dwBytesTransferred);
+
+ if(ntohs(ethHeader->EthType) == ARP_ETYPE_ARP){
+
+ pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER));
+
+ if(ntohs(pBody->opcode) == ARP_RESPONSE){
+ #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ struct in_addr IPAddr = {0};
+
+ memcpy(&IPAddr, &pBody->SenderIpAddr, IP_ADDR_LEN);
+
+ if(memcmp(pBody->DestHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN) == 0){
+
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ ipAddr = inet_ntoa(IPAddr);
+
+ if (!MultiByteToWideChar (
+ CP_ACP,
+ 0,
+ ipAddr,
+ -1, // string is null terminated
+ unicodeIpAddr,
+ sizeof(unicodeIpAddr)/sizeof(WCHAR)
+ )) {
+ Display(TEXT("AnsitoUnicode conversion failed"));
+
+ }
+
+ DisplayV(TEXT("Target IP Address: %ws"), unicodeIpAddr);
+
+ DisplayV(TEXT("Target Mac Address: %02X-%02X-%02X-%02X-%02X-%02X-"),
+ pBody->SenderHwAddr[0],
+ pBody->SenderHwAddr[1],
+ pBody->SenderHwAddr[2],
+ pBody->SenderHwAddr[3],
+ pBody->SenderHwAddr[4],
+ pBody->SenderHwAddr[5]
+ );
+ memcpy(deviceInfo->TargetMacAddr, pBody->SenderHwAddr, MAC_ADDR_LEN);
+
+ SetEvent(deviceInfo->PingEvent);
+ return;
+ }
+ }
+ }
+
+ if(!ReadFileEx(pRCB->DeviceInfo->hDevice, pRCB->Buffer, sizeof(pRCB->Buffer),
+ &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadMacAddrComplete)){
+ Display(TEXT("ReadMacAddrComplete: ReadFileEx failed %x"), GetLastError());
+ }
+
+ }
+}
+
+BOOL
+GetTargetMac(
+ PDEVICE_INFO DeviceInfo,
+ PRCB pRCB
+ )
+{
+ char *Buffer = NULL;
+ PETH_HEADER ethHeader = NULL;
+ PARP_BODY pBody = NULL;
+ unsigned int retries =0;
+ DWORD status;
+ HANDLE hDevice = pRCB->DeviceInfo->hDevice;
+ PTCB pTCB = NULL;
+
+ if(!ReadFileEx(hDevice, pRCB->Buffer, sizeof(pRCB->Buffer),
+ &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadMacAddrComplete))
+ {
+ Display(TEXT("GetTargetMac: Error in ReadFile %x"), GetLastError());
+ return FALSE;
+ }
+
+ //
+ // We will try asking for mac address ten times. If we don't get valid response,
+ // we will bail out.
+ //
+ while(retries < 10){
+
+ //
+ // Allocate memory for the TCB and it's buffer. Writes are overlapped.
+ // We don't wait for the write requests to complete before posting
+ // another one.
+ //
+ pTCB = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCB));
+ if(!pTCB){
+ Display(TEXT("Ping: HeapAlloc Failed"));
+ return FALSE;
+ }
+
+ pTCB->Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ETH_MAX_PACKET_SIZE);
+ if(!pTCB->Buffer){
+ Display(TEXT("Ping: HeapAlloc Failed"));
+ HeapFree (GetProcessHeap(), 0, pTCB);
+ return FALSE;
+ }
+
+ pTCB->BufferLength = ETH_MAX_PACKET_SIZE;
+ memset(&pTCB->Overlapped, 0, sizeof(OVERLAPPED));
+ pTCB->DeviceInfo = DeviceInfo;
+
+ Buffer = pTCB->Buffer;
+ memset(Buffer, 0, ETH_MIN_PACKET_SIZE);
+
+ ethHeader = (PETH_HEADER) Buffer;
+
+
+ memcpy(ethHeader->SrcAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN);
+ memset(ethHeader->DstAddr, 0xff, MAC_ADDR_LEN);
+ ethHeader->EthType = htons(ARP_ETYPE_ARP); //Network byte order
+
+ pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER));
+ pBody->hw = htons(ARP_REQUEST); //Network byte order
+ pBody->pro = htons(IP_PROT_TYPE); //Network byte order
+ pBody->hlen = MAC_ADDR_LEN;
+ pBody->plen = IP_ADDR_LEN;
+ pBody->opcode = 0x0100;
+
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ pBody->SenderIpAddr = inet_addr(DeviceInfo->SourceIp);
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ pBody->DestIPAddr = inet_addr(DeviceInfo->DestIp);
+
+ memcpy(pBody->SenderHwAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN);
+
+ if(!WriteFileEx(hDevice, pTCB->Buffer, ETH_MIN_PACKET_SIZE, &pTCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteComplete))
+ {
+ Display(TEXT("GetTargetMac WriteFile failed %x"), GetLastError());
+ HeapFree (GetProcessHeap(), 0, pTCB->Buffer);
+ HeapFree (GetProcessHeap(), 0, pTCB);
+ return FALSE;
+ }
+
+ retries++;
+ //
+ // Wait for the PingEvent to be signalled. This even is signalled when the
+ // ReadMacAddrComplete received a valid packet
+ //
+wait:
+ status = WaitForSingleObjectEx(DeviceInfo->PingEvent, 1000, TRUE );
+
+ if ( status == WAIT_OBJECT_0 ) { // event fired, not timeout
+ //
+ // Got a valid response. Hurray!
+ //
+ return TRUE;
+ }
+
+ if ( status == WAIT_IO_COMPLETION ) {
+ // Either Read/Write completed. Go back to waiting until the completion rotuine
+ // processes the response and sigals the event.
+ goto wait;
+ }
+ if (status != WAIT_TIMEOUT){
+ //
+ // It has to be timeout at this point. Or else something fatal, break out.
+ Display(TEXT("WaitForSingleObjectEx returned error %d"), status);
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL
+GetSrcMac(
+ HANDLE Handle,
+ PUCHAR pSrcMacAddr
+ )
+{
+ DWORD BytesReturned;
+ BOOLEAN bSuccess;
+ UCHAR QueryBuffer[sizeof(NDISPROT_QUERY_OID) + MAC_ADDR_LEN];
+ PNDISPROT_QUERY_OID pQueryOid;
+
+
+ DisplayV(TEXT("Trying to get src mac address"), NULL);
+
+ pQueryOid = (PNDISPROT_QUERY_OID)&QueryBuffer[0];
+ pQueryOid->Oid = OID_802_3_CURRENT_ADDRESS;
+
+ bSuccess = (BOOLEAN)DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_QUERY_OID_VALUE,
+ (LPVOID)&QueryBuffer[0],
+ sizeof(QueryBuffer),
+ (LPVOID)&QueryBuffer[0],
+ sizeof(QueryBuffer),
+ &BytesReturned,
+ NULL);
+
+ if (bSuccess)
+ {
+ DisplayV(TEXT("GetSrcMac: IoControl success"));
+ memcpy(pSrcMacAddr, &pQueryOid->Data[0], MAC_ADDR_LEN);
+
+
+ }
+ else
+ {
+ Display(TEXT("GetSrcMac: IoControl failed %x\n"), GetLastError());
+ }
+
+ return (bSuccess);
+}
+
+VOID
+PrintIpHeader(
+ IpHeader *pIpHeader
+ )
+{
+ #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ struct in_addr IPAddr = {0};
+
+ DisplayV(TEXT("Ip Proto %x"), pIpHeader->proto);
+ DisplayV(TEXT("Ip VerLen %x"), pIpHeader->verlen);
+ DisplayV(TEXT("Ip Total Len %d"), pIpHeader->total_len);
+ DisplayV(TEXT("Ip Ident %d"), pIpHeader->ident);
+ DisplayV(TEXT("Ip tos %x"), pIpHeader->tos);
+
+ memcpy(&IPAddr, &pIpHeader->sourceIP, IP_ADDR_LEN);
+
+ // Display(TEXT("Source IP %s"), inet_ntoa(IPAddr));
+
+ memcpy(&IPAddr, &pIpHeader->destIP, IP_ADDR_LEN);
+
+ // Display(TEXT("Dest IP %s"), inet_ntoa(IPAddr));
+
+}
+
+
+BOOL
+SetPacketFilter(
+ HANDLE Handle,
+ ULONG PacketFilter
+ )
+{
+ DWORD BytesReturned;
+ BOOLEAN bSuccess;
+ NDISPROT_SET_OID SetOid;
+
+
+ DisplayV(TEXT("Trying to SetPacketFilter"), NULL);
+
+ SetOid.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+
+ memcpy(&SetOid.Data[0], &PacketFilter, sizeof(ULONG));
+
+ bSuccess = (BOOLEAN)DeviceIoControl(
+ Handle,
+ IOCTL_NDISPROT_SET_OID_VALUE,
+ (LPVOID)&SetOid,
+ sizeof(NDISPROT_SET_OID),
+ NULL,
+ 0,
+ &BytesReturned,
+ NULL);
+
+ if (!bSuccess)
+ {
+ Display(TEXT("SetPacketFilter: IoControl failed: %d"), GetLastError());
+ }
+
+ return (bSuccess);
+}
+
+
+VOID
+ProcessReadBuffer(
+ PRCB pRCB,
+ ULONG BufferLength
+ )
+{
+ char *Buffer = pRCB->Buffer;
+ PETH_HEADER ethHeader = (PETH_HEADER) Buffer;
+ PARP_BODY pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER));
+ char ArpResponse[ETH_MIN_PACKET_SIZE] = {0};
+ PETH_HEADER pResEthHeader = (PETH_HEADER)ArpResponse;
+ PARP_BODY pRespBody = (PARP_BODY)(ArpResponse + sizeof(ETH_HEADER));
+ OVERLAPPED ov = {0};
+ PDEVICE_INFO deviceInfo = pRCB->DeviceInfo;
+ HANDLE hDevice = deviceInfo->hDevice;
+
+ // Check whether its a broadcast ARP request
+ if (ethHeader->DstAddr[0] == 0xff &&
+ ethHeader->DstAddr[1] == 0xff )
+ {
+
+ if(ntohs(ethHeader->EthType) != ARP_ETYPE_ARP){
+ deviceInfo->Sleep = FALSE;
+ DisplayV(TEXT("Non an arp eth request"));
+ goto End;
+ }
+
+ if (IP_PROT_TYPE != ntohs(pBody->pro) ||
+ MAC_ADDR_LEN != pBody->hlen ||
+ IP_ADDR_LEN != pBody->plen )
+ {
+ //
+ // these are just sanity checks
+ //
+ deviceInfo->Sleep = FALSE;
+ DisplayV(TEXT("Non an arp packet"));
+ goto End;
+ }
+
+ DisplayV(TEXT("This is an arp request"));
+
+ memcpy(pResEthHeader->DstAddr, ethHeader->SrcAddr, MAC_ADDR_LEN);
+ memcpy(pResEthHeader->SrcAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN);
+ pResEthHeader->EthType = ethHeader->EthType;
+
+ pRespBody->hw = pBody->hw; // Hardware address space. = 00 01
+
+ pRespBody->pro = pBody->pro; // Protocol address space. = 08 00
+
+ pRespBody->hlen = MAC_ADDR_LEN; // 6
+
+ pRespBody->plen = IP_ADDR_LEN; // 4
+
+ pRespBody->opcode = htons(ARP_RESPONSE); // Opcode.
+
+ memcpy(pRespBody->SenderHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); // Destination HW address.
+
+ pRespBody->SenderIpAddr = pBody->DestIPAddr ; // Source protocol address.
+
+ memcpy(pRespBody->DestHwAddr, pBody->SenderHwAddr, MAC_ADDR_LEN); // Destination HW address.
+
+ pRespBody->DestIPAddr = pBody->SenderIpAddr;
+
+ PostNextRead(pRCB);
+
+ DisplayV(TEXT("Writing Arp response\n"));
+ if(!WriteFileEx(hDevice, ArpResponse, sizeof(ArpResponse), &ov, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteCompleteArp))
+ {
+ Display(TEXT("Couldn't write arp response %d"), GetLastError());
+ return ;
+ }
+ }
+ // Check whether its an unicast ARP request
+ else if (ethHeader->DstAddr[0] == deviceInfo->SrcMacAddr[0] &&
+ ethHeader->DstAddr[1] == deviceInfo->SrcMacAddr[1] &&
+ ethHeader->DstAddr[2] == deviceInfo->SrcMacAddr[2] &&
+ ethHeader->DstAddr[3] == deviceInfo->SrcMacAddr[3] &&
+ ethHeader->DstAddr[4] == deviceInfo->SrcMacAddr[4] &&
+ ethHeader->DstAddr[5] == deviceInfo->SrcMacAddr[5] &&
+ ntohs(ethHeader->EthType) == ARP_ETYPE_ARP &&
+ IP_PROT_TYPE == ntohs(pBody->pro) &&
+ MAC_ADDR_LEN == pBody->hlen &&
+ IP_ADDR_LEN == pBody->plen) {
+
+ // If it passed all these checks, its an ARP request
+ memcpy(pResEthHeader->DstAddr, ethHeader->SrcAddr, MAC_ADDR_LEN);
+ memcpy(pResEthHeader->SrcAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN);
+ pResEthHeader->EthType = ethHeader->EthType;
+
+ pRespBody->hw = pBody->hw; // Hardware address space. = 00 01
+
+ pRespBody->pro = pBody->pro; // Protocol address space. = 08 00
+
+ pRespBody->hlen = MAC_ADDR_LEN; // 6
+
+ pRespBody->plen = IP_ADDR_LEN; // 4
+
+ pRespBody->opcode = htons(ARP_RESPONSE); // Opcode.
+
+ memcpy(pRespBody->SenderHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); // Destination HW address.
+
+ pRespBody->SenderIpAddr = pBody->DestIPAddr ; // Source protocol address.
+
+ memcpy(pRespBody->DestHwAddr, pBody->SenderHwAddr, MAC_ADDR_LEN); // Destination HW address.
+
+ pRespBody->DestIPAddr = pBody->SenderIpAddr;
+
+ PostNextRead(pRCB);
+
+ DisplayV(TEXT("Writing Arp response\n"));
+ if(!WriteFileEx(hDevice, ArpResponse, sizeof(ArpResponse), &ov, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteCompleteArp))
+ {
+ Display(TEXT("Couldn't write arp response %d"), GetLastError());
+ return ;
+ }
+ }
+ else {
+
+ IpHeader *pIpHeader = (IpHeader *)(Buffer + sizeof(ETH_HEADER));
+ IcmpHeader *pIcmpHeader = (IcmpHeader *)(Buffer + sizeof(ETH_HEADER)+sizeof(IpHeader));//TODO: Find the iP len from the packet
+ ULONG datalen = BufferLength - sizeof(ETH_HEADER) - sizeof(IpHeader) - sizeof(IcmpHeader);
+ #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ struct in_addr IPAddr = {0};
+ char *ipAddr;
+ WCHAR unicodeIpAddr[MAX_LEN];
+
+ PrintIpHeader(pIpHeader);
+
+ if(pIpHeader->proto == PROTOCOL_ICMP && pIcmpHeader->i_type == ICMPV4_ECHO_REPLY_TYPE &&
+ pIcmpHeader->i_type == ICMPV4_ECHO_REPLY_CODE){
+
+ memcpy(&IPAddr, &pIpHeader->sourceIP, IP_ADDR_LEN);
+
+ #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6")
+ ipAddr = inet_ntoa(IPAddr);
+
+ if (!MultiByteToWideChar (
+ CP_ACP,
+ 0,
+ ipAddr,
+ -1,
+ unicodeIpAddr,
+ sizeof(unicodeIpAddr)/sizeof(unicodeIpAddr[0])
+ )) {
+ Display(TEXT("AnsitoUnicode conversion failed"));
+
+ }
+
+ #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above")
+ Display(TEXT("Reply %d from %ws: bytes=%d time<%dms TTL=%d"),
+ ntohs(pIcmpHeader->i_id),
+ unicodeIpAddr,
+ datalen,
+ (GetTickCount()-ntohl(pIcmpHeader->timestamp)),
+ pIpHeader->ttl);
+
+ deviceInfo->NumberOfRequestSent++;
+ deviceInfo->Sleep = TRUE;
+
+ }
+
+ }
+
+End:
+ PostNextRead(pRCB);
+ SetEvent(deviceInfo->PingEvent);
+
+}
+VOID
+ReadComplete(
+ DWORD dwError,
+ DWORD dwBytesTransferred,
+ LPOVERLAPPED pOvl
+ )
+{
+ if (ERROR_OPERATION_ABORTED != dwError)
+ {
+ RCB* pRCB = (RCB *)pOvl;
+ DisplayV(TEXT("ReadComplete: %d"), dwBytesTransferred);
+ ProcessReadBuffer(pRCB, dwBytesTransferred);
+ }
+}
+
+VOID
+PostNextRead(
+ RCB *pRCB
+ )
+{
+
+ if(!ReadFileEx(pRCB->DeviceInfo->hDevice, pRCB->Buffer, sizeof(pRCB->Buffer),
+ &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadComplete))
+ {
+ Display(TEXT("Error in ReadFile: %x"), GetLastError());
+ }
+
+}
+
+
+BOOLEAN
+Ping(
+ PDEVICE_INFO DeviceInfo
+ )
+{
+ HANDLE hDevice = DeviceInfo->hDevice;
+ char *icmpbuf;
+ char *ipHeader;
+ char *etherHeader;
+ unsigned int icmpbuflen, packetlen;
+ PTCB pTCB = NULL;
+
+ packetlen = sizeof(IcmpHeader) + sizeof(IpHeader) + sizeof(ETH_HEADER);
+
+ // Add in the data size
+ if(FAILED(UIntAdd(packetlen, DeviceInfo->PacketSize, &packetlen))) {
+ Display(TEXT("Ping: UIntAdd Failed"));
+ goto Error;
+ }
+
+ pTCB = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCB));
+ if(!pTCB){
+ Display(TEXT("Ping: HeapAlloc Failed"));
+ goto Error;
+ }
+
+ pTCB->Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);
+ if(!pTCB->Buffer){
+ Display(TEXT("Ping: HeapAlloc Failed"));
+ goto Error;
+ }
+
+ pTCB->BufferLength = packetlen;
+ memset(&pTCB->Overlapped, 0, sizeof(OVERLAPPED));
+
+
+ // Allocate the buffer that will contain the ICMP request
+ etherHeader = pTCB->Buffer;
+
+ ipHeader = etherHeader + sizeof(ETH_HEADER);
+
+ icmpbuf = ipHeader + sizeof(IpHeader);
+
+
+ icmpbuflen = sizeof(IcmpHeader) + DeviceInfo->PacketSize;
+
+ InitEtherHeader(DeviceInfo, (PETH_HEADER)etherHeader);
+
+
+ InitIcmpHeader(icmpbuf, icmpbuflen, DeviceInfo->PacketSize);
+
+ // Set the sequence number and compute the checksum
+ SetIcmpSequence(icmpbuf, sizeof(IcmpHeader));
+
+ DisplayV(TEXT("Icmp header %d packetlen %d"), sizeof(IcmpHeader), icmpbuflen);
+
+ ComputeIcmpChecksum(icmpbuf, sizeof(IcmpHeader), icmpbuflen);
+
+ if(!InitIpHeader(DeviceInfo, (IpHeader *)ipHeader, (USHORT)icmpbuflen+sizeof(IpHeader))){
+ goto Error;
+ }
+
+ ComputeIPChecksum((IpHeader *)ipHeader);
+
+ PrintIpHeader((IpHeader *)ipHeader);
+
+ if(!WriteFileEx(hDevice, etherHeader, packetlen, &pTCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteComplete))
+ {
+ Display(TEXT("Ping: WriteFile failed %x"), GetLastError());
+ goto Error;
+ }
+
+ return TRUE;
+
+Error:
+
+ if(pTCB) {
+ if(pTCB->Buffer){
+ HeapFree (GetProcessHeap(), 0, pTCB->Buffer);
+ }
+ HeapFree (GetProcessHeap(), 0, pTCB);
+ }
+ return FALSE;
+}
+
+DWORD
+PingThread (
+ PDEVICE_INFO DeviceInfo
+ )
+{
+ RCB RCB;
+ HANDLE hDevice = DeviceInfo->hDevice;
+ DWORD status;
+
+
+ Display(TEXT("Pinging %ws from %ws with %d bytes of data"),
+ DeviceInfo->UnicodeDestIp,
+ DeviceInfo->UnicodeSourceIp,
+ DeviceInfo->PacketSize);
+ Sleep(1000);
+
+ //
+ // Every time a ping response is recevied, PingEvent will
+ // be signalled.
+ //
+ DeviceInfo->PingEvent = CreateEvent(NULL, FALSE, FALSE, L"PingEvent");
+ if (DeviceInfo->PingEvent == NULL) {
+ Display(TEXT("CreateEvent failed 0x%x"), GetLastError());
+ goto Exit;
+ }
+
+ DeviceInfo->NumberOfRequestSent = 0;
+ DeviceInfo->Sleep = FALSE;
+ DeviceInfo->TimeOut = 0;
+ PacketId = 1;
+
+ //
+ // Get the MAC address of the local NIC
+ //
+ if (!GetSrcMac(hDevice, DeviceInfo->SrcMacAddr))
+ {
+ Display(TEXT("Failed to obtain local MAC address"));
+ goto Exit;
+ }
+
+ //
+ // Set the hardware filter to receive directed on broadcast packets.
+ //
+ if (!SetPacketFilter(hDevice, NDIS_PACKET_TYPE_DIRECTED|NDIS_PACKET_TYPE_BROADCAST))
+ {
+ Display(TEXT("Failed to set packet filter"));
+ goto Exit;
+ }
+
+ //
+ // Initialize read control block. Reads requests are serialized.
+ // Only one read is outstanding at any time. We allocate memory
+ // for the RCB in the stack.
+ //
+ RCB.DeviceInfo = DeviceInfo;
+ memset(&RCB.Overlapped, 0, sizeof(OVERLAPPED));
+
+
+ //
+ // Get MAC address of the target machine by sending an ARP
+ // request. We have the target machine's IP address from the user.
+ //
+ if(!GetTargetMac(DeviceInfo, &RCB)){
+ Display(TEXT("Couldn't find the host"));
+ goto Exit;
+ }
+
+ //
+ // Set the hardware filter to receive directed packets only
+ //
+ if (!SetPacketFilter(hDevice, NDIS_PACKET_TYPE_DIRECTED))
+ {
+ Display(TEXT("Failed to set packet filter"));
+ goto Exit;
+ }
+
+ //
+ // Post a read buffer and start sending ping packets.
+ //
+ PostNextRead(&RCB);
+
+ Ping(DeviceInfo);
+
+ //
+ // We will exit out of this thread if the number of ping count
+ // exceeds the DEFAULT_SEND_COUNT or the main thread requested
+ // us to exit by setting ExitThread value to TRUE.
+ //
+ while(DeviceInfo->NumberOfRequestSent < DEFAULT_SEND_COUNT
+ && DeviceInfo->ExitThread == FALSE){
+
+ status = WaitForSingleObjectEx(DeviceInfo->PingEvent, 1000, TRUE );
+ if ( status == WAIT_OBJECT_0 ) { // event fired, not timeout
+ //
+ // Probably we received a valid ping response from the target.
+ //
+ if(DeviceInfo->Sleep){
+ Sleep(PING_SLEEP_TIME); // sleep for a sec before sending another ECHO
+ }
+ Ping(DeviceInfo);
+ continue;
+ }
+ //
+ // This is just a notification that either Read/Write operation got
+ // completed. We will know the result of the acutal operation later
+ // when the APC is called.
+ //
+ if( status == WAIT_IO_COMPLETION ) {
+ continue;
+ }
+ if (status != WAIT_TIMEOUT){
+
+ Display(TEXT("WaitForSingleObjectEx returned error %d"), status);
+ break;
+ }
+ //
+ // It seems like the wait timed out. So let us send another ping
+ // and see if we get any response.
+ //
+ DeviceInfo->TimeOut++;
+ if(DeviceInfo->TimeOut > MAX_PING_RETRY) {
+ Display(TEXT("No response from the target"));
+ break;
+ }
+
+ Ping(DeviceInfo);
+ }
+
+Exit:
+
+ CloseHandle(DeviceInfo->hDevice);
+ DeviceInfo->hDevice = INVALID_HANDLE_VALUE;
+ DeviceInfo->ThreadHandle = NULL;
+ if (DeviceInfo->PingEvent) {
+ CloseHandle(DeviceInfo->PingEvent);
+ DeviceInfo->PingEvent = NULL;
+ }
+
+ Display(TEXT("PingThread is exiting"));
+ return 0;
+}
+
+
+
+
+
diff --git a/general/pcidrv/test/myping.vcxproj b/general/pcidrv/test/myping.vcxproj
new file mode 100644
index 00000000..182ebe8c
--- /dev/null
+++ b/general/pcidrv/test/myping.vcxproj
@@ -0,0 +1,201 @@
+<?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>{AAB2FA59-187D-45F7-A84F-09C7089848B3}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{E28A6724-75F7-4959-8204-0A5787BBF7B9}</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 />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</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" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>myping</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>myping</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>myping</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>myping</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies>
+ <BaseAddress>0x01000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies>
+ <BaseAddress>0x01000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies>
+ <BaseAddress>0x01000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies>
+ <BaseAddress>0x01000000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="myping.c" />
+ <ClCompile Include="testapp.c" />
+ <ResourceCompile Include="testapp.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/general/pcidrv/test/myping.vcxproj.Filters b/general/pcidrv/test/myping.vcxproj.Filters
new file mode 100644
index 00000000..32295c73
--- /dev/null
+++ b/general/pcidrv/test/myping.vcxproj.Filters
@@ -0,0 +1,30 @@
+<?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>{B8B1F2DC-5ED4-4A1F-BFEE-587F0F5312D5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{8259798A-8FE0-4AE5-B848-77626974747D}</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>{48C95CA9-FD65-42C9-8FAF-C20DEB7390E8}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="myping.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="testapp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="testapp.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/pcidrv/test/resource.h b/general/pcidrv/test/resource.h
new file mode 100644
index 00000000..96cfe365
--- /dev/null
+++ b/general/pcidrv/test/resource.h
@@ -0,0 +1,17 @@
+#define ID_EDIT 1
+
+#define IDM_PING 100
+#define IDM_CLOSE 101
+#define IDM_EXIT 102
+#define IDM_CLEAR 103
+#define IDM_ENUMERATE 104
+#define IDM_VERBOSE 105
+
+#define IDD_DIALOG 115
+#define ID_OK 118
+#define ID_CANCEL 119
+#define IDC_DEVICE_INDEX 1000
+#define IDC_SOURCE_IP 1001
+#define IDC_DESTINATION_IP 1002
+#define IDC_PACKET_SIZE 1003
+#define IDC_STATIC -1
diff --git a/general/pcidrv/test/testapp.c b/general/pcidrv/test/testapp.c
new file mode 100644
index 00000000..cd83f633
--- /dev/null
+++ b/general/pcidrv/test/testapp.c
@@ -0,0 +1,1224 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name: Testapp.c
+
+
+Abstract:
+
+ Testapp for PCIDRV
+
+Environment:
+
+ User mode only.
+
+--*/
+
+#include "testapp.h"
+
+
+//
+// Global variables
+//
+HINSTANCE HWndInstance;
+HWND HWndList; // handle to the embedded list box
+TCHAR WindowTitle[]=TEXT("MyPing - Test Application for PCIDRV");
+LIST_ENTRY ListHead;
+HDEVNOTIFY InterfaceNotificationHandle;
+TCHAR OutText[500];
+UINT ListBoxIndex = 0;
+GUID InterfaceGuid;// = GUID_DEVINTERFACE_PCIDRV;
+ULONG DeviceIndex;
+BOOLEAN Verbose = FALSE;
+
+
+VOID
+Display(
+ _In_ LPWSTR pstrFormat, // @parm A printf style format string
+ ... // @parm | ... | Variable paramters based on <p pstrFormat>
+ )
+{
+ HRESULT hr;
+ va_list va;
+
+ va_start(va, pstrFormat);
+ //
+ // Truncation is acceptable.
+ //
+ hr = StringCbVPrintf(OutText, sizeof(OutText)-sizeof(WCHAR), pstrFormat, va);
+ va_end(va);
+
+ if(FAILED(hr)){
+ return;
+ }
+
+ SendMessage(HWndList, LB_INSERTSTRING, ListBoxIndex, (LPARAM)OutText);
+ SendMessage(HWndList, LB_SETCURSEL, ListBoxIndex, 0);
+ ListBoxIndex++;
+
+}
+
+_Use_decl_annotations_
+int
+PASCAL
+WinMain (
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nShowCmd
+ )
+{
+ static TCHAR szAppName[]=TEXT("MYPING");
+ HWND hWnd;
+ MSG msg;
+ WNDCLASS wndclass;
+
+ InterfaceGuid = GUID_DEVINTERFACE_PCIDRV;
+ HWndInstance=hInstance;
+
+ if (!hPrevInstance)
+ {
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground= GetStockObject(WHITE_BRUSH);
+ wndclass.lpszMenuName = TEXT("GenericMenu");
+ wndclass.lpszClassName= szAppName;
+
+ RegisterClass(&wndclass);
+ }
+
+ hWnd = CreateWindow (szAppName,
+ WindowTitle,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ ShowWindow (hWnd, nShowCmd);
+ UpdateWindow(hWnd);
+
+ while (GetMessage (&msg, NULL, 0,0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return (0);
+}
+
+
+LRESULT FAR PASCAL
+WndProc (HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ DWORD nEventType = (DWORD)wParam;
+ PDEV_BROADCAST_HDR p = (PDEV_BROADCAST_HDR) lParam;
+ DEV_BROADCAST_DEVICEINTERFACE filter;
+ WSADATA wsd;
+
+ switch (message)
+ {
+
+ case WM_COMMAND:
+ HandleCommands(hWnd, message, wParam, lParam);
+ return 0;
+
+ case WM_CREATE:
+
+ // Load Winsock
+ if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
+ {
+ MessageBox(hWnd, TEXT("WSAStartup failed"), TEXT("Error"), MB_OK);
+ exit(0);
+ }
+
+ HWndList = CreateWindow (TEXT("listbox"),
+ NULL,
+ WS_CHILD|WS_VISIBLE|LBS_NOTIFY |
+ WS_VSCROLL | WS_BORDER,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ hWnd,
+ (HMENU)ID_EDIT,
+ HWndInstance,
+ NULL);
+
+ filter.dbcc_size = sizeof(filter);
+ filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ filter.dbcc_classguid = InterfaceGuid;
+ InterfaceNotificationHandle = RegisterDeviceNotification(hWnd, &filter, 0);
+
+ InitializeListHead(&ListHead);
+ EnumExistingDevices(hWnd);
+
+ return 0;
+
+ case WM_SIZE:
+
+ MoveWindow(HWndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
+ return 0;
+
+ case WM_SETFOCUS:
+ SetFocus(HWndList);
+ return 0;
+
+ case WM_DEVICECHANGE:
+
+ //
+ // The DBT_DEVNODES_CHANGED broadcast message is sent
+ // everytime a device is added or removed. This message
+ // is typically handled by Device Manager kind of apps,
+ // which uses it to refresh window whenever something changes.
+ // The lParam is always NULL in this case.
+ //
+ if(DBT_DEVNODES_CHANGED == wParam) {
+ DisplayV(TEXT("Received DBT_DEVNODES_CHANGED broadcast message"));
+ return 0;
+ }
+
+ //
+ // All the events we're interested in come with lParam pointing to
+ // a structure headed by a DEV_BROADCAST_HDR. This is denoted by
+ // bit 15 of wParam being set, and bit 14 being clear.
+ //
+ if((wParam & 0xC000) == 0x8000) {
+
+ if (!p)
+ return 0;
+
+ if (p->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
+
+ HandleDeviceInterfaceChange(hWnd, nEventType, (PDEV_BROADCAST_DEVICEINTERFACE) p);
+ } else if (p->dbch_devicetype == DBT_DEVTYP_HANDLE) {
+
+ HandleDeviceChange(hWnd, nEventType, (PDEV_BROADCAST_HANDLE) p);
+ }
+ }
+ return 0;
+
+ case WM_POWERBROADCAST:
+ HandlePowerBroadcast(hWnd, wParam, lParam);
+ return 0;
+
+ case WM_CLOSE:
+ Cleanup(hWnd);
+ UnregisterDeviceNotification(InterfaceNotificationHandle);
+ return DefWindowProc(hWnd,message, wParam, lParam);
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+ return DefWindowProc(hWnd,message, wParam, lParam);
+ }
+
+
+LRESULT
+HandleCommands(
+ HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+
+{
+ PDIALOG_RESULT result = NULL;
+ PDEVICE_INFO deviceInfo = NULL;
+
+ switch (wParam) {
+
+ case IDM_CLOSE:
+ Cleanup(hWnd);
+ Display(TEXT("Handle to the device closed"));
+ EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_GRAYED);
+ EnableMenuItem(GetMenu(hWnd), IDM_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ break;
+
+ case IDM_ENUMERATE:
+ //
+ // First cleanup everything, and then reenumerate all the devices.
+ Cleanup(hWnd);
+ EnumExistingDevices(hWnd);
+ EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_ENABLED);
+ break;
+
+ case IDM_PING:
+
+ result = (PDIALOG_RESULT)DialogBox(HWndInstance, MAKEINTRESOURCE(IDD_DIALOG), hWnd, DlgProc);
+ if(result) {
+ deviceInfo = FindDeviceInfo(result);
+ if(!deviceInfo){
+ MessageBox(hWnd, TEXT("FindDeviceInfo failed"), TEXT("Error"), MB_OK);
+ break;
+ }
+
+ if(!OpenDevice(hWnd, deviceInfo)){
+ MessageBox(hWnd, TEXT("OpenDevice failed"), TEXT("Error"), MB_OK);
+ break;
+ }
+
+ if (!CreatePingThread(deviceInfo)) {
+ MessageBox(hWnd, TEXT("CreatePingThread failed"), TEXT("Error"), MB_OK);
+ break;
+ }
+
+ EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_GRAYED);
+ EnableMenuItem(GetMenu(hWnd), IDM_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+
+ }
+ break;
+
+ case IDM_CLEAR:
+ SendMessage(HWndList, LB_RESETCONTENT, 0, 0);
+ ListBoxIndex = 0;
+ break;
+
+ case IDM_VERBOSE: {
+
+ HMENU hMenu = GetMenu(hWnd);
+ Verbose = !Verbose;
+ if(Verbose) {
+ CheckMenuItem(hMenu, (UINT)wParam, MF_CHECKED);
+ } else {
+ CheckMenuItem(hMenu, (UINT)wParam, MF_UNCHECKED);
+ }
+ }
+ break;
+
+ case IDM_EXIT:
+ Cleanup(hWnd);
+ PostQuitMessage(0);
+ break;
+
+ default:
+ break;
+ }
+
+ if(result) {
+ HeapFree (GetProcessHeap(), 0, result);
+ }
+ return TRUE;
+}
+
+INT_PTR CALLBACK
+DlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ BOOL success;
+ PDIALOG_RESULT dialogResult = NULL;
+ ULONG value;
+ WCHAR SourceIP[80];
+ WCHAR DestinationIP[80];
+ DWORD SourceIPLen = sizeof(SourceIP);
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ //
+ // Set default values.
+ //
+ if(GetRegistryInfo(SourceIP, &SourceIPLen, DestinationIP, &SourceIPLen)) {
+ SetDlgItemText(hDlg, IDC_SOURCE_IP, SourceIP);
+ SetDlgItemText(hDlg, IDC_DESTINATION_IP, DestinationIP);
+ } else {
+ SetDlgItemText(hDlg, IDC_SOURCE_IP, DEF_SOURCE_IP);
+ SetDlgItemText(hDlg, IDC_DESTINATION_IP, DEF_DEST_IP);
+
+ }
+
+ SetDlgItemInt(hDlg, IDC_PACKET_SIZE, MAX_PAYLOAD_SIZE, FALSE);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch( wParam)
+ {
+ case ID_OK:
+ //
+ // Allocate memory to store the input values.
+ //
+ dialogResult = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(DIALOG_RESULT));
+ if(dialogResult) {
+
+ dialogResult->DeviceIndex = GetDlgItemInt(hDlg,
+ IDC_DEVICE_INDEX, &success, FALSE );
+ if(!success){
+ break;
+ }
+ value = GetDlgItemText(hDlg, IDC_SOURCE_IP,
+ dialogResult->SourceIp, MAX_LEN-1 );
+ if(!value){
+ break;
+ }
+
+
+ GetDlgItemText(hDlg, IDC_DESTINATION_IP,
+ dialogResult->DestIp, MAX_LEN-1 );
+ if(!value){
+ break;
+ }
+
+ value = GetDlgItemInt(hDlg,IDC_PACKET_SIZE, &success, FALSE );
+ if(success){
+ value = min(value, MAX_PAYLOAD_SIZE);
+ value = max(value, MIN_PAYLOAD_SIZE);
+
+ } else {
+ value = MIN_PAYLOAD_SIZE;
+ }
+
+ dialogResult->PacketSize = value;
+
+ SetRegistryInfo(dialogResult->SourceIp,
+ sizeof(dialogResult->SourceIp),
+ dialogResult->DestIp,
+ sizeof(dialogResult->DestIp));
+
+ }
+ EndDialog(hDlg, (UINT_PTR)dialogResult);
+ return TRUE;
+ case ID_CANCEL:
+ EndDialog(hDlg, 0);
+ return TRUE;
+
+ }
+ break;
+
+ }
+ return FALSE;
+}
+
+
+BOOL
+HandleDeviceInterfaceChange(
+ HWND hWnd,
+ DWORD evtype,
+ PDEV_BROADCAST_DEVICEINTERFACE dip
+ )
+{
+ switch (evtype)
+ {
+ case DBT_DEVICEARRIVAL:
+ //
+ // New device arrived. Create a devicinfo structure and record
+ // information about the device.
+ //
+ Display(TEXT("New device Arrived (Interface Change Notification)"));
+
+ if(!CreateDeviceInfo(dip->dbcc_name)) {
+ return FALSE;
+ }
+
+ break;
+
+ case DBT_DEVICEREMOVECOMPLETE:
+ //
+ // Device Removed.
+ //
+ Display(TEXT("Remove Complete (Interface Change Notification)"), NULL);
+ break;
+
+ default:
+ DisplayV(TEXT("Unknown (Interface Change Notification)"), NULL);
+ break;
+ }
+ return TRUE;
+}
+
+BOOL
+HandleDeviceChange(
+ HWND hWnd,
+ DWORD evtype,
+ PDEV_BROADCAST_HANDLE dhp
+ )
+{
+ PDEVICE_INFO deviceInfo = NULL;
+ PLIST_ENTRY thisEntry;
+
+ //
+ // Walk the list to get the deviceInfo for this device
+ // by matching the notification handle saved in our deviceInfo
+ // and the one provided as part of the message.
+ //
+ for(thisEntry = ListHead.Flink; thisEntry != &ListHead;
+ thisEntry = thisEntry->Flink)
+ {
+ deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry);
+ if(dhp->dbch_hdevnotify == deviceInfo->hHandleNotification) {
+ break;
+ }
+ deviceInfo = NULL;
+ }
+
+ if(!deviceInfo) {
+ Display(TEXT("Error: spurious message Event Type %x, Device Type %x"),
+ evtype, dhp->dbch_devicetype);
+ return FALSE;
+ }
+
+ switch (evtype)
+ {
+
+ case DBT_DEVICEQUERYREMOVE:
+
+ Display(TEXT("Query Remove (Handle Notification): %ws"),
+ deviceInfo->DeviceName);
+ // User is trying to disable, uninstall, or eject our device.
+ // Terminate the ping thread and close the handle
+ // to the device so that the target device can
+ // get removed. Do not unregister the notification
+ // at this point, because we want to know whether
+ // the device is successfully removed or not.
+ //
+ TerminatePingThread(deviceInfo);
+ break;
+
+ case DBT_DEVICEREMOVECOMPLETE:
+
+ Display(TEXT("Remove Complete (Handle Notification):%ws"),
+ deviceInfo->DeviceName);
+ //
+ // Device is getting surprise removed. So terminate the
+ // ping thread to close the handle to device and
+ // unregister the PNP notification.
+ //
+ TerminatePingThread(deviceInfo);
+
+ if (deviceInfo->hHandleNotification) {
+ UnregisterDeviceNotification(deviceInfo->hHandleNotification);
+ deviceInfo->hHandleNotification = NULL;
+ }
+
+ //
+ // Unlink this deviceInfo from the list and free the memory
+ //
+ RemoveEntryList(&deviceInfo->ListEntry);
+ HeapFree (GetProcessHeap(), 0, deviceInfo);
+
+ break;
+
+ case DBT_DEVICEREMOVEPENDING:
+
+ Display(TEXT("Remove Pending (Handle Notification):%ws"),
+ deviceInfo->DeviceName);
+ //
+ // Device is successfully removed so unregister the notification
+ // and free the memory.
+ //
+ FreeDeviceInfo(deviceInfo);
+
+ break;
+
+ case DBT_DEVICEQUERYREMOVEFAILED :
+ Display(TEXT("Remove failed (Handle Notification):%ws"),
+ deviceInfo->DeviceName);
+ //
+ // Remove failed. So reopen the device and register for
+ // notification on the new handle. But first we should unregister
+ // the previous notification.
+ //
+ if (deviceInfo->hHandleNotification) {
+ UnregisterDeviceNotification(deviceInfo->hHandleNotification);
+ deviceInfo->hHandleNotification = NULL;
+ }
+
+ if(!OpenDevice(hWnd, deviceInfo)) {
+ Display(TEXT("Failed to reopen the device: %ws"),
+ deviceInfo->DeviceName);
+ FreeDeviceInfo(deviceInfo);
+ break;
+ }
+
+ Display(TEXT("Reopened device %ws"), deviceInfo->DeviceName);
+ //
+ // Restart the ping operation.
+ //
+ if(CreatePingThread(deviceInfo)){
+ FreeDeviceInfo(deviceInfo);
+ break;
+ }
+
+ break;
+
+ default:
+ Display(TEXT("Unknown (Handle Notification)"));
+ break;
+
+ }
+ return TRUE;
+}
+
+
+BOOLEAN
+EnumExistingDevices(
+ HWND hWnd
+)
+{
+ HDEVINFO hardwareDeviceInfo;
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
+ ULONG predictedLength = 0;
+ ULONG requiredLength = 0, i;
+ DWORD error;
+ PDEVICE_INFO deviceInfo =NULL;
+
+ DisplayV(TEXT("Entered EnumExistingDevices"));
+
+ //
+ // Make sure the list is empty
+ //
+ if(!IsListEmpty(&ListHead) ){
+ MessageBox(hWnd, TEXT("ListHead should be empty"), TEXT("Error!"), MB_OK);
+ return FALSE;
+ }
+
+ DeviceIndex = 0;
+
+ hardwareDeviceInfo = SetupDiGetClassDevs (
+ (LPGUID)&InterfaceGuid,
+ NULL, // Define no enumerator (global)
+ NULL, // Define no
+ (DIGCF_PRESENT | // Only Devices present
+ DIGCF_DEVICEINTERFACE)); // Function class devices.
+ if(INVALID_HANDLE_VALUE == hardwareDeviceInfo)
+ {
+ goto Error;
+ }
+
+ //
+ // Enumerate devices of a specific interface class
+ //
+ deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
+
+ for(i=0; SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
+ 0, // No care about specific PDOs
+ (LPGUID)&InterfaceGuid,
+ i, //
+ &deviceInterfaceData); i++ ) {
+
+ //
+ // Allocate a function class device data structure to
+ // receive the information about this particular device.
+ //
+
+ //
+ // First find out required length of the buffer
+ //
+ if (deviceInterfaceDetailData) {
+ HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData);
+ deviceInterfaceDetailData = NULL;
+ }
+
+ if(!SetupDiGetDeviceInterfaceDetail (
+ hardwareDeviceInfo,
+ &deviceInterfaceData,
+ NULL, // probing so no output buffer yet
+ 0, // probing so output buffer length of zero
+ &requiredLength,
+ NULL) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ {
+ goto Error;
+ }
+ predictedLength = requiredLength;
+
+ deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ predictedLength);
+ if (deviceInterfaceDetailData == NULL) {
+ goto Error;
+ }
+
+ deviceInterfaceDetailData->cbSize =
+ sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
+
+
+ if (! SetupDiGetDeviceInterfaceDetail (
+ hardwareDeviceInfo,
+ &deviceInterfaceData,
+ deviceInterfaceDetailData,
+ predictedLength,
+ &requiredLength,
+ NULL)) {
+ goto Error;
+ }
+
+ deviceInfo = CreateDeviceInfo(deviceInterfaceDetailData->DevicePath);
+
+ if(!deviceInfo)
+ goto Error;
+
+
+ }
+
+ if(deviceInterfaceDetailData) {
+ HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData);
+ }
+
+ SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
+ return 0;
+
+Error:
+
+ error = GetLastError();
+ MessageBox(hWnd, TEXT("EnumExisting Devices failed"), TEXT("Error!"), MB_OK);
+ if(deviceInterfaceDetailData)
+ HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData);
+
+ SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
+ Cleanup(hWnd);
+ return 0;
+}
+
+PDEVICE_INFO
+FindDeviceInfo(
+ PDIALOG_RESULT InputInfo
+ )
+{
+ PLIST_ENTRY thisEntry, listHead;
+ PDEVICE_INFO deviceInfo = NULL, result = NULL;
+
+ listHead = &ListHead;
+
+ for(thisEntry = listHead->Flink;
+ thisEntry != listHead;
+ thisEntry = thisEntry->Flink){
+
+ deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry);
+
+ if(deviceInfo->DeviceIndex == InputInfo->DeviceIndex){
+
+ if(deviceInfo->IsANetworkMiniport){
+ Display(TEXT("You can't use this app on a device installed as a network device"));
+ break;
+ }
+
+ if(deviceInfo->hDevice &&
+ deviceInfo->hDevice != INVALID_HANDLE_VALUE){
+ Display(TEXT("%ws device is already in use"),
+ deviceInfo->DeviceName);
+ break;
+ }
+
+
+ deviceInfo->DeviceIndex = InputInfo->DeviceIndex;
+ deviceInfo->PacketSize = InputInfo->PacketSize;
+ memcpy(deviceInfo->UnicodeSourceIp, InputInfo->SourceIp, MAX_LEN);
+ memcpy(deviceInfo->UnicodeDestIp, InputInfo->DestIp, MAX_LEN);
+ //
+ // Convert the unicode source and destination IP string
+ // to ANSI and store it.
+ //
+ WideCharToMultiByte(CP_ACP, //ANSI code page
+ 0, deviceInfo->UnicodeSourceIp, -1,
+ deviceInfo->SourceIp, MAX_LEN, NULL, NULL);
+
+ //
+ // Convert Unicode string to ANSI.
+ //
+ WideCharToMultiByte(CP_ACP, 0, deviceInfo->UnicodeDestIp, -1,
+ deviceInfo->DestIp, MAX_LEN, NULL, NULL);
+
+
+ result = deviceInfo;
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+PDEVICE_INFO
+CreateDeviceInfo(
+ _In_ LPWSTR DevicePath
+ )
+{
+ PDEVICE_INFO deviceInfo = NULL;
+ HRESULT hr;
+
+ DisplayV(TEXT("Entered CreateDeviceInfo"));
+
+ deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO));
+ if(!deviceInfo) {
+ goto Error;
+ }
+
+
+ if(!GetDeviceDescription(DevicePath,
+ deviceInfo->DeviceName,
+ sizeof(deviceInfo->DeviceName),
+ &deviceInfo->IsANetworkMiniport
+ )) {
+ Display(TEXT("GetDeviceDescription failed %x"), GetLastError());
+ goto Error;
+ }
+
+
+ //
+ // Copy the device path so that we can open the device using CreateFile.
+ //
+ hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, DevicePath);
+ if(FAILED(hr)){
+ goto Error;
+ }
+
+ DeviceIndex++;
+ deviceInfo->DeviceIndex = DeviceIndex;
+
+ //
+ // Link this to the global list of devices.
+ //
+ InitializeListHead(&deviceInfo->ListEntry);
+ InsertTailList(&ListHead, &deviceInfo->ListEntry);
+
+ Display(TEXT("Device %d is %ws"), DeviceIndex, deviceInfo->DeviceName);
+
+ return deviceInfo;
+
+Error:
+
+ if(deviceInfo) {
+ HeapFree (GetProcessHeap(), 0, deviceInfo);
+ }
+ return NULL;
+
+}
+
+VOID
+FreeDeviceInfo(
+ _In_ PDEVICE_INFO DeviceInfo
+ )
+{
+ DisplayV(TEXT("Entered FreeDeviceInfo"));
+
+ if (DeviceInfo->hHandleNotification) {
+ UnregisterDeviceNotification(DeviceInfo->hHandleNotification);
+ DeviceInfo->hHandleNotification = NULL;
+ }
+ if (DeviceInfo->hDevice != INVALID_HANDLE_VALUE &&
+ DeviceInfo->hDevice != NULL) {
+ CloseHandle(DeviceInfo->hDevice);
+ DeviceInfo->hDevice = INVALID_HANDLE_VALUE;
+ Display(TEXT("Closed handle to device %ws"), DeviceInfo->DeviceName );
+ }
+
+ RemoveEntryList(&DeviceInfo->ListEntry);
+
+ HeapFree (GetProcessHeap(), 0, DeviceInfo);
+
+ return;
+}
+
+BOOL
+SetRegistryInfo(
+ _In_reads_bytes_(SourceIPLen) LPWSTR SourceIP,
+ _In_ DWORD SourceIPLen,
+ _In_reads_bytes_(DestinationIPLen) LPWSTR DestinationIP,
+ _In_ DWORD DestinationIPLen
+ )
+{
+ HKEY hKey;
+ BOOL ret = FALSE;
+ size_t srcStrLen, destStrLen;
+
+ if (FAILED(StringCbLengthW(SourceIP, SourceIPLen, &srcStrLen))) {
+ return ret;
+ }
+
+ if (FAILED(StringCbLengthW(DestinationIP, DestinationIPLen, &destStrLen))) {
+ return ret;
+ }
+
+ //
+ // RegSetValueEx takes a DWORD, in the rare case that size_t is larger than
+ // a DWORD return an error.
+ //
+ if (srcStrLen > (DWORD_MAX - sizeof(WCHAR))||
+ destStrLen > (DWORD_MAX - sizeof(WCHAR))) {
+ return ret;
+ }
+
+ if (RegOpenKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) {
+
+ if (ERROR_SUCCESS != RegCreateKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) {
+ Display(TEXT("RegCreateKey failed: %x"), GetLastError());
+ return ret;
+ }
+ }
+
+ if (ERROR_SUCCESS == RegSetValueEx(hKey, L"SourceIP", 0, REG_SZ,
+ (LPBYTE)SourceIP, (DWORD) srcStrLen+sizeof(WCHAR))) {
+
+ if (ERROR_SUCCESS == RegSetValueEx(hKey, L"DestinationIP", 0, REG_SZ,
+ (LPBYTE)DestinationIP, (DWORD) destStrLen+sizeof(WCHAR))) {
+ ret = TRUE;
+ }
+ }
+
+ RegCloseKey(hKey);
+ return ret;
+}
+
+_Success_(return)
+BOOL
+GetRegistryInfo(
+ _Out_writes_bytes_(* SourceIPLen) PWSTR SourceIP,
+ _Inout_ LPDWORD SourceIPLen,
+ _Out_writes_bytes_(* DestinationIPLen) PWSTR DestinationIP,
+ _Inout_ LPDWORD DestinationIPLen
+ )
+{
+ HKEY hKey;
+ DWORD dwType = REG_SZ;
+ BOOL ret = FALSE;
+
+ if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) {
+
+ if(ERROR_SUCCESS == RegQueryValueEx(hKey, L"SourceIP", NULL, &dwType,
+ (LPBYTE)SourceIP, SourceIPLen)){
+
+ if(ERROR_SUCCESS == RegQueryValueEx(hKey, L"DestinationIP", NULL, &dwType,
+ (LPBYTE)DestinationIP, DestinationIPLen)){
+
+ ret = TRUE;
+ }
+
+ }
+ RegCloseKey(hKey);
+ }
+
+ return ret;
+}
+
+
+
+BOOLEAN
+OpenDevice(
+ _In_ HWND HWnd,
+ _In_ PDEVICE_INFO DeviceInfo
+ )
+{
+ DEV_BROADCAST_HANDLE filter;
+ HANDLE hDevice;
+
+ DisplayV(TEXT("Entered OpenDevice"));
+
+ //
+ // Open an handle to the device.
+ //
+ hDevice = CreateFile (
+ DeviceInfo->DevicePath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL, // no SECURITY_ATTRIBUTES structure
+ OPEN_EXISTING, // No special create flags
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (INVALID_HANDLE_VALUE == hDevice) {
+ Display(TEXT("Failed to open the device: %ws"),
+ DeviceInfo->DeviceName);
+ return FALSE;
+ }
+
+ Display(TEXT("Opened handled to the device: %ws"),
+ DeviceInfo->DeviceName);
+ //
+ // Register handle based notification to receive pnp
+ // device change notification on the handle.
+ //
+
+ memset (&filter, 0, sizeof(filter)); //zero the structure
+ filter.dbch_size = sizeof(filter);
+ filter.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ filter.dbch_handle = hDevice;
+
+ DeviceInfo->hHandleNotification = RegisterDeviceNotification(HWnd, &filter, 0);
+ if(!DeviceInfo->hHandleNotification){
+ Display(TEXT("Failed to register notification: %ws"),
+ DeviceInfo->DeviceName);
+ CloseHandle(hDevice);
+ return FALSE;
+ }
+
+ DeviceInfo->hDevice = hDevice;
+
+ return TRUE;
+
+}
+
+
+BOOL
+CreatePingThread(
+ PDEVICE_INFO DeviceInfo
+ )
+{
+ ULONG id;
+
+ DisplayV(TEXT("CreatePingThread"));
+
+ DeviceInfo->ExitThread = FALSE;
+
+ //
+ // Start the ping operation in a separate thread.
+ //
+ DeviceInfo->ThreadHandle = CreateThread( NULL, // security attributes
+ 0, // initial stack size
+ (LPTHREAD_START_ROUTINE) PingThread, // Main() function
+ DeviceInfo, // arg to Reader thread
+ 0, // creation flags
+ (LPDWORD)&id); // returned thread id
+
+ if ( NULL == DeviceInfo->ThreadHandle) {
+ Display(TEXT("CreateThread failed %x"), GetLastError());
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+VOID
+TerminatePingThread(
+ PDEVICE_INFO DeviceInfo
+ )
+{
+ DWORD status;
+
+ DisplayV(TEXT("TerminatePingThread"));
+
+ if(DeviceInfo->ThreadHandle){
+
+ DeviceInfo->ExitThread = TRUE;
+ //
+ // Wait for the thread to exit
+ //
+ status = WaitForSingleObjectEx(DeviceInfo->ThreadHandle, 1000, TRUE );
+ if(status == WAIT_FAILED){
+ Display(TEXT("Wait failed %x"), GetLastError());
+ }
+ CloseHandle(DeviceInfo->ThreadHandle);
+ DeviceInfo->ThreadHandle = NULL;
+ }
+
+}
+
+BOOLEAN
+Cleanup(
+ HWND hWnd
+ )
+/*++
+
+ This routine walks the global list of currently enumerated devices
+ and close all handles and frees the memory.
+ --*/
+{
+ PDEVICE_INFO deviceInfo =NULL;
+ PLIST_ENTRY thisEntry;
+
+ DisplayV(TEXT("Entered Cleanup"));
+
+ while (!IsListEmpty(&ListHead)) {
+ thisEntry = ListHead.Flink;
+ deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry);
+ //
+ // First let us make sure the PingThread is not running.
+ //
+ TerminatePingThread(deviceInfo);
+ FreeDeviceInfo(deviceInfo);
+ }
+ return TRUE;
+}
+
+
+_Success_(return != FALSE)
+BOOL
+GetDeviceDescription(
+ _In_ LPTSTR DevPath,
+ _Out_writes_bytes_all_(OutBufferLen) LPTSTR OutBuffer,
+ _In_ ULONG OutBufferLen,
+ BOOL *NetClassDevice
+)
+{
+ HDEVINFO hardwareDeviceInfo = NULL;
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
+ SP_DEVINFO_DATA deviceInfoData;
+ DWORD dwRegType, error;
+ TCHAR classGuidString[MAX_GUID_STRING_LEN];
+ HRESULT hr;
+ GUID classGuid;
+ BOOL ret = FALSE;
+
+ DisplayV(TEXT("GetDeviceDescription"));
+
+ hardwareDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL);
+ if(INVALID_HANDLE_VALUE == hardwareDeviceInfo)
+ {
+ Display(TEXT("Couldn't create DeviceInfoList: %x"), GetLastError());
+ goto Error;
+ }
+
+ //
+ // Enumerate devices of toaster class
+ //
+ deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
+
+ SetupDiOpenDeviceInterface (hardwareDeviceInfo, DevPath,
+ 0, //
+ &deviceInterfaceData);
+
+ deviceInfoData.cbSize = sizeof(deviceInfoData);
+ if(!SetupDiGetDeviceInterfaceDetail (
+ hardwareDeviceInfo,
+ &deviceInterfaceData,
+ NULL, // probing so no output buffer yet
+ 0, // probing so output buffer length of zero
+ NULL,
+ &deviceInfoData) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
+ {
+ Display(TEXT("Couldn't get interface detail: %x"), GetLastError());
+ goto Error;
+ }
+ //
+ // Get the friendly name for this instance, if that fails
+ // try to get the device description.
+ //
+
+ if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData,
+ SPDRP_FRIENDLYNAME,
+ &dwRegType,
+ (BYTE*) OutBuffer,
+ OutBufferLen,
+ NULL))
+ {
+ if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData,
+ SPDRP_DEVICEDESC,
+ &dwRegType,
+ (BYTE*) OutBuffer,
+ OutBufferLen,
+ NULL)){
+ Display(TEXT("Couldn't get friendlyname: %x"), GetLastError());
+ goto Error;
+
+ }
+
+
+ }
+
+ //
+ // Get the class guid of the device and find out whether this is a
+ // network miniport.
+ //
+ if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo,
+ &deviceInfoData,
+ SPDRP_CLASSGUID,
+ &dwRegType,
+ (BYTE*) classGuidString,
+ sizeof(classGuidString),
+ NULL)) {
+ Display(TEXT("Class guid is not available for device: %ws"), OutBuffer );
+ }
+
+ hr = CLSIDFromString(classGuidString, &classGuid);
+ if(FAILED(hr)) {
+ goto Error;
+ }
+
+ if(IsEqualGUID(&classGuid, &GUID_DEVCLASS_NET)){
+ *NetClassDevice = TRUE;
+ } else {
+ *NetClassDevice = FALSE;
+ }
+
+ ret = TRUE;
+
+Error:
+
+ if(hardwareDeviceInfo) {
+ SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
+ }
+ return ret;
+}
+
+
+BOOL
+HandlePowerBroadcast(
+ HWND hWnd,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ BOOL fRet = TRUE;
+
+ switch (wParam)
+ {
+ case PBT_APMQUERYSTANDBY:
+ DisplayV(TEXT("PBT_APMQUERYSTANDBY"));
+ break;
+ case PBT_APMQUERYSUSPEND:
+ DisplayV(TEXT("PBT_APMQUERYSUSPEND"));
+ break;
+ case PBT_APMSTANDBY :
+ DisplayV(TEXT("PBT_APMSTANDBY"));
+ break;
+ case PBT_APMSUSPEND :
+ DisplayV(TEXT("PBT_APMSUSPEND"));
+ break;
+ case PBT_APMQUERYSTANDBYFAILED:
+ DisplayV(TEXT("PBT_APMQUERYSTANDBYFAILED"));
+ break;
+ case PBT_APMRESUMESTANDBY:
+ DisplayV(TEXT("PBT_APMRESUMESTANDBY"));
+ break;
+ case PBT_APMQUERYSUSPENDFAILED:
+ DisplayV(TEXT("PBT_APMQUERYSUSPENDFAILED"));
+ break;
+ case PBT_APMRESUMESUSPEND:
+ DisplayV(TEXT("PBT_APMRESUMESUSPEND"));
+ break;
+ case PBT_APMBATTERYLOW:
+ DisplayV(TEXT("PBT_APMBATTERYLOW"));
+ break;
+ case PBT_APMOEMEVENT:
+ DisplayV(TEXT("PBT_APMOEMEVENT"));
+ break;
+ case PBT_APMRESUMEAUTOMATIC:
+ DisplayV(TEXT("PBT_APMRESUMEAUTOMATIC"));
+ break;
+ case PBT_APMRESUMECRITICAL:
+ DisplayV(TEXT("PBT_APMRESUMECRITICAL"));
+ break;
+ case PBT_APMPOWERSTATUSCHANGE:
+ DisplayV(TEXT("PBT_APMPOWERSTATUSCHANGE"));
+ break;
+ default:
+ DisplayV(TEXT("Default"));
+ break;
+ }
+ return fRet;
+}
+
+
diff --git a/general/pcidrv/test/testapp.h b/general/pcidrv/test/testapp.h
new file mode 100644
index 00000000..3a75e4f5
--- /dev/null
+++ b/general/pcidrv/test/testapp.h
@@ -0,0 +1,260 @@
+/*++
+Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ notify.h
+
+Abstract:
+
+--*/
+
+#ifndef __TESTAPP_H
+#define __TESTAPP_H
+
+#pragma warning(disable:4214 4201 4115 4100)
+
+#define UNICODE 1
+#define INITGUID
+
+#include <windows.h> // for using Windows data types and functions
+#include <winsock2.h> // for using winsock utility inet_addr/ntohs functions.
+#include <setupapi.h> // for using SetupDi functions
+#include <dbt.h> // for PNP device notification interfaces
+#include <winioctl.h> // for defining ioctls
+#include <ntddndis.h> // for NDIS OIDs
+#include <strsafe.h> // for safe string functions
+#include <devguid.h> // for GUID_DEVCLASS_NET
+#include <cfgmgr32.h> // for MAX_GUID_STRING_LEN
+#include <OBJBASE.H> // for CLSIDFromString. Link to ole32.lib
+
+#include "public.h"
+#include "resource.h"
+#include <dontuse.h>
+
+//
+// Registry path where the IP addresses are saved
+//
+#define REG_PATH L"Software\\Microsoft\\PCIDRV\\MyPing"
+#define DEF_SOURCE_IP L"192.168.0.2"
+#define DEF_DEST_IP L"192.168.0.1"
+
+#define PING_SLEEP_TIME 100
+#define MAC_ADDR_LEN 6
+
+#define MAX_LEN 64
+#define MAX_PAYLOAD_SIZE 1428
+#define MIN_PAYLOAD_SIZE 32
+#define MAX_PING_RETRY 10
+
+extern BOOLEAN Verbose;
+
+typedef struct _DEVICE_INFO
+{
+ LIST_ENTRY ListEntry;
+ HANDLE hDevice; // file handle
+ HDEVNOTIFY hHandleNotification; // notification handle
+ TCHAR DeviceName[MAX_PATH];// friendly name of device description
+ TCHAR DevicePath[MAX_PATH];//
+ ULONG DeviceIndex; // Serial number of the device.
+ CHAR SourceIp[MAX_LEN];
+ CHAR DestIp[MAX_LEN];
+ WCHAR UnicodeSourceIp[MAX_LEN];
+ WCHAR UnicodeDestIp[MAX_LEN];
+ ULONG PacketSize;
+ UCHAR SrcMacAddr[MAC_ADDR_LEN];
+ UCHAR TargetMacAddr[MAC_ADDR_LEN];
+ HANDLE PingEvent;
+ ULONG NumberOfRequestSent;
+ BOOL Sleep;
+ ULONG TimeOut;
+ BOOL IsANetworkMiniport;
+ BOOLEAN ExitThread;
+ HANDLE ThreadHandle;
+
+} DEVICE_INFO, *PDEVICE_INFO;
+
+
+typedef struct _DIALOG_RESULT
+{
+ ULONG DeviceIndex;
+ WCHAR SourceIp[MAX_LEN];
+ WCHAR DestIp[MAX_LEN];
+ ULONG PacketSize;
+} DIALOG_RESULT, *PDIALOG_RESULT;
+
+
+//
+// Copied Macros from ntddk.h. Used to using the kernel-mode
+// style of linked list.
+//
+
+#define CONTAINING_RECORD(address, type, field) ((type *)( \
+ (PCHAR)(address) - \
+ (ULONG_PTR)(&((type *)0)->field)))
+
+
+#define InitializeListHead(ListHead) (\
+ (ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+#define RemoveHeadList(ListHead) \
+ (ListHead)->Flink;\
+ {RemoveEntryList((ListHead)->Flink)}
+
+#define IsListEmpty(ListHead) \
+ ((ListHead)->Flink == (ListHead))
+
+
+#define RemoveEntryList(Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_Flink;\
+ _EX_Flink = (Entry)->Flink;\
+ _EX_Blink = (Entry)->Blink;\
+ _EX_Blink->Flink = _EX_Flink;\
+ _EX_Flink->Blink = _EX_Blink;\
+ }
+
+#define InsertTailList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Blink = _EX_ListHead->Blink;\
+ (Entry)->Flink = _EX_ListHead;\
+ (Entry)->Blink = _EX_Blink;\
+ _EX_Blink->Flink = (Entry);\
+ _EX_ListHead->Blink = (Entry);\
+ }
+
+
+#ifndef min
+#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b))
+#endif
+
+#ifndef max
+#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b))
+#endif
+
+#define DisplayV(pstrFormat, ...) if (Verbose) {Display(pstrFormat, __VA_ARGS__);}
+
+LRESULT FAR PASCAL
+WndProc (
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOLEAN EnumExistingDevices(
+ HWND hWnd
+ );
+
+BOOL HandleDeviceInterfaceChange(
+ HWND hwnd,
+ DWORD evtype,
+ PDEV_BROADCAST_DEVICEINTERFACE dip
+ );
+
+BOOL HandleDeviceChange(
+ HWND hwnd,
+ DWORD evtype,
+ PDEV_BROADCAST_HANDLE dhp
+ );
+
+LRESULT
+HandleCommands(
+ HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+HandlePowerBroadcast(
+ HWND hWnd,
+ WPARAM wParam,
+ LPARAM lParam);
+
+BOOLEAN Cleanup(
+ HWND hWnd
+ );
+
+_Success_(return != FALSE)
+BOOL
+GetDeviceDescription(
+ _In_ LPTSTR DevPath,
+ _Out_writes_bytes_all_(OutBufferLen) LPTSTR OutBuffer,
+ _In_ ULONG OutBufferLen,
+ BOOL *NetClassDevice
+);
+
+BOOLEAN
+OpenDevice(
+ _In_ HWND HWnd,
+ _In_ PDEVICE_INFO DeviceInfo
+ );
+
+
+INT_PTR CALLBACK
+DlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+DWORD
+PingThread (
+ PDEVICE_INFO DeviceInfo
+ );
+
+VOID Display(
+ _In_ LPWSTR pstrFormat,
+ ...
+ ) ;
+
+
+BOOL
+CreatePingThread(
+ PDEVICE_INFO DeviceInfo
+ );
+
+PDEVICE_INFO
+FindDeviceInfo(
+ PDIALOG_RESULT InputInfo
+ );
+
+VOID
+FreeDeviceInfo(
+ _In_ PDEVICE_INFO DeviceInfo
+ );
+
+PDEVICE_INFO
+CreateDeviceInfo(
+ _In_ LPWSTR DevicePath
+ );
+
+VOID
+TerminatePingThread(
+ PDEVICE_INFO DeviceInfo
+ );
+
+_Success_(return)
+BOOL
+GetRegistryInfo(
+ _Out_writes_bytes_(* SourceIPLen) PWSTR SourceIP,
+ _Inout_ LPDWORD SourceIPLen,
+ _Out_writes_bytes_(* DestinationIPLen) PWSTR DestinationIP,
+ _Inout_ LPDWORD DestinationIPLen
+ );
+
+BOOL
+SetRegistryInfo(
+ _In_reads_bytes_(SourceIPLen) LPWSTR SourceIP,
+ _In_ DWORD SourceIPLen,
+ _In_reads_bytes_(DestinationIPLen) LPWSTR DestinationIP,
+ _In_ DWORD DestinationIPLen
+ );
+
+
+#endif
+
+
diff --git a/general/pcidrv/test/testapp.rc b/general/pcidrv/test/testapp.rc
new file mode 100644
index 00000000..dcef4be0
--- /dev/null
+++ b/general/pcidrv/test/testapp.rc
@@ -0,0 +1,37 @@
+#include <windows.h>
+#include "resource.h"
+
+GenericMenu MENU
+ {
+ POPUP "&Menu"
+ {
+ MENUITEM "&Start Ping", IDM_PING
+ MENUITEM "&Stop", IDM_CLOSE
+ MENUITEM "&Re-enumerate All Devices" IDM_ENUMERATE
+ MENUITEM "Clear &Display", IDM_CLEAR
+ MENUITEM "Verbose", IDM_VERBOSE
+ MENUITEM "E&xit", IDM_EXIT
+ }
+ }
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DIALOG DIALOG DISCARDABLE 0, 0, 291, 118
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Ping"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK",ID_OK,71,96,50,14,BS_NOTIFY
+ PUSHBUTTON "CANCEL",ID_CANCEL,167,96,50,14,BS_NOTIFY
+ LTEXT "Device Index :",IDC_STATIC,19,13,55,8
+ LTEXT "Source IP :",IDC_STATIC,19,35,55,8
+ EDITTEXT IDC_DEVICE_INDEX,75,11,24,14,ES_NUMBER
+ EDITTEXT IDC_SOURCE_IP,76,32,103,14,ES_AUTOHSCROLL
+ LTEXT "Destination IP :",IDC_STATIC,18,55,55,8
+ EDITTEXT IDC_DESTINATION_IP,75,53,101,14,ES_AUTOHSCROLL
+ LTEXT "Packet Size",IDC_STATIC,18,77,55,8
+ EDITTEXT IDC_PACKET_SIZE,75,75,24,14,ES_NUMBER
+END