diff options
| author | J M Rossy <[email protected]> | 2015-07-29 15:40:09 -0700 |
|---|---|---|
| committer | J M Rossy <[email protected]> | 2015-07-29 16:34:40 -0700 |
| commit | 5d61a4a79a1e96dc5d9af1e5e712c84507307544 (patch) | |
| tree | 49ed270893578cd18758b74ffcca16dc7ab948d6 /usb | |
| parent | 5d41613e26e147d2300c786bb2b34cb4b4067a25 (diff) | |
Samples update for public Windows 10 release
Fix #2 Enabling WPP Recorder in Sensors Samples causes errors
Fix #4 Add back fixed KMDOD sample
Add new BarcodeScanner sample in pos folder
Add new MagneticStripeReader sample in pos folder
Add new SynpaticsTouch sample in input folder
Add new Power Engine Plugin sample in pofx folder
Add new DeviceMft sample in avstream folder
Add new AvsCamera sample in root
Add new SimBatt sample in root
Add other pre-existing samples not yet released for Win10
Diffstat (limited to 'usb')
135 files changed, 28796 insertions, 510 deletions
diff --git a/usb/kmdf_enumswitches/kmdf_enumswitches.sln b/usb/kmdf_enumswitches/kmdf_enumswitches.sln index 241354f4..32b903cb 100644 --- a/usb/kmdf_enumswitches/kmdf_enumswitches.sln +++ b/usb/kmdf_enumswitches/kmdf_enumswitches.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmdf_enumswitches", "sys\kmdf_enumswitches.vcxproj", "{2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kmdf_enumswitches", "sys\kmdf_enumswitches.vcxproj", "{CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|Win32.ActiveCfg = Debug|Win32 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|Win32.Build.0 = Debug|Win32 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|Win32.ActiveCfg = Release|Win32 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|Win32.Build.0 = Release|Win32 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|x64.ActiveCfg = Debug|x64 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Debug|x64.Build.0 = Debug|x64 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|x64.ActiveCfg = Release|x64 - {2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}.Release|x64.Build.0 = Release|x64 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Debug|Win32.ActiveCfg = Debug|Win32 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Debug|Win32.Build.0 = Debug|Win32 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Release|Win32.ActiveCfg = Release|Win32 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Release|Win32.Build.0 = Release|Win32 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Debug|x64.ActiveCfg = Debug|x64 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Debug|x64.Build.0 = Debug|x64 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Release|x64.ActiveCfg = Release|x64 + {CE94DCE1-20AE-4D06-BFA9-13E9D92D339A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.inx b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.inx index adab710e..6ecf53ba 100644 --- a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.inx +++ b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.inx @@ -20,7 +20,7 @@ Signature="$WINDOWS NT$" Class=Sample ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} -Provider=%MSFT% +Provider=%ProviderName% DriverVer=03/20/2003,5.00.3788 CatalogFile=KmdfSamples.cat @@ -38,9 +38,9 @@ HKR,,Icon,,-5 ; ================= Device section ===================== [Manufacturer] -%MfgName%=Microsoft,NT$ARCH$ +%MfgName%=OSR,NT$ARCH$ -[Microsoft.NT$ARCH$] +[OSR.NT$ARCH$] %USB\VID_045E&PID_930A.DeviceDesc%=kmdf_enumswitches.Dev, USB\VID_0547&PID_1002 %Switch.DeviceDesc%=Switch.Dev, {6FDE7521-1B65-48ae-B628-80BE62016026}\OsrUsbFxRawPdo @@ -102,7 +102,7 @@ KmdfLibraryVersion = $KMDFVERSION$ ;---------------------------------------------------------------; [Strings] -MSFT="Microsoft" +ProviderName="TODO-Set-Provider" MfgName="OSR" Disk_Description="OSRUSBFX2 Installation Disk" USB\VID_045E&PID_930A.DeviceDesc="WDF Sample Bus Driver for OSR USB-FX2 Learning Kit" diff --git a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj index 6b2eac58..46f1b42e 100644 --- a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj +++ b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj @@ -19,18 +19,18 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{2EE39DF5-47CC-427F-8C78-B7C1D9C3EF45}</ProjectGuid> + <ProjectGuid>{96607BB4-3861-408E-B117-CAA8D0B6D372}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{629058BB-4E85-43D3-B519-FCEA0871305D}</SampleGuid> + <SampleGuid>{3017F5B6-A432-4BC6-982C-92EDBF88C56D}</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> + <DriverTargetPlatform>Universal</DriverTargetPlatform> <DriverType>KMDF</DriverType> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <ConfigurationType>Driver</ConfigurationType> @@ -38,7 +38,7 @@ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <TargetVersion>Windows10</TargetVersion> <UseDebugLibraries>True</UseDebugLibraries> - <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverTargetPlatform>Universal</DriverTargetPlatform> <DriverType>KMDF</DriverType> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <ConfigurationType>Driver</ConfigurationType> @@ -46,7 +46,7 @@ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <TargetVersion>Windows10</TargetVersion> <UseDebugLibraries>False</UseDebugLibraries> - <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverTargetPlatform>Universal</DriverTargetPlatform> <DriverType>KMDF</DriverType> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <ConfigurationType>Driver</ConfigurationType> @@ -54,7 +54,7 @@ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <TargetVersion>Windows10</TargetVersion> <UseDebugLibraries>True</UseDebugLibraries> - <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverTargetPlatform>Universal</DriverTargetPlatform> <DriverType>KMDF</DriverType> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <ConfigurationType>Driver</ConfigurationType> @@ -215,7 +215,6 @@ <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" /> diff --git a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters index afc896f0..6d286cd3 100644 --- a/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters +++ b/usb/kmdf_enumswitches/sys/kmdf_enumswitches.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{D1F8A3E1-FDAA-4BB1-9ED5-5C2237B070A1}</UniqueIdentifier> + <UniqueIdentifier>{51861499-AB32-435D-A5D8-467D00D1A71D}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{63723244-91AD-468B-B2D5-C9720A362381}</UniqueIdentifier> + <UniqueIdentifier>{407A2F5C-65A7-44BA-AF3B-6543832CDE3F}</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>{F64A4E05-C5D3-41CE-9B8E-4B303D852777}</UniqueIdentifier> + <UniqueIdentifier>{CDF3E397-8551-4B6E-BD1F-6E63053324D5}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{ACD4D5C7-344D-4734-BF67-DF249474349A}</UniqueIdentifier> + <UniqueIdentifier>{59DF9552-63A9-4ABC-8DAF-9E8811DE79AE}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> @@ -33,9 +33,6 @@ </ClCompile> </ItemGroup> <ItemGroup> - <FilesToPackage Include=".\Debug\\kmdf_enumswitches.inf"> - <Filter>Driver Files</Filter> - </FilesToPackage> <Inf Include="kmdf_enumswitches.inx"> <Filter>Driver Files</Filter> </Inf> diff --git a/usb/kmdf_fx2/ReadMe.md b/usb/kmdf_fx2/ReadMe.md new file mode 100644 index 00000000..2e276ff0 --- /dev/null +++ b/usb/kmdf_fx2/ReadMe.md @@ -0,0 +1,393 @@ +Sample KMDF Function Driver for OSR USB-FX2 +=========================================== + +The kmdf\_fx2 sample is a Kernel-Mode Driver Framework (KMDF) driver for the OSR USB-FX2 device. It includes a test app and sample device metadata. + +In the Windows Driver Kit (WDK), the osrusbfx2 sample demonstrated how to perform bulk and interrupt data transfers to an USB device. The sample was written for the OSR USB-FX2 Learning Kit. + +The specification for the device is at <http://www.osronline.com/hardware/OSRFX2_32.pdf>. The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. + +## Universal Windows Driver Compliant +This sample builds a Universal Windows Driver. It uses only APIs and DDIs that are included in OneCoreUAP. + + +Related topics +-------------- + +**** + +[umdf\_fx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) + +[wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) + + + +Build the sample +---------------- + +The default Solution build configuration is Windows 8.1 Debug and Win32. You can change the default configuration to build for Windows 7 or Windows Vista version of the operating system. + +**To select a configuration and build a driver** + +1. Open the driver project or solution in Visual Studio 2013 (find *filtername*.sln or *filtername*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the **Build** menu, click **Build Solution** (Ctrl+Shift+B). + +Overview +-------- + +Here is the overview of the device: + +- The device is based on the development board supplied with the Cypress EZ-USB FX2 Development Kit (CY3681). +- It contains 1 interface and 3 endpoints (Interrupt IN, Bulk Out, Bulk IN). +- Firmware supports vendor commands to query or set LED Bar graph display and 7-segment LED display, and to query toggle switch states. +- Interrupt endpoint: + - Sends an 8-bit value that represents the state of the switches. + - Sent on startup, resume from suspend, and whenever the switch pack setting changes. + - Firmware does not de-bounce the switch pack. + - One switch change can result in multiple bytes being sent. + - Bits are in the reverse order of the labels on the pack (for example, bit 0x80 is labeled 1 on the pack). +- Bulk endpoints are configured for loopback: + - The device moves data from IN endpoint to OUT endpoint. + - The device does not change the values of the data it receives nor does it internally create any data. + - Endpoints are always double buffered. + - Maximum packet size depends on speed (64 full speed, 512 high speed). +- Event Tracing for Windows (ETW) events: + - Included osrusbfx2.man, which describes events added. + - Three events are targeted to the event log: + - Failure during the add device routine. + - Failure to start the OSR device on a USB 1.1 controller. + - Invocation of the “re-enumerate device” IOCTL. + - Read/write start/stop events can be used to measure the time taken. + - For more information, see Unified Tracing later in this document. + +Sample Contents +--------------- + +Folder + +Description + +usb\\kmdf\_fx2\\driver + +This directory contains driver code that demonstrates the following functionality: + +- Loads the driver and responds to PnP and Power events. You can install, uninstall, disable, enable, suspend, and resume the system. +- Creates a context with the WDFDEVICE object. +- Initializes the USB device by registering a *EvtPrepareHardware* callback. +- Marks the interface restricted so that it can be accessed by a privileged Windows Store device app. +- Creates a default parallel queue to receive an IOCTL request to set bar graph display. +- Retrieves memory handle from the requests and uses it to send a vendor command to the USB device. +- Registers read and write events on the default queue. +- Retrieves memory from read and write requests, formats the requests, and sends it to a USB target. +- Creates two separate sequential queues and configures them to dispatch read and write requests directly. (*\*kmdf\_fx2 only*) +- Enables wait-wake and selective suspend support. (*\*kmdf\_fx2 only*) +- Configures a USB target continuous reader to read toggle switch states asynchronously from the interrupt endpoint. (*\*kmdf\_fx2 only*) +- Supports additional IOCTLs to get and set the 7-segment display and toggle switches, and to reset and re-enumerate the device. (*\*kmdf\_fx2 only*) +- Creates ETW provider to log two events to the event log, and read/write start stop events. (*\*kmdf\_fx2 only*) +- WPP tracing. + +usb\\kmdf\_fx2\\exe + +This directory contains a test application that can be used to drive the KMDF driver and FX2 device. + +usb\\kmdf\_fx2\\deviceMetadata + +This directory contains the device metadata package for the sample. You must copy the device metadata to the system before installing the device. For information on how to update and deploy device metadata, see the [Custom driver access sample](http://go.microsoft.com/fwlink/p/?LinkID=248288). + +Testing the driver +------------------ + +You can use the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample as a testing method. + +The sample also includes a test application, osrusbfx2.exe, that you can use to test the device. This console application enumerates the interface registered by the driver and opens the device to send read, write, or IOCTL requests based on the command line options. + +Usage for Read/Write test: + +- -r [*n*], where *n* is number of bytes to read. +- -w [*n*], where *n* is number of bytes to write. +- -c [*n*], where *n* is number of iterations (default = 1). +- -v, shows verbose read data. +- -p, plays with Bar Display, Dip Switch, 7-Segment Display. +- -a, performs asynchronous I/O operation. +- -u, dumps USB configuration and pipe information. + +**Playing with the 7 segment display, toggle switches, and bar graph display** + +Use the command, **osrusbfx2.exe -p** options 1-9, to set and clear bar graph display, set and get 7 segment state, and read the toggle switch states. The following shows the function options: + +1. Light bar +2. Clear bar +3. Light entire bar graph +4. Clear entire bar graph +5. Get bar graph state +6. Get switch state +7. Get switch interrupt message +8. Get 7 segment state +9. Set 7 segment state +10. Reset the device +11. Re-enumerate the device + +0. Exit + +Selection: + +**Reset and re-enumerate the device** + +Use the command, osrusbfx2.exe -p with option 10 and 11, to either reset the device or re-enumerate the device. + +**Read and write to bulk endpoints** + +The following commands send read and write requests to the device's bulk endpoint. + +- `osrusbfx2.exe -r 64` + + The preceding command reads 64 bytes to the bulk IN endpoint. + +- `osrusbfx2.exe -w 64 ` + + The preceding command writes 64 bytes to the bulk OUT endpoint. + +- `osrusbfx2.exe -r 64 -w 64 -c 100 -v` + + The preceding command first writes 64 bytes of data to bulk OUT endpoint (Pipe 1), then reads 64 bytes from bulk IN endpoint (Pipe 2), and then compares the read buffer with write buffer to see if they match. If the buffer contents match, it repeats this operation 100 times. + +- `osrusbfx2.exe -a` + + The preceding command reads and writes to the device asynchronously in an infinite loop. + +The bulk endpoints are double buffered. Depending on the operational speed (full or high), the buffer size is either 64 bytes or 512 bytes, respectively. A request to read data does not complete if the buffers are empty. If the buffers are full, a request to write data does not complete until the buffers are emptied. When you are doing a synchronous read, make sure the endpoint buffer has data (for example, when you send a 512 bytes write request to the device operating in full speed mode). Because the endpoints are double buffered, the total buffer capacity is 256 bytes. The first 256 bytes fills the buffer, and the write request waits in the USB stack until the buffers are emptied. If you run another instance of the application to read 512 bytes of data, both write and read requests complete successfully. + +**Displaying descriptors** + +The following command displays all the descriptors and endpoint information. + +**osrusbfx2.exe -u** + +If the device is operating in high speed mode, you will get the following information: + +`===================` + +`USB_CONFIGURATION_DESCRIPTOR` + +`bLength = 0x9, decimal 9` + +`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` + +`wTotalLength = 0x27, decimal 39` + +`bNumInterfaces = 0x1, decimal 1` + +`bConfigurationValue = 0x1, decimal 1` + +`iConfiguration = 0x4, decimal 4` + +`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` + +`MaxPower = 0x32, decimal 50` + +`-----------------------------` + +`USB_INTERFACE_DESCRIPTOR #0` + +`bLength = 0x9` + +`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` + +`bInterfaceNumber = 0x0` + +`bAlternateSetting = 0x0` + +`bNumEndpoints = 0x3` + +`bInterfaceClass = 0xff` + +`bInterfaceSubClass = 0x0` + +`bInterfaceProtocol = 0x0` + +`bInterface = 0x0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe00` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x81 ( INPUT )` + +`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` + +`wMaxPacketSize= 0x49, decimal 73` + +`bInterval = 0x1, decimal 1` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe01` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x6 ( OUTPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x200, ` + +`decimal 512 bInterval = 0x0, ` + +`decimal 0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe02` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x88 ( INPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x200, decimal 512` + +`bInterval = 0x0, decimal 0` + +If the device is operating in low speed mode, you will get the following information: + +`===================` + +`USB_CONFIGURATION_DESCRIPTOR` + +`bLength = 0x9, decimal 9` + +`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` + +`wTotalLength = 0x27, decimal 39` + +`bNumInterfaces = 0x1, decimal 1` + +`bConfigurationValue = 0x1, decimal 1` + +`iConfiguration = 0x3, decimal 3` + +`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` + +`MaxPower = 0x32, decimal 50 ` + +`-----------------------------` + +`USB_INTERFACE_DESCRIPTOR #0` + +`bLength = 0x9` + +`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` + +`bInterfaceNumber = 0x0 bAlternateSetting = 0x0` + +`bNumEndpoints = 0x3` + +`bInterfaceClass = 0xff` + +`bInterfaceSubClass = 0x0` + +`bInterfaceProtocol = 0x0` + +`bInterface = 0x0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe00` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x81 ( INPUT )` + +`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` + +`wMaxPacketSize= 0x49, decimal 73` + +`bInterval = 0x1, decimal 1` + +`------- -----------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe01` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x6 ( OUTPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x40, decimal 64` + +`bInterval = 0x0, decimal 0` + +`------------------------------` + +`USB_ENDPOINT_DESCRIPTOR for Pipe02` + +`bLength = 0x7` + +`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` + +`bEndpointAddress= 0x88 ( INPUT )` + +`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` + +`wMaxPacketSize= 0x40, decimal 64` + +`bInterval = 0x0, decimal 0 ` + +Unified tracing +--------------- + +To view events the provider manifest must be installed. As part of the installation, from an elevated prompt run the following: `wevtutil im osrusbfx2.man` + +Registering the manifest sets up the appropriate paths where the system can find information for decoding the events. The OSR event log can be found in the system event viewer under Event Viewer\\Applications and Services Logs\\OSRUSBFx2\\Operational channel eventlog. Triggering a device re-enumeration through osrusbfx2.exe sends an event to this log. + +To trace, you can use the in-box tools, logman and tracerpt, or download XPerf (Windows Performance Toolkit) from Microsoft. + +**Using in-box tools** + +**To start/stop the trace by using logman:** + +1. Start tracing by using the following command: + + `logman start sample -o osrusbfx2.etl -ets -p OSRUSBFX2` + +2. Generate activity through the osrusbfx2 test application, such as `osrusbfx2.exe –a`. +3. Stop tracing by using the following command: + + `Logman stop sample` + +4. View the trace file using tracerpt: + + `tracerpt -of csv OSRUSBFX2.etl ` + +**To start/stop the trace by using Xperf (Windows Performance Toolkit):** + +1. Start tracing by using the following command: + + `xperf -start sample -f osrusbfx2.etl -on OSRUSBFX2` + +2. Generate activity through the osrusbfx2 test application, such as `osrusbfx2.exe –a`. +3. Stop tracing by using the following command: + + `xperf -stop sample` + +4. View the trace file using Xperf: + + `xperfview OSRUSBFX2.etl` + + diff --git a/usb/kmdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms b/usb/kmdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms Binary files differnew file mode 100644 index 00000000..5f8e82ee --- /dev/null +++ b/usb/kmdf_fx2/deviceMetadata/B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms diff --git a/usb/kmdf_fx2/driver/Device.c b/usb/kmdf_fx2/driver/Device.c new file mode 100644 index 00000000..87ead857 --- /dev/null +++ b/usb/kmdf_fx2/driver/Device.c @@ -0,0 +1,1051 @@ +/*++ + +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: + + Device.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + + +--*/ + +#include <osrusbfx2.h> +#include <devpkey.h> + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, OsrFxEvtDeviceAdd) +#pragma alloc_text(PAGE, OsrFxEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, OsrFxEvtDeviceD0Exit) +#pragma alloc_text(PAGE, SelectInterfaces) +#pragma alloc_text(PAGE, OsrFxSetPowerPolicy) +#pragma alloc_text(PAGE, OsrFxReadFdoRegistryKeyValue) +#pragma alloc_text(PAGE, GetDeviceEventLoggingNames) +#pragma alloc_text(PAGE, OsrFxValidateConfigurationDescriptor) +#endif + + +NTSTATUS +OsrFxEvtDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + PDEVICE_CONTEXT pDevContext; + WDFQUEUE queue; + GUID activity; + UNICODE_STRING symbolicLinkName; + WDFSTRING symbolicLinkString; + DEVPROP_BOOLEAN isRestricted; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + // + // For usb devices, PrepareHardware callback is the to place select the + // interface and configure the device. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; + + // + // These two callbacks start and stop the wdfusb pipe continuous reader + // as we go in and out of the D0-working state. + // + + pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + // + // Now specify the size of device extension where we track per device + // context.DeviceInit is completely initialized. So call the framework + // to create the device and attach it to the lower stack. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + return status; + } + + // + // Setup the activity ID so that we can log events using it. + // + + activity = DeviceToActivityId(device); + + // + // Get the DeviceObject context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. + // + pDevContext = GetDeviceContext(device); + + // + // Get the device's friendly name and location so that we can use it in + // error logging. If this fails then it will setup dummy strings. + // + + GetDeviceEventLoggingNames(device); + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode when you surprise remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // Create a parallel default queue and register an event callback to + // receive ioctl requests. We will create separate queues for + // handling read and write requests. All other requests will be + // completed with error status automatically by the framework. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests for + // long time or forward them to other drivers. + // If the EvtIoStop callback is not implemented, the framework waits for + // all driver-owned requests to be done before moving in the Dx/sleep + // states or before removing the device, which is the correct behavior + // for this type of driver. If the requests were taking an indeterminate + // amount of time to complete, or if the driver forwarded the requests + // to a lower driver/another stack, the queue should have an + // EvtIoStop/EvtIoResume. + // + __analysis_assume(ioQueueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue);// pointer to default queue + __analysis_assume(ioQueueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // We will create a separate sequential queue and configure it + // to receive read requests. We also need to register a EvtIoStop + // handler so that we can acknowledge requests that are pending + // at the target driver. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeRead); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + + // + // We will create another sequential queue and configure it + // to receive write requests. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + // + // Register a manual I/O queue for handling Interrupt Message Read Requests. + // This queue will be used for storing Requests that need to wait for an + // interrupt to occur before they can be completed. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); + + // + // This queue is used for requests that dont directly access the device. The + // requests in this queue are serviced only when the device is in a fully + // powered state and sends an interrupt. So we can use a non-power managed + // queue to park the requests since we dont care whether the device is idle + // or fully powered up. + // + ioQueueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->InterruptMsgQueue + ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + // + // Register a device interface so that app can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL); // Reference String + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); + goto Error; + } + + // + // Create the lock that we use to serialize calls to ResetDevice(). As an + // alternative to using a WDFWAITLOCK to serialize the calls, a sequential + // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + + status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfWaitLockCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // Get the string for the device interface and set the restricted + // property on it to allow applications bound with device metadata + // to access the interface. + // + if (g_pIoSetDeviceInterfacePropertyData != NULL) { + + status = WdfStringCreate(NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfStringCreate failed %!STATUS!\n", status); + goto Error; + } + + status = WdfDeviceRetrieveDeviceInterfaceString(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL, + symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceRetrieveDeviceInterfaceString failed %!STATUS!\n", status); + goto Error; + } + + WdfStringGetUnicodeString(symbolicLinkString, &symbolicLinkName); + + isRestricted = DEVPROP_TRUE; + + status = g_pIoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_Restricted, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(isRestricted), + &isRestricted ); + + WdfObjectDelete(symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IoSetDeviceInterfacePropertyData failed %!STATUS!\n", status); + goto Error; + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); + + return status; + +Error: + + // + // Log fail to add device to the event log + // + EventWriteFailAddDevice(&activity, + pDevContext->DeviceName, + pDevContext->Location, + status); + + return status; +} + +NTSTATUS +OsrFxEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourceList, + WDFCMRESLIST ResourceListTranslated + ) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. In the case of a USB device, this involves + reading and selecting descriptors. + +Arguments: + + Device - handle to a device + + ResourceList - handle to a resource-list object that identifies the + raw hardware resources that the PnP manager assigned + to the device + + ResourceListTranslated - handle to a resource-list object that + identifies the translated hardware resources + that the PnP manager assigned to the device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + WDF_USB_DEVICE_INFORMATION deviceInfo; + ULONG waitWakeEnable; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + waitWakeEnable = FALSE; + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // Create a USB device handle so that we can communicate with the + // underlying USB stack. The WDFUSBDEVICE handle is used to query, + // configure, and manage all aspects of the USB device. + // These aspects include device properties, bus properties, + // and I/O creation and synchronization. We only create device the first + // the PrepareHardware is called. If the device is restarted by pnp manager + // for resource rebalance, we will use the same device handle but then select + // the interfaces again because the USB stack could reconfigure the device on + // restart. + // + if (pDeviceContext->UsbDevice == NULL) { + WDF_USB_DEVICE_CREATE_CONFIG config; + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, + USBD_CLIENT_CONTRACT_VERSION_602); + + status = WdfUsbTargetDeviceCreateWithParameters(Device, + &config, + WDF_NO_OBJECT_ATTRIBUTES, + &pDeviceContext->UsbDevice); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceCreateWithParameters failed with Status code %!STATUS!\n", status); + return status; + } + + // + // TODO: If you are fetching configuration descriptor from device for + // selecting a configuration or to parse other descriptors, call OsrFxValidateConfigurationDescriptor + // to do basic validation on the descriptors before you access them . + // + } + + // + // Retrieve USBD version information, port driver capabilites and device + // capabilites such as speed, power, etc. + // + WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); + + status = WdfUsbTargetDeviceRetrieveInformation( + pDeviceContext->UsbDevice, + &deviceInfo); + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceSelfPowered: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); + + waitWakeEnable = deviceInfo.Traits & + WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceRemoteWakeable: %s\n", + waitWakeEnable ? "TRUE" : "FALSE"); + // + // Save these for use later. + // + pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; + } + else { + pDeviceContext->UsbDeviceTraits = 0; + } + + status = SelectInterfaces(Device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "SelectInterfaces failed 0x%x\n", status); + return status; + } + + // + // Enable wait-wake and idle timeout if the device supports it + // + if (waitWakeEnable) { + status = OsrFxSetPowerPolicy(Device); + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxSetPowerPolicy failed %!STATUS!\n", status); + return status; + } + } + + status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Entry( + WDFDEVICE Device, + 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 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 + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + BOOLEAN isTargetStarted; + + pDeviceContext = GetDeviceContext(Device); + isTargetStarted = FALSE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(PreviousState)); + + // + // Since continuous reader is configured for this interrupt-pipe, we must explicitly start + // the I/O target to get the framework to post read requests. + // + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "Failed to start interrupt pipe %!STATUS!\n", status); + goto End; + } + + isTargetStarted = TRUE; + +End: + + if (!NT_SUCCESS(status)) { + // + // Failure in D0Entry will lead to device being removed. So let us stop the continuous + // reader in preparation for the ensuing remove. + // + if (isTargetStarted) { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Exit( + WDFDEVICE Device, + 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. + + + 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. + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtDeviceD0Exit - moving to %s\n", + DbgDevicePowerString(TargetState)); + + pDeviceContext = GetDeviceContext(Device); + + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); + + return STATUS_SUCCESS; +} + +VOID +OsrFxEvtDeviceSelfManagedIoFlush( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine handles flush activity for the device's + self-managed I/O operations. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + // Service the interrupt message queue to drain any outstanding + // requests + OsrUsbIoctlGetInterruptMessage(Device, STATUS_DEVICE_REMOVED); +} + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ) +/*++ + +Routine Description: + + Validates a USB Configuration Descriptor + +Parameters: + + ConfigDesc: Pointer to the entire USB Configuration descriptor returned by the device + + BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) + + Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will + be set to the address within the ConfigDesc buffer where the failure occured. + +Return Value: + + USBD_STATUS + Success implies the configuration descriptor is valid. + +--*/ +{ + + + USBD_STATUS status = USBD_STATUS_SUCCESS; + USHORT ValidationLevel = 3; + + PAGED_CODE(); + + // + // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. + // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. + // It also checks for interface numbers, number of endpoints in an interface etc. + // Please refer to msdn documentation for this function for more information. + // + + status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); + if (!(NT_SUCCESS (status)) ){ + return status; + } + + // + // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor + // Check that all such descriptors have size >= sizeof(the descriptor they point to) + // Check for any association between them if required + // + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(Device, &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(Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignSxWakeSettings failed %x\n", status); + return status; + } + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine selects the configuration, interface and + creates a context for every pipe (end point) in that interface. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_CONTEXT pDeviceContext; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + UCHAR index; + UCHAR numberConfiguredPipes; + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); + + status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, + WDF_NO_OBJECT_ATTRIBUTES, + &configParams); + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", + status); + + // + // Since the Osr USB fx2 device is capable of working at high speed, the only reason + // the device would not be working at high speed is if the port doesn't + // support it. If the port doesn't support high speed it is a 1.1 port + // + if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { + GUID activity = DeviceToActivityId(Device); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " On a 1.1 USB port on Windows Vista" + " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" + " doesn't conform to the USB specification. Windows Vista detects this and" + " returns an error. \n" + ); + EventWriteSelectConfigFailure( + &activity, + pDeviceContext->DeviceName, + pDeviceContext->Location, + status + ); + } + + return status; + } + + pDeviceContext->UsbInterface = + configParams.Types.SingleInterface.ConfiguredUsbInterface; + + numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; + + // + // Get pipe handles + // + for(index=0; index < numberConfiguredPipes; index++) { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + pDeviceContext->UsbInterface, + index, //PipeIndex, + &pipeInfo + ); + // + // Tell the framework that it's okay to read less than + // MaximumPacketSize + // + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); + + if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "Interrupt Pipe is 0x%p\n", pipe); + pDeviceContext->InterruptPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsInEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkInput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkReadPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsOutEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkOutput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkWritePipe = pipe; + } + + } + + // + // If we didn't find all the 3 pipes, fail the start. + // + if(!(pDeviceContext->BulkWritePipe + && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { + status = STATUS_INVALID_DEVICE_STATE; + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Device is not configured properly %!STATUS!\n", + status); + + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Retrieve the friendly name and the location string into WDFMEMORY objects + and store them in the device context. + +Arguments: + +Return Value: + + None + +--*/ +{ + PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device); + + WDF_OBJECT_ATTRIBUTES objectAttributes; + + WDFMEMORY deviceNameMemory = NULL; + WDFMEMORY locationMemory = NULL; + + NTSTATUS status; + + PAGED_CODE(); + + // + // We want both memory objects to be children of the device so they will + // be deleted automatically when the device is removed. + // + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = Device; + + // + // First get the length of the string. If the FriendlyName + // is not there then get the lenght of device description. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyFriendlyName, + NonPagedPool, + &objectAttributes, + &deviceNameMemory); + + if (!NT_SUCCESS(status)) + { + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyDeviceDescription, + NonPagedPool, + &objectAttributes, + &deviceNameMemory); + } + + if (NT_SUCCESS(status)) + { + pDevContext->DeviceNameMemory = deviceNameMemory; + pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL); + } + else + { + pDevContext->DeviceNameMemory = NULL; + pDevContext->DeviceName = L"(error retrieving name)"; + } + + // + // Retrieve the device location string. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyLocationInformation, + NonPagedPool, + WDF_NO_OBJECT_ATTRIBUTES, + &locationMemory); + + if (NT_SUCCESS(status)) + { + pDevContext->LocationMemory = locationMemory; + pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL); + } + else + { + pDevContext->LocationMemory = NULL; + pDevContext->Location = L"(error retrieving location)"; + } + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ) +{ + 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"; + } +} + + + diff --git a/usb/kmdf_fx2/driver/bulkrwr.c b/usb/kmdf_fx2/driver/bulkrwr.c new file mode 100644 index 00000000..eabda192 --- /dev/null +++ b/usb/kmdf_fx2/driver/bulkrwr.c @@ -0,0 +1,436 @@ +/*++ + +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: + + bulkrwr.c + +Abstract: + + This file has routines to perform reads and writes. + The read and writes are targeted bulk to endpoints. + +Environment: + + Kernel mode + +--*/ + +#include <osrusbfx2.h> + + +#if defined(EVENT_TRACING) +#include "bulkrwr.tmh" +#endif + +#pragma warning(disable:4267) + +VOID +OsrFxEvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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: + + +--*/ +{ + WDFUSBPIPE pipe; + NTSTATUS status; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + // + // Log read start event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkReadPipe; + + status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + goto Exit; + } + + // + // The format call validates to make sure that you are reading or + // writing to the right pipe type, sets the appropriate transfer flags, + // creates an URB and initializes the request. + // + status = WdfUsbTargetPipeFormatRequestForRead(pipe, + Request, + reqMemory, + NULL // Offsets + ); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestReadCompletionRoutine, + pipe); + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + + +Exit: + if (!NT_SUCCESS(status)) { + // + // log event read failed + // + EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); + + return; +} + +VOID +EvtRequestReadCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesRead = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesRead = usbCompletionParams->Parameters.PipeRead.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "Number of bytes read: %I64d\n", (INT64)bytesRead); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "Read failed - request status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + + } + + // + // Log read stop event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesRead, + status, + usbCompletionParams->UsbdStatus); + + WdfRequestCompleteWithInformation(Request, status, bytesRead); + + return; +} + +VOID +OsrFxEvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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; + WDFUSBPIPE pipe; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + + // + // Log write start event, using IRP activity ID if available or request + // handle otherwise. + // + EventWriteWriteStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkWritePipe; + + status = WdfRequestRetrieveInputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); + goto Exit; + } + + status = WdfUsbTargetPipeFormatRequestForWrite(pipe, + Request, + reqMemory, + NULL); // Offset + + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfUsbTargetPipeFormatRequestForWrite failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestWriteCompletionRoutine, + pipe); + + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) { + // + // log event write failed + // + EventWriteWriteFail(&activity, WdfIoQueueGetDevice(Queue), status); + + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); + + return; +} + +VOID +EvtRequestWriteCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesWritten = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "Number of bytes written: %I64d\n", (INT64)bytesWritten); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Write failed: request Status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + } + + // + // Log write stop event, using IRP activtiy ID if available or request + // handle otherwise + // + EventWriteWriteStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesWritten, + status, + usbCompletionParams->UsbdStatus); + + + WdfRequestCompleteWithInformation(Request, status, bytesWritten); + + return; +} + + +VOID +OsrFxEvtIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ + +Routine Description: + + This callback is invoked on every inflight request when the device + is suspended or removed. Since our inflight read and write requests + are actually pending in the target device, we will just acknowledge + its presence. Until we acknowledge, complete, or requeue the requests + framework will wait before allowing the device suspend or remove to + proceeed. When the underlying USB stack gets the request to suspend or + remove, it will fail all the pending requests. + +Arguments: + + Queue - handle to queue object that is associated with the I/O request + + Request - handle to a request object + + ActionFlags - bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS flags + +Return Value: + None + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + if (ActionFlags & WdfRequestStopActionSuspend ) { + WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue + } else if(ActionFlags & WdfRequestStopActionPurge) { + WdfRequestCancelSentRequest(Request); + } + return; +} + + diff --git a/usb/kmdf_fx2/driver/driver.c b/usb/kmdf_fx2/driver/driver.c new file mode 100644 index 00000000..d3b44573 --- /dev/null +++ b/usb/kmdf_fx2/driver/driver.c @@ -0,0 +1,299 @@ +/*++ + +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: + + Driver.c + +Abstract: + + Main module. + + This driver is for Open System Resources USB-FX2 Learning Kit designed + and built by OSR specifically for use in teaching software developers how to write + drivers for USB devices. + + The board supports a single configuration. The board automatically + detects the speed of the host controller, and supplies either the + high or full speed configuration based on the host controller's speed. + + The firmware supports 3 endpoints: + + Endpoint number 1 is used to indicate the state of the 8-switch + switch-pack on the OSR USB-FX2 board. A single byte representing + the switch state is sent (a) when the board is first started, + (b) when the board resumes after selective-suspend, + (c) whenever the state of the switches is changed. + + Endpoints 6 and 8 perform an internal loop-back function. + Data that is sent to the board at EP6 is returned to the host on EP8. + + For further information on the endpoints, please refer to the spec + http://www.osronline.com/hardware/OSRFX2_32.pdf. + + Vendor ID of the device is 0x4705 and Product ID is 0x210. + +Environment: + + Kernel mode only + +--*/ + +#include <osrusbfx2.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 trace.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 "driver.tmh" +#else +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; +PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, OsrFxEvtDriverContextCleanup) +#endif + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL or another NTSTATUS error code otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + UNICODE_STRING funcName; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n"); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Built %s %s\n", __DATE__, __TIME__); + + // + // IRP activity ID functions are available on some versions, save them into + // globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoGetActivityIdIrp"); + g_pIoGetActivityIdIrp = (PFN_IO_GET_ACTIVITY_ID_IRP) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // The Device interface property set is available on some version, save it + // into globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoSetDeviceInterfacePropertyData"); + g_pIoSetDeviceInterfacePropertyData = (PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // Register with ETW (unified tracing) + // + EventRegisterOSRUSBFX2(); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + OsrFxEvtDeviceAdd + ); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, // Driver Object Attributes + &config, // Driver Config Info + WDF_NO_HANDLE // hDriver + ); + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status 0x%x\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); + EventUnregisterOSRUSBFX2(); + } + + return status; +} + +VOID +OsrFxEvtDriverContextCleanup( + WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are not automatically + cleaned up by the framework. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PAGED_CODE (); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "--> OsrFxEvtDriverContextCleanup\n"); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver )); + + UNREFERENCED_PARAMETER(Driver); // For the case when WPP is not being used. + + EventUnregisterOSRUSBFX2(); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + DebugPrintLevel - print level between 0 and 3, with 3 the most verbose + DebugPrintFlag - message mask + DebugMessage - format string of the message to print + ... - values used by the format string + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + 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 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + + + + diff --git a/usb/kmdf_fx2/driver/interrupt.c b/usb/kmdf_fx2/driver/interrupt.c new file mode 100644 index 00000000..00ea3550 --- /dev/null +++ b/usb/kmdf_fx2/driver/interrupt.c @@ -0,0 +1,184 @@ +/*++ + +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: + + Interrupt.c + +Abstract: + + This modules has routines configure a continuous reader on an + interrupt pipe to asynchronously read toggle switch states. + +Environment: + + Kernel mode + +--*/ + +#include <osrusbfx2.h> + +#if defined(EVENT_TRACING) +#include "interrupt.tmh" +#endif + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ) +/*++ + +Routine Description: + + This routine configures a continuous reader on the + interrupt endpoint. It's called from the PrepareHarware event. + +Arguments: + + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; + NTSTATUS status; + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, + OsrFxEvtUsbInterruptPipeReadComplete, + DeviceContext, // Context + sizeof(UCHAR)); // TransferLength + + contReaderConfig.EvtUsbTargetPipeReadersFailed = OsrFxEvtUsbInterruptReadersFailed; + + // + // Reader requests are not posted to the target automatically. + // Driver must explictly call WdfIoTargetStart to kick start the + // reader. In this sample, it's done in D0Entry. + // By defaut, framework queues two requests to the target + // endpoint. Driver can configure up to 10 requests with CONFIG macro. + // + status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, + &contReaderConfig); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxConfigContReaderForInterruptEndPoint failed %x\n", + status); + return status; + } + + return status; +} + +VOID +OsrFxEvtUsbInterruptPipeReadComplete( + WDFUSBPIPE Pipe, + WDFMEMORY Buffer, + size_t NumBytesTransferred, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This the completion routine of the continour reader. This can + called concurrently on multiprocessor system if there are + more than one readers configured. So make sure to protect + access to global resources. + +Arguments: + + Buffer - This buffer is freed when this call returns. + If the driver wants to delay processing of the buffer, it + can take an additional referrence. + + Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro + +Return Value: + + NT status value + +--*/ +{ + PUCHAR switchState = NULL; + WDFDEVICE device; + PDEVICE_CONTEXT pDeviceContext = Context; + + UNREFERENCED_PARAMETER(Pipe); + + device = WdfObjectContextGetObject(pDeviceContext); + + // + // Make sure that there is data in the read packet. Depending on the device + // specification, it is possible for it to return a 0 length read in + // certain conditions. + // + + if (NumBytesTransferred == 0) { + TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete Zero length read " + "occured on the Interrupt Pipe's Continuous Reader\n" + ); + return; + } + + + NT_ASSERT(NumBytesTransferred == sizeof(UCHAR)); + + switchState = WdfMemoryGetBuffer(Buffer, NULL); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n", + *switchState); + + pDeviceContext->CurrentSwitchState = *switchState; + + // + // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device + // will generate an interrupt message when the the device resumes from a low + // power state. So if the Interrupt Message IOCTL was sent after the device + // has gone to a low power state, the pending Interrupt Message IOCTL will + // get completed in the function call below, before the user twiddles the + // dip switches on the OSR USB device. If this is not the desired behavior + // for your driver, then you could handle this condition by maintaining a + // state variable on D0Entry to track interrupt messages caused by power up. + // + OsrUsbIoctlGetInterruptMessage(device, STATUS_SUCCESS); + +} + +BOOLEAN +OsrFxEvtUsbInterruptReadersFailed( + _In_ WDFUSBPIPE Pipe, + _In_ NTSTATUS Status, + _In_ USBD_STATUS UsbdStatus + ) +{ + WDFDEVICE device = WdfIoTargetGetDevice(WdfUsbTargetPipeGetIoTarget(Pipe)); + PDEVICE_CONTEXT pDeviceContext = GetDeviceContext(device); + + UNREFERENCED_PARAMETER(UsbdStatus); + + // + // Clear the current switch state. + // + pDeviceContext->CurrentSwitchState = 0; + + // + // Service the pending interrupt switch change request + // + OsrUsbIoctlGetInterruptMessage(device, Status); + + return TRUE; +} + diff --git a/usb/kmdf_fx2/driver/ioctl.c b/usb/kmdf_fx2/driver/ioctl.c new file mode 100644 index 00000000..0f29dc8c --- /dev/null +++ b/usb/kmdf_fx2/driver/ioctl.c @@ -0,0 +1,1057 @@ +/*++ + +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: + + Ioctl.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + +--*/ + +#include <osrusbfx2.h> + +#if defined(EVENT_TRACING) +#include "ioctl.tmh" +#endif + +#pragma alloc_text(PAGE, OsrFxEvtIoDeviceControl) +#pragma alloc_text(PAGE, ResetPipe) +#pragma alloc_text(PAGE, ResetDevice) +#pragma alloc_text(PAGE, ReenumerateDevice) +#pragma alloc_text(PAGE, GetBarGraphState) +#pragma alloc_text(PAGE, SetBarGraphState) +#pragma alloc_text(PAGE, GetSevenSegmentState) +#pragma alloc_text(PAGE, SetSevenSegmentState) +#pragma alloc_text(PAGE, GetSwitchState) + +VOID +OsrFxEvtIoDeviceControl( + _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 + +--*/ +{ + WDFDEVICE device; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PBAR_GRAPH_STATE barGraphState = NULL; + PSWITCH_STATE switchState = NULL; + PUCHAR sevenSegment = NULL; + BOOLEAN requestPending = FALSE; + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(OutputBufferLength); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); + // + // initialize variables + // + device = WdfIoQueueGetDevice(Queue); + pDevContext = GetDeviceContext(device); + + switch(IoControlCode) { + + case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { + + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; + USHORT requiredSize = 0; + + // + // First get the size of the config descriptor + // + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + NULL, + &requiredSize); + + if (status != STATUS_BUFFER_TOO_SMALL) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + // + // Get the buffer - make sure the buffer is big enough + // + status = WdfRequestRetrieveOutputBuffer(Request, + (size_t)requiredSize, // MinimumRequired + &configurationDescriptor, + NULL); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); + break; + } + + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + configurationDescriptor, + &requiredSize); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + bytesReturned = requiredSize; + + } + break; + + case IOCTL_OSRUSBFX2_RESET_DEVICE: + + status = ResetDevice(device); + break; + + case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: + + // + // Otherwise, call our function to reenumerate the + // device + // + status = ReenumerateDevice(pDevContext); + + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: + + // + // Make sure the caller's output buffer is large enough + // to hold the state of the bar graph + // + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + // + // Call our function to get the bar graph state + // + status = GetBarGraphState(pDevContext, barGraphState); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(BAR_GRAPH_STATE); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + + // + // Call our routine to set the bar graph state + // + status = SetBarGraphState(pDevContext, barGraphState); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an UCHAR\n"); + break; + } + + // + // Call our function to get the 7 segment state + // + status = GetSevenSegmentState(pDevContext, sevenSegment); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(UCHAR); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an UCHAR\n"); + bytesReturned = sizeof(UCHAR); + break; + } + + // + // Call our routine to set the 7 segment state + // + status = SetSevenSegmentState(pDevContext, sevenSegment); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_READ_SWITCHES: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + break; + + } + + // + // Call our routine to get the state of the switches + // + status = GetSwitchState(pDevContext, switchState); + + // + // If successful, return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(SWITCH_STATE); + + } else { + // + // Don't return any data + // + bytesReturned = 0; + } + break; + + case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: + + // + // Forward the request to an interrupt message queue and dont complete + // the request until an interrupt from the USB device occurs. + // + status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); + if (NT_SUCCESS(status)) { + requestPending = TRUE; + } + + break; + + default : + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (requestPending == FALSE) { + WdfRequestCompleteWithInformation(Request, status, bytesReturned); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine resets the pipe. + +Arguments: + + Pipe - framework pipe handle + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + // + status = WdfUsbTargetPipeResetSynchronously(Pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL // PWDF_REQUEST_SEND_OPTIONS + ); + + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "ResetPipe - success\n"); + status = STATUS_SUCCESS; + } + else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetPipe - failed\n"); + } + + return status; +} + +VOID +StopAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe), + WdfIoTargetCancelSentIo); +} + +NTSTATUS +StartAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still + connected. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> ResetDevice\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // A NULL timeout indicates an infinite wake + // + status = WdfWaitLockAcquire(pDeviceContext->ResetDeviceWaitLock, NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice - could not acquire lock\n"); + return status; + } + + StopAllPipes(pDeviceContext); + + status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->UsbDevice); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice failed - 0x%x\n", status); + } + + status = StartAllPipes(pDeviceContext); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Failed to start all pipes - 0x%x\n", status); + } + + WdfWaitLockRelease(pDeviceContext->ResetDeviceWaitLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- ResetDevice\n"); + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ) +/*++ + +Routine Description + + This routine re-enumerates the USB device. + +Arguments: + + pDevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + GUID activity; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_REENUMERATE, // Request + 0, // Value + 0); // Index + + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + NULL, // MemoryDescriptor + NULL); // BytesTransferred + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); + + // + // Send event to eventlog + // + + activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); + EventWriteDeviceReenumerated(&activity, + DevContext->DeviceName, + DevContext->Location, + status); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine gets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that receives the bar graph's state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + BarGraphState->BarsAsUChar = 0; + + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetBarGraphState: Failed to GetBarGraphState - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine sets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that describes the bar graph's desired state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetBarGraphState: Failed - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine gets the state of the 7 segment display on the board + by sending a synchronous control command. + + NOTE: It's not a good practice to send a synchronous request in the + context of the user thread because if the transfer takes long + time to complete, you end up holding the user thread. + + I'm choosing to do synchronous transfer because a) I know this one + completes immediately b) and for demonstration. + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - receives the state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + *SevenSegment = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status); + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine sets the state of the 7 segment display on the board + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - desired state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ) +/*++ + +Routine Description + + This routine gets the state of the switches on the board + +Arguments: + + DevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_SWITCHES, // Request + 0, // Value + 0); // Index + + SwitchState->SwitchesAsUChar = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SwitchState, + sizeof(SWITCH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSwitchState: Failed to Get switches - 0x%x \n", status); + + } else { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n"); + + return status; + +} + + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ) +/*++ + +Routine Description + + This method handles the completion of the pended request for the IOCTL + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE. + +Arguments: + + Device - Handle to a framework device. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + WDFREQUEST request; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PSWITCH_STATE switchState = NULL; + + pDevContext = GetDeviceContext(Device); + + do { + + // + // Check if there are any pending requests in the Interrupt Message Queue. + // If a request is found then complete the pending request. + // + status = WdfIoQueueRetrieveNextRequest(pDevContext->InterruptMsgQueue, &request); + + if (NT_SUCCESS(status)) { + status = WdfRequestRetrieveOutputBuffer(request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + + } else { + + // + // Copy the state information saved by the continuous reader. + // + if (NT_SUCCESS(ReaderStatus)) { + switchState->SwitchesAsUChar = pDevContext->CurrentSwitchState; + bytesReturned = sizeof(SWITCH_STATE); + } else { + bytesReturned = 0; + } + } + + // + // Complete the request. If we failed to get the output buffer then + // complete with that status. Otherwise complete with the status from the reader. + // + WdfRequestCompleteWithInformation(request, + NT_SUCCESS(status) ? ReaderStatus : status, + bytesReturned); + status = STATUS_SUCCESS; + + } else if (status != STATUS_NO_MORE_ENTRIES) { + KdPrint(("WdfIoQueueRetrieveNextRequest status %08x\n", status)); + } + + request = NULL; + + } while (status == STATUS_SUCCESS); + + return; + +} + + diff --git a/usb/kmdf_fx2/driver/osrusbfx2.h b/usb/kmdf_fx2/driver/osrusbfx2.h new file mode 100644 index 00000000..909e347d --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.h @@ -0,0 +1,335 @@ +/*++ + +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: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#include <initguid.h> +#include <ntddk.h> +#include "usbdi.h" +#include "usbdlib.h" +#include "public.h" +#include "driverspecs.h" +#include <wdf.h> +#include <wdfusb.h> +#define NTSTRSAFE_LIB +#include <ntstrsafe.h> + +#include "trace.h" + +// +// Include auto-generated ETW event functions (created by MC.EXE from +// osrusbfx2.man) +// +#include "fx2Events.h" + +#ifndef _PRIVATE_H +#define _PRIVATE_H + +#define POOL_TAG (ULONG) 'FRSO' +#define _DRIVER_NAME_ "OSRUSBFX2" + +#define TEST_BOARD_TRANSFER_BUFFER_SIZE (64*1024) +#define DEVICE_DESC_LENGTH 256 + +extern const __declspec(selectany) LONGLONG DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; + +// +// Define the vendor commands supported by our device +// +#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 +#define USBFX2LK_READ_SWITCHES 0xD6 +#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 +#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 +#define USBFX2LK_IS_HIGH_SPEED 0xD9 +#define USBFX2LK_REENUMERATE 0xDA +#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB + +// +// Define the features that we can clear +// and set on our device +// +#define USBFX2LK_FEATURE_EPSTALL 0x00 +#define USBFX2LK_FEATURE_WAKE 0x01 + +// +// Order of endpoints in the interface descriptor +// +#define INTERRUPT_IN_ENDPOINT_INDEX 0 +#define BULK_OUT_ENDPOINT_INDEX 1 +#define BULK_IN_ENDPOINT_INDEX 2 + +// +// A structure representing the instance information associated with +// this particular device. +// + +typedef struct _DEVICE_CONTEXT { + + WDFUSBDEVICE UsbDevice; + + WDFUSBINTERFACE UsbInterface; + + WDFUSBPIPE BulkReadPipe; + + WDFUSBPIPE BulkWritePipe; + + WDFUSBPIPE InterruptPipe; + + WDFWAITLOCK ResetDeviceWaitLock; + + UCHAR CurrentSwitchState; + + WDFQUEUE InterruptMsgQueue; + + ULONG UsbDeviceTraits; + + // + // The following fields are used during event logging to + // report the events relative to this specific instance + // of the device. + // + + WDFMEMORY DeviceNameMemory; + PCWSTR DeviceName; + + WDFMEMORY LocationMemory; + PCWSTR Location; + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) + +extern ULONG DebugLevel; + +typedef +NTSTATUS +(*PFN_IO_GET_ACTIVITY_ID_IRP) ( + _In_ PIRP Irp, + _Out_ LPGUID Guid + ); + +typedef +NTSTATUS +(*PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) ( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ CONST DEVPROPKEY *PropertyKey, + _In_ LCID Lcid, + _In_ ULONG Flags, + _In_ DEVPROPTYPE Type, + _In_ ULONG Size, + _In_opt_ PVOID Data + ); + +// +// Global function pointer set in DriverEntry +// Check for NULL before using +// +extern PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; + +extern PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP OsrFxEvtDriverContextCleanup; + +EVT_WDF_DRIVER_DEVICE_ADD OsrFxEvtDeviceAdd; + +EVT_WDF_DEVICE_PREPARE_HARDWARE OsrFxEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ OsrFxEvtIoRead; + +EVT_WDF_IO_QUEUE_IO_WRITE OsrFxEvtIoWrite; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OsrFxEvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ); + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +EVT_WDF_USB_READER_COMPLETION_ROUTINE OsrFxEvtUsbInterruptPipeReadComplete; + +EVT_WDF_USB_READERS_FAILED OsrFxEvtUsbInterruptReadersFailed; + +EVT_WDF_IO_QUEUE_IO_STOP OsrFxEvtIoStop; + +EVT_WDF_DEVICE_D0_ENTRY OsrFxEvtDeviceD0Entry; + +EVT_WDF_DEVICE_D0_EXIT OsrFxEvtDeviceD0Exit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH OsrFxEvtDeviceSelfManagedIoFlush; + +_IRQL_requires_(PASSIVE_LEVEL) +BOOLEAN +OsrFxReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWCHAR Name, + _Out_ PULONG Value + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +OsrFxEnumerateChildren( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ); + + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ); + +FORCEINLINE +GUID +RequestToActivityId( + _In_ WDFREQUEST Request + ) +{ + GUID activity = {0}; + NTSTATUS status = STATUS_SUCCESS; + + if (g_pIoGetActivityIdIrp != NULL) { + + // + // Use activity ID generated by application (or IO manager) + // + status = g_pIoGetActivityIdIrp(WdfRequestWdmGetIrp(Request), &activity); + } + + if (g_pIoGetActivityIdIrp == NULL || !NT_SUCCESS(status)) { + + // + // Fall back to using the WDFREQUEST handle as the activity ID + // + RtlCopyMemory(&activity, &Request, sizeof(WDFREQUEST)); + } + + + return activity; +} + +FORCEINLINE +GUID +DeviceToActivityId( + _In_ WDFDEVICE Device + ) +{ + GUID activity = {0}; + RtlCopyMemory(&activity, &Device, sizeof(WDFDEVICE)); + return activity; +} + + +#endif + + diff --git a/usb/kmdf_fx2/driver/osrusbfx2.inx b/usb/kmdf_fx2/driver/osrusbfx2.inx new file mode 100644 index 00000000..6bb5ccc5 --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.inx @@ -0,0 +1,112 @@ +;/*++ +; +;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: +; +; OSRUSBFX2.INF +; +;Abstract: +; Installation inf for OSR USB-FX2 Learning Kit +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%ProviderName% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=KmdfSamples.cat + + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + + +; ================= Device section ===================== + +[Manufacturer] +%MfgName%=OSR,NT$ARCH$ + +[OSR.NT$ARCH$] +%USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2.Dev, USB\VID_0547&PID_1002 +%Switch.DeviceDesc%=Switch.Dev, {6FDE7521-1B65-48ae-B628-80BE62016026}\OsrUsbFxRawPdo + + +[osrusbfx2.Dev.NT] +CopyFiles=osrusbfx2.Files.Ext + +[Switch.Dev.NT] +;dummy section + +[Switch.Dev.NT.Services] +AddService = , %SPSVCINST_ASSOCSERVICE%, + +[osrusbfx2.Dev.NT.Services] +AddService = osrusbfx2, %SPSVCINST_ASSOCSERVICE%, osrusbfx2.AddService + +[osrusbfx2.AddService] +DisplayName = %osrusbfx2.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %10%\System32\Drivers\osrusbfx2.sys + +[osrusbfx2.Files.Ext] +osrusbfx2.sys + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +osrusbfx2.sys = 1 + +[DestinationDirs] +DefaultDestDir = 12 + +;-------------- WDF Coinstaller installation + +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[osrusbfx2.Dev.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" + +[osrusbfx2.Dev.NT.Wdf] +KmdfService = osrusbfx2, osrusbfx2_wdfsect +[osrusbfx2_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +;---------------------------------------------------------------; + +[Strings] +ProviderName="TODO-Set-Provider" +MfgName="OSR" +Disk_Description="OSRUSBFX2 Installation Disk" +USB\VID_045E&PID_930A.DeviceDesc="WDF Sample Driver for OSR USB-FX2 Learning Kit" +osrusbfx2.SvcDesc="WDF Sample Driver for OSR USB-FX2 Learning Kit" +ClassName = "Sample Device" +Switch.DeviceDesc = "OsrUsbFX2 RawPdo For Switch" +SPSVCINST_ASSOCSERVICE= 0x00000002 diff --git a/usb/kmdf_fx2/driver/osrusbfx2.man b/usb/kmdf_fx2/driver/osrusbfx2.man new file mode 100644 index 00000000..176dfc89 --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.man @@ -0,0 +1,309 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes'?> +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" + > + <instrumentation> + <events> + <provider + guid="{69cd60e3-430f-4da4-b1b3-e3bdaf945875}" + messageFileName="%Systemroot%\System32\drivers\osrusbfx2.SYS" + name="OSRUSBFX2" + resourceFileName="%SystemRoot%\System32\drivers\osrusbfx2.SYS" + symbol="OSRUSBFX2_PROVIDER" + > + <channels> + <channel + chid="Analytic" + enabled="false" + name="OsrUsbfx2/Analytic" + symbol="OSRUSBFX2_ANALYTIC" + type="Analytic" + /> + <channel + chid="operational" + enabled="true" + isolation="System" + message="$(string.OSRUSBFX2_OPERATIONAL.Name)" + name="OsrUsbFx2/Operational" + symbol="OSRUSBFX2_OPERATIONAL" + type="Operational" + /> + </channels> + <keywords> + <keyword + mask="0x0000000000000010" + message="$(string.OSRUSBFX2_DEVICE_INFO_KEYWORD.message)" + name="deviceinfo" + symbol="OSRUSBFX2_DEVICE_INFO_KEYWORD" + /> + <keyword + mask="0x0000000000000040" + message="$(string.OSRUSBFX2_READ_WRITE_KEYWORD.message)" + name="readwrite" + symbol="OSRUSBFX2_READ_WRITE_KEYWORD" + /> + </keywords> + <opcodes> + <!-- Defining our own custom opcode instead of using standard opcodes defined by winmeta.xml --> + <opcode + name="add" + symbol="OSRUSBFX2_DEVICE_ADD" + value="10" + /> + <opcode + name="fail" + symbol="OSRUSBFX2_FAIL" + value="11" + /> + </opcodes> + <tasks> + <!-- Support for XP and W2K3 : MC.exe will create a MOF file --> + <!-- Requires an associated eventGUID attribute for each task that is defined --> + <!-- For the MOF file : --> + <!-- Semantically, the event GUID represents a set of logical events that are logged by the provider. --> + <task + eventGUID="{872c3c43-6899-4f1d-89b8-51a82f6db657}" + name="deviceInit" + symbol="OSRUSBFX2_DEVICE_INIT" + value="1" + /> + <task + eventGUID="{872c3c45-6899-4f1d-89b8-51a82f6db657}" + name="read" + symbol="OSRUSBFX2_READ" + value="2" + /> + <task + eventGUID="{872c3c46-6899-4f1d-89b8-51a82f6db657}" + name="write" + symbol="OSRUSBFX2_WRITE" + value="3" + /> + </tasks> + <templates> + <template tid="tid_DeviceStatus"> + <data + inType="win:UnicodeString" + name="FriendlyName" + outType="xs:string" + /> + <data + inType="win:UnicodeString" + name="Location" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + </template> + <template tid="tid_ReadWrite"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="Length" + outType="xs:unsignedInt" + /> + </template> + <template tid="tid_ReadWriteFail"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + </template> + <template tid="tid_ReadWriteCompletion"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="Length" + outType="xs:unsignedInt" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + <data + inType="win:UInt32" + name="UsbdStatus" + outType="xs:unsignedInt" + /> + </template> + </templates> + <events> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadStart.EventMessage)" + level="win:Informational" + opcode="win:Start" + symbol="ReadStart" + task="read" + template="tid_ReadWrite" + value="1" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadStop.EventMessage)" + level="win:Informational" + opcode="win:Stop" + symbol="ReadStop" + task="read" + template="tid_ReadWriteCompletion" + value="2" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadFail.EventMessage)" + level="win:Error" + opcode="fail" + symbol="ReadFail" + task="read" + template="tid_ReadWriteFail" + value="3" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteStart.EventMessage)" + level="win:Informational" + opcode="win:Start" + symbol="WriteStart" + task="write" + template="tid_ReadWrite" + value="4" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteStop.EventMessage)" + level="win:Informational" + opcode="win:Stop" + symbol="WriteStop" + task="write" + template="tid_ReadWriteCompletion" + value="5" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteFail.EventMessage)" + level="win:Error" + opcode="fail" + symbol="WriteFail" + task="write" + template="tid_ReadWriteFail" + value="6" + /> + <event + channel="operational" + keywords="deviceinfo" + level="win:Error" + message="$(string.DeviceFailAdd.EventMessage)" + opcode="add" + symbol="FailAddDevice" + task="deviceInit" + template="tid_DeviceStatus" + value="100" + /> + <event + channel="operational" + keywords="deviceinfo" + message="$(string.DeviceReenumerated.EventMessage)" + opcode="win:Start" + symbol="DeviceReenumerated" + task="deviceInit" + template="tid_DeviceStatus" + value="101" + /> + <event + channel="operational" + keywords="deviceinfo" + level="win:Error" + message="$(string.SelectConfigFailure.Message)" + opcode="fail" + symbol="SelectConfigFailure" + task="deviceInit" + template="tid_DeviceStatus" + value="102" + /> + </events> + </provider> + </events> + </instrumentation> + <localization xmlns="http://schemas.microsoft.com/win/2004/08/events"> + <resources culture="en-US"> + <stringTable> + <string + id="OSRUSBFX2_DEVICE_INFO_KEYWORD.message" + value="Device events: fail to load, reenumerate" + /> + <string + id="OSRUSBFX2_READ_WRITE_KEYWORD.message" + value="Read, Write events" + /> + <string + id="OSRUSBFX2_OPERATIONAL.Name" + value="Operational channel eventlog" + /> + <string + id="ReadStart.EventMessage" + value="Read. Device = %1, Length = %2" + /> + <string + id="ReadStop.EventMessage" + value="Read complete. Device = %1, Length = %2, Status = %3, UsbStatus = %4" + /> + <string + id="ReadFail.EventMessage" + value="Read error. Device = %1, Status = %2" + /> + <string + id="WriteStart.EventMessage" + value="Write. Device = %1, Length = %2" + /> + <string + id="WriteStop.EventMessage" + value="Write complete. Device = %1, Length = %2, Status = %3, UsbStatus = %4" + /> + <string + id="WriteFail.EventMessage" + value="Write error. Device = %1, Status = %2" + /> + <string + id="DeviceReenumerated.EventMessage" + value="Device %1 (location %2) was reenumerated" + /> + <string + id="DeviceFailAdd.EventMessage" + value="Fail to add device %1 (location %2), status %3" + /> + <string + id="SelectConfigFailure.Message" + value="This error occurs when an OSR USB Fx2 board is attached to a USB 1.1 port on a machine running Windows Vista. This error occurs because the OSR USB Fx2 board's Interrupt end-point descriptor does not conform to the USB specification. Windows Vista detects this and returns an error. You should plug the device into a USB 2.0 (or higher) port." + /> + </stringTable> + </resources> + </localization> +</instrumentationManifest> diff --git a/usb/kmdf_fx2/driver/osrusbfx2.rc b/usb/kmdf_fx2/driver/osrusbfx2.rc new file mode 100644 index 00000000..092ec195 --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.rc @@ -0,0 +1,18 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Sample Driver for OSR USB-FX2 Learning Kit" +#define VER_INTERNALNAME_STR "osrusbfx2.sys" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.sys" + +#include "common.ver" + +// +// Include auto-generated string resources (created by MC.EXE from +// osrusbfx2.man) +// + +#include "fx2Events.rc" diff --git a/usb/kmdf_fx2/driver/osrusbfx2.vcxproj b/usb/kmdf_fx2/driver/osrusbfx2.vcxproj new file mode 100644 index 00000000..29fe9c3a --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.vcxproj @@ -0,0 +1,269 @@ +<?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>{E7ECAF21-2522-4E7D-8475-67C4A5E43F70}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{95AAF552-36F7-487B-A556-B969D823DC9F}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</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>Universal</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>Universal</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>Universal</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="driver.c; device.c; ioctl.c; bulkrwr.c; Interrupt.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </ClCompile> + <Inf Include=".\osrusbfx2.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\osrusbfx2.inf</CopyOutput> + </Inf> + <MessageCompile Include="osrusbfx2.man"> + <GenerateKernelModeLoggingMacros>true</GenerateKernelModeLoggingMacros> + <GenerateMofFile>true</GenerateMofFile> + <HeaderFilePath>.\$(IntDir)</HeaderFilePath> + <GeneratedHeaderPath>true</GeneratedHeaderPath> + <RCFilePath>.\$(IntDir)</RCFilePath> + <GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath> + <GeneratedFilesBaseName>fx2Events</GeneratedFilesBaseName> + <UseBaseNameOfInput>true</UseBaseNameOfInput> + </MessageCompile> + <OtherWpp Include="osrusbfx2.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <ItemGroup> + <FilesToPackage Include="..\deviceMetadata\B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms" /> + <None Include="..\deviceMetadata\B4D697F5-1C56-4807-ACCD-B28C09D37FF0.devicemetadata-ms" /> + </ItemGroup> + <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> + <ResourceCompile Include="osrusbfx2.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Include="*.txt" Exclude="@(None)" /> + <None Include="*.htm" Exclude="@(None)" /> + <None Include="*.html" Exclude="@(None)" /> + <None Include="*.ico" Exclude="@(None)" /> + <None Include="*.cur" Exclude="@(None)" /> + <None Include="*.bmp" Exclude="@(None)" /> + <None Include="*.dlg" Exclude="@(None)" /> + <None Include="*.rct" Exclude="@(None)" /> + <None Include="*.gif" Exclude="@(None)" /> + <None Include="*.jpg" Exclude="@(None)" /> + <None Include="*.jpeg" Exclude="@(None)" /> + <None Include="*.wav" Exclude="@(None)" /> + <None Include="*.jpe" Exclude="@(None)" /> + <None Include="*.tiff" Exclude="@(None)" /> + <None Include="*.tif" Exclude="@(None)" /> + <None Include="*.png" Exclude="@(None)" /> + <None Include="*.rc2" Exclude="@(None)" /> + <None Include="*.def" Exclude="@(None)" /> + <None Include="*.bat" Exclude="@(None)" /> + <None Include="*.hpj" Exclude="@(None)" /> + <None Include="*.asmx" Exclude="@(None)" /> + </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/usb/kmdf_fx2/driver/osrusbfx2.vcxproj.Filters b/usb/kmdf_fx2/driver/osrusbfx2.vcxproj.Filters new file mode 100644 index 00000000..296911ee --- /dev/null +++ b/usb/kmdf_fx2/driver/osrusbfx2.vcxproj.Filters @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{50246F0E-8E24-4871-83C5-D835604F0997}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{3A59DDAC-0E70-44F4-BDA7-AF03A36ADAD4}</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>{E82DF9C5-AE82-4CFF-A0C5-AA939075A927}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{57D03874-86BB-4AC8-B719-A39C7A4EF75F}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="bulkrwr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Interrupt.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ioctl.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Include=".\osrusbfx2.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <MessageCompile Include="osrusbfx2.man"> + <Filter>Resource Files</Filter> + </MessageCompile> + <ResourceCompile Include="osrusbfx2.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/kmdf_fx2/driver/trace.h b/usb/kmdf_fx2/driver/trace.h new file mode 100644 index 00000000..518ff5f1 --- /dev/null +++ b/usb/kmdf_fx2/driver/trace.h @@ -0,0 +1,115 @@ +/*++ + +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. + +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_IOCTL 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 + + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ); + +#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. +// +// NOTE: If you are adopting this sample for your driver, please generate +// a new guid, using tools\other\i386\guidgen.exe present in the +// DDK. +// +// Name of the logger is OSRUSBFX2 and the guid is +// {D23A0C5A-D307-4f0e-AE8E-E2A355AD5DAB} +// (0xd23a0c5a, 0xd307, 0x4f0e, 0xae, 0x8e, 0xe2, 0xa3, 0x55, 0xad, 0x5d, 0xab); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ + 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_IOCTL) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + /* 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) + + +#endif + + + diff --git a/usb/kmdf_fx2/exe/dump.c b/usb/kmdf_fx2/exe/dump.c new file mode 100644 index 00000000..69074bf1 --- /dev/null +++ b/usb/kmdf_fx2/exe/dump.c @@ -0,0 +1,444 @@ +/*++ + +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: + + DUMP.C + +Abstract: + + Routines to dump the descriptors information in a human readable form. + +Environment: + + user mode only + +--*/ + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "devioctl.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include <basetyps.h> +#include "usbdi.h" +#include "public.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ); + + +char* +usbDescriptorTypeString(UCHAR bDescriptorType ) +/*++ +Routine Description: + + Called to get ascii string of USB descriptor + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bDescriptorType or + PUSB_DEVICE_DESCRIPTOR->bDescriptorType or + PUSB_INTERFACE_DESCRIPTOR->bDescriptorType or + PUSB_STRING_DESCRIPTOR->bDescriptorType or + PUSB_POWER_DESCRIPTOR->bDescriptorType or + PUSB_CONFIGURATION_DESCRIPTOR->bDescriptorType + +Return Value: + + ptr to string + +--*/ +{ + + switch(bDescriptorType) { + + case USB_DEVICE_DESCRIPTOR_TYPE: + return "USB_DEVICE_DESCRIPTOR_TYPE"; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + return "USB_CONFIGURATION_DESCRIPTOR_TYPE"; + + + case USB_STRING_DESCRIPTOR_TYPE: + return "USB_STRING_DESCRIPTOR_TYPE"; + + + case USB_INTERFACE_DESCRIPTOR_TYPE: + return "USB_INTERFACE_DESCRIPTOR_TYPE"; + + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + return "USB_ENDPOINT_DESCRIPTOR_TYPE"; + + +#ifdef USB_POWER_DESCRIPTOR_TYPE // this is the older definintion which is actually obsolete + // workaround for temporary bug in 98ddk, older USB100.h file + case USB_POWER_DESCRIPTOR_TYPE: + return "USB_POWER_DESCRIPTOR_TYPE"; +#endif + +#ifdef USB_RESERVED_DESCRIPTOR_TYPE // this is the current version of USB100.h as in NT5DDK + + case USB_RESERVED_DESCRIPTOR_TYPE: + return "USB_RESERVED_DESCRIPTOR_TYPE"; + + case USB_CONFIG_POWER_DESCRIPTOR_TYPE: + return "USB_CONFIG_POWER_DESCRIPTOR_TYPE"; + + case USB_INTERFACE_POWER_DESCRIPTOR_TYPE: + return "USB_INTERFACE_POWER_DESCRIPTOR_TYPE"; +#endif // for current nt5ddk version of USB100.h + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbEndPointTypeString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of endpt descriptor type + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_ENDPOINT_TYPE_MASK; + + + switch( typ) { + case USB_ENDPOINT_TYPE_INTERRUPT: + return "USB_ENDPOINT_TYPE_INTERRUPT"; + + case USB_ENDPOINT_TYPE_BULK: + return "USB_ENDPOINT_TYPE_BULK"; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + return "USB_ENDPOINT_TYPE_ISOCHRONOUS"; + + case USB_ENDPOINT_TYPE_CONTROL: + return "USB_ENDPOINT_TYPE_CONTROL"; + + default: + return "??? UNKNOWN!!"; + } +} + + +char * +usbConfigAttributesString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of USB_CONFIGURATION_DESCRIPTOR attributes + +Arguments: + + PUSB_CONFIGURATION_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_CONFIG_POWERED_MASK; + + + switch( typ) { + + case USB_CONFIG_BUS_POWERED: + return "USB_CONFIG_BUS_POWERED"; + + case USB_CONFIG_SELF_POWERED: + return "USB_CONFIG_SELF_POWERED"; + + case USB_CONFIG_REMOTE_WAKEUP: + return "USB_CONFIG_REMOTE_WAKEUP"; + + + default: + return "??? UNKNOWN!!"; + } +} + + +void +print_USB_CONFIGURATION_DESCRIPTOR(PUSB_CONFIGURATION_DESCRIPTOR cd) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB config descriptor + +Arguments: + + ptr to USB configuration descriptor + +Return Value: + + none + +--*/ +{ + printf("\n===================\nUSB_CONFIGURATION_DESCRIPTOR\n"); + + printf( + "bLength = 0x%x, decimal %d\n", cd->bLength, cd->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", cd->bDescriptorType, + usbDescriptorTypeString( cd->bDescriptorType ) + ); + + printf( + "wTotalLength = 0x%x, decimal %d\n", cd->wTotalLength, cd->wTotalLength + ); + + printf( + "bNumInterfaces = 0x%x, decimal %d\n", cd->bNumInterfaces, cd->bNumInterfaces + ); + + printf( + "bConfigurationValue = 0x%x, decimal %d\n", + cd->bConfigurationValue, cd->bConfigurationValue + ); + + printf( + "iConfiguration = 0x%x, decimal %d\n", cd->iConfiguration, cd->iConfiguration + ); + + printf( + "bmAttributes = 0x%x ( %s )\n", cd->bmAttributes, + usbConfigAttributesString( cd->bmAttributes ) + ); + + printf( + "MaxPower = 0x%x, decimal %d\n", cd->MaxPower, cd->MaxPower + ); +} + + +void +print_USB_INTERFACE_DESCRIPTOR(PUSB_INTERFACE_DESCRIPTOR id, UINT ix) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB interface descriptor + +Arguments: + + ptr to USB interface descriptor + +Return Value: + + none + +--*/ +{ + printf("\n-----------------------------\nUSB_INTERFACE_DESCRIPTOR #%d\n", ix); + + + printf( + "bLength = 0x%x\n", id->bLength + ); + + + printf( + "bDescriptorType = 0x%x ( %s )\n", id->bDescriptorType, + usbDescriptorTypeString( id->bDescriptorType ) + ); + + + printf( + "bInterfaceNumber = 0x%x\n", id->bInterfaceNumber + ); + printf( + "bAlternateSetting = 0x%x\n", id->bAlternateSetting + ); + printf( + "bNumEndpoints = 0x%x\n", id->bNumEndpoints + ); + printf( + "bInterfaceClass = 0x%x\n", id->bInterfaceClass + ); + printf( + "bInterfaceSubClass = 0x%x\n", id->bInterfaceSubClass + ); + printf( + "bInterfaceProtocol = 0x%x\n", id->bInterfaceProtocol + ); + printf( + "bInterface = 0x%x\n", id->iInterface + ); +} + + +void +print_USB_ENDPOINT_DESCRIPTOR(PUSB_ENDPOINT_DESCRIPTOR ed, int i) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB endpoint descriptor + +Arguments: + + ptr to USB endpoint descriptor, + index of this endpt in interface desc + +Return Value: + + none + +--*/ +{ + printf( + "------------------------------\nUSB_ENDPOINT_DESCRIPTOR for Pipe%02d\n", i + ); + + printf( + "bLength = 0x%x\n", ed->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", ed->bDescriptorType, + usbDescriptorTypeString( ed->bDescriptorType ) + ); + + if ( USB_ENDPOINT_DIRECTION_IN( ed->bEndpointAddress ) ) { + printf( + "bEndpointAddress= 0x%x ( INPUT )\n", ed->bEndpointAddress + ); + } else { + printf( + "bEndpointAddress= 0x%x ( OUTPUT )\n", ed->bEndpointAddress + ); + } + + printf( + "bmAttributes= 0x%x ( %s )\n", ed->bmAttributes, + usbEndPointTypeString ( ed->bmAttributes ) + ); + + printf( + "wMaxPacketSize= 0x%x, decimal %d\n", ed->wMaxPacketSize, + ed->wMaxPacketSize + ); + + printf( + "bInterval = 0x%x, decimal %d\n", ed->bInterval, ed->bInterval + ); +} + + +BOOL +DumpUsbConfig() +/*++ +Routine Description: + + Called to do formatted ascii dump to console of USB + configuration, interface, and endpoint descriptors. + +Arguments: + + none + +Return Value: + + TRUE or FALSE + +--*/ +{ + HANDLE hDev; + UINT success; + int siz, nBytes; + char buf[256] = {'\0'}; + + hDev = OpenDevice(TRUE); + if(hDev == INVALID_HANDLE_VALUE) + { + return FALSE; + } + + siz = sizeof(buf); + + success = DeviceIoControl(hDev, + IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR, + buf, + siz, + buf, + siz, + (PULONG) &nBytes, + NULL); + + if(success == FALSE) { + printf("Ioct - GetConfigDesc failed %d\n", GetLastError()); + } else { + + ULONG i; + UINT j, n; + char *pch; + PUSB_CONFIGURATION_DESCRIPTOR cd; + PUSB_INTERFACE_DESCRIPTOR id; + PUSB_ENDPOINT_DESCRIPTOR ed; + + pch = buf; + n = 0; + + cd = (PUSB_CONFIGURATION_DESCRIPTOR) pch; + + print_USB_CONFIGURATION_DESCRIPTOR( cd ); + + pch += cd->bLength; + + do { + id = (PUSB_INTERFACE_DESCRIPTOR) pch; + + print_USB_INTERFACE_DESCRIPTOR(id, n++); + + pch += id->bLength; + for (j=0; j<id->bNumEndpoints; j++) { + + ed = (PUSB_ENDPOINT_DESCRIPTOR) pch; + + print_USB_ENDPOINT_DESCRIPTOR(ed,j); + + pch += ed->bLength; + } + i = (ULONG)(pch - buf); + + } while (i<cd->wTotalLength); + } + + CloseHandle(hDev); + + return success; + +} + diff --git a/usb/kmdf_fx2/exe/osrusbfx2.vcxproj b/usb/kmdf_fx2/exe/osrusbfx2.vcxproj new file mode 100644 index 00000000..b2388c67 --- /dev/null +++ b/usb/kmdf_fx2/exe/osrusbfx2.vcxproj @@ -0,0 +1,192 @@ +<?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>{7289C9A2-233A-449D-AEEC-0D9FC929E0F0}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{6BC89B61-F14B-48F5-93B6-6F897425DDDA}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</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>Universal</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>Universal</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>Universal</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>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc;..\sys\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="dump.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'" /> + </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/usb/kmdf_fx2/exe/osrusbfx2.vcxproj.Filters b/usb/kmdf_fx2/exe/osrusbfx2.vcxproj.Filters new file mode 100644 index 00000000..485e09f4 --- /dev/null +++ b/usb/kmdf_fx2/exe/osrusbfx2.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>{2C8645BA-E3D5-49E8-97D5-033593663D52}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F8EADFE4-D5EF-4492-96A2-7C5534C7FEF2}</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>{61995FA8-8FC0-43EA-A5CA-17AEEA8827B6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dump.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/usb/kmdf_fx2/exe/test.cmd b/usb/kmdf_fx2/exe/test.cmd new file mode 100644 index 00000000..30b18b85 --- /dev/null +++ b/usb/kmdf_fx2/exe/test.cmd @@ -0,0 +1,6 @@ +FOR /L %%i IN (0,1,100000) do ( + + osrusbfx2.exe -r 512 -w 512 -c 1000000 -v + +) + diff --git a/usb/kmdf_fx2/exe/testapp.c b/usb/kmdf_fx2/exe/testapp.c new file mode 100644 index 00000000..fce915b5 --- /dev/null +++ b/usb/kmdf_fx2/exe/testapp.c @@ -0,0 +1,1210 @@ +/*++ + +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: + + Console test app for osrusbfx2 driver. + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "devioctl.h" +#include "strsafe.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include <cfgmgr32.h> +#include <basetyps.h> +#include "usbdi.h" +#include "public.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +#define WHILE(a) \ +while(__pragma(warning(disable:4127)) a __pragma(warning(disable:4127))) + +#define MAX_DEVPATH_LENGTH 256 +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE 1024 +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +BOOL G_fDumpUsbConfig = FALSE; // flags set in response to console command line switches +BOOL G_fDumpReadData = FALSE; +BOOL G_fRead = FALSE; +BOOL G_fWrite = FALSE; +BOOL G_fPlayWithDevice = FALSE; +BOOL G_fPerformAsyncIo = FALSE; +ULONG G_IterationCount = 1; //count of iterations of the test we are to perform +ULONG G_WriteLen = 512; // #bytes to write +ULONG G_ReadLen = 512; // #bytes to read + +BOOL +DumpUsbConfig( // defined in dump.c + ); + +typedef enum _INPUT_FUNCTION { + LIGHT_ONE_BAR = 1, + CLEAR_ONE_BAR, + LIGHT_ALL_BARS, + CLEAR_ALL_BARS, + GET_BAR_GRAPH_LIGHT_STATE, + GET_SWITCH_STATE, + GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE, + GET_7_SEGEMENT_STATE, + SET_7_SEGEMENT_STATE, + RESET_DEVICE, + REENUMERATE_DEVICE, +} INPUT_FUNCTION; + +_Success_(return) +BOOL +GetDevicePath( + _In_ LPGUID InterfaceGuid, + _Out_writes_z_(BufLen) PWCHAR DevicePath, + _In_ size_t BufLen + ) +{ + CONFIGRET cr = CR_SUCCESS; + PWSTR deviceInterfaceList = NULL; + ULONG deviceInterfaceListLength = 0; + PWSTR nextInterface; + HRESULT hr = E_FAIL; + BOOL bRet = TRUE; + + cr = CM_Get_Device_Interface_List_Size( + &deviceInterfaceListLength, + InterfaceGuid, + NULL, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list size.\n", cr); + goto clean0; + } + + if (deviceInterfaceListLength <= 1) { + bRet = FALSE; + printf("Error: No active device interfaces found.\n" + " Is the sample driver loaded?"); + goto clean0; + } + + deviceInterfaceList = (PWSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR)); + if (deviceInterfaceList == NULL) { + printf("Error allocating memory for device interface list.\n"); + goto clean0; + } + ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR)); + + cr = CM_Get_Device_Interface_List( + InterfaceGuid, + NULL, + deviceInterfaceList, + deviceInterfaceListLength, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) { + printf("Error 0x%x retrieving device interface list.\n", cr); + goto clean0; + } + + nextInterface = deviceInterfaceList + wcslen(deviceInterfaceList) + 1; + if (*nextInterface != UNICODE_NULL) { + printf("Warning: More than one device interface instance found. \n" + "Selecting first matching device.\n\n"); + } + + hr = StringCchCopy(DevicePath, BufLen, deviceInterfaceList); + if (FAILED(hr)) { + bRet = FALSE; + printf("Error: StringCchCopy failed with HRESULT 0x%x", hr); + goto clean0; + } + +clean0: + if (deviceInterfaceList != NULL) { + free(deviceInterfaceList); + } + if (CR_SUCCESS != cr) { + bRet = FALSE; + } + + return bRet; +} + + +HANDLE +OpenDevice( + _In_ BOOL Synchronous + ) + +/*++ +Routine Description: + + Called by main() to open an instance of our device after obtaining its name + +Arguments: + + Synchronous - TRUE, if Device is to be opened for synchronous access. + FALSE, otherwise. + +Return Value: + + Device handle on success else INVALID_HANDLE_VALUE + +--*/ + +{ + HANDLE hDev; + WCHAR completeDeviceName[MAX_DEVPATH_LENGTH]; + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + completeDeviceName, + sizeof(completeDeviceName)/sizeof(completeDeviceName[0])) ) + { + return INVALID_HANDLE_VALUE; + } + + printf("DeviceName = (%S)\n", completeDeviceName); + + if(Synchronous) { + hDev = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, // default security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + } else { + + hDev = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, // default security + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + } + + if (hDev == INVALID_HANDLE_VALUE) { + printf("Failed to open the device, error - %d", GetLastError()); + } else { + printf("Opened the device successfully.\n"); + } + + return hDev; +} + + + +VOID +Usage() + +/*++ +Routine Description: + + Called by main() to dump usage info to the console when + the app is called with no parms or with an invalid parm + +Arguments: + + None + +Return Value: + + None + +--*/ + +{ + printf("Usage for osrusbfx2 testapp:\n"); + printf("-r [n] where n is number of bytes to read\n"); + printf("-w [n] where n is number of bytes to write\n"); + printf("-c [n] where n is number of iterations (default = 1)\n"); + printf("-v verbose -- dumps read data\n"); + printf("-p to control bar LEDs, seven segment, and dip switch\n"); + printf("-a to perform asynchronous I/O\n"); + printf("-u to dump USB configuration and pipe info \n"); + + return; +} + + +void +Parse( + _In_ int argc, + _In_reads_(argc) LPSTR *argv + ) + +/*++ +Routine Description: + + Called by main() to parse command line parms + +Arguments: + + argc and argv that was passed to main() + +Return Value: + + Sets global flags as per user function request + +--*/ + +{ + int i; + + if ( argc < 2 ) // give usage if invoked with no parms + Usage(); + + for (i=0; i<argc; i++) { + if (argv[i][0] == '-' || + argv[i][0] == '/') { + switch(argv[i][1]) { + case 'r': + case 'R': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { +#pragma warning(suppress: 6385) + G_ReadLen = atoi(&argv[i+1][0]); + G_fRead = TRUE; + } + i++; + break; + case 'w': + case 'W': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_WriteLen = atoi(&argv[i+1][0]); + G_fWrite = TRUE; + } + i++; + break; + case 'c': + case 'C': + if (i+1 >= argc) { + Usage(); + exit(1); + } + else { + G_IterationCount = atoi(&argv[i+1][0]); + } + i++; + break; + case 'u': + case 'U': + G_fDumpUsbConfig = TRUE; + break; + case 'p': + case 'P': + G_fPlayWithDevice = TRUE; + break; + case 'a': + case 'A': + G_fPerformAsyncIo = TRUE; + break; + case 'v': + case 'V': + G_fDumpReadData = TRUE; + break; + default: + Usage(); + } + } + } +} + +BOOL +Compare_Buffs( + _In_reads_bytes_(buff1length) char *buff1, + _In_ ULONG buff1length, + _In_reads_bytes_(buff2length) char *buff2, + _In_ ULONG buff2length + ) +/*++ +Routine Description: + + Called to verify read and write buffers match for loopback test + +Arguments: + + buffers to compare and length + +Return Value: + + TRUE if buffers match, else FALSE + +--*/ +{ + int ok = 1; + + if (buff1length != buff2length || memcmp(buff1, buff2, buff1length )) { + // Edi, and Esi point to the mismatching char and ecx indicates the + // remaining length. + ok = 0; + } + + return ok; +} + +#define NPERLN 8 + +VOID +Dump( + UCHAR *b, + int len +) + +/*++ +Routine Description: + + Called to do formatted ascii dump to console of the io buffer + +Arguments: + + buffer and length + +Return Value: + + none + +--*/ + +{ + ULONG i; + ULONG longLen = (ULONG)len / sizeof( ULONG ); + PULONG pBuf = (PULONG) b; + + // dump an ordinal ULONG for each sizeof(ULONG)'th byte + printf("\n****** BEGIN DUMP LEN decimal %d, 0x%x\n", len,len); + for (i=0; i<longLen; i++) { + printf("%04X ", *pBuf++); + if (i % NPERLN == (NPERLN - 1)) { + printf("\n"); + } + } + if (i % NPERLN != 0) { + printf("\n"); + } + printf("\n****** END DUMP LEN decimal %d, 0x%x\n", len,len); +} + + +BOOL +PlayWithDevice() +{ + HANDLE deviceHandle; + DWORD code; + ULONG index; + INPUT_FUNCTION function; + BAR_GRAPH_STATE barGraphState; + ULONG bar; + SWITCH_STATE switchState; + UCHAR sevenSegment = 0; + UCHAR i; + BOOL result = FALSE; + + deviceHandle = OpenDevice(FALSE); + + if (deviceHandle == INVALID_HANDLE_VALUE) { + + printf("Unable to find any OSR FX2 devices!\n"); + + return FALSE; + + } + + // + // Infinitely print out the list of choices, ask for input, process + // the request + // + WHILE(TRUE) { + + printf ("\nUSBFX TEST -- Functions:\n\n"); + printf ("\t1. Light Bar\n"); + printf ("\t2. Clear Bar\n"); + printf ("\t3. Light entire Bar graph\n"); + printf ("\t4. Clear entire Bar graph\n"); + printf ("\t5. Get bar graph state\n"); + printf ("\t6. Get Switch state\n"); + printf ("\t7. Get Switch Interrupt Message\n"); + printf ("\t8. Get 7 segment state\n"); + printf ("\t9. Set 7 segment state\n"); + printf ("\t10. Reset the device\n"); + printf ("\t11. Reenumerate the device\n"); + printf ("\n\t0. Exit\n"); + printf ("\n\tSelection: "); + + if (scanf_s ("%d", &function) <= 0) { + + printf("Error reading input!\n"); + goto Error; + + } + + switch(function) { + + case LIGHT_ONE_BAR: + + printf("Which Bar (input number 1 thru 8)?\n"); + if (scanf_s ("%d", &bar) <= 0) { + + printf("Error reading input!\n"); + goto Error; + + } + + if(bar == 0 || bar > 8){ + printf("Invalid bar number!\n"); + goto Error; + } + + bar--; // normalize to 0 to 7 + + barGraphState.BarsAsUChar = 1 << (UCHAR)bar; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ONE_BAR: + + + printf("Which Bar (input number 1 thru 8)?\n"); + if (scanf_s ("%d", &bar) <= 0) { + + printf("Error reading input!\n"); + goto Error; + + } + + if(bar == 0 || bar > 8){ + printf("Invalid bar number!\n"); + goto Error; + } + + bar--; + + // + // Read the current state + // + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + if (barGraphState.BarsAsUChar & (1 << bar)) { + + printf("Bar is set...Clearing it\n"); + barGraphState.BarsAsUChar &= ~(1 << bar); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + + } + + } else { + + printf("Bar not set.\n"); + + } + + break; + + case LIGHT_ALL_BARS: + + barGraphState.BarsAsUChar = 0xFF; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case CLEAR_ALL_BARS: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY, + &barGraphState, // Ptr to InBuffer + sizeof(BAR_GRAPH_STATE), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + + case GET_BAR_GRAPH_LIGHT_STATE: + + barGraphState.BarsAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &barGraphState, // Ptr to OutBuffer + sizeof(BAR_GRAPH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Bar Graph: \n"); + printf(" Bar8 is %s\n", barGraphState.Bar8 ? "ON" : "OFF"); + printf(" Bar7 is %s\n", barGraphState.Bar7 ? "ON" : "OFF"); + printf(" Bar6 is %s\n", barGraphState.Bar6 ? "ON" : "OFF"); + printf(" Bar5 is %s\n", barGraphState.Bar5 ? "ON" : "OFF"); + printf(" Bar4 is %s\n", barGraphState.Bar4 ? "ON" : "OFF"); + printf(" Bar3 is %s\n", barGraphState.Bar3 ? "ON" : "OFF"); + printf(" Bar2 is %s\n", barGraphState.Bar2 ? "ON" : "OFF"); + printf(" Bar1 is %s\n", barGraphState.Bar1 ? "ON" : "OFF"); + + break; + + case GET_SWITCH_STATE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_READ_SWITCHES, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(SWITCH_STATE), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Switches: \n"); + printf(" Switch8 is %s\n", switchState.Switch8 ? "ON" : "OFF"); + printf(" Switch7 is %s\n", switchState.Switch7 ? "ON" : "OFF"); + printf(" Switch6 is %s\n", switchState.Switch6 ? "ON" : "OFF"); + printf(" Switch5 is %s\n", switchState.Switch5 ? "ON" : "OFF"); + printf(" Switch4 is %s\n", switchState.Switch4 ? "ON" : "OFF"); + printf(" Switch3 is %s\n", switchState.Switch3 ? "ON" : "OFF"); + printf(" Switch2 is %s\n", switchState.Switch2 ? "ON" : "OFF"); + printf(" Switch1 is %s\n", switchState.Switch1 ? "ON" : "OFF"); + + break; + + case GET_SWITCH_STATE_AS_INTERRUPT_MESSAGE: + + switchState.SwitchesAsUChar = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &switchState, // Ptr to OutBuffer + sizeof(switchState), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("Switches: %d\n",index); + printf(" Switch8 is %s\n", switchState.Switch8 ? "ON" : "OFF"); + printf(" Switch7 is %s\n", switchState.Switch7 ? "ON" : "OFF"); + printf(" Switch6 is %s\n", switchState.Switch6 ? "ON" : "OFF"); + printf(" Switch5 is %s\n", switchState.Switch5 ? "ON" : "OFF"); + printf(" Switch4 is %s\n", switchState.Switch4 ? "ON" : "OFF"); + printf(" Switch3 is %s\n", switchState.Switch3 ? "ON" : "OFF"); + printf(" Switch2 is %s\n", switchState.Switch2 ? "ON" : "OFF"); + printf(" Switch1 is %s\n", switchState.Switch1 ? "ON" : "OFF"); + + break; + + case GET_7_SEGEMENT_STATE: + + sevenSegment = 0; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + &sevenSegment, // Ptr to OutBuffer + sizeof(UCHAR), // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("7 Segment mask: 0x%x\n", sevenSegment); + break; + + case SET_7_SEGEMENT_STATE: + + for (i = 0; i < 8; i++) { + + sevenSegment = 1 << i; + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY, + &sevenSegment, // Ptr to InBuffer + sizeof(UCHAR), // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + 0)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + printf("This is %d\n", i); + Sleep(500); + + } + + printf("7 Segment mask: 0x%x\n", sevenSegment); + break; + + case RESET_DEVICE: + + printf("Reset the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_RESET_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + break; + + case REENUMERATE_DEVICE: + + printf("Re-enumerate the device\n"); + + if (!DeviceIoControl(deviceHandle, + IOCTL_OSRUSBFX2_REENUMERATE_DEVICE, + NULL, // Ptr to InBuffer + 0, // Length of InBuffer + NULL, // Ptr to OutBuffer + 0, // Length of OutBuffer + &index, // BytesReturned + NULL)) { // Ptr to Overlapped structure + + code = GetLastError(); + + printf("DeviceIoControl failed with error 0x%x\n", code); + + goto Error; + } + + // + // Close the handle to the device and exit out so that + // the driver can unload when the device is surprise-removed + // and reenumerated. + // + default: + + result = TRUE; + goto Error; + + } + + } // end of while loop + +Error: + + CloseHandle(deviceHandle); + return result; + +} + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG error; + + hDevice = OpenDevice(FALSE); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open device %d\n", GetLastError()); + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + goto Error; + } + + pOvList = (OVERLAPPED *)malloc(NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + goto Error; + } + + buf = (PUCHAR)malloc(NUM_ASYNCH_IO * BUFFER_SIZE); + + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + goto Error; + } + + ZeroMemory(pOvList, NUM_ASYNCH_IO * sizeof(OVERLAPPED)); + ZeroMemory(buf, NUM_ASYNCH_IO * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < NUM_ASYNCH_IO; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %Iu th read failed %d \n",i, GetLastError()); + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %Iu th write failed %d \n",i, GetLastError()); + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + OVERLAPPED *completedOv; + ULONG_PTR key; + ULONG numberOfBytesTransferred; + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, + &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + goto Error; + } + + // + // Read successfully completed. Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + + printf("Number of bytes read by request number %Iu is %d\n", + i, numberOfBytesTransferred); + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%Iu th Read failed %d \n", i, GetLastError()); + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %Iu is %d\n", + i, numberOfBytesTransferred); + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%Iu th write failed %d \n", i, GetLastError()); + goto Error; + } + } + } + } + +Error: + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if (hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if (pOvList) { + free(pOvList); + } + if (buf) { + free(buf); + } + + return 1; + +} + + +int +_cdecl +main( + _In_ int argc, + _In_reads_(argc) LPSTR *argv + ) +/*++ +Routine Description: + + Entry point to rwbulk.exe + Parses cmdline, performs user-requested tests + +Arguments: + + argc, argv standard console 'c' app arguments + +Return Value: + + Zero + +--*/ + +{ + char * pinBuf = NULL; + char * poutBuf = NULL; + ULONG nBytesRead; + ULONG nBytesWrite = 0; + int ok; + int retValue = 0; + UINT success; + HANDLE hRead = INVALID_HANDLE_VALUE; + HANDLE hWrite = INVALID_HANDLE_VALUE; + ULONG fail = 0L; + ULONG i; + + + Parse(argc, argv ); + + // + // dump USB configuation and pipe info + // + if (G_fDumpUsbConfig) { + DumpUsbConfig(); + } + + if (G_fPlayWithDevice) { + PlayWithDevice(); + goto exit; + } + + if (G_fPerformAsyncIo) { + HANDLE th1; + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + retValue = 1; + goto exit; + } + + // + // Use this thread for peforming write. + // + AsyncIo((PVOID)WRITER_TYPE); + + goto exit; + } + + // + // doing a read, write, or both test + // + if ((G_fRead) || (G_fWrite)) { + + if (G_fRead) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_ReadLen % sizeof( ULONG ) ) { + G_ReadLen++; + } + } + + // + // open the output file + // + hRead = OpenDevice(TRUE); + if(hRead == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + pinBuf = malloc(G_ReadLen); + } + + if (G_fWrite) { + if ( G_fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( G_WriteLen % sizeof( ULONG ) ) { + G_WriteLen++; + } + } + + // + // open the output file + // + hWrite = OpenDevice(TRUE); + if(hWrite == INVALID_HANDLE_VALUE) { + retValue = 1; + goto exit; + } + + poutBuf = malloc(G_WriteLen); + } + + for (i = 0; i < G_IterationCount; i++) { + ULONG j; + + if (G_fWrite && poutBuf && hWrite != INVALID_HANDLE_VALUE) { + + PULONG pOut = (PULONG) poutBuf; + ULONG numLongs = G_WriteLen / sizeof( ULONG ); + + // + // put some data in the output buffer + // + for (j=0; j<numLongs; j++) { + *(pOut+j) = j; + } + + // + // send the write + // + success = WriteFile(hWrite, poutBuf, G_WriteLen, &nBytesWrite, NULL); + if(success == 0) { + printf("WriteFile failed - error %d\n", GetLastError()); + retValue = 1; + goto exit; + } + printf("Write (%04.4u) : request %06.6u bytes -- %06.6u bytes written\n", + i, G_WriteLen, nBytesWrite); + + assert(nBytesWrite == G_WriteLen); + } + + if (G_fRead && pinBuf) { + + success = ReadFile(hRead, pinBuf, G_ReadLen, &nBytesRead, NULL); + if(success == 0) { + printf("ReadFile failed - error %d\n", GetLastError()); + retValue = 1; + goto exit; + } + + printf("Read (%04.4u) : request %06.6u bytes -- %06.6u bytes read\n", + i, G_ReadLen, nBytesRead); + + if (G_fWrite && poutBuf) { + + // + // validate the input buffer against what + // we sent to the 82930 (loopback test) + // + ok = Compare_Buffs(pinBuf, nBytesRead, poutBuf, nBytesWrite); + + if( G_fDumpReadData ) { + printf("Dumping read buffer\n"); + Dump( (PUCHAR) pinBuf, nBytesRead ); + printf("Dumping write buffer\n"); + Dump( (PUCHAR) poutBuf, nBytesRead ); + } + assert(ok); + + if(ok != 1) { + fail++; + } + + assert(G_ReadLen == G_WriteLen); + assert(nBytesRead == G_ReadLen); + } + } + } + + } + +exit: + + if (pinBuf) { + free(pinBuf); + } + + if (poutBuf) { + free(poutBuf); + } + + // close devices if needed + if (hRead != INVALID_HANDLE_VALUE) { + CloseHandle(hRead); + } + + if (hWrite != INVALID_HANDLE_VALUE) { + CloseHandle(hWrite); + } + + return retValue; +} + + diff --git a/usb/kmdf_fx2/exe/testapp.rc b/usb/kmdf_fx2/exe/testapp.rc new file mode 100644 index 00000000..3947204a --- /dev/null +++ b/usb/kmdf_fx2/exe/testapp.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "OSRUSBFX2 Bulk & Isoch Read and Write test App" +#define VER_INTERNALNAME_STR "osrusbfx2.exe" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.exe" + +#include <common.ver> + diff --git a/usb/kmdf_fx2/inc/prototypes.h b/usb/kmdf_fx2/inc/prototypes.h new file mode 100644 index 00000000..cc99cdfe --- /dev/null +++ b/usb/kmdf_fx2/inc/prototypes.h @@ -0,0 +1,14 @@ +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd; + +EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDriverContextCleanup; +EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ EvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + diff --git a/usb/kmdf_fx2/inc/public.h b/usb/kmdf_fx2/inc/public.h new file mode 100644 index 00000000..12ddf21f --- /dev/null +++ b/usb/kmdf_fx2/inc/public.h @@ -0,0 +1,173 @@ +/*++ + +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: + +Environment: + + User & Kernel mode + +--*/ + +#ifndef _PUBLIC_H +#define _PUBLIC_H + +#include <initguid.h> + +// {573E8C73-0CB4-4471-A1BF-FAB26C31D384} +DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, + 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84); + +#pragma warning(push) +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +// +// Define the structures that will be used by the IOCTL +// interface to the driver +// + +// +// BAR_GRAPH_STATE +// +// BAR_GRAPH_STATE is a bit field structure with each +// bit corresponding to one of the bar graph on the +// OSRFX2 Development Board +// +#include <pshpack1.h> +typedef struct _BAR_GRAPH_STATE { + + union { + + struct { + // + // Individual bars starting from the + // top of the stack of bars + // + // NOTE: There are actually 10 bars, + // but the very top two do not light + // and are not counted here + // + UCHAR Bar1 : 1; + UCHAR Bar2 : 1; + UCHAR Bar3 : 1; + UCHAR Bar4 : 1; + UCHAR Bar5 : 1; + UCHAR Bar6 : 1; + UCHAR Bar7 : 1; + UCHAR Bar8 : 1; + }; + + // + // The state of all the bar graph as a single + // UCHAR + // + UCHAR BarsAsUChar; + + }; + +}BAR_GRAPH_STATE, *PBAR_GRAPH_STATE; + +// +// SWITCH_STATE +// +// SWITCH_STATE is a bit field structure with each +// bit corresponding to one of the switches on the +// OSRFX2 Development Board +// +typedef struct _SWITCH_STATE { + + union { + struct { + // + // Individual switches starting from the + // left of the set of switches + // + UCHAR Switch1 : 1; + UCHAR Switch2 : 1; + UCHAR Switch3 : 1; + UCHAR Switch4 : 1; + UCHAR Switch5 : 1; + UCHAR Switch6 : 1; + UCHAR Switch7 : 1; + UCHAR Switch8 : 1; + }; + + // + // The state of all the switches as a single + // UCHAR + // + UCHAR SwitchesAsUChar; + + }; + + +}SWITCH_STATE, *PSWITCH_STATE; + +#include <poppack.h> + +#pragma warning(pop) + +#define IOCTL_INDEX 0x800 +#define FILE_DEVICE_OSRUSBFX2 0x65500 + +#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 1, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 3, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 4, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 5, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + + +#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 6, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 7, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 8, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 9, \ + METHOD_OUT_DIRECT, \ + FILE_READ_ACCESS) + +#endif diff --git a/usb/kmdf_fx2/kmdf_fx2.sln b/usb/kmdf_fx2/kmdf_fx2.sln new file mode 100644 index 00000000..59e8e548 --- /dev/null +++ b/usb/kmdf_fx2/kmdf_fx2.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{219EAF9D-A9F6-4F9D-897D-91AB46B2A71B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{7E5E361E-E36E-4728-9D4C-E030A0134F40}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "driver\osrusbfx2.vcxproj", "{E7ECAF21-2522-4E7D-8475-67C4A5E43F70}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "exe\osrusbfx2.vcxproj", "{7289C9A2-233A-449D-AEEC-0D9FC929E0F0}" +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 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Debug|Win32.ActiveCfg = Debug|Win32 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Debug|Win32.Build.0 = Debug|Win32 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Release|Win32.ActiveCfg = Release|Win32 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Release|Win32.Build.0 = Release|Win32 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Debug|x64.ActiveCfg = Debug|x64 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Debug|x64.Build.0 = Debug|x64 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Release|x64.ActiveCfg = Release|x64 + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70}.Release|x64.Build.0 = Release|x64 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Debug|Win32.ActiveCfg = Debug|Win32 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Debug|Win32.Build.0 = Debug|Win32 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Release|Win32.ActiveCfg = Release|Win32 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Release|Win32.Build.0 = Release|Win32 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Debug|x64.ActiveCfg = Debug|x64 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Debug|x64.Build.0 = Debug|x64 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Release|x64.ActiveCfg = Release|x64 + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E7ECAF21-2522-4E7D-8475-67C4A5E43F70} = {219EAF9D-A9F6-4F9D-897D-91AB46B2A71B} + {7289C9A2-233A-449D-AEEC-0D9FC929E0F0} = {7E5E361E-E36E-4728-9D4C-E030A0134F40} + EndGlobalSection +EndGlobal diff --git a/usb/ufxclientsample/UfxClientSample.inx b/usb/ufxclientsample/UfxClientSample.inx Binary files differnew file mode 100644 index 00000000..51525cc8 --- /dev/null +++ b/usb/ufxclientsample/UfxClientSample.inx diff --git a/usb/ufxclientsample/UfxClientSample.man b/usb/ufxclientsample/UfxClientSample.man new file mode 100644 index 00000000..122aa6dd --- /dev/null +++ b/usb/ufxclientsample/UfxClientSample.man @@ -0,0 +1,298 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes'?> +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + > + <instrumentation> + <events> + <provider + guid="{3D46B9FE-2CE2-4833-A55E-A8B92E9D2560}" + messageFileName="ufxclientsample.sys" + name="UfxClientSample" + resourceFileName="ufxclientsample.sys" + symbol="UfxClientSampleGuid" + > + <channels/> + <keywords> + <keyword + mask="0x0000000000000001" + message="$(string.Keyword.Error)" + name="Error" + /> + <keyword + mask="0x0000000000000002" + message="$(string.Keyword.Performance)" + name="Performance" + /> + <keyword + mask="0x0000000000000004" + message="$(string.Keyword.Debug)" + name="Debug" + /> + <keyword + mask="0x0000000000000008" + message="$(string.Keyword.Registers)" + name="Registers" + /> + <keyword + mask="0x0000000000000010" + message="$(string.Keyword.Endpoint)" + name="Endpoint" + /> + </keywords> + <tasks> + <task + eventGUID="{872c3c43-6899-4f1d-89b8-51a82f6db657}" + name="Error" + value="1" + /> + <task + eventGUID="{172c3c43-6899-4f1d-89b8-51a82f6db657}" + name="Debug" + value="2" + /> + <task + eventGUID="{272c3c43-6899-4f1d-89b8-51a82f6db657}" + name="FailedNtStatus" + value="3" + /> + <task + eventGUID="{372c3c43-6899-4f1d-89b8-51a82f6db657}" + name="RegisterRead" + value="4" + /> + <task + eventGUID="{472c3c43-6899-4f1d-89b8-51a82f6db657}" + name="RegisterWrite" + value="5" + /> + <task + eventGUID="{572c3c43-6899-4f1d-89b8-51a82f6db657}" + name="Transfer" + value="6" + /> + <task + eventGUID="{672c3c43-6899-4f1d-89b8-51a82f6db657}" + name="EndpointCommand" + value="7" + /> + </tasks> + <templates> + <template tid="tFailedNtStatus"> + <data + inType="win:AnsiString" + name="File" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="Line" + /> + <data + inType="win:UInt32" + name="Status" + outType="win:HexInt32" + /> + </template> + <template tid="tRegister"> + <data + inType="win:UInt32" + name="Offset" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Value" + outType="win:HexInt32" + /> + </template> + <template tid="tTransfer"> + <data + inType="win:AnsiString" + name="Stage" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="Endpoint" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="PhysicalEndpoint" + /> + <data + inType="win:UInt32" + name="Request" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Transaction" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="BytesRequested" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="BytesProgrammed" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="BytesTransferred" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="SgProgrammed" + /> + <data + inType="win:UInt32" + name="SgLength" + /> + </template> + <template tid="tEndpointCommand"> + <data + inType="win:AnsiString" + name="Name" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="Endpoint" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="PhysicalEndpoint" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Command" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Parameter0" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Parameter1" + outType="win:HexInt32" + /> + <data + inType="win:UInt32" + name="Parameter2" + outType="win:HexInt32" + /> + </template> + </templates> + <events> + <event + keywords="Error" + level="win:Error" + message="$(string.Event.FailedNtStatus)" + opcode="win:Info" + symbol="FailedNtStatus" + task="FailedNtStatus" + template="tFailedNtStatus" + value="100" + /> + <event + keywords="Registers" + level="win:Verbose" + message="$(string.Event.RegisterRead)" + opcode="win:Info" + symbol="RegisterRead" + task="RegisterRead" + template="tRegister" + value="101" + /> + <event + keywords="Registers" + level="win:Verbose" + message="$(string.Event.RegisterWrite)" + opcode="win:Info" + symbol="RegisterWrite" + task="RegisterWrite" + template="tRegister" + value="102" + /> + <event + keywords="Endpoint" + level="win:Informational" + message="$(string.Event.Transfer)" + opcode="win:Info" + symbol="Transfer" + task="Transfer" + template="tTransfer" + value="200" + /> + <event + keywords="Endpoint" + level="win:Verbose" + message="$(string.Event.EndpointCommand)" + opcode="win:Info" + symbol="EndpointCommand" + task="Transfer" + template="tEndpointCommand" + value="202" + /> + </events> + </provider> + </events> + </instrumentation> + <localization> + <resources culture="en-US"> + <stringTable> + <string + id="Keyword.Error" + value="Error" + /> + <string + id="Keyword.Performance" + value="Performance" + /> + <string + id="Keyword.Debug" + value="Debug" + /> + <string + id="Keyword.Registers" + value="Registers" + /> + <string + id="Keyword.Endpoint" + value="Endpoint" + /> + <string + id="Event.FailedNtStatus" + value="Failed with status %3 in file %1 on line %2" + /> + <string + id="Event.RegisterRead" + value="READ %1 %2" + /> + <string + id="Event.RegisterWrite" + value="WRITE %1 %2" + /> + <string + id="Event.Transfer" + value="TRANSFER %1: %2 (%3), RQ: %4, DMA: %5, BytesReq: %6, BytesProg: %7, BytesTrans: %8, SG: %9/%10" + /> + <string + id="Event.EndpointCommand" + value="COMMAND %1: %2 (%3) -- %4 %5 %6 %7" + /> + </stringTable> + </resources> + </localization> +</instrumentationManifest> diff --git a/usb/ufxclientsample/defaultqueue.c b/usb/ufxclientsample/defaultqueue.c new file mode 100644 index 00000000..111b48c8 --- /dev/null +++ b/usb/ufxclientsample/defaultqueue.c @@ -0,0 +1,200 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + defaultqueue.c + +Abstract: + + Implements the device's default queue callbacks. + +Environment: + + Kernel mode + +--*/ + +#include "device.h" +#include "defaultqueue.h" +#include "defaultqueue.tmh" + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL DefaultQueue_EvtIoDeviceControl; +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL DefaultQueue_EvtIoInternalDeviceControl; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, DefaultQueueCreate) +#endif + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +DefaultQueueCreate( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Creates and configures the default IO Queue for the device. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + Appropriate NTSTATUS message + +--*/ +{ + NTSTATUS Status; + WDF_IO_QUEUE_CONFIG QueueConfig; + + TraceEntry(); + + PAGED_CODE(); + + // + // Create the default queue + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &QueueConfig, + WdfIoQueueDispatchParallel + ); + + QueueConfig.PowerManaged = WdfTrue; + QueueConfig.EvtIoDeviceControl = DefaultQueue_EvtIoDeviceControl; + QueueConfig.EvtIoInternalDeviceControl = DefaultQueue_EvtIoInternalDeviceControl; + + Status = WdfIoQueueCreate( + Device, + &QueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + NULL); + + CHK_NT_MSG(Status, "WdfIoQueueCreate failed"); + +End: + + TraceExit(); + return Status; +} + +VOID +DefaultQueue_EvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ + +Routine Description: + + EvtIoDeviceControl handler for the default Queue + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + OutputBufferLength - Size of the output buffer in bytes + + InputBufferLength - Size of the input buffer in bytes + + IoControlCode - I/O control code. + +--*/ +{ + WDFDEVICE WdfDevice; + PCONTROLLER_CONTEXT ControllerContext; + BOOLEAN HandledbyUfx; + + TraceEntry(); + + TraceVerbose("Queue 0x%p, Request 0x%p, OutputBufferLength %d, " + "InputBufferLength %d, IoControlCode %d", + Queue, Request, (int) OutputBufferLength, + (int) InputBufferLength, IoControlCode); + + WdfDevice = WdfIoQueueGetDevice(Queue); + ControllerContext = DeviceGetControllerContext(WdfDevice); + + HandledbyUfx = UfxDeviceIoControl( + ControllerContext->UfxDevice, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode); + + if (!HandledbyUfx) { + TraceError("Recieved an unsupported IOCTL"); + WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST); + } + + TraceExit(); +} + +VOID +DefaultQueue_EvtIoInternalDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ + +Routine Description: + + EvtIoInternalDeviceControl handler for the default Queue + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + OutputBufferLength - Size of the output buffer in bytes + + InputBufferLength - Size of the input buffer in bytes + + IoControlCode - I/O control code. + +--*/ +{ + WDFDEVICE WdfDevice; + PCONTROLLER_CONTEXT ControllerContext; + BOOLEAN HandledbyUfx; + + TraceEntry(); + + TraceVerbose("InternalQueue 0x%p, Request 0x%p, OutputBufferLength %d, " + "InputBufferLength %d, IoControlCode %d", + Queue, Request, (int) OutputBufferLength, + (int) InputBufferLength, IoControlCode); + + WdfDevice = WdfIoQueueGetDevice(Queue); + ControllerContext = DeviceGetControllerContext(WdfDevice); + + HandledbyUfx = UfxDeviceIoInternalControl( + ControllerContext->UfxDevice, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode); + + if (!HandledbyUfx) { + TraceError("Recieved an un supported IOCTL"); + WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST); + } + + TraceExit(); +} + diff --git a/usb/ufxclientsample/defaultqueue.h b/usb/ufxclientsample/defaultqueue.h new file mode 100644 index 00000000..f32eb104 --- /dev/null +++ b/usb/ufxclientsample/defaultqueue.h @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + defaultqueue.h + +Abstract: + + Defines the export functions for the UFXDEVICE object. + +Environment: + + Kernel mode + +--*/ + +// +// This is the context that can be placed per queue +// and would contain per queue information. +// +typedef struct _QUEUE_CONTEXT { + + ULONG PrivateDeviceData; // just a placeholder + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) + + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +DefaultQueueCreate( + _In_ WDFDEVICE Device + ); + diff --git a/usb/ufxclientsample/device.c b/usb/ufxclientsample/device.c new file mode 100644 index 00000000..8bb12b52 --- /dev/null +++ b/usb/ufxclientsample/device.c @@ -0,0 +1,566 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + device.c - WDFDEVICE creation and callback handling for the sample + controller device. + +Abstract: + + This file contains the device entry points and callbacks. + +Environment: + + Kernel-mode Driver Framework + +--*/ + +#include "initguid.h" +#include "device.h" +#include "ufxdevice.h" +#include "registers.h" +#include "ufxendpoint.h" +#include "interrupt.h" +#include "defaultqueue.h" +#include "usbfnioctl.h" +#include "device.tmh" + +// +// Minimum amount of time to wait before exiting D0. The purpose of waiting +// is to ensure that the current state / port are stabilized. For example, +// on IDCP, we may be connected to a suspended PC or disconnected hub, and +// in these cases we will get a suspend interrupt after ~3ms. +// +#define IDLE_TIMEOUT (100) + +EVT_WDF_DEVICE_PREPARE_HARDWARE OnEvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE OnEvtDeviceReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY OnEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT OnEvtDeviceD0Exit; + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +static +NTSTATUS +DeviceInitialize( + _In_ WDFDEVICE Device + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, UfxClientDeviceCreate) +#pragma alloc_text (PAGE, OnEvtDevicePrepareHardware) +#pragma alloc_text (PAGE, OnEvtDeviceReleaseHardware) +#endif + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +UfxClientDeviceCreate( + _In_ WDFDRIVER Driver, + _In_ PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + Worker routine called to create a device and its software resources. + +Arguments: + + Driver - WDF driver object + + DeviceInit - Pointer to an opaque init structure. Memory for this + structure will be freed by the framework when the WdfDeviceCreate + succeeds. So don't access the structure after that point. + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + WDF_OBJECT_ATTRIBUTES DeviceAttributes; + WDFDEVICE WdfDevice; + NTSTATUS Status; + WDF_PNPPOWER_EVENT_CALLBACKS PnpCallbacks; + WDF_DMA_ENABLER_CONFIG DmaConfig; + PCONTROLLER_CONTEXT ControllerContext; + + PAGED_CODE(); + + TraceEntry(); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, CONTROLLER_CONTEXT); + + // + // Do UFX-specific initialization + // + Status = UfxFdoInit(Driver, DeviceInit, &DeviceAttributes); + CHK_NT_MSG(Status, "Failed UFX initialization"); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpCallbacks); + PnpCallbacks.EvtDevicePrepareHardware = OnEvtDevicePrepareHardware; + PnpCallbacks.EvtDeviceReleaseHardware = OnEvtDeviceReleaseHardware; + PnpCallbacks.EvtDeviceD0Entry = OnEvtDeviceD0Entry; + PnpCallbacks.EvtDeviceD0Exit = OnEvtDeviceD0Exit; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpCallbacks); + + Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &WdfDevice); + CHK_NT_MSG(Status, "Failed to create wdf device"); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + KeInitializeEvent(&ControllerContext->DetachEvent, + NotificationEvent, + FALSE); + + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&ControllerContext->IdleSettings, IdleCanWakeFromS0); + ControllerContext->IdleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; + ControllerContext->IdleSettings.IdleTimeout = IDLE_TIMEOUT; + ControllerContext->IdleSettings.DxState = PowerDeviceD3; + + Status = WdfDeviceAssignS0IdleSettings(WdfDevice, &ControllerContext->IdleSettings); + LOG_NT_MSG(Status, "Failed to set S0 Idle Settings"); + + // + // Create and initialize device's default queue + // + Status = DefaultQueueCreate(WdfDevice); + CHK_NT_MSG(Status, "Failed to intialize default queue"); + + // + // Set alignment required by controller + // + WdfDeviceSetAlignmentRequirement(WdfDevice, UFX_CLIENT_ALIGNMENT); + + // + // Create and Initialize DMA Enabler object for the device. + // + WDF_DMA_ENABLER_CONFIG_INIT( + &DmaConfig, + WdfDmaProfileScatterGatherDuplex, + MAX_DMA_LENGTH); + // + // Version 3 is required to perform multiple + // simultaneous transfers. + // + DmaConfig.WdmDmaVersionOverride = 3; + + Status = WdfDmaEnablerCreate( + WdfDevice, + &DmaConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &ControllerContext->DmaEnabler); + CHK_NT_MSG(Status, "Failed to create DMA enabler object"); + + // + // Create UFXDEVICE object + // + Status = UfxDevice_DeviceCreate(WdfDevice); + CHK_NT_MSG(Status, "Failed to create UFX Device object"); + + // + // Create DPC Lock + // + Status = WdfSpinLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->DpcLock); + CHK_NT_MSG(Status, "Failed to create DPC lock"); + + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->InitializeDefaultEndpointLock); + CHK_NT_MSG(Status, "Failed to create Ep0 init lock"); + +End: + TraceExit(); + return Status; +} + + + +NTSTATUS +OnEvtDevicePrepareHardware ( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourcesRaw, + _In_ WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDevicePrepareHardware callback handler for the controller FDO. + It expects Register memory and two interrupts - Device and Wake. + +Arguments: + + Device - WDFDEVICE object representing the controller. + + ResourcesRaw - Raw resources relative to the parent bus driver. + + ResourcesTranslated - Translated resources available for the controller. + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + NTSTATUS Status; + ULONG ResCount; + ULONG ResIndex; + PCONTROLLER_CONTEXT ControllerContext; + BOOLEAN MemoryResourceMapped; + + PAGED_CODE(); + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(Device); + MemoryResourceMapped = FALSE; + + ResCount = WdfCmResourceListGetCount(ResourcesRaw); + + Status = STATUS_SUCCESS; + + for (ResIndex = 0; ResIndex < ResCount; ResIndex++) { + + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptorRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptorTranslated; + + ResourceDescriptorRaw = WdfCmResourceListGetDescriptor( + ResourcesRaw, + ResIndex); + switch (ResourceDescriptorRaw->Type) { + + case CmResourceTypeMemory: + if (MemoryResourceMapped == FALSE) { + MemoryResourceMapped = TRUE; + Status = RegistersCreate(Device, ResourceDescriptorRaw); + CHK_NT_MSG(Status, "Failed to read the HW registers"); + } + break; + + case CmResourceTypeInterrupt: + ResourceDescriptorTranslated = WdfCmResourceListGetDescriptor( + ResourcesTranslated, + ResIndex); + Status = InterruptCreate( + Device, + ResourceDescriptorRaw, + ResourceDescriptorTranslated); + CHK_NT_MSG(Status, "Failed to create WDFINTERRUPT object"); + break; + + default: + break; + } + } + + NT_ASSERT(ControllerContext->DeviceInterrupt != NULL); + +End: + TraceExit(); + return STATUS_SUCCESS; +} + + +NTSTATUS +OnEvtDeviceReleaseHardware ( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDeviceReleaseHardware callback handler for the controller FDO. + It expects Register memory and two interrupts - Device and Wake. + +Arguments: + + Device - WDFDEVICE object representing the controller. + + ResourcesTranslated - Translated resources available for the controller. + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + PREGISTERS_CONTEXT RegistersContext; + PCONTROLLER_CONTEXT ControllerContext; + + TraceEntry(); + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(ResourcesTranslated); + + ControllerContext = DeviceGetControllerContext(Device); + ControllerContext->DeviceInterrupt = NULL; + ControllerContext->AttachDetachInterrupt = NULL; + + RegistersContext = DeviceGetRegistersContext(Device); + if ((RegistersContext == NULL) || (RegistersContext->RegisterBase == NULL)) { + goto End; + } + + MmUnmapIoSpace(RegistersContext->RegisterBase, RegistersContext->RegistersLength); + RtlZeroMemory(RegistersContext, sizeof(*RegistersContext)); + +End: + TraceExit(); + return STATUS_SUCCESS; +} + +NTSTATUS +OnEvtDeviceD0Entry ( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +/*++ + +Routine Description: + + Called by the framework after entering D0 state. + +Arguments: + + Device - WDFDEVICE framework handle to the bus FDO. + + PreviousState - The WDF_POWER_DEVICE_STATE from which the stack is + making this transition. + +Return Value: + + Returns STATUS_SUCCESS or an appropriate NTSTATUS code otherwise. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(Device); + + if (PreviousState > WdfPowerDeviceD1) { + DevicePerformSoftReset(Device); + + WdfWaitLockAcquire(ControllerContext->InitializeDefaultEndpointLock, NULL); + ControllerContext->InitializeDefaultEndpoint = TRUE; + WdfWaitLockRelease(ControllerContext->InitializeDefaultEndpointLock); + } + + if (PreviousState == WdfPowerDeviceD3Final) { + // + // Notify UFX that HW is now ready + // + UfxDeviceNotifyHardwareReady(ControllerContext->UfxDevice); + } + + TraceExit(); + return STATUS_SUCCESS; +} + +NTSTATUS +OnEvtDeviceD0Exit ( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + Called by the framework when leaving our operational state (D0). + +Arguments: + + Device - WDFDEVICE framework handle to the bus FDO. + + TargetState - The WDF_POWER_DEVICE_STATE to which the stack is + making its transition. + + +Return Value: + + Returns STATUS_SUCCESS. + Any failed status code will leave the device stack in failed state and + device will not get any D0Entry callbacks after that. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(Device); + + WdfWaitLockAcquire(ControllerContext->InitializeDefaultEndpointLock, NULL); + ControllerContext->InitializeDefaultEndpoint = FALSE; + WdfWaitLockRelease(ControllerContext->InitializeDefaultEndpointLock); + + if (TargetState != WdfPowerDeviceD3Final) { + goto End; + } + + // + // If the stack is being removed while we are attached to a host, simulate a detach. At this + // point all attach/detach notification mechanisms are disabled, so no other code will report a + // detach, nor will "WasAttached" change from underneath us. + // + if (ControllerContext->WasAttached) { + KeClearEvent(&ControllerContext->DetachEvent); + UfxDeviceNotifyDetach(ControllerContext->UfxDevice); + ControllerContext->WasAttached = FALSE; + KeWaitForSingleObject(&ControllerContext->DetachEvent, + Executive, + KernelMode, + FALSE, + NULL); + } + +End: + TraceExit(); + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +DevicePerformSoftReset ( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This functions performs soft reset of the controller and completes + any initialization that needs to be done afterwards. + +Arguments: + + Device - Wdf FDO device object representing the controller + +--*/ +{ + + TraceEntry(); + + UNREFERENCED_PARAMETER(Device); + + // + // #### TODO: Insert code that performs a controller soft reset #### + // + + TraceExit(); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceInitializeDefaultEndpoint ( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This function initializes the default control endpoint + +Arguments: + + Device - Wdf FDO device object representing the controller + +--*/ +{ + UFXENDPOINT Endpoint; + PUFXDEVICE_CONTEXT DeviceContext; + PCONTROLLER_CONTEXT ControllerContext; + NTSTATUS Status; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(Device); + DeviceContext = UfxDeviceGetContext(ControllerContext->UfxDevice); + + if (DeviceContext->PhysicalEndpointToUfxEndpoint[0] != NULL) { + Endpoint = DeviceContext->PhysicalEndpointToUfxEndpoint[0]; + + // + // Re-initialize endpoint 0 + // + TransferDestroy(Endpoint); + + Status = TransferInitialize(Endpoint); + LOG_NT_MSG(Status, "Failed to initialize default endpoint"); + + UfxEndpointConfigureHardware(Endpoint, FALSE); + TransferStart(Endpoint); + + } else { + NT_ASSERT(FALSE); + } + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +DeviceHardwareFailure ( + _In_ WDFDEVICE Device, + _In_ ULONG ExceptionCode + ) +/*++ + +Routine Description: + + The client driver may call this function if the controller has encountered a non-recoverable error, to + allow UFX to attempt to reset the controller if possible. + +Arguments: + + Device - Wdf FDO device object representing the controller + + ExceptionCode - Exception code indicating the specific failure encountered by the controller. This + value is specific to the type of controller. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + PUFXDEVICE_CONTEXT DeviceContext; + PHARDWARE_FAILURE_CONTEXT HardwareFailureContext; + TraceEntry(); + + NT_ASSERT(ExceptionCode < ExceptionMaximum); + + ControllerContext = DeviceGetControllerContext(Device); + DeviceContext = UfxDeviceGetContext(ControllerContext->UfxDevice); + +#pragma prefast(suppress:6014, "Memory allocation is expected") + HardwareFailureContext = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(HARDWARE_FAILURE_CONTEXT), + UFX_CLIENT_TAG); + + if (HardwareFailureContext) { + HardwareFailureContext->Size = sizeof(*HardwareFailureContext); + HardwareFailureContext->ExceptionCode = ExceptionCode; + + RtlCopyMemory( + &HardwareFailureContext->ControllerContext, + ControllerContext, + sizeof(CONTROLLER_CONTEXT)); + + RtlCopyMemory( + &HardwareFailureContext->DeviceContext, + DeviceContext, + sizeof(UFXDEVICE_CONTEXT)); + + } else { + TraceError("Failed to allocate hardware failure context!"); + } + + UfxDeviceNotifyHardwareFailure( + ControllerContext->UfxDevice, + (PUFX_HARDWARE_FAILURE_CONTEXT) HardwareFailureContext); + + TraceExit(); +} diff --git a/usb/ufxclientsample/device.h b/usb/ufxclientsample/device.h new file mode 100644 index 00000000..7df5a4a3 --- /dev/null +++ b/usb/ufxclientsample/device.h @@ -0,0 +1,141 @@ +/*++ + +Module Name: + + device.h + +Abstract: + + This file contains the device definitions. + +Environment: + + Kernel-mode Driver Framework + +--*/ +#pragma once + +#include "driver.h" +#include "transfer.h" +#include "registers.h" +#include "ufxdevice.h" +#include <ntstrsafe.h> + +#define UFXCLIENT_TAG ('CXFU') // UFXC + +#define TEST_BIT(value, bitNumber) ((value) & (1<<(bitNumber))) ? TRUE : FALSE + +#define MAX_DMA_LENGTH 0x1000 + +#define UFX_CLIENT_ALIGNMENT 128 + +// +// Time interval to wait after being suspended and before requesting remote +// wakeup request +// +#define REMOTE_WAKEUP_TIMEOUT_INTERVAL_MS 1 + +// +// Context space for WDFDEVICE object representing the controller +// +typedef struct _CONTROLLER_CONTEXT { + + UFXDEVICE UfxDevice; + + WDFINTERRUPT DeviceInterrupt; + + WDFINTERRUPT WakeInterrupt; + + WDFINTERRUPT AttachDetachInterrupt; + + KEVENT DetachEvent; + + WDFDMAENABLER DmaEnabler; + + // + // This variable tells us if we have indicated to UFX, via UfxDeviceNotifyAttach, that we are + // attached. + // + BOOLEAN WasAttached; + + // + // This variable tracks what the hardware thinks about the current + // attachment status. It is updated right away based on incoming notifications. + // + volatile BOOLEAN Attached; + + // + // This variable tracks whether there was some change, possibly transient, in the attachment + // status. Simply inspecting "Attached", one may conclude that there was no change at all, but + // this variable will tell us if there was a rapid attach-detach or detach-attach event. + BOOLEAN GotAttachOrDetach; + + WDFSPINLOCK DpcLock; + + BOOLEAN RemoteWakeupRequested; + + BOOLEAN StopPending; + + BOOLEAN Connect; + + BOOLEAN Suspended; + + USB_DEVICE_SPEED Speed; + + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS IdleSettings; + + BOOLEAN InitializeDefaultEndpoint; + + WDFWAITLOCK InitializeDefaultEndpointLock; + +} CONTROLLER_CONTEXT, *PCONTROLLER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROLLER_CONTEXT, DeviceGetControllerContext) + + +typedef enum _UFX_CLIENT_EXCEPTION_CODE { + ExceptionDisconnectTimeout = 0, + ExceptionMaximum +} UFX_CLIENT_EXCEPTION_CODE, *PUFX_CLIENT_EXCEPTION_CODE; + +typedef struct _HARDWARE_FAILURE_CONTEXT { + ULONG Size; + UFX_CLIENT_EXCEPTION_CODE ExceptionCode; + CONTROLLER_CONTEXT ControllerContext; + UFXDEVICE_CONTEXT DeviceContext; +} HARDWARE_FAILURE_CONTEXT, *PHARDWARE_FAILURE_CONTEXT; + +// +// Function to initialize the device and its callbacks +// +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +UfxClientDeviceCreate ( + _In_ WDFDRIVER Driver, + _In_ PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +DevicePerformSoftReset ( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +DeviceHardwareFailure ( + _In_ WDFDEVICE Device, + _In_ ULONG ExceptionCode + ); + +VOID +DeviceVendorReset ( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceInitializeDefaultEndpoint ( + _In_ WDFDEVICE Device + ); diff --git a/usb/ufxclientsample/driver.c b/usb/ufxclientsample/driver.c new file mode 100644 index 00000000..1a1f5e1e --- /dev/null +++ b/usb/ufxclientsample/driver.c @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + driver.c + +Abstract: + + This file contains the driver entry points and callbacks. + +Environment: + + Kernel-mode Driver Framework + +--*/ + +#include "driver.h" +#include "device.h" +#include "driver.tmh" + + +DRIVER_INITIALIZE DriverEntry; + +// +// WDFDRIVER object Callbacks +// +EVT_WDF_DRIVER_DEVICE_ADD OnEvtDriverDeviceAdd; +EVT_WDF_DRIVER_UNLOAD OnEvtDriverUnload; + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, OnEvtDriverDeviceAdd) +#pragma alloc_text (PAGE, OnEvtDriverUnload) +#endif + + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. + + RegistryPath - represents the driver specific path in the Registry. + +Return Value: + + STATUS_SUCCESS if successful, appropriate NTSTATUS message otherwise. + +--*/ +{ + NTSTATUS Status; + WDF_DRIVER_CONFIG DriverConfig; + WDF_OBJECT_ATTRIBUTES DriverAttributes; + + // + // Enable ETW tracing + // + EventRegisterUfxClientSample(); + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING(DriverObject, RegistryPath); + + TraceEntry(); + + // + // Register 'EvtDriverUnload' to de-register WPP and ETW. + // + WDF_OBJECT_ATTRIBUTES_INIT(&DriverAttributes); + + WDF_DRIVER_CONFIG_INIT(&DriverConfig, OnEvtDriverDeviceAdd); + DriverConfig.DriverPoolTag = UFX_CLIENT_TAG; + DriverConfig.EvtDriverUnload = OnEvtDriverUnload; + + Status = WdfDriverCreate( + DriverObject, + RegistryPath, + &DriverAttributes, + &DriverConfig, + WDF_NO_HANDLE); + CHK_NT_MSG(Status, "Failed to create WDFDRIVER object"); + +End: + + if (NT_SUCCESS(Status) != TRUE) { + + // + // Stop WPP Tracing + // + WPP_CLEANUP(DriverObject); + + // + // Unregister ETW tracing + // + EventUnregisterUfxClientSample(); + goto Return; + } + + TraceExit(); +Return: + + return Status; +} + +NTSTATUS +OnEvtDriverDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDriverDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status; + + PAGED_CODE(); + + TraceEntry(); + + Status = UfxClientDeviceCreate(Driver, DeviceInit); + CHK_NT_MSG(Status, "Failed to create wdf device"); + +End: + TraceExit(); + return Status; +} + +VOID +OnEvtDriverUnload( + _In_ WDFDRIVER WdfDriver + ) +/*++ +Routine Description: + + Free-up all the driver wide common resources like WPP and ETW. + +Arguments: + + WdfDriver - Driver object being unload. + +--*/ +{ + PAGED_CODE (); + + TraceEntry(); + + // + // Stop WPP Tracing + // + WPP_CLEANUP(WdfDriverWdmGetDriverObject(WdfDriver)); + // + // Unregister ETW tracing + // + EventUnregisterUfxClientSample(); +} diff --git a/usb/ufxclientsample/driver.h b/usb/ufxclientsample/driver.h new file mode 100644 index 00000000..bed33089 --- /dev/null +++ b/usb/ufxclientsample/driver.h @@ -0,0 +1,33 @@ +/*++ + +Module Name: + + driver.h + +Abstract: + + This file contains the driver definitions. + +Environment: + + Kernel-mode Driver Framework + +--*/ + +#pragma once + +#include <ntddk.h> +#include <wdf.h> +#include "ufxclient.h" +#include "registers.h" +#include "trace.h" + +#define UFX_CLIENT_TAG ('cXFU') + + +//--------------------------------------------------------------------------- +// While macro to supress 4127 warning: Constant expression +//--------------------------------------------------------------------------- +#define WHILE(constant) \ + __pragma(warning(suppress:4127)) while(constant) + diff --git a/usb/ufxclientsample/event.c b/usb/ufxclientsample/event.c new file mode 100644 index 00000000..8f31c381 --- /dev/null +++ b/usb/ufxclientsample/event.c @@ -0,0 +1,340 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + events.c + +Abstract: + + Event handler + +Environment: + + Kernel mode + +--*/ + +#include "device.h" +#include "ufxdevice.h" +#include "ufxendpoint.h" +#include "transfer.h" +#include <usbspec.h> +#include "event.h" +#include "event.tmh" + + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleUsbReset ( + WDFDEVICE WdfDevice + ) +/*++ + +Routine Description: + + Handles a reset event notification from the controller. + +Arguments: + + WdfDevice - WDFDEVICE object representing the controller. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + UfxDevice_Reset(ControllerContext->UfxDevice); + + ControllerContext->RemoteWakeupRequested = FALSE; + + // + // Update the controller to set device address to 0 + // + + // + // #### TODO: Add code to set the USB device address to 0 on the controller #### + // + + TraceExit(); +} + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleUsbConnect ( + WDFDEVICE WdfDevice + ) +/*++ + +Routine Description: + + Handles a connect event from the controller. + +Arguments: + + WDfDevice - WDFDEVICE object representing the controller. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + USB_DEVICE_SPEED DeviceSpeed; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + // + // Read the device speed. + // + + // + // #### TODO: Add code to read device speed from the controller #### + // + + // Sample will assume SuperSpeed operation for illustration purposes + DeviceSpeed = UsbSuperSpeed; + + // + // #### TODO: Add any code needed to configure the controller after connect has occurred #### + // + + + ControllerContext->Speed = DeviceSpeed; + TraceInformation("Connected Speed is %d!", DeviceSpeed); + + // + // Notify UFX about reset, which will take care of updating + // Max Packet Size for EP0 by calling descriptor update. + // + UfxDeviceNotifyReset(ControllerContext->UfxDevice, DeviceSpeed); + + ControllerContext->Connect = TRUE; + + TraceExit(); +} + + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleUsbDisconnect ( + WDFDEVICE WdfDevice + ) +/*++ + +Routine Description: + + Handles a disconnect event from the controller. + +Arguments: + + WdfDevice - WDFDEVICE object representing the controller. + +--*/ +{ + TraceEntry(); + + UNREFERENCED_PARAMETER(WdfDevice); + + // + // #### TODO: Add any code needed to configure controller after disconnect event #### + // + + TraceExit(); +} + + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleUSBLinkStateChange ( + WDFDEVICE WdfDevice + ) +/*++ + +Routine Description: + + Handles a link change event from the controller. + +Arguments: + + WdfDevice - WDFDEVICE object representing the controller. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + ULONG UsbLinkEvent; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + // + // #### TODO: Add code to read link state from controller #### + // + // For sample purposes use U0. + UsbLinkEvent = USB_LINK_STATE_U0; + + if (UsbLinkEvent == USB_LINK_STATE_U0) { + + if(ControllerContext->Suspended) { + ControllerContext->Suspended = FALSE; + UfxDeviceNotifyResume(ControllerContext->UfxDevice); + } + + ControllerContext->RemoteWakeupRequested = FALSE; + + } else { + TraceVerbose("Ignoring link state change event: 0X%X", UsbLinkEvent); + } + + TraceExit(); +} + + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleDeviceEvent ( + WDFDEVICE WdfDevice, + DEVICE_EVENT DeviceEvent + ) +/*++ + +Routine Description: + + Function to dispatch device events from the controller. + +Arguments: + + WdfDevice - Wdf device object corresponding to the FDO + + DeviceEvent - Device specific event. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + switch (DeviceEvent) { + + case DeviceEventDisconnect: + ControllerContext->Suspended = FALSE; + HandleUsbDisconnect(WdfDevice); + break; + + case DeviceEventUSBReset: + ControllerContext->Suspended = FALSE; + HandleUsbReset(WdfDevice); + break; + + case DeviceEventConnect: + HandleUsbConnect(WdfDevice); + break; + + case DeviceEventUSBLinkStateChange: + HandleUSBLinkStateChange(WdfDevice); + break; + + case DeviceEventWakeUp: + if (ControllerContext->Suspended) { + ControllerContext->Suspended = FALSE; + UfxDeviceNotifyResume(ControllerContext->UfxDevice); + } + break; + + case DeviceEventSuspend: + if (!ControllerContext->Suspended) { + ControllerContext->Suspended = TRUE; + UfxDeviceNotifySuspend(ControllerContext->UfxDevice); + } + break; + + default: + TraceError("Unknown device event raised by controller"); + NT_ASSERT(FALSE); + break; + } + + TraceExit(); +} + + + + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleEndpointEvent ( + WDFDEVICE WdfDevice, + ENDPOINT_EVENT EndpointEvent + ) +/*++ + +Routine Description: + + Function to dispatch endpoint events. + +Arguments: + + WdfDevice - Wdf device object corresponding to the FDO + + EndpointEvent - Endpoint specific event. + +--*/ +{ + UFXENDPOINT Endpoint; + PCONTROLLER_CONTEXT ControllerContext; + PUFXDEVICE_CONTEXT DeviceContext; + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + DeviceContext = UfxDeviceGetContext(ControllerContext->UfxDevice); + + // + // #### TODO: Insert code to extract endpoint event and endpoint number #### + // + + // Sample will assume a transfer complete event on endpoint 1 for illustration purposes + EndpointEvent = EndpointEventTransferComplete; + + Endpoint = DeviceContext->PhysicalEndpointToUfxEndpoint[1]; + + switch (EndpointEvent) { + + case EndpointEventTransferComplete: + TraceInformation("ENDPOINT EVENT: TransferComplete"); + TransferComplete(Endpoint); + break; + + case EndpointEventStartTransferComplete: + TraceInformation("ENDPOINT EVENT: Complete Start Transfer"); + TransferCommandStartComplete(Endpoint); + break; + + case EndpointEventEndTransferComplete: + TraceInformation("ENDPOINT EVENT: Complete End Transfer"); + TransferCommandEndComplete(Endpoint); + break; + + case EndpointEventSetStall: + TraceInformation("ENDPOINT EVENT: Command Complete Stall Set"); + TransferStallSetComplete(Endpoint); + break; + + case EndpointEventClearStall: + TraceInformation("ENDPOINT EVENT: Command Complete Stall Clear"); + TransferStallClearComplete(Endpoint); + break; + + default: + TraceError("Unexpected endpoint event!"); + NT_ASSERT(FALSE); + } + + TraceExit(); +}
\ No newline at end of file diff --git a/usb/ufxclientsample/event.h b/usb/ufxclientsample/event.h new file mode 100644 index 00000000..54532415 --- /dev/null +++ b/usb/ufxclientsample/event.h @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + eventbuffer.h + +Abstract: + + Defines the sample controller's events + +Environment: + + Kernel mode + +--*/ +#pragma once + +typedef enum _CONTROLLER_EVENT_TYPE { + EventTypeDevice = 0, + EventTypeEndpoint = 1 +} CONTROLLER_EVENT_TYPE; + +typedef enum _DEVICE_EVENT { + DeviceEventDisconnect = 0, + DeviceEventUSBReset = 1, + DeviceEventConnect = 2, + DeviceEventUSBLinkStateChange = 3, + DeviceEventWakeUp = 4, + DeviceEventHibernationRequest = 5, + DeviceEventSuspend = 6, + DeviceEventCommandComplete = 7 +} DEVICE_EVENT, *PDEVICE_EVENT; + +typedef enum _ENDPOINT_EVENT { + EndpointEventTransferComplete = 0, + EndpointEventStartTransferComplete = 1, + EndpointEventEndTransferComplete = 2, + EndpointEventSetStall = 3, + EndpointEventClearStall = 4 +} ENDPOINT_EVENT, *PENDPOINT_EVENT; + +typedef struct _CONTROLLER_EVENT { + CONTROLLER_EVENT_TYPE Type; + + union { + DEVICE_EVENT DeviceEvent; + ENDPOINT_EVENT EndpointEvent; + } u; +} CONTROLLER_EVENT; + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleEndpointEvent ( + WDFDEVICE WdfDevice, + ENDPOINT_EVENT EndpointEvent + ); + +_IRQL_requires_(DISPATCH_LEVEL) +VOID +HandleDeviceEvent ( + WDFDEVICE WdfDevice, + DEVICE_EVENT DeviceEvent + ); diff --git a/usb/ufxclientsample/interrupt.c b/usb/ufxclientsample/interrupt.c new file mode 100644 index 00000000..2ce10c25 --- /dev/null +++ b/usb/ufxclientsample/interrupt.c @@ -0,0 +1,315 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + interrupt.c + +Abstract: + + Implements the WDF interrupt object's callbacks and functions to manage + the interrupts. + +Environment: + + Kernel mode + +--*/ + + +#include "device.h" +#include "interrupt.h" +#include "interrupt.tmh" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, InterruptCreate) +#endif + +EVT_WDF_INTERRUPT_ISR DeviceInterrupt_EvtInterruptIsr; +EVT_WDF_INTERRUPT_DPC DeviceInterrupt_EvtInterruptDpc; +EVT_WDF_INTERRUPT_ISR DeviceInterrupt_EvtAttachDetachInterruptIsr; + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +InterruptCreate ( + _In_ WDFDEVICE Device, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceRaw, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceTranslated + ) +/*++ + +Routine Description: + + Helper function to create device's WDFINTERRUPT object and any other + needed WDF resources that the interrupt needs for proper functioning. + + It assumes the first interrupt resource with which this is invoked is + the device interrupt, and the second is the attach/detach interrupt. + +Arguments: + + Device - Wdf device object corresponding to the FDO + + InterruptResourceRaw - Raw resource for the interrupt + + InterruptResourceTranslated - Translated resource for the interrupt + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + NTSTATUS Status; + WDF_INTERRUPT_CONFIG InterruptConfig; + PCONTROLLER_CONTEXT ControllerContext; + WDF_OBJECT_ATTRIBUTES Attributes; + WDFINTERRUPT* InterruptToCreate; + + TraceEntry(); + + PAGED_CODE(); + + ControllerContext = DeviceGetControllerContext(Device); + + WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); + + if (ControllerContext->DeviceInterrupt == NULL) { + WDF_INTERRUPT_CONFIG_INIT( + &InterruptConfig, + DeviceInterrupt_EvtInterruptIsr, + DeviceInterrupt_EvtInterruptDpc); + + WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE( + &Attributes, + DEVICE_INTERRUPT_CONTEXT); + + InterruptToCreate = &ControllerContext->DeviceInterrupt; + + } else if (ControllerContext->AttachDetachInterrupt == NULL) { + WDF_INTERRUPT_CONFIG_INIT( + &InterruptConfig, + DeviceInterrupt_EvtAttachDetachInterruptIsr, + DeviceInterrupt_EvtInterruptDpc); + InterruptConfig.CanWakeDevice = TRUE; + InterruptConfig.PassiveHandling = TRUE; + InterruptToCreate = &ControllerContext->AttachDetachInterrupt; + + } else { + TraceWarning("Other interrupt resource [0X%X] is detected and is being" + " ignored", InterruptResourceRaw->u.Interrupt.Vector); + Status = STATUS_SUCCESS; + goto End; + } + + InterruptConfig.InterruptRaw = InterruptResourceRaw; + InterruptConfig.InterruptTranslated = InterruptResourceTranslated; + + Status = WdfInterruptCreate( + Device, + &InterruptConfig, + &Attributes, + InterruptToCreate); + CHK_NT_MSG(Status, "Failed to create Device interrupt"); + +End: + TraceExit(); + return Status; +} + +BOOLEAN +DeviceInterrupt_EvtInterruptIsr( + _In_ WDFINTERRUPT Interrupt, + _In_ ULONG MessageID + ) +/*++ + +Routine Description: + + 'EvtInterruptIsr' handler for the device interrupt object. + http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx + +Arguments: + + Interrupt - Associated interrupt object. + + MessageID - Message IDs for MSI + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + BOOLEAN PendingEvents; + + TraceEntry(); + + UNREFERENCED_PARAMETER(MessageID); + + // + // #### TODO: Determine if controller has pending events. #### + // + + // Sample will assume there is always a pending event for illustration purposes. + PendingEvents = TRUE; + + if (PendingEvents) { + // + // Enqueue the DPC to handle the events. + // + WdfInterruptQueueDpcForIsr(Interrupt); + } + + TraceExit(); + return TRUE; +} + +VOID +DeviceInterrupt_EvtInterruptDpc ( + _In_ WDFINTERRUPT Interrupt, + _In_ WDFOBJECT AssociatedObject + ) +/*++ + +Routine Description: + + 'EvtInterruptDpc' handler for the device interrupt object. + http://msdn.microsoft.com/en-us/library/windows/hardware/ff541721(v=vs.85).aspx + +Arguments: + + Interrupt - Associated interrupt object. + + AssociatedObject - FDO Object + +--*/ +{ + WDFDEVICE WdfDevice; + PDEVICE_INTERRUPT_CONTEXT InterruptContext; + PCONTROLLER_CONTEXT ControllerContext; + BOOLEAN Attached; + BOOLEAN GotAttachOrDetach; + CONTROLLER_EVENT ControllerEvent; + + UNREFERENCED_PARAMETER(Interrupt); + + TraceEntry(); + + WdfDevice = (WDFDEVICE) AssociatedObject; + ControllerContext = DeviceGetControllerContext(WdfDevice); + + WdfSpinLockAcquire(ControllerContext->DpcLock); + + WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt); + Attached = ControllerContext->Attached; + GotAttachOrDetach = ControllerContext->GotAttachOrDetach; + ControllerContext->GotAttachOrDetach = FALSE; + WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt); + + // + // Handle attach/detach events + // + if (GotAttachOrDetach) { + if (Attached && ControllerContext->WasAttached) { + // + // We must have gotten at least one detach. Need to reset the state. + // + ControllerContext->RemoteWakeupRequested = FALSE; + ControllerContext->Suspended = FALSE; + UfxDeviceNotifyDetach(ControllerContext->UfxDevice); + } + + if (Attached) { + ControllerContext->RemoteWakeupRequested = FALSE; + ControllerContext->Suspended = FALSE; + UfxDeviceNotifyAttach(ControllerContext->UfxDevice); + } + } + + ControllerContext->WasAttached = Attached; + + InterruptContext = DeviceInterruptGetContext(ControllerContext->DeviceInterrupt); + + // + // #### TODO: Insert code to read and dispatch events from the controller #### + // + + // The sample will assume an endpoint event of EndpointEventTransferComplete + ControllerEvent.Type = EventTypeEndpoint; + ControllerEvent.u.EndpointEvent = EndpointEventTransferComplete; + + // + // Handle events from the controller + // + switch (ControllerEvent.Type) { + case EventTypeDevice: + HandleDeviceEvent(WdfDevice, ControllerEvent.u.DeviceEvent); + break; + + case EventTypeEndpoint: + HandleEndpointEvent(WdfDevice, ControllerEvent.u.EndpointEvent); + break; + } + + WdfSpinLockRelease(ControllerContext->DpcLock); + + TraceExit(); +} + +BOOLEAN +DeviceInterrupt_EvtAttachDetachInterruptIsr ( + _In_ WDFINTERRUPT Interrupt, + _In_ ULONG MessageID + ) +/*++ + +Routine Description: + + 'EvtInterruptIsr' handler for the attach/detach interrupt object. + http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx + +Arguments: + + Interrupt - Associated interrupt object. + + MessageID - Message IDs for MSI + +Return Value: + + BOOLEAN + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + + UNREFERENCED_PARAMETER(MessageID); + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfInterruptGetDevice(Interrupt)); + + WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt); + + // + // This is an ActiveBoth interrupt used for attach/detach. State is determined + // by counting interrupts. Previous state was attached, so this is a detach. + // + if (!ControllerContext->Attached) { + ControllerContext->Attached = TRUE; + ControllerContext->GotAttachOrDetach = TRUE; + + (void) WdfInterruptQueueDpcForIsr(Interrupt); + } else { + ControllerContext->Attached = FALSE; + ControllerContext->GotAttachOrDetach = TRUE; + (void) WdfInterruptQueueDpcForIsr(Interrupt); + } + + WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt); + + TraceExit(); + return TRUE; +} diff --git a/usb/ufxclientsample/interrupt.h b/usb/ufxclientsample/interrupt.h new file mode 100644 index 00000000..9fe520d2 --- /dev/null +++ b/usb/ufxclientsample/interrupt.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + interrupt.h + +Abstract: + + Defines the structures and functions needed to manage wdf interrupt object. + +Environment: + + Kernel mode + +--*/ +#pragma once + +#include "registers.h" + +// +// Context space for device WDFINTERRUPT object +// +typedef struct _DEVICE_INTERRUPT_CONTEXT { + + WDFCOMMONBUFFER Buffer; + +} DEVICE_INTERRUPT_CONTEXT, *PDEVICE_INTERRUPT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_INTERRUPT_CONTEXT, DeviceInterruptGetContext) + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +InterruptCreate ( + _In_ WDFDEVICE Device, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceRaw, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceTranslated + ); + + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +InterruptProgramEventBuffers ( + _In_ WDFINTERRUPT DeviceInterrupt + );
\ No newline at end of file diff --git a/usb/ufxclientsample/readme.md b/usb/ufxclientsample/readme.md new file mode 100644 index 00000000..ec39fd35 --- /dev/null +++ b/usb/ufxclientsample/readme.md @@ -0,0 +1,28 @@ +USB Function Client Driver +========================== + +This is a skeleton sample driver that shows how to create a Windows USB function controller driver using the USB function class extension driver (UFX). + +This sample demonstrates the following: + +- Registration with the UFX class extension driver +- Handling USB transfers +- Handling function controller events +- Handling attach and detach notifications +- Handling charger/port detection +- Power management + +Operating system requirements +----------------------------- + +Windows 10 Mobile + +Customizing the sample for your device +-------------------------------------- + +This sample is not a functional driver. It is a skeleton driver intended to illustrate the general design of a UFX client driver. The sample contains a number of comments prefaced with " #### TODO ", which indicates where code will need to be added to perform the controller operation as described in the comment. + +Installation Note +----------------- + +Installation on Windows 10 Mobile requires the creation of a package. To properly interact with the USB UI on Windows 10 Mobile, the package must include a Security Element that specifies the ID_CAP_USB capability with DEVICE_READ and DEVICE_WRITE rights. diff --git a/usb/ufxclientsample/registers.c b/usb/ufxclientsample/registers.c new file mode 100644 index 00000000..3784f90e --- /dev/null +++ b/usb/ufxclientsample/registers.c @@ -0,0 +1,90 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + registers.c + +Abstract: + + Memory mapping the controller's registers + +Environment: + + Kernel mode + +--*/ + +#include "device.h" +#include "registers.h" +#include "registers.tmh" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, RegistersCreate) +#endif + + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RegistersCreate( + _In_ WDFDEVICE Device, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR RegistersResource + ) +/*++ + +Routine Description: + + Helper function to map the memory resources to the HW registers. + +Arguments: + + Device - Wdf device object corresponding to the FDO + + RegisterResource - Raw resource for the memory + +Return Value: + + Appropriate NTSTATUS value + +--*/ +{ + NTSTATUS Status; + PREGISTERS_CONTEXT Context; + WDF_OBJECT_ATTRIBUTES Attributes; + + TraceEntry(); + + PAGED_CODE(); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, REGISTERS_CONTEXT); + + Status = WdfObjectAllocateContext(Device, &Attributes, &Context); + if (Status == STATUS_OBJECT_NAME_EXISTS) { + // + // In the case of a resource rebalance, the context allocated + // previously still exists. + // + Status = STATUS_SUCCESS; + RtlZeroMemory(Context, sizeof(*Context)); + } + CHK_NT_MSG(Status, "Failed to allocate context for registers"); + + Context->RegisterBase = MmMapIoSpaceEx( + RegistersResource->u.Memory.Start, + RegistersResource->u.Memory.Length, + PAGE_NOCACHE | PAGE_READWRITE); + + if (Context->RegisterBase == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + CHK_NT_MSG(Status, "MmMapIoSpaceEx failed"); + } + + Context->RegistersLength = RegistersResource->u.Memory.Length; + +End: + + TraceExit(); + return Status; +}
\ No newline at end of file diff --git a/usb/ufxclientsample/registers.h b/usb/ufxclientsample/registers.h new file mode 100644 index 00000000..bf88e9e8 --- /dev/null +++ b/usb/ufxclientsample/registers.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + registers.h + +Abstract: + +Environment: + + Kernel mode + +--*/ +#pragma once + +#include <pshpack4.h> +#pragma warning(push) +// +// #### TODO: Add controller data structure definitions here #### +// +#pragma warning(pop) +#include <poppack.h> + + +#define USB_LINK_STATE_U0 0 +#define USB_LINK_STATE_U1 1 +#define USB_LINK_STATE_U2 2 +#define USB_LINK_STATE_U3 3 +#define USB_LINK_STATE_SS_DISABLED 4 +#define USB_LINK_STATE_RX_DETECT 5 +#define USB_LINK_STATE_SS_INACTIVE 6 +#define USB_LINK_STATE_POLLING 7 +#define USB_LINK_STATE_RECOVERY 8 +#define USB_LINK_STATE_HOT_RESET 9 +#define USB_LINK_STATE_COMPLIANCE_MODE 10 +#define USB_LINK_STATE_LOOPBACK 11 +#define USB_LINK_STATE_RESUME_RESET 15 + + +typedef struct _REGISTERS_CONTEXT { + + PUCHAR RegisterBase; + + SIZE_T RegistersLength; + +} REGISTERS_CONTEXT, *PREGISTERS_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REGISTERS_CONTEXT, DeviceGetRegistersContext) + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +RegistersCreate( + _In_ WDFDEVICE Device, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR RegistersResource + );
\ No newline at end of file diff --git a/usb/ufxclientsample/trace.h b/usb/ufxclientsample/trace.h new file mode 100644 index 00000000..00ce3513 --- /dev/null +++ b/usb/ufxclientsample/trace.h @@ -0,0 +1,113 @@ +/*++ + +Module Name: + + Trace.h + +Abstract: + + Header file for the debug tracing related functions and macros. + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#include "UfxClientSample.h" + +// +// Define the tracing flags. +// +// WPP Tracing GUID - 302A11C3-1DB2-4B1E-B549-F5300003894A +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + UfxClientSampleWPPGuid, (302A11C3,1DB2,4B1E,B549,F5300003894A), \ + WPP_DEFINE_BIT(FlagDriverWideLog) \ + WPP_DEFINE_BIT(FlagCallStack) \ + ) + +#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) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace* functions +// +// begin_wpp config +// FUNC TraceMessage(LEVEL,FLAGS, MSG,...); +// FUNC TraceFatal{LEVEL=TRACE_LEVEL_FATAL,FLAGS=FlagDriverWideLog}(MSG,...); +// FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR,FLAGS=FlagDriverWideLog}(MSG,...); +// FUNC TraceWarning{LEVEL=TRACE_LEVEL_WARNING,FLAGS=FlagDriverWideLog}(MSG,...); +// FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION,FLAGS=FlagDriverWideLog}(MSG,...); +// FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=FlagDriverWideLog}(MSG,...); +// end_wpp +// + + +// This block defines the function entry and exit functions +// +// begin_wpp config +// FUNC TraceEntry(); +// FUNC TraceExit(); +// USESUFFIX(TraceEntry, "==>%!FUNC!"); +// USESUFFIX(TraceExit, "<==%!FUNC!"); +// end_wpp +// +#define WPP__ENABLED() WPP_LEVEL_ENABLED(FlagCallStack) +#define WPP__LOGGER() WPP_LEVEL_LOGGER(FlagCallStack) + + +// +// This block defines a CHK_NT_MSG macro that: +// 1. Checks the NTSTATUS message in the first parameter +// 2. Logs status message to WPP and ETW, if the status indicates a failure +// 3. Jumps to label "End" +// +// begin_wpp config +// FUNC CHK_NT_MSG{CHK=DUMMY,LEVEL=TRACE_LEVEL_ERROR,FLAGS=FlagDriverWideLog}(STATUS, MSG, ...); +// USESUFFIX(CHK_NT_MSG, "[%!STATUS!]", STATUS); +// end_wpp +// +#define WPP_CHK_LEVEL_FLAGS_STATUS_PRE(CHK,LEVEL,FLAGS,STATUS) { \ + if (NT_SUCCESS(STATUS) != TRUE) { + +#define WPP_CHK_LEVEL_FLAGS_STATUS_POST(CHK,LEVEL,FLAGS,STATUS) ;\ + EventWriteFailedNtStatus(&UfxClientSampleGuid, __FILE__, __LINE__, STATUS); \ + goto End; \ + } } +#define WPP_CHK_LEVEL_FLAGS_STATUS_ENABLED(chk,level,flags,status) WPP_LEVEL_ENABLED(flags) +#define WPP_CHK_LEVEL_FLAGS_STATUS_LOGGER(chk,level,flags,status) WPP_LEVEL_LOGGER(flags) + +// +// This block defines a LOG_NT_MSG macro that: +// 1. Checks the NTSTATUS message in the first parameter +// 2. And just logs the status message to WPP and ETW, if it indicates a failure +// +// begin_wpp config +// FUNC LOG_NT_MSG{LOG=DUMMY,LEVEL=TRACE_LEVEL_ERROR,FLAGS=FlagDriverWideLog}(STATUS, MSG, ...); +// USESUFFIX(CHK_NT_MSG, "[%!STATUS!]", STATUS); +// end_wpp +// +#define WPP_LOG_LEVEL_FLAGS_STATUS_PRE(CHK,LEVEL,FLAGS,STATUS) { \ + if (NT_SUCCESS(STATUS) != TRUE) { + +#define WPP_LOG_LEVEL_FLAGS_STATUS_POST(CHK,LEVEL,FLAGS,STATUS) ;\ + EventWriteFailedNtStatus(&UfxClientSampleGuid, __FILE__, __LINE__, STATUS); \ + } } + +#define WPP_LOG_LEVEL_FLAGS_STATUS_ENABLED(chk,level,flags,status) WPP_LEVEL_ENABLED(flags) +#define WPP_LOG_LEVEL_FLAGS_STATUS_LOGGER(chk,level,flags,status) WPP_LEVEL_LOGGER(flags) + +// +// This should optimize WPP macros by disbaling checking for 'WPP_INIT_TRACING' +// (okay, because we enable WPP tracing in Driver entry) +// +#define WPP_CHECK_INIT diff --git a/usb/ufxclientsample/transfer.c b/usb/ufxclientsample/transfer.c new file mode 100644 index 00000000..0a34b8f4 --- /dev/null +++ b/usb/ufxclientsample/transfer.c @@ -0,0 +1,2230 @@ +/*++ + +Module Name: + + transfer.c + +Abstract: + + Transfer related functions + +Environment: + + Kernel mode + +--*/ + +#include "transfer.h" +#include "ufxendpoint.h" +#include "registers.h" +#include "device.h" +#include "ufxdevice.h" +#include <usbfnioctl.h> +#include "trace.h" +#include "transfer.tmh" + +#define MAX_PHYSICAL_ENDPOINTS 32 +#define COMMON_BUFFER_ALIGNMENT 15 +#define ENDPOINT_COMMON_BUFFER_SIZE 0x60 +#define DATA_ALIGNMENT 63 + +FORCEINLINE +VOID +TraceTransfer ( + _In_ PCSTR Stage, + _In_ UFXENDPOINT Endpoint, + _In_opt_ WDFREQUEST Request + ) +{ + WDFDMATRANSACTION Transaction; + ULONG BytesRequested; + ULONG BytesProgrammed; + ULONG BytesTransferred; + ULONG SgProgrammed; + ULONG SgLength; + + Transaction = NULL; + BytesRequested = 0; + BytesProgrammed = 0; + BytesTransferred = 0; + SgProgrammed = 0; + SgLength = 0; + + if (Request == NULL) { + Transaction = UfxEndpointGetTransferContext(Endpoint)->Transaction; + if (Transaction != NULL) { + PDMA_CONTEXT DmaContext; + DmaContext = DmaGetContext(Transaction); + Request = DmaContext->Request; + } + } + + if (Request != NULL) { + PREQUEST_CONTEXT RequestContext; + RequestContext = RequestGetContext(Request); + + if (RequestContext->Transaction != NULL) { + PDMA_CONTEXT DmaContext; + DmaContext = DmaGetContext(RequestContext->Transaction); + + Transaction = RequestContext->Transaction; + BytesRequested = DmaContext->BytesRequested; + BytesProgrammed = DmaContext->BytesProgrammed; + BytesTransferred = BytesProgrammed - DmaContext->BytesRemaining; + if (DmaContext->SgList != NULL) { + SgProgrammed = DmaContext->SgIndex; + SgLength = DmaContext->SgList->NumberOfElements; + } + } + } + + EventWriteTransfer( + &UfxClientSampleGuid, + Stage, + (ULONG) Endpoint, + UfxEndpointGetContext(Endpoint)->PhysicalEndpoint, + (ULONG) Request, + (ULONG) Transaction, + BytesRequested, + BytesProgrammed, + BytesTransferred, + SgProgrammed, + SgLength); + + TraceInformation("TRANSFER %s: %08X (%d), RQ: %08X, DMA: %08X, BytesReq: %08X, BytesProg: %08X, BytesTrans: %08X, SG: %d/%d", + Stage, (ULONG) Endpoint, UfxEndpointGetContext(Endpoint)->PhysicalEndpoint, (ULONG) Request, + (ULONG) Transaction, BytesRequested, BytesProgrammed, BytesTransferred, SgProgrammed, SgLength); +} + +#define TRACE_TRANSFER(Stage, Endpoint, Request) \ + TraceTransfer(Stage, Endpoint, Request) + +EVT_WDF_PROGRAM_DMA OnEvtProgramDma; +EVT_WDF_REQUEST_CANCEL OnEvtRequestCancel; +EVT_WDF_WORKITEM TransferCompleteNext; + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferNextRequest ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferRequestTryUnmarkCancelableAndCleanup ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferCancelCleanup ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +_IRQL_saves_global_(EpTransferLock, Endpoint) +VOID +TransferLock ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Recursive Spinlock Lock + +Parameters Description: + + Endpoint - The endpoint to lock + +--*/ +{ + WdfSpinLockAcquire(UfxEndpointGetTransferContext(Endpoint)->TransferLock); +} + +_IRQL_requires_(DISPATCH_LEVEL) +_IRQL_restores_global_(EpTransferLock, Endpoint) +VOID +TransferUnlock ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Recursive Spinlock Unlock + +Parameters Description: + + Endpoint - The endpoint to unlock + +--*/ +{ + WdfSpinLockRelease(UfxEndpointGetTransferContext(Endpoint)->TransferLock); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +CommandStallSet ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Sends a stall set command on the endpoint. + +Parameters Description: + + Endpoint - Endpoint to set stall. +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + // + // #### TODO: Insert code to set stall on the endpoint #### + // + + TransferContext->Stalled = TRUE; + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +CommandStallClear ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Sends a stall clear command on the endpoint. + +Parameters Description: + + Endpoint - Endpoint to clear stall. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + NT_ASSERT(!CONTROL_ENDPOINT(Endpoint)); + + // + // #### TODO: Insert code to clear stall on the endpoint #### + // + + TransferContext->Stalled = FALSE; + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandEnd ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Commands the controller to End Transfer. + +Parameters Description: + + Endpoint - The endpoint on which to transfer. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + NT_ASSERT(TransferContext->TransferStarted); + if (!TransferContext->EndRequested) { + + TransferContext->EndRequested = TRUE; + + // + // #### TODO: Insert code to end the transfer on the endpoint #### + // + + } + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStart ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Commands the controller to Start Transfer. + +Parameters Description: + + Endpoint - The endpoint on which to transfer. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + TransferContext->TransferStarted = TRUE; + TransferContext->TransferCommandStartComplete = FALSE; + + // + // #### TODO: Insert code to start the transfer on the endpoint #### + // + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandUpdate ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Commands the controller to Update Transfer. + +Parameters Description: + + Endpoint - The endpoint on which to transfer. + +--*/ +{ + TraceEntry(); + + UNREFERENCED_PARAMETER(Endpoint); + + // + // #### TODO: Insert code to update the transfer on the endpoint #### + // + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStartOrUpdate ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + If Start Transfer has not been called the the ProgrammingRequest, + then this will call Start Transfer, otherwise Update Transfer. + +Parameters Description: + + Endpoint - The endpoint on which to transfer. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + if (TransferContext->TransferStarted) { + TransferCommandUpdate(Endpoint); + + } else { + TransferCommandStart(Endpoint); + } + + TraceExit(); +} + +VOID +TransferDmaExecute ( + _In_opt_ WDFDMATRANSACTION Transaction + ) +/*++ +Routine Description: + + Execute a DMA transfer for non-zero length transfer. + +Parameters Description: + + Transaction - Transaction to execute. + +--*/ +{ + TraceEntry(); + + if (Transaction != NULL) { + NTSTATUS Status; + PDMA_CONTEXT DmaContext; + UFXENDPOINT Endpoint; + + DmaContext = DmaGetContext(Transaction); + Endpoint = DmaContext->Endpoint; + + if (!DmaContext->ZeroLength) { + Status = WdfDmaTransactionExecute(Transaction, DmaContext->Endpoint); + LOG_NT_MSG(Status, "Failed to execute DMA Transaction"); + + if (!NT_SUCCESS(Status)) { + WDFDMATRANSACTION NewTransaction = NULL; + + TransferLock(Endpoint); + if (DmaContext->CleanupOnProgramDma) { + NewTransaction = TransferCancelCleanup(Endpoint); + } else { + NewTransaction = TransferRequestTryUnmarkCancelableAndCleanup(Endpoint); + } + TransferUnlock(Endpoint); + TransferDmaExecute(NewTransaction); + } + } + } + + TraceExit(); +} + +VOID +OnEvtRequestCancel ( + _In_ WDFREQUEST Request + ) +/*++ +Routine Description: + + EvtRequestCancel callback for cancellable transfer requests. + This cancels a programmed transfer request by issuing a corresponding + 'TransferEnd' command to the contoller. + +Parameters Description: + + Request - Request being cancelled. + +--*/ +{ + TraceEntry(); + TransferRequestCancel(Request, FALSE); + TraceExit(); +} + +_Use_decl_annotations_ +VOID +TransferRequestCancel ( + WDFREQUEST Request, + BOOLEAN QueueIsStopped + ) +/*++ +Routine Description: + + This cancels a programmed transfer request by issuing a corresponding + 'TransferEnd' command to the contoller. + +Parameters Description: + + Request - Request being cancelled. + + QueueIsStopped - indicates if this request is being stopped and cancellation + should avoid fetching subsequent request from queue + +--*/ +{ + PREQUEST_CONTEXT RequestContext; + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION NewTransaction; + UFXENDPOINT Endpoint; + NTSTATUS Status; + BOOLEAN Cleanup; + + TraceEntry(); + + RequestContext = RequestGetContext(Request); + TransferContext = UfxEndpointGetTransferContext(RequestContext->Endpoint); + NewTransaction = NULL; + Endpoint = RequestContext->Endpoint; + + TransferLock(Endpoint); + + if (QueueIsStopped) { + TRACE_TRANSFER("STOP", Endpoint, Request); + RequestContext->QueueIsStopped = TRUE; + + Status = WdfRequestUnmarkCancelable(Request); + CHK_NT_MSG(Status, "WdfRequestUnmarkCancelable failed during queue stop"); + + } else { + TRACE_TRANSFER("CANCEL", Endpoint, Request); + } + + // + // After this function exists, KMDF will release the reference to this + // request. Acquire a reference to make sure it doesn't get deleted. + // + RequestContext->ReferencedOnCancel = TRUE; + WdfObjectReference(Request); + + Cleanup = TRUE; + if (RequestContext->Transaction != NULL) { + PDMA_CONTEXT DmaContext; + + DmaContext = DmaGetContext(RequestContext->Transaction); + + // + // Try to cancel the transaction. If we succeed, we can complete the request. + // + if (!DmaContext->State == NotExecuted) { + if (WdfDmaTransactionCancel(RequestContext->Transaction)) { + // + // Contrary to what MSDN says, completing the transaction at this point + // is considered an error by driver verifier since the DMA state is + // FxDmaTransactionStateTransferFailed. + // + + DmaContext->State = Cancelled; + + } else { + DmaContext->CleanupOnProgramDma = TRUE; + Cleanup = FALSE; + } + } + } + + // + // If a transfer is in progress, end it. Otherwise, just clean + // up the request. + // + if (TransferContext->TransferStarted) { + TransferContext->CleanupOnEndComplete = TRUE; + TransferCommandEnd(Endpoint); + + } else if (Cleanup) { + NewTransaction = TransferCancelCleanup(Endpoint); + } + +End: + TransferUnlock(Endpoint); + TransferDmaExecute(NewTransaction); + + TraceExit(); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferSetupPacket ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Programs a setup packet for a control endpoint. This must be called + when the endpoint is first configured, when it is stalled, + and every time a handshake is completed. + +Parameters Description: + + Endpoint - The endpoint on which to transfer. + +--*/ +{ + PCONTROL_CONTEXT ControlContext; + + TraceEntry(); + + ControlContext = UfxEndpointGetControlContext(Endpoint); + + TRACE_TRANSFER("SETUP", Endpoint, NULL); + + // + // Start transfer + // + + TransferCommandStart(Endpoint); + ControlContext->SetupRequested = TRUE; + ControlContext->HandshakeRequested = FALSE; + ControlContext->DataStageExists = FALSE; + ControlContext->ReadyForHandshake = FALSE; + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferRequestTryUnmarkCancelableAndCleanup ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Attempt to cancel a pending transfer for an endpoint + +Parameters Description: + + Endpoint - The endpoint for the transfer to be cancelled. + +--*/ +{ + NTSTATUS Status; + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION NewTransaction; + WDFREQUEST RequestToCancel; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + NewTransaction = NULL; + RequestToCancel = NULL; + + // + // Try to find a request to clean up. + // + if (TransferContext->Transaction != NULL) { + PDMA_CONTEXT DmaContext; + DmaContext = DmaGetContext(TransferContext->Transaction); + + RequestToCancel = DmaContext->Request; + + } else if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + ControlContext = UfxEndpointGetControlContext(Endpoint); + + RequestToCancel = ControlContext->HandshakeRequest; + } + + // + // Before canceling, we need to make sure we can unmark it cancelable. + // If not, then EvtRequestCancel will get called, and it will cancel + // the request. + // + if (RequestToCancel != NULL) { + Status = WdfRequestUnmarkCancelable(RequestToCancel); + CHK_NT_MSG(Status, "Failed to unmark cancelable on try cleanup"); + } + + NewTransaction = TransferCancelCleanup(Endpoint); + +End: + TraceExit(); + return NewTransaction; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferCancelCleanup ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Cleans up and cancels the current transfer for an endpoint + +Parameters Description: + + Endpoint - The endpoint for the transfer to be cancelled. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + NTSTATUS Status; + WDFDMATRANSACTION Transaction; + BOOLEAN FetchNextRequest; + WDFREQUEST RequestToCancel; + WDFDMATRANSACTION NewTransaction; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + FetchNextRequest = FALSE; + Transaction = NULL; + RequestToCancel = NULL; + NewTransaction = NULL; + + // + // Reset data transfer state and complete request + // + Transaction = TransferContext->Transaction; + if (Transaction != NULL) { + PDMA_CONTEXT DmaContext; + + DmaContext = DmaGetContext(Transaction); + + RequestToCancel = DmaContext->Request; + TRACE_TRANSFER("CLEANUP (Data)", Endpoint, RequestToCancel); + if (DmaContext->State == Executed) { + (void) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &Status); + DmaContext->State = Completed; + } + WdfObjectDelete(Transaction); + TransferContext->Transaction = NULL; + } + + // + // Reset control endpoint state. + // + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + + ControlContext = UfxEndpointGetControlContext(Endpoint); + ControlContext->DataStageExists = FALSE; + ControlContext->HandshakeRequested = FALSE; + ControlContext->SetupRequested = FALSE; + ControlContext->ReadyForHandshake = FALSE; + if (ControlContext->HandshakeRequest != NULL) { + RequestToCancel = ControlContext->HandshakeRequest; + TRACE_TRANSFER("CLEANUP (Handshake)", Endpoint, RequestToCancel); + ControlContext->HandshakeRequest = NULL; + } + } + + if (RequestToCancel != NULL) { + BOOLEAN Referenced; + PREQUEST_CONTEXT RequestContext; + + RequestContext = RequestGetContext(RequestToCancel); + + FetchNextRequest = !RequestContext->QueueIsStopped; + + Referenced = RequestContext->ReferencedOnCancel; + + // + // In case the completion work-item has already been queued, prevent + // it from also trying to complete this request when it executes. + // + TransferContext->PendingCompletion = FALSE; + + WdfRequestComplete(RequestToCancel, STATUS_CANCELLED); + if (Referenced) { + WdfObjectDereference(RequestToCancel); + } + } + + // + // If endpoint is disabled, need to clear any stall. + // + if (!TransferContext->Enabled) { + if (TransferContext->Stalled) { + CommandStallClear(Endpoint); + } + + // + // Bring control endpoint back to setup stage. + // + } else if (CONTROL_ENDPOINT(Endpoint)) { + TransferSetupPacket(Endpoint); + + // + // Otherwise, we can check if there's another request. + // + } else if (FetchNextRequest) { + NewTransaction = TransferNextRequest(Endpoint); + } + + TraceExit(); + + return NewTransaction; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferProgram ( + UFXENDPOINT Endpoint, + WDFDMATRANSACTION Transaction + ) +/*++ +Routine Description: + + DMA callback for transfers that use DMA. This function may be called + multiple times for a single transfer request. + +Parameters Description: + + Endpoint - The endpoint for the transfer. + + Transaction - The DMA transaction object associated with the request. + +Return Value: + + TRUE if nothing went wrong, FALSE otherwise. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + PDMA_CONTEXT DmaContext; + PUFXENDPOINT_CONTEXT EpContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + EpContext = UfxEndpointGetContext(Endpoint); + DmaContext = DmaGetContext(Transaction); + + DmaContext->BytesProgrammedCurrent = 0; + DmaContext->BytesRemaining = 0; + + TRACE_TRANSFER("PROGRAMMING", Endpoint, DmaContext->Request); + + // + // Try to program transfer structures + // + while (DmaContext->SgIndex < DmaContext->SgList->NumberOfElements) { + PSCATTER_GATHER_ELEMENT Sg; + BOOLEAN NoMoreSgs; + BOOLEAN DmaComplete; + BOOLEAN LastSgInDma; + + Sg = &DmaContext->SgList->Elements[DmaContext->SgIndex]; + + NoMoreSgs = (DmaContext->SgIndex == DmaContext->SgList->NumberOfElements - 1); + LastSgInDma = ((DmaContext->BytesProgrammed + Sg->Length) == DmaContext->BytesRequested); + + // + // #### TODO: Insert code to map scatter gather buffers to controller transfer structures #### + // + + // + // Need to remember how much we really programmed + // + DmaContext->BytesProgrammed += Sg->Length; + DmaContext->BytesProgrammedCurrent += Sg->Length; + DmaComplete = (DmaContext->BytesProgrammed == DmaContext->BytesRequested); + + // + // Advance to next SG + // + DmaContext->SgIndex += 1; + } + + // + // Append IN ZLP or extra OUT buffer if needed. + // + if (DmaContext->BytesProgrammed == DmaContext->BytesRequested && + DmaContext->NeedExtraBuffer) { + + TRACE_TRANSFER("EXTRA", Endpoint, DmaContext->Request); + + // + // #### TODO: Insert code to append an extra buffer to the transfer structures #### + // + + } + + // + // Update the BytesRemaining to reflect all the programmed bytes + // + DmaContext->BytesRemaining = DmaContext->BytesProgrammedCurrent; + + // + // Finally, send the command to start or continue this transfer. + // + TransferCommandStartOrUpdate(Endpoint); + + TRACE_TRANSFER("PROGRAMMING--", Endpoint, DmaContext->Request); + + TraceExit(); +} + +BOOLEAN +OnEvtProgramDma ( + _In_ WDFDMATRANSACTION Transaction, + _In_ WDFDEVICE Device, + _In_ WDFCONTEXT Context, + _In_ WDF_DMA_DIRECTION Direction, + _In_ PSCATTER_GATHER_LIST SgList + ) +/*++ +Routine Description: + + WDF EvtProgramDma event callback function + +Parameters Description: + + Transaction - The DMA transaction object associated with the request. + + Device - The device. + + Context - The UFXENDPOINT associated with the request. + + Direction - The direction of the transfer. + + SgList - An array of logical pointers to chunks of the data buffer. + +--*/ +{ + NTSTATUS Status; + UFXENDPOINT Endpoint; + PDMA_CONTEXT DmaContext; + WDFDMATRANSACTION NewTransaction; + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Direction); + + TraceEntry(); + + Endpoint = (UFXENDPOINT) Context; + DmaContext = DmaGetContext(Transaction); + + TransferLock(Endpoint); + + DmaContext->State = Executed; + NewTransaction = NULL; + + // + // EvtRequestCancel was called, but couldn't cancel the + // request becuase this function needed to run. + // + if (DmaContext->CleanupOnProgramDma) { + NewTransaction = TransferCancelCleanup(Endpoint); + goto End; + } + + // + // Don't program cancelled requests. + // + Status = WdfRequestUnmarkCancelable(DmaContext->Request); + CHK_NT_MSG(Status, "WdfRequestUnmarkCancelable failed during programming"); + + Status = WdfRequestMarkCancelableEx(DmaContext->Request, OnEvtRequestCancel); + if (Status == STATUS_CANCELLED) { + LOG_NT_MSG(Status, "Request cancelled during programming"); + NewTransaction = TransferCancelCleanup(Endpoint); + goto End; + + } else { + CHK_NT_MSG(Status, "Failed to mark request cancelable"); + } + + DmaContext->SgList = SgList; + DmaContext->SgIndex = 0; + TransferProgram(Endpoint, Transaction); + Transaction = NULL; + +End: + TransferUnlock(Endpoint); + TransferDmaExecute(NewTransaction); + TraceExit(); + return TRUE; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandEndComplete ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles endpoint command complete event for the End Transfer commmand. + +Parameters Description: + + Endpoint - The endpoint that received the event. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION Transaction; + + TraceEntry(); + + TransferLock(Endpoint); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + TransferContext->TransferStarted = FALSE; + TransferContext->EndRequested = FALSE; + + Transaction = NULL; + if (TransferContext->CleanupOnEndComplete) { + TransferContext->CleanupOnEndComplete = FALSE; + Transaction = TransferCancelCleanup(Endpoint); + } + + TransferUnlock(Endpoint); + TransferDmaExecute(Transaction); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStartComplete ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles endpoint command complete event for the Start Transfer commmand. + +Parameters Description: + + Endpoint - The endpoint that received the event. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION Transaction; + ULONG CommandStatus; + + TraceEntry(); + + TransferLock(Endpoint); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + Transaction = NULL; + + // + // #### TODO: Insert code to determine status of command #### + // + + // sample will assume no error for illustration purposes + CommandStatus = 0; + + // + // Command start has failed. Clean up the request. + // + if (CommandStatus != 0) { + TRACE_TRANSFER("START FAIL", Endpoint, NULL); + + TransferContext->TransferStarted = FALSE; + + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + + ControlContext = UfxEndpointGetControlContext(Endpoint); + + if (ControlContext->SetupRequested) { + // + // Error on a setup request. Wait for host to reset us or user reconnect. + // + TraceError("ERROR: Failed a setup packet!"); + NT_ASSERT(FALSE); + + } else { + CommandStallSet(Endpoint); + } + + } else { + Transaction = TransferRequestTryUnmarkCancelableAndCleanup(Endpoint); + } + + } else { + TransferContext->TransferCommandStartComplete = TRUE; + } + + TransferUnlock(Endpoint); + TransferDmaExecute(Transaction); + TraceExit(); +} + +VOID +TransferCompleteNext ( + WDFWORKITEM WorkItem +) +/*++ +Routine Description: + + Work item function that handles completion of a transfer + +Parameters Description: + + WorkItem - Work item that was queued to execute this function. + +--*/ +{ + NTSTATUS Status; + WDFDMATRANSACTION Transaction; + PTRANSFER_CONTEXT TransferContext; + PDMA_CONTEXT DmaContext; + UFXENDPOINT Endpoint; + + TraceEntry(); + + Endpoint = WdfWorkItemGetParentObject(WorkItem); + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + TransferLock(Endpoint); + + // + // See if the request was completed by the cancellation code + // before this work-item executed. + // + if (TransferContext->PendingCompletion == FALSE) { + Transaction = NULL; + goto End; + } + + Transaction = TransferContext->Transaction; + + // + // Make sure request wasn't cancelled before work item got to run. + // + if (Transaction == NULL) { + goto End; + } + + DmaContext = DmaGetContext(Transaction); + + if (DmaContext->State == Executed) { + DmaContext->State = Completed; + (void) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &Status); + } + + Status = WdfRequestUnmarkCancelable(DmaContext->Request); + if (NT_SUCCESS(Status)) { + ULONG BytesTransferred; + TRACE_TRANSFER("COMPLETE", Endpoint, DmaContext->Request); + + BytesTransferred = DmaContext->BytesProgrammed - DmaContext->BytesRemaining; + if (BytesTransferred > DmaContext->BytesRequested) { + TraceWarning("Transferred more than what is asked for: " + "Bytes Requested: %d, Bytes Transferred:%d", + DmaContext->BytesRequested, BytesTransferred); + BytesTransferred = DmaContext->BytesRequested; + } + + TransferContext->PendingCompletion = FALSE; + + WdfRequestCompleteWithInformation( + DmaContext->Request, + Status, + BytesTransferred); + WdfObjectDelete(Transaction); + TransferContext->Transaction = NULL; + } else { + Transaction = NULL; + CHK_NT_MSG(Status, "Failed to unmark status cancellable"); + } + + TransferContext->TransferStarted = FALSE; + Transaction = TransferNextRequest(Endpoint); + +End: + TransferUnlock(Endpoint); + + if (Transaction != NULL) { + TransferDmaExecute(Transaction); + } + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCompleteData ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles completion of a data transfer for an endpoint. + +Parameters Description: + + Endpoint - The endpoint that completed the data transfer. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + ULONG BytesRemaining; + WDFDMATRANSACTION Transaction; + PDMA_CONTEXT DmaContext; + WDFDMATRANSACTION NewTransaction; + BOOLEAN TransferComplete; + + TraceEntry(); + + TransferLock(Endpoint); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + BytesRemaining = 0; + NewTransaction = NULL; + + // + // Make sure request wasn't cancelled. + // + Transaction = TransferContext->Transaction; + if (Transaction == NULL) { + TRACE_TRANSFER("COMPLETION SKIPPED - Cancelled", Endpoint, NULL); + goto End; + } + + DmaContext = DmaGetContext(Transaction); + + // + // #### TODO: Insert code to determine if the transfer is complete, or terminated due to a short packet. #### + + // Sample will assume transfer is complete + TransferComplete = TRUE; + + // + // If the transfer is complete we need to complete the request. + // + if (TransferComplete) { + DmaContext->BytesRemaining = BytesRemaining; + TRACE_TRANSFER("COMPLETE (Last packet or short packet)", Endpoint, NULL); + TransferContext->PendingCompletion = TRUE; + WdfWorkItemEnqueue(TransferContext->CompletionWorkItem); + + // + // If transfer is still in progress, we need to program more transfers + // + } else { + NTSTATUS Status; + ULONG BytesTransferred; + + TRACE_TRANSFER("COMPLETE (In Progress)", Endpoint, NULL); + + DmaContext->State = NotExecuted; + + BytesTransferred = DmaContext->BytesProgrammedCurrent - BytesRemaining; + + TransferUnlock(Endpoint); + WdfDmaTransactionDmaCompletedWithLength(Transaction, BytesTransferred, &Status); + TransferLock(Endpoint); + + NT_ASSERT(!NT_SUCCESS(Status)); + + if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status)) { + NewTransaction = TransferRequestTryUnmarkCancelableAndCleanup(Endpoint); + } + } + +End: + TransferUnlock(Endpoint); + TransferDmaExecute(NewTransaction); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCompleteControl ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles completion control transfer stage. + +Parameters Description: + + Endpoint - The control endpoint that completed the control transfer stage. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + PCONTROL_CONTEXT ControlContext; + + TraceEntry(); + + TransferLock(Endpoint); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + ControlContext = UfxEndpointGetControlContext(Endpoint); + + NT_ASSERT(!(ControlContext->SetupRequested && ControlContext->HandshakeRequested)); + + // + // Handle setup packet completion + // + if (ControlContext->SetupRequested) { + TRACE_TRANSFER("COMPLETE (Setup)", Endpoint, NULL); + + ControlContext->SetupRequested = FALSE; + TransferContext->TransferStarted = FALSE; + + UfxEndpointNotifySetup(Endpoint, ControlContext->SetupPacket); + + // + // Handle control status handshake completion + // + } else if (ControlContext->HandshakeRequested) { + NTSTATUS Status; + + TRACE_TRANSFER("COMPLETE (Handshake)", Endpoint, ControlContext->HandshakeRequest); + + Status = WdfRequestUnmarkCancelable(ControlContext->HandshakeRequest); + if (Status != STATUS_CANCELLED) { + WdfRequestComplete(ControlContext->HandshakeRequest, Status); + } else { + CHK_NT_MSG(Status, "Failed to unmark cancelable"); + } + + ControlContext->HandshakeRequested = FALSE; + ControlContext->HandshakeRequest = NULL; + TransferContext->TransferStarted = FALSE; + + TransferSetupPacket(Endpoint); + + // + // Handle data stage + // + } else if (ControlContext->DataStageExists) { + TransferUnlock(Endpoint); + TransferCompleteData(Endpoint); + TransferLock(Endpoint); + + } else { + TraceWarning("Unexpected transfer complete on control endpoint!"); + NT_ASSERT(FALSE); + } + +End: + TransferUnlock(Endpoint); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferComplete ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles endpoint XferComplete or XferInProgress events. + +Parameters Description: + + Endpoint - The endpoint that received the event. + + Event - The event received. + +--*/ +{ + TraceEntry(); + + if (CONTROL_ENDPOINT(Endpoint)) { + TransferCompleteControl(Endpoint); + + } else { + TransferCompleteData(Endpoint); + } + + TraceExit(); +} + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +TransferDestroy ( + _In_ UFXENDPOINT Endpoint + ) + +/*++ +Routine Description: + + Cleans up the endpoint's TRANSFER_CONTEXT during endpoint destroy + +Parameters Description: + + Endpoint - Endpoint being destroyed + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + PUFXENDPOINT_CONTEXT EpContext; + PUFXDEVICE_CONTEXT DeviceContext; + WDFCOMMONBUFFER ExtraBuffer; + WDFCOMMONBUFFER SetupPacketBuffer; + + TraceEntry(); + + TransferLock(Endpoint); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + EpContext = UfxEndpointGetContext(Endpoint); + DeviceContext = UfxDeviceGetContext(EpContext->UfxDevice); + + DeviceContext->PhysicalEndpointToUfxEndpoint[EpContext->PhysicalEndpoint] = NULL; + if (CONTROL_ENDPOINT(Endpoint)) { + DeviceContext->PhysicalEndpointToUfxEndpoint[EpContext->PhysicalEndpoint + 1] = NULL; + } + + // + // Need to do this first so another transfer isn't scheduled on cleanup. + // + TransferContext->Enabled = FALSE; + + TransferRequestTryUnmarkCancelableAndCleanup(Endpoint); + + ExtraBuffer = TransferContext->ExtraBuffer; + TransferContext->ExtraBuffer = NULL; + + SetupPacketBuffer = NULL; + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + + ControlContext = UfxEndpointGetControlContext(Endpoint); + SetupPacketBuffer = ControlContext->SetupPacketBuffer; + ControlContext->SetupPacketBuffer = NULL; + } + + // + // Most of these are probably already reset, but let's + // reset them anyway. + // + TransferContext->TransferStarted = FALSE; + TransferContext->Stalled = FALSE; + TransferContext->EndRequested = FALSE; + TransferContext->TransferCommandStartComplete = FALSE; + TransferContext->CleanupOnEndComplete = FALSE; + + // + // Cannot delete common buffers with spinlock held. + // + TransferUnlock(Endpoint); + + if (ExtraBuffer != NULL) { + WdfObjectDelete(ExtraBuffer); + } + + if (SetupPacketBuffer != NULL) { + WdfObjectDelete(SetupPacketBuffer); + } + + TraceExit(); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +TransferInitialize ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Sets up all fields in the endpoint's TRANSFER_CONTEXT during + endpoint creation. + +Parameters Description: + + Endpoint - The UFXENDPOINT which may have pending transfers. + +Return Value: + + STATUS_SUCCESS if successful, appropriate NTSTATUS message otherwise. + +--*/ +{ + NTSTATUS Status; + PCONTROLLER_CONTEXT ControllerContext; + PUFXENDPOINT_CONTEXT EpContext; + PTRANSFER_CONTEXT TransferContext; + PUFXDEVICE_CONTEXT DeviceContext; + WDF_OBJECT_ATTRIBUTES Attributes; + ULONG PhysicalEndpoint; + WDF_COMMON_BUFFER_CONFIG BufferConfig; + PUCHAR Buffer; + WDF_WORKITEM_CONFIG WorkItemConfig; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + ControllerContext = DeviceGetControllerContext(EpContext->WdfDevice); + DeviceContext = UfxDeviceGetContext(EpContext->UfxDevice); + + // + // Allocate transfer-related context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, TRANSFER_CONTEXT); + WdfObjectAllocateContext(Endpoint, &Attributes, (PVOID*) &TransferContext); + TransferContext->WdfDevice = EpContext->WdfDevice; + + // + // Create transfer spin lock + // + if (TransferContext->TransferLock == NULL) { + WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); + Attributes.ParentObject = Endpoint; + Status = WdfSpinLockCreate(&Attributes, &TransferContext->TransferLock); + CHK_NT_MSG(Status, "Failed to create transfer spinlock"); + } + + // + // Allocate and initialize common buffer for the endpoint + // + if (TransferContext->CommonBuffer == NULL) { + WDF_COMMON_BUFFER_CONFIG_INIT(&BufferConfig, COMMON_BUFFER_ALIGNMENT); + Status = WdfCommonBufferCreateWithConfig( + ControllerContext->DmaEnabler, + ENDPOINT_COMMON_BUFFER_SIZE, + &BufferConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &TransferContext->CommonBuffer); + CHK_NT_MSG(Status, "Failed to create common buffer"); + } + + Buffer = WdfCommonBufferGetAlignedVirtualAddress(TransferContext->CommonBuffer); + TransferContext->LogicalCommonBuffer = + WdfCommonBufferGetAlignedLogicalAddress(TransferContext->CommonBuffer); + TransferContext->Buffer = Buffer; + + RtlZeroMemory(TransferContext->CommonBuffer, ENDPOINT_COMMON_BUFFER_SIZE); + + // + // #### TODO: Insert code to initialize controller data structures in the shared common buffer + // + + // + // Map physical endpoint + // + PhysicalEndpoint = (EpContext->Descriptor.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK) * 2; + if (DIRECTION_IN(Endpoint) && !CONTROL_ENDPOINT(Endpoint)) { + PhysicalEndpoint++; + } + + if (PhysicalEndpoint >= MAX_PHYSICAL_ENDPOINTS) { + NT_ASSERTMSG("Physical endpoint maxium exceeded", FALSE); + Status = STATUS_UNSUCCESSFUL; + CHK_NT_MSG(Status, "Physical endpoint maxium exceeded"); + } + + DeviceContext->PhysicalEndpointToUfxEndpoint[PhysicalEndpoint] = Endpoint; + EpContext->PhysicalEndpoint = PhysicalEndpoint; + + // + // Control endpoints have two consecutive physical endpoints and + // need a place to store setup packets + // + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, CONTROL_CONTEXT); + WdfObjectAllocateContext(Endpoint, &Attributes, (PVOID*) &ControlContext); + + PhysicalEndpoint++; + + if (PhysicalEndpoint >= MAX_PHYSICAL_ENDPOINTS) { + NT_ASSERTMSG("Physical endpoint maxium exceeded", FALSE); + Status = STATUS_UNSUCCESSFUL; + CHK_NT_MSG(Status, "Physical endpoint maxium exceeded"); + } + + DeviceContext->PhysicalEndpointToUfxEndpoint[PhysicalEndpoint] = Endpoint; + + if (ControlContext->SetupPacketBuffer == NULL) { + WDF_COMMON_BUFFER_CONFIG_INIT(&BufferConfig, DATA_ALIGNMENT); + Status = WdfCommonBufferCreateWithConfig( + ControllerContext->DmaEnabler, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), + &BufferConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &ControlContext->SetupPacketBuffer); + CHK_NT_MSG(Status, "Failed to create setup packet buffer"); + } + + Buffer = WdfCommonBufferGetAlignedVirtualAddress(ControlContext->SetupPacketBuffer); + ControlContext->SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) Buffer; + } + + // + // Extra buffer for OUT transfers + // + if (TransferContext->ExtraBuffer == NULL) { + WDF_COMMON_BUFFER_CONFIG_INIT(&BufferConfig, DATA_ALIGNMENT); + Status = WdfCommonBufferCreateWithConfig( + ControllerContext->DmaEnabler, + 1024, + &BufferConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &TransferContext->ExtraBuffer); + CHK_NT_MSG(Status, "Failed to create extra OUT buffer"); + } + + if (TransferContext->CompletionWorkItem == NULL) { + WDF_WORKITEM_CONFIG_INIT(&WorkItemConfig, TransferCompleteNext); + Attributes.ParentObject = Endpoint; + Status = WdfWorkItemCreate(&WorkItemConfig, &Attributes, &TransferContext->CompletionWorkItem); + CHK_NT_MSG(Status, "Failed to create completion work item"); + } + + Status = STATUS_SUCCESS; + +End: + TraceExit(); + return Status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferBegin ( + _In_ UFXENDPOINT Endpoint, + _In_ WDFREQUEST Request, + _In_ BOOLEAN DirectionIn, + _In_ BOOLEAN AppendZlp + ) +/*++ +Routine Description: + + Starts a DMA transfer on the endpoint. + +Parameters Description: + + Endpoint - The endpoint to transfer on. + + Request - The WDFREQUEST which requested this transfer. + + DirectionIn - Transfer to host. + + AppendZlp - Append zero-length packet at the end of the transfer. + Only valid for DirectionIn. + +--*/ +{ + NTSTATUS Status; + PCONTROLLER_CONTEXT ControllerContext; + PUFXENDPOINT_CONTEXT EpContext; + PTRANSFER_CONTEXT TransferContext; + WDF_OBJECT_ATTRIBUTES Attributes; + PDMA_CONTEXT DmaContext; + PREQUEST_CONTEXT RequestContext; + WDFDMATRANSACTION Transaction; + WDF_REQUEST_PARAMETERS Params; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + TransferContext = UfxEndpointGetTransferContext(Endpoint); + ControllerContext = DeviceGetControllerContext(EpContext->WdfDevice); + + NT_ASSERT(DirectionIn || !AppendZlp); + + TransferContext->PendingCompletion = FALSE; + + // + // Create a DMA Transaction over the data + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, DMA_CONTEXT); + Status = WdfDmaTransactionCreate(ControllerContext->DmaEnabler, + &Attributes, + &Transaction); + CHK_NT_MSG(Status, "Failed to create DMA Transaction"); + + // + // Set up DMA context + // + WDF_REQUEST_PARAMETERS_INIT(&Params); + WdfRequestGetParameters(Request, &Params); + DmaContext = DmaGetContext(Transaction); + DmaContext->NeedExtraBuffer = AppendZlp; + DmaContext->DirectionIn = DirectionIn; + DmaContext->Endpoint = Endpoint; + DmaContext->Request = Request; + DmaContext->BytesRequested = (ULONG) Params.Parameters.DeviceIoControl.OutputBufferLength; + + // + // Need to add extra buffer if OUT transfer not multiple of MaxPacketSize + // + if (!DirectionIn) { + if ((DmaContext->BytesRequested % EpContext->Descriptor.wMaxPacketSize) > 0) { + DmaContext->ExtraBytes = EpContext->Descriptor.wMaxPacketSize - + (DmaContext->BytesRequested % EpContext->Descriptor.wMaxPacketSize); + DmaContext->NeedExtraBuffer = TRUE; + } + } + + DmaContext->State = NotExecuted; + + // + // Set up request context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, REQUEST_CONTEXT); + Status = WdfObjectAllocateContext(Request, &Attributes, (PVOID*) &RequestContext); + CHK_NT_MSG(Status, "Failed to allocate request context"); + + // + // It's possible that the request was reused, in which case the context already + // exists. Therefore, we need to make sure to zero it out. + // + RtlZeroMemory(RequestContext, sizeof(REQUEST_CONTEXT)); + + RequestContext->Endpoint = Endpoint; + RequestContext->Transaction = Transaction; + + // + // Set up control data stage context + // + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + ControlContext = UfxEndpointGetControlContext(Endpoint); + ControlContext->DataStageExists = TRUE; + } + + // + // Keep track of DMA + // + TransferContext->Transaction = Transaction; + + // + // We need to mark cancelable before starting DMA (which may take time) + // + Status = WdfRequestMarkCancelableEx(Request, OnEvtRequestCancel); + CHK_NT_MSG(Status, "Failed to mark request cancellable"); + + TRACE_TRANSFER("BEGIN", Endpoint, Request); + + // + // Can't use a DMA transaction for 0-length transfers. + // + if (DmaContext->BytesRequested == 0) { + + DmaContext->ZeroLength = TRUE; + + TRACE_TRANSFER("ZERO LENGTH", Endpoint, DmaContext->Request); + + DmaContext->ExtraBytes = 0; + + TransferCommandStartOrUpdate(Endpoint); + + } else { + // + // Use request to initialize DMA + // + Status = WdfDmaTransactionInitializeUsingRequest( + Transaction, + Request, + OnEvtProgramDma, + DirectionIn ? WdfDmaDirectionWriteToDevice : WdfDmaDirectionReadFromDevice); + CHK_NT_MSG(Status, "Failed to initialize DMA transaction using request"); + + // + // Caller is expected to execute the DMA. + // + } + +End: + if (!NT_SUCCESS(Status)) { + WdfRequestComplete(Request, Status); + if (Transaction != NULL) { + TransferContext->Transaction = NULL; + WdfObjectDelete(Transaction); + Transaction = NULL; + } + } + + TraceExit(); + return Transaction; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferHandshake ( + _In_ UFXENDPOINT Endpoint, + _In_ WDFREQUEST Request, + _In_ BOOLEAN DirectionIn + ) +/*++ +Routine Description: + + Starts a control handshake (zero-length packet) transfer on the endpoint. + The caller is expected to acquire the TransferLock. + +Parameters Description: + + Endpoint - The endpoint to transfer on. + + Request - The WDFREQUEST which requested this transfer. + + DirectionIn - Transfer to host. + +--*/ +{ + NTSTATUS Status; + PCONTROL_CONTEXT ControlContext; + PREQUEST_CONTEXT RequestContext; + WDF_OBJECT_ATTRIBUTES Attributes; + + TraceEntry(); + + UNREFERENCED_PARAMETER(DirectionIn); + + ControlContext = UfxEndpointGetControlContext(Endpoint); + + NT_ASSERT(CONTROL_ENDPOINT(Endpoint)); + NT_ASSERT(ControlContext->SetupRequested == FALSE); + NT_ASSERT(ControlContext->HandshakeRequested == FALSE); + NT_ASSERT(ControlContext->HandshakeRequest == Request || + ControlContext->HandshakeRequest == NULL); + + Status = STATUS_SUCCESS; + + if (ControlContext->HandshakeRequest != Request) { + // + // Set up request context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, REQUEST_CONTEXT); + Status = WdfObjectAllocateContext(Request, &Attributes, (PVOID*) &RequestContext); + CHK_NT_MSG(Status, "Failed to allocate request context"); + + // + // It's possible that the request was reused, in which case the context already + // exists. Therefore, we need to make sure to zero it out. + // + RtlZeroMemory(RequestContext, sizeof(REQUEST_CONTEXT)); + + RequestContext->Endpoint = Endpoint; + + // + // Mark request cancellable, in case host takes a long time. + // + Status = WdfRequestMarkCancelableEx(Request, OnEvtRequestCancel); + CHK_NT_MSG(Status, "Failed to mark quest cancelable"); + } + + ControlContext->HandshakeRequest = Request; + + // + // #### TODO: Insert code to initialize endpoint data structures for handshake #### + // + + TRACE_TRANSFER("HANDSHAKE", Endpoint, Request); + + // + // We should always start a new transfer for this, since it must be in + // the opposite direction of the DMA or Setup Packet. + // + TransferCommandStart(Endpoint); + ControlContext->HandshakeRequested = TRUE; + +End: + if (!NT_SUCCESS(Status)) { + WdfRequestComplete(Request, Status); + } + TraceExit(); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFDMATRANSACTION +TransferNextRequest ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles IOCTL requests on the endpoint. + +Parameters Description: + + Endpoint - Endpoint with request. + +--*/ +{ + NTSTATUS Status; + WDFREQUEST Request; + WDF_REQUEST_PARAMETERS Params; + ULONG Ioctl; + PUFXENDPOINT_CONTEXT EpContext; + WDFDMATRANSACTION Transaction; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + Transaction = NULL; + +Fetch: + + // + // Fetch next request + // + Status = WdfIoQueueRetrieveNextRequest(UfxEndpointGetTransferQueue(Endpoint), + &Request); + if (Status == STATUS_NO_MORE_ENTRIES || Status == STATUS_WDF_PAUSED) { + goto End; + } + + CHK_NT_MSG(Status, "Failed to retrieve next request"); + + WDF_REQUEST_PARAMETERS_INIT(&Params); + WdfRequestGetParameters(Request, &Params); + Ioctl = Params.Parameters.DeviceIoControl.IoControlCode; + + if (Ioctl == IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN) { + TransferHandshake(Endpoint, Request, TRUE); + + } else if (Ioctl == IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT) { + TransferHandshake(Endpoint, Request, FALSE); + + } else if (DIRECTION_IN(Endpoint) && + Ioctl == IOCTL_INTERNAL_USBFN_TRANSFER_IN) { + + Transaction = TransferBegin(Endpoint, Request, TRUE, FALSE); + + } else if (DIRECTION_IN(Endpoint) && + Ioctl == IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT) { + + Transaction = TransferBegin(Endpoint, Request, TRUE, TRUE); + + } else if (DIRECTION_OUT(Endpoint) && + Ioctl == IOCTL_INTERNAL_USBFN_TRANSFER_OUT) { + + Transaction = TransferBegin(Endpoint, Request, FALSE, FALSE); + + } else { + TraceWarning("INVALID: %08X (%d), Ioctl: %08X", + (ULONG) Endpoint, EpContext->PhysicalEndpoint, Ioctl); + WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST); + goto Fetch; + } + +End: + TraceExit(); + + return Transaction; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferReset ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Disables and ends an endpoint. On end complete, if the endpoint + is stalled, it will be cleared. After end complete, the endpoint + can be re-configured. + +Parameters Description: + + Endpoint - endpoint to reset + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + TransferLock(Endpoint); + + TRACE_TRANSFER("RESET", Endpoint, NULL); + + // + // Need to get EP0 back to "setup" stage. + // + if (EpContext->PhysicalEndpoint <= 1) { + PCONTROL_CONTEXT ControlContext; + + ControlContext = UfxEndpointGetControlContext(Endpoint); + + if (!ControlContext->SetupRequested) { + if (TransferContext->TransferStarted) { + TransferCommandEnd(Endpoint); + } else { + CommandStallSet(Endpoint); + } + } + + } else { + TransferContext->Enabled = FALSE; + if (TransferContext->TransferStarted) { + TransferCommandEnd(Endpoint); + } + } + + TransferUnlock(Endpoint); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStart ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Enables an endpoint to start transfers and starts fetching + requests. If this is a control endpoint, programs a setup + packet. + +Parameters Description: + + Endpoint - endpoint to start + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION Transaction; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + Transaction = NULL; + + TransferLock(Endpoint); + + TRACE_TRANSFER("START", Endpoint, NULL); + + TransferContext->Enabled = TRUE; + + // + // EP0 is programmed once on creation, not on each reset. + // + if (CONTROL_ENDPOINT(Endpoint)) { + TransferSetupPacket(Endpoint); + + } else { + Transaction = TransferNextRequest(Endpoint); + } + + TransferUnlock(Endpoint); + TransferDmaExecute(Transaction); + TraceExit(); +} + +VOID +TransferReadyNotify ( + WDFQUEUE Queue, + WDFCONTEXT Context + ) +/*++ +Routine Description: + + Indicates the number of events in the queue went from 0 -> 1. + This will fetch the next request and program it. + +Parameters Description: + + Queue - queue with request. + + Context - UFXENDPOINT + +--*/ +{ + UFXENDPOINT Endpoint; + PTRANSFER_CONTEXT TransferContext; + WDFDMATRANSACTION Transaction; + + UNREFERENCED_PARAMETER(Queue); + + TraceEntry(); + + Endpoint = (UFXENDPOINT) Context; + TransferContext = UfxEndpointGetTransferContext(Endpoint); + Transaction = NULL; + + // + // Make sure we didn't get hijacked from WdfRequestComplete... + // + if (TransferContext->TransferStarted) { + goto Skip; + } + + TransferLock(Endpoint); + + if (TransferContext->Enabled && TransferContext->Transaction == NULL) { + if (CONTROL_ENDPOINT(Endpoint)) { + PCONTROL_CONTEXT ControlContext; + ControlContext = UfxEndpointGetControlContext(Endpoint); + + if (!ControlContext->SetupRequested) { + Transaction = TransferNextRequest(Endpoint); + } + + } else { + Transaction = TransferNextRequest(Endpoint); + } + } + + TransferUnlock(Endpoint); + TransferDmaExecute(Transaction); +Skip: + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStallSetComplete ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles command completion event for Stall Set. If this is a + control endpoint, programs a setup packet. + +Parameters Description: + + Endpoint - Endpoint associated with event. + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + PTRANSFER_CONTEXT TransferContext; + WDFREQUEST Request; + WDFDMATRANSACTION NewTransaction; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + TransferContext = UfxEndpointGetTransferContext(Endpoint); + NewTransaction = NULL; + + TransferLock(Endpoint); + + // + // If we stall a control endpoint, we need to reset its state and start + // over from the setup packet request. + // + if (CONTROL_ENDPOINT(Endpoint)) { + TransferContext->Stalled = FALSE; + if (!TransferContext->TransferStarted) { + NewTransaction = TransferRequestTryUnmarkCancelableAndCleanup(Endpoint); + } + } + + if (EpContext->StallRequest) { + Request = EpContext->StallRequest; + EpContext->StallRequest = NULL; + WdfRequestComplete(Request, STATUS_SUCCESS); + } + + TransferUnlock(Endpoint); + TransferDmaExecute(NewTransaction); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStallClearComplete ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Handles command completion event for Stall Clear. + +Parameters Description: + + Endpoint - Endpoint associated with event. + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + WDFREQUEST Request; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + + TransferLock(Endpoint); + + NT_ASSERT(!CONTROL_ENDPOINT(Endpoint)); + + if (EpContext->ClearRequest) { + Request = EpContext->ClearRequest; + EpContext->ClearRequest = NULL; + WdfRequestComplete(Request, STATUS_SUCCESS); + } + + TransferUnlock(Endpoint); + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStallSet ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Sets an endpoint to the STALL state. + +Parameters Description: + + Endpoint - Endpoint to set the STALL state on. + +--*/ +{ + TraceEntry(); + + TransferLock(Endpoint); + + CommandStallSet(Endpoint); + + TransferUnlock(Endpoint); + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStallClear ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Clears an endpoint to the STALL state. + +Parameters Description: + + Endpoint - Endpoint to clear the STALL state on. + +--*/ +{ + TraceEntry(); + + TransferLock(Endpoint); + + CommandStallClear(Endpoint); + + TransferUnlock(Endpoint); + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferGetStall ( + _In_ UFXENDPOINT Endpoint, + _Out_ PBOOLEAN Stalled + ) +/*++ +Routine Description: + + Returns the current STALL state for an endpoint. + +Parameters Description: + + Endpoint - Endpoint to retreive the STALL state for. + + Stalled - Pointer to a boolean value to receive the STALL state. + +--*/ +{ + PTRANSFER_CONTEXT TransferContext; + + TraceEntry(); + + TransferContext = UfxEndpointGetTransferContext(Endpoint); + + TransferLock(Endpoint); + + *Stalled = TransferContext->Stalled; + + TransferUnlock(Endpoint); + + TraceExit(); +}
\ No newline at end of file diff --git a/usb/ufxclientsample/transfer.h b/usb/ufxclientsample/transfer.h new file mode 100644 index 00000000..42ef209f --- /dev/null +++ b/usb/ufxclientsample/transfer.h @@ -0,0 +1,180 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + transfer.h + +Abstract: + + Header file for the transfer related functions + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#include "ufxclient.h" +#include "registers.h" +#include "event.h" + +#define MAX_TRANSFER_SIZE 0x20000000 + +// nonstandard extension used : bit field types other than int +#pragma warning(disable:4214) + +typedef enum _DMA_STATE { + NotExecuted = 0, + Executed, + Cancelled, + Completed +} DMA_STATE; + +typedef struct _CONTROL_CONTEXT { + WDFCOMMONBUFFER SetupPacketBuffer; + BOOLEAN SetupRequested; + BOOLEAN ReadyForHandshake; + BOOLEAN HandshakeRequested; + BOOLEAN DataStageExists; + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + WDFREQUEST HandshakeRequest; +} CONTROL_CONTEXT, *PCONTROL_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CONTROL_CONTEXT, UfxEndpointGetControlContext); + +typedef struct _TRANSFER_CONTEXT { + WDFDEVICE WdfDevice; + WDFCOMMONBUFFER CommonBuffer; + WDFCOMMONBUFFER ExtraBuffer; + WDFDMATRANSACTION Transaction; + PHYSICAL_ADDRESS LogicalCommonBuffer; + PUCHAR Buffer; + WDFSPINLOCK TransferLock; + BOOLEAN TransferStarted; + BOOLEAN EndRequested; + BOOLEAN Stalled; + BOOLEAN Enabled; + BOOLEAN TransferCommandStartComplete; + BOOLEAN CleanupOnEndComplete; + WDFWORKITEM CompletionWorkItem; + BOOLEAN PendingCompletion; +} TRANSFER_CONTEXT, *PTRANSFER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(TRANSFER_CONTEXT, UfxEndpointGetTransferContext); + +typedef struct _DMA_CONTEXT { + UFXENDPOINT Endpoint; + ULONG BytesRequested; + ULONG BytesProgrammed; + ULONG BytesProgrammedCurrent; + ULONG ExtraBytes; + BOOLEAN DirectionIn; + PSCATTER_GATHER_LIST SgList; + ULONG SgIndex; + WDFREQUEST Request; + BOOLEAN ZeroLength; + DMA_STATE State; + ULONG BytesRemaining; + BOOLEAN CleanupOnProgramDma; + BOOLEAN NeedExtraBuffer; +} DMA_CONTEXT, *PDMA_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DMA_CONTEXT, DmaGetContext); + +typedef struct _REQUEST_CONTEXT { + UFXENDPOINT Endpoint; + WDFDMATRANSACTION Transaction; + BOOLEAN QueueIsStopped; + BOOLEAN ReferencedOnCancel; +} REQUEST_CONTEXT, *PREQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, RequestGetContext); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +TransferInitialize ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStartComplete ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandEndComplete ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID + +TransferComplete ( + _In_ UFXENDPOINT Endpoint + ); + + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +TransferDestroy ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferReset ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStart ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferRequestCancel ( + _In_ WDFREQUEST Request, + _In_ BOOLEAN QueueIsStopped + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStallClear ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferCommandStallSet ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStallClearComplete ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferStallSetComplete ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +TransferGetStall ( + _In_ UFXENDPOINT Endpoint, + _Out_ PBOOLEAN Stalled + ); + +EVT_WDF_IO_QUEUE_STATE TransferReadyNotify;
\ No newline at end of file diff --git a/usb/ufxclientsample/ufxclientsample.rc b/usb/ufxclientsample/ufxclientsample.rc new file mode 100644 index 00000000..1b249a20 --- /dev/null +++ b/usb/ufxclientsample/ufxclientsample.rc @@ -0,0 +1,14 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "UFX Client Sample Driver" +#define VER_INTERNALNAME_STR "ufxclientsample.sys" +#define VER_ORIGINALFILENAME_STR "ufxclientsample.sys" + +#include "common.ver" diff --git a/usb/ufxclientsample/ufxclientsample.sln b/usb/ufxclientsample/ufxclientsample.sln new file mode 100644 index 00000000..63b6eb8d --- /dev/null +++ b/usb/ufxclientsample/ufxclientsample.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ufxclientsample", "ufxclientsample.vcxproj", "{53F86825-E305-471C-8180-34E9987E4431}" +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 + {53F86825-E305-471C-8180-34E9987E4431}.Debug|Win32.ActiveCfg = Debug|Win32 + {53F86825-E305-471C-8180-34E9987E4431}.Debug|Win32.Build.0 = Debug|Win32 + {53F86825-E305-471C-8180-34E9987E4431}.Release|Win32.ActiveCfg = Release|Win32 + {53F86825-E305-471C-8180-34E9987E4431}.Release|Win32.Build.0 = Release|Win32 + {53F86825-E305-471C-8180-34E9987E4431}.Debug|x64.ActiveCfg = Debug|x64 + {53F86825-E305-471C-8180-34E9987E4431}.Debug|x64.Build.0 = Debug|x64 + {53F86825-E305-471C-8180-34E9987E4431}.Release|x64.ActiveCfg = Release|x64 + {53F86825-E305-471C-8180-34E9987E4431}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/usb/ufxclientsample/ufxclientsample.vcxproj b/usb/ufxclientsample/ufxclientsample.vcxproj new file mode 100644 index 00000000..df653028 --- /dev/null +++ b/usb/ufxclientsample/ufxclientsample.vcxproj @@ -0,0 +1,219 @@ +<?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>{53F86825-E305-471C-8180-34E9987E4431}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{0A165ABC-5762-4BCF-AE58-360CF9D52BD8}</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="defaultqueue.c; device.c; driver.c; event.c; interrupt.c; ufxdevice.c; ufxendpoint.c; transfer.c; registers.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppModuleName>ufxclientsample</WppModuleName> + <WppScanConfigurationData>trace.h</WppScanConfigurationData> + </ClCompile> + <Inf Include=".\ufxclientsample.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\ufxclientsample.inf</CopyOutput> + </Inf> + <MessageCompile Include="ufxclientsample.man"> + <GenerateKernelModeLoggingMacros>true</GenerateKernelModeLoggingMacros> + <GenerateMofFile>true</GenerateMofFile> + <HeaderFilePath>.\$(IntDir)</HeaderFilePath> + <GeneratedHeaderPath>true</GeneratedHeaderPath> + <RCFilePath>.\$(IntDir)</RCFilePath> + <GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath> + <GeneratedFilesBaseName>ufxclientsample</GeneratedFilesBaseName> + <UseBaseNameOfInput>true</UseBaseNameOfInput> + </MessageCompile> + <OtherWpp Include="ufxclientsample.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppModuleName>ufxclientsample</WppModuleName> + <WppScanConfigurationData>trace.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ufxclientsample</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ufxclientsample</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ufxclientsample</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ufxclientsample</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ufx\1.1\ufxstub.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ufx\1.1\ufxstub.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ufx\1.1\ufxstub.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ufx\1.1\ufxstub.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)\ufx\1.1</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);KERNEL_MODE</PreprocessorDefinitions> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="ufxclientsample.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </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/usb/ufxclientsample/ufxclientsample.vcxproj.Filters b/usb/ufxclientsample/ufxclientsample.vcxproj.Filters new file mode 100644 index 00000000..ba38b7e1 --- /dev/null +++ b/usb/ufxclientsample/ufxclientsample.vcxproj.Filters @@ -0,0 +1,63 @@ +<?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>{913D3EC7-37FD-4BC5-B8F3-5B0316F839BD}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{CFA48238-7E09-4139-BABE-B24CA80F2A32}</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>{088F289C-03FC-4BBE-B6D4-FEBA220934FD}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{B057205B-0933-44FF-A94F-65B1491C15CE}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="defaultqueue.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="event.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="interrupt.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="registers.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="transfer.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ufxdevice.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ufxendpoint.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Include=".\ufxclientsample.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <MessageCompile Include="ufxclientsample.man"> + <Filter>Resource Files</Filter> + </MessageCompile> + <ResourceCompile Include="ufxclientsample.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/ufxclientsample/ufxdevice.c b/usb/ufxclientsample/ufxdevice.c new file mode 100644 index 00000000..0894ff69 --- /dev/null +++ b/usb/ufxclientsample/ufxdevice.c @@ -0,0 +1,902 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ufxdevice.c + +Abstract: + + Implements the UFXDEVICE functionality and callbacks. + +Environment: + + Kernel mode + +--*/ + + +#include "device.h" +#include "ufxdevice.h" +#include "ufxendpoint.h" +#include "transfer.h" +#include "interrupt.h" +#include <usbspec.h> + +#include "ufxdevice.tmh" + +#define DISCONNECT_TIMEOUT WDF_REL_TIMEOUT_IN_MS(2000) + +// +// UFXDEVICE callbacks +// +EVT_UFX_DEVICE_HOST_CONNECT UfxDevice_EvtDeviceHostConnect; +EVT_UFX_DEVICE_HOST_DISCONNECT UfxDevice_EvtDeviceHostDisconnect; +EVT_UFX_DEVICE_ADDRESSED UfxDevice_EvtDeviceAddressed; +EVT_UFX_DEVICE_ENDPOINT_ADD UfxDevice_EvtDeviceEndpointAdd; +EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD UfxDevice_EvtDeviceDefaultEndpointAdd; +EVT_UFX_DEVICE_USB_STATE_CHANGE UfxDevice_EvtDeviceUsbStateChange; +EVT_UFX_DEVICE_PORT_CHANGE UfxDevice_EvtDevicePortChange; +EVT_UFX_DEVICE_PORT_DETECT UfxDevice_EvtDevicePortDetect; +EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL UfxDevice_EvtDeviceRemoteWakeupSignal; +EVT_UFX_DEVICE_TEST_MODE_SET UfxDevice_EvtDeviceTestModeSet; +EVT_UFX_DEVICE_SUPER_SPEED_POWER_FEATURE UfxDevice_EvtDeviceSuperSpeedPowerFeature; + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxDeviceStopOrResumeIdle ( + _In_ UFXDEVICE Device, + _In_ USBFN_DEVICE_STATE UsbState, + _In_ USBFN_PORT_TYPE UsbPort + ); + +// +// WDFOBJECT callbacks +// +EVT_WDF_OBJECT_CONTEXT_CLEANUP UfxDevice_EvtCleanupCallback; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, UfxDevice_DeviceCreate) +#pragma alloc_text (PAGE, UfxDevice_EvtDeviceUsbStateChange) +#pragma alloc_text (PAGE, UfxDevice_EvtDevicePortChange) +#pragma alloc_text (PAGE, UfxDeviceStopOrResumeIdle) +#pragma alloc_text (PAGE, UfxDevice_EvtDeviceDefaultEndpointAdd) +#pragma alloc_text (PAGE, UfxDevice_EvtDeviceRemoteWakeupSignal) +#endif + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxDevice_DeviceCreate ( + _In_ WDFDEVICE WdfDevice + ) +/*++ + +Routine Description: + + Routine that registers with UFX and creates the UFX device object. + +Arguments: + + WdfDevice - Wdf object representing the device. + +Return Value: + + NTSTATUS. + +--*/ +{ + NTSTATUS Status; + PCONTROLLER_CONTEXT ControllerContext; + UFX_DEVICE_CALLBACKS UfxDeviceCallbacks; + UFX_DEVICE_CAPABILITIES UfxDeviceCapabilities; + PUFXDEVICE_CONTEXT UfxDeviceContext; + UFXDEVICE UfxDevice; + WDF_OBJECT_ATTRIBUTES Attributes; + + PAGED_CODE(); + + TraceEntry(); + + ControllerContext = DeviceGetControllerContext(WdfDevice); + + UFX_DEVICE_CAPABILITIES_INIT(&UfxDeviceCapabilities); + UfxDeviceCapabilities.MaxSpeed = UsbSuperSpeed; + UfxDeviceCapabilities.RemoteWakeSignalDelay = REMOTE_WAKEUP_TIMEOUT_INTERVAL_MS; + + // + // Set bitmasks that define the IN and OUT endpoint numbers that are available on the controller + // + + // + // #### TODO: Set the IN endpoint mask here if not all endpoint addresses are supported #### + // + // For illustration purposes sample will set default control endpoint 0, 1-4, 8 + UfxDeviceCapabilities.InEndpointBitmap = 0x011F; + + // + // #### TODO: Set the OUT endpoint mask here if not all endpoint addresses are supported #### + // + // For illustration purposes sample will set default control endpoint 0, 2-7 + // + UfxDeviceCapabilities.OutEndpointBitmap = 0x00FD; + + // + // Set the event callbacks for the ufxdevice + // + UFX_DEVICE_CALLBACKS_INIT(&UfxDeviceCallbacks); + UfxDeviceCallbacks.EvtDeviceHostConnect = UfxDevice_EvtDeviceHostConnect; + UfxDeviceCallbacks.EvtDeviceHostDisconnect = UfxDevice_EvtDeviceHostDisconnect; + UfxDeviceCallbacks.EvtDeviceAddressed = UfxDevice_EvtDeviceAddressed; + UfxDeviceCallbacks.EvtDeviceEndpointAdd = UfxDevice_EvtDeviceEndpointAdd; + UfxDeviceCallbacks.EvtDeviceDefaultEndpointAdd = UfxDevice_EvtDeviceDefaultEndpointAdd; + UfxDeviceCallbacks.EvtDeviceUsbStateChange = UfxDevice_EvtDeviceUsbStateChange; + UfxDeviceCallbacks.EvtDevicePortChange = UfxDevice_EvtDevicePortChange; + UfxDeviceCallbacks.EvtDevicePortDetect = UfxDevice_EvtDevicePortDetect; + UfxDeviceCallbacks.EvtDeviceRemoteWakeupSignal = UfxDevice_EvtDeviceRemoteWakeupSignal; + UfxDeviceCallbacks.EvtDeviceTestModeSet = UfxDevice_EvtDeviceTestModeSet; + UfxDeviceCallbacks.EvtDeviceSuperSpeedPowerFeature = UfxDevice_EvtDeviceSuperSpeedPowerFeature; + + // Context associated with UFXDEVICE object + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, UFXDEVICE_CONTEXT); + Attributes.EvtCleanupCallback = UfxDevice_EvtCleanupCallback; + + // Create the UFXDEVICE object + Status = UfxDeviceCreate(WdfDevice, + &UfxDeviceCallbacks, + &UfxDeviceCapabilities, + &Attributes, + &UfxDevice); + CHK_NT_MSG(Status, "Failed to create UFXDEVICE object"); + + // Initialize the client context space in UFXDEVICE object + UfxDeviceContext = UfxDeviceGetContext(UfxDevice); + UfxDeviceContext->FdoWdfDevice = WdfDevice; + UfxDeviceContext->UsbState = UsbfnDeviceStateDetached; + UfxDeviceContext->UsbPort = UsbfnUnknownPort; + UfxDeviceContext->IsIdle = TRUE; + + ControllerContext->UfxDevice = UfxDevice; + + // + // Create endpoints collection + // + WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); + Attributes.ParentObject = UfxDevice; + Status = WdfCollectionCreate(&Attributes, &UfxDeviceContext->Endpoints); + CHK_NT_MSG(Status, "Failed to create endpoint collection object"); + +End: + TraceExit(); + return Status; +} + + +VOID +UfxDevice_EvtCleanupCallback ( + _In_ WDFOBJECT UfxDevice + ) +/*++ + +Routine Description: + + EvtCleanupCallback handler for the UFXDEVICE object. + +Arguments: + + UfxDevice - Wdf object representing the UFXDEVICE + +--*/ +{ + PUFXDEVICE_CONTEXT DeviceContext = NULL; + PCONTROLLER_CONTEXT ControllerContext = NULL; + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(UfxDevice); + ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); + + TraceExit(); +} + + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxDeviceSetRunStop ( + _In_ UFXDEVICE UfxDevice, + _In_ BOOLEAN Set + ) +/*++ + +Routine Description: + + Function that sets or clears the run/stop state on the controller. Setting the + run state will initiate a connect to the host. + +Arguments: + + UfxDevice - Wdf object representing the UFXDEVICE + + Set - TRUE if setting the run state, FALSE if clearing the run state. + +--*/ +{ + PCONTROLLER_CONTEXT ControllerContext; + PUFXDEVICE_CONTEXT DeviceContext; + BOOLEAN EventComplete; + + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(UfxDevice); + ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); + + EventComplete = TRUE; + + WdfSpinLockAcquire(ControllerContext->DpcLock); + + if (Set) { + // + // #### TODO: Insert code to set the run state on the controller #### + // + } else { + // + // #### TODO: Insert code to clear the run state on the controller #### + // + } + + WdfSpinLockRelease(ControllerContext->DpcLock); + + if (EventComplete) { + UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); + } + + TraceExit(); +} + +VOID +UfxDevice_EvtDeviceHostConnect ( + _In_ UFXDEVICE UfxDevice + ) +/*++ + +Routine Description: + + EvtDeviceHostConnect callback handler for UFXDEVICE object. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +--*/ +{ + TraceEntry(); + + UfxDeviceSetRunStop(UfxDevice, TRUE); + + TraceExit(); +} + + +VOID +UfxDevice_EvtDeviceHostDisconnect ( + _In_ UFXDEVICE UfxDevice + ) +/*++ + +Routine Description: + + EvtDeviceHostDisconnect callback handler for UFXDEVICE object. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +--*/ +{ + TraceEntry(); + + UfxDevice_Reset(UfxDevice); + + UfxDeviceSetRunStop(UfxDevice, FALSE); + + TraceExit(); +} + + +VOID +UfxDevice_EvtDeviceAddressed ( + _In_ UFXDEVICE UfxDevice, + _In_ USHORT DeviceAddress + ) +/*++ + +Routine Description: + + EvtDeviceAddressed handler for the UFXDEVICE object. + Sets the Address indicated by 'DeviceAddress' on the controller. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + DeviceAddress - USB Device Address, as determined by the UFX. + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceAddress); + + TraceEntry(); + + // + // Set the device address on the controller + // + + // + // #### Insert code to set the device address on controller #### + // + + UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); + + TraceExit(); +} + + +NTSTATUS +UfxDevice_EvtDeviceEndpointAdd ( + _In_ UFXDEVICE UfxDevice, + _In_ const PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, + _Inout_ PUFXENDPOINT_INIT EndpointInit + ) +/*++ + +Routine Description: + + EvtDeviceEndpointAdd handler for the UFXDEVICE object. + Creates UFXENDPOINT object corresponding to the newly reported endpoint. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + EndpointDescriptor - Cosntant Pointer to Endpoint descriptor for the + newly reported endpoint. + + EndpointInit - Pointer to the Opaque UFXENDPOINT_INIT object + +Return Value: + + STATUS_SUCCESS on success, or an appropirate NTSTATUS message on failure. + +--*/ +{ + NTSTATUS Status; + + TraceEntry(); + + Status = UfxEndpointAdd(UfxDevice, EndpointDescriptor, EndpointInit); + CHK_NT_MSG(Status, "Failed to create endpoint"); + +End: + + TraceExit(); + return Status; +} + + +VOID +UfxDevice_EvtDeviceDefaultEndpointAdd ( + _In_ UFXDEVICE UfxDevice, + _In_ USHORT MaxPacketSize, + _Inout_ PUFXENDPOINT_INIT EndpointInit + ) +/*++ + +Routine Description: + + EvtDeviceDefaultEndpointAdd handler for the UFXDEVICE object. + Creates UFXENDPOINT object corresponding to the default endpoint of the + device. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + MaxPacketSize - Max packet size of the device's default endpoint. + + EndpointInit - Pointer to the Opaque UFXENDPOINT_INIT object + +--*/ +{ + NTSTATUS Status; + USB_ENDPOINT_DESCRIPTOR Descriptor; + + PAGED_CODE(); + + TraceEntry(); + + Descriptor.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; + Descriptor.bEndpointAddress = 0; + Descriptor.bInterval = 0; + Descriptor.bLength = sizeof(USB_ENDPOINT_DESCRIPTOR); + Descriptor.bmAttributes = USB_ENDPOINT_TYPE_CONTROL; + Descriptor.wMaxPacketSize = MaxPacketSize; + + Status = UfxEndpointAdd(UfxDevice, &Descriptor, EndpointInit); + CHK_NT_MSG(Status, "Failed to create default endpoint!"); + +End: + UfxDeviceEventComplete(UfxDevice, Status); + TraceExit(); +} + + +VOID +UfxDevice_EvtDeviceUsbStateChange ( + _In_ UFXDEVICE UfxDevice, + _In_ USBFN_DEVICE_STATE NewState +) +/*++ + +Routine Description: + + EvtDeviceUsbStateChange handler for the UFXDEVICE object. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + NewState - The new device state. + +--*/ +{ + NTSTATUS Status; + PUFXDEVICE_CONTEXT Context; + PCONTROLLER_CONTEXT ControllerContext; + ULONG EpIndex; + USBFN_DEVICE_STATE OldState; + + PAGED_CODE(); + + TraceEntry(); + + Context = UfxDeviceGetContext(UfxDevice); + ControllerContext = DeviceGetControllerContext(Context->FdoWdfDevice); + OldState = Context->UsbState; + + TraceInformation("New STATE: %d", NewState); + + Status = UfxDeviceStopOrResumeIdle(UfxDevice, NewState, Context->UsbPort); + LOG_NT_MSG(Status, "Failed to stop or resume idle"); + + WdfWaitLockAcquire(ControllerContext->InitializeDefaultEndpointLock, NULL); + if (ControllerContext->InitializeDefaultEndpoint == TRUE) { + // + // Reset endpoint 0. This is the last part of soft reset, which was postponed + // until now, since we need to make sure EP0 is created by UFX. + // + DeviceInitializeDefaultEndpoint(Context->FdoWdfDevice); + ControllerContext->InitializeDefaultEndpoint = FALSE; + } + WdfWaitLockRelease(ControllerContext->InitializeDefaultEndpointLock); + + if (NewState == UsbfnDeviceStateConfigured && OldState != UsbfnDeviceStateSuspended) { + + for (EpIndex = 1; EpIndex < WdfCollectionGetCount(Context->Endpoints); EpIndex++) { + UfxEndpointConfigure(WdfCollectionGetItem(Context->Endpoints, EpIndex)); + } + + // + // #### TODO: Insert code to allow the controller to accept U1/U2, if supported #### + // + + } + + + if (NewState == UsbfnDeviceStateDetached) { + KeSetEvent(&ControllerContext->DetachEvent, + IO_NO_INCREMENT, + FALSE); + } + + UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); + TraceExit(); +} + +_Function_class_(EVT_UFX_DEVICE_PORT_CHANGE) +_IRQL_requires_(PASSIVE_LEVEL) +VOID +UfxDevice_EvtDevicePortChange ( + _In_ + UFXDEVICE UfxDevice, + _In_ + USBFN_PORT_TYPE NewPort + ) +/*++ + +Routine Description: + + EvtDevicePortChange handler for the UFXDEVICE object. + Caches the new port type, and stops or resumes idle as needed. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + NewPort - New port type + +--*/ +{ + NTSTATUS Status; + PUFXDEVICE_CONTEXT Context; + + PAGED_CODE(); + + TraceEntry(); + + Context = UfxDeviceGetContext(UfxDevice); + + TraceInformation("New PORT: %d", NewPort); + + Status = UfxDeviceStopOrResumeIdle(UfxDevice, Context->UsbState, NewPort); + LOG_NT_MSG(Status, "Failed to stop or resume idle"); + + UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxDevice_Reset ( + _In_ UFXDEVICE Device + ) +/*++ + +Routine Description: + + Cancels all transfers and disables non-zero endpoints in + response to USB reset. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +--*/ +{ + PUFXDEVICE_CONTEXT DeviceContext; + PREGISTERS_CONTEXT RegistersContext; + ULONG EpIndex; + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(Device); + RegistersContext = DeviceGetRegistersContext(DeviceContext->FdoWdfDevice); + + // + // Get EP0 back to setup stage. + // + TransferReset(WdfCollectionGetFirstItem(DeviceContext->Endpoints)); + + // + // Disable all non-default endpoints + // + + // + // #### TODO: Insert code to disable non-default endpoints #### + // + + // + // End any transfers on non-default endpoints. + // + for (EpIndex = 1; EpIndex < WdfCollectionGetCount(DeviceContext->Endpoints); EpIndex++) { + TransferReset(WdfCollectionGetItem(DeviceContext->Endpoints, EpIndex)); + } + + TraceExit(); +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxDeviceStopOrResumeIdle ( + _In_ UFXDEVICE Device, + _In_ USBFN_DEVICE_STATE UsbState, + _In_ USBFN_PORT_TYPE UsbPort + ) +/*++ + +Routine Description: + + Examines the device USB state and port type and determines + if it needs to stop or resume idle. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +Return Value: + + STATUS_SUCCESS on success, or an appropirate NTSTATUS message on failure. + +--*/ +{ + PUFXDEVICE_CONTEXT DeviceContext; + PCONTROLLER_CONTEXT ControllerContext; + NTSTATUS Status; + BOOLEAN NeedPower; + DEVICE_POWER_STATE DxState = PowerDeviceD3; + + PAGED_CODE(); + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(Device); + ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); + + switch (UsbState) { + + case UsbfnDeviceStateAttached: + __fallthrough; + case UsbfnDeviceStateDefault: + + switch (UsbPort) { + + case UsbfnStandardDownstreamPort: + __fallthrough; + case UsbfnChargingDownstreamPort: + __fallthrough; + case UsbfnUnknownPort: + NeedPower = TRUE; + break; + + case UsbfnDedicatedChargingPort: + case UsbfnProprietaryDedicatedChargingPort: + NeedPower = FALSE; + DxState = PowerDeviceD2; + break; + + default: + NeedPower = FALSE; + } + break; + + case UsbfnDeviceStateSuspended: + NeedPower = FALSE; + DxState = PowerDeviceD2; + break; + + case UsbfnDeviceStateAddressed: + __fallthrough; + + case UsbfnDeviceStateConfigured: + NeedPower = TRUE; + break; + + default: + NeedPower = FALSE; + } + + // + // Determine if our lowest idle state has changed, and set it if so + // + if (DxState != ControllerContext->IdleSettings.DxState) + { + ControllerContext->IdleSettings.DxState = DxState; + Status = WdfDeviceAssignS0IdleSettings( + DeviceContext->FdoWdfDevice, + &ControllerContext->IdleSettings); + CHK_NT_MSG(Status, "Failed to update device idle settings"); + } + + if (NeedPower && DeviceContext->IsIdle) { + // + // We don't want to update the USB state /port until we stop idle to + // prevent D0 -> DX path from reading the wrong state. + // + TraceInformation("Stopping idle"); + Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE); + CHK_NT_MSG(Status, "Failed to stop idle"); + DeviceContext->UsbState = UsbState; + DeviceContext->UsbPort = UsbPort; + DeviceContext->IsIdle = FALSE; + + } else if (!NeedPower && !DeviceContext->IsIdle) { + // + // We need to update USB state / port before resume idle to ensure + // D0 -> DX path reads the correct state. + // + DeviceContext->UsbState = UsbState; + DeviceContext->UsbPort = UsbPort; + DeviceContext->IsIdle = TRUE; + TraceInformation("Resuming idle"); + WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice); + + } else { + TraceInformation("No idle action"); + DeviceContext->UsbState = UsbState; + DeviceContext->UsbPort = UsbPort; + } + + Status = STATUS_SUCCESS; + +End: + TraceExit(); + return Status; +} + +VOID +UfxDevice_EvtDevicePortDetect ( + _In_ UFXDEVICE UfxDevice + ) +/*++ +Routine Description: + + Starts the port detection state machine + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +--*/ +{ + PUFXDEVICE_CONTEXT DeviceContext; + PCONTROLLER_CONTEXT ControllerContext; + + DeviceContext = UfxDeviceGetContext(UfxDevice); + ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); + + // + // #### TODO: Insert code to determine port/charger type #### + // + // In this example we will return an unknown port type. This will allow UFX to connect to a host if + // one is present. UFX will timeout after 5 seconds if no host is present and transition to + // an invalid charger type, which will allow the controller to exit D0. + // + UfxDevicePortDetectComplete(ControllerContext->UfxDevice, UsbfnUnknownPort); +} + + +VOID +UfxDevice_EvtDeviceRemoteWakeupSignal ( + _In_ UFXDEVICE UfxDevice + ) +/*++ +Routine Description: + + Signals Remote Wakeup to the Host by issuing a link state change command. + It acquires and releases the power reference to ensure a valid power state + before accessing the device. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + +--*/ +{ + NTSTATUS Status; + PUFXDEVICE_CONTEXT DeviceContext; + + PAGED_CODE(); + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(UfxDevice); + + // + // Stop Idle to ensure the device is in working state + // + Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE); + if (!NT_SUCCESS(Status)) { + TraceError("Failed to stop idle %!STATUS!", Status); + goto End; + } + + // + // Issue a Link State Change Request. + // + + // + // #### TODO: Insert code to issue a link state change on the controller #### + // + + WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice); + +End: + UfxDeviceEventComplete(UfxDevice, Status); + TraceExit(); +} + +VOID +UfxDevice_EvtDeviceTestModeSet ( + _In_ UFXDEVICE UfxDevice, + _In_ ULONG TestMode + ) +/*++ + +Routine Description: + + EvtDeviceTestModeSet handler for the UFXDEVICE object. + + Handles a set test mode request from the host. Places the controller into + the specified test mode. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + TestMode - Test mode value. See Section 7.1.20 of the USB 2.0 specification for definitions of + each test mode. + +--*/ +{ + NTSTATUS Status; + + UNREFERENCED_PARAMETER(TestMode); + + TraceEntry(); + + // + // #### TODO: Insert code to put the controller into the specified test mode #### + // + + Status = STATUS_SUCCESS; + + UfxDeviceEventComplete(UfxDevice, Status); + TraceExit(); +} + +VOID +UfxDevice_EvtDeviceSuperSpeedPowerFeature ( + _In_ UFXDEVICE Device, + _In_ USHORT Feature, + _In_ BOOLEAN Set + ) +/*++ + +Routine Description: + + EvtDeviceSuperSpeedPowerFeature handler for the UFXDEVICE object. + + Handles a set or clear U1/U2 request from the host. + +Arguments: + + UfxDevice - UFXDEVICE object representing the device. + + Feature - Indicates the feature being set or cleared. Either U1 or U2 enable. + + Set - Indicates if the feature should be set or cleared + +--*/ +{ + TraceEntry(); + + if (Feature == USB_FEATURE_U1_ENABLE) { + if (Set == TRUE) { + // + // #### TODO: Insert code to initiate U1 #### + // + } else { + // + // #### TODO: Insert code to exit U1 #### + // + } + } else if (Feature == USB_FEATURE_U2_ENABLE) { + if (Set == TRUE) { + // + // #### TODO: Insert code to initiate U2 #### + // + } else { + // + // #### TODO: Insert code to exit U2 #### + // + } + } else { + NT_ASSERT(FALSE); + } + + UfxDeviceEventComplete(Device, STATUS_SUCCESS); + TraceExit(); +} + diff --git a/usb/ufxclientsample/ufxdevice.h b/usb/ufxclientsample/ufxdevice.h new file mode 100644 index 00000000..4b78caba --- /dev/null +++ b/usb/ufxclientsample/ufxdevice.h @@ -0,0 +1,67 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ufxdevice.h + +Abstract: + + Defines the structures needed for UFXDEVICE object + +Environment: + + Kernel mode + +--*/ +#pragma once + +#define MAX_PHYSICAL_ENDPOINTS 32 + +// +// Context space for Sample UFXDEVICE object +// +typedef struct _UFXDEVICE_CONTEXT { + WDFDEVICE FdoWdfDevice; + + // + // This is an out-of-order collection of endpoints, since endpoints can be + // re-ordered as UFX brings interfaces up and down. However, endpoint 0 + // is always at index 0. + // + WDFCOLLECTION Endpoints; + UFXENDPOINT PhysicalEndpointToUfxEndpoint[MAX_PHYSICAL_ENDPOINTS]; + USBFN_DEVICE_STATE UsbState; + USBFN_PORT_TYPE UsbPort; + BOOLEAN IsIdle; +} UFXDEVICE_CONTEXT, *PUFXDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(UFXDEVICE_CONTEXT, UfxDeviceGetContext); + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxDevice_DeviceCreate( + _In_ WDFDEVICE WdfDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxDevice_Reset ( + _In_ UFXDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxDeviceSetRunStop ( + _In_ UFXDEVICE UfxDevice, + _In_ BOOLEAN Set + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxDevice_StartConfiguration ( + _In_ UFXDEVICE Device, + _In_ BOOLEAN SoftReset + ); diff --git a/usb/ufxclientsample/ufxendpoint.c b/usb/ufxclientsample/ufxendpoint.c new file mode 100644 index 00000000..195501ec --- /dev/null +++ b/usb/ufxclientsample/ufxendpoint.c @@ -0,0 +1,481 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ufxendpoint.c + +Abstract: + + Defines the functions needed for UFXENDPOINT object + +Environment: + + Kernel mode + +--*/ + +#include "ufxendpoint.h" +#include "ufxdevice.h" +#include "transfer.h" +#include <usbfnioctl.h> +#include "registers.h" +#include "trace.h" +#include "device.h" +#include "ufxendpoint.tmh" + +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; +EVT_WDF_IO_QUEUE_IO_STOP EndpointQueue_EvtIoStop; +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtEndpointCommandQueue; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP UfxEndpoint_Cleanup; + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +UfxEndpointDescriptorUpdate ( + _In_ UFXENDPOINT Endpoint, + _In_ PUSB_ENDPOINT_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxEndpointAdd ( + _In_ UFXDEVICE Device, + _In_ PUSB_ENDPOINT_DESCRIPTOR Descriptor, + _Inout_ PUFXENDPOINT_INIT EndpointInit + ) +/*++ +Routine Description: + + Creates a UFXENDPOINT object, and initializes its contexts. + +Parameters Description: + + Device - UFXDEVICE associated with the endpoint. + + Descriptor - Endpoint descriptor for this endpoint. + + EndpointInit - Opaque structure from UFX. + +Return Value: + + STATUS_SUCCESS if successful, appropriate NTSTATUS message otherwise. +--*/ +{ + NTSTATUS Status; + WDF_OBJECT_ATTRIBUTES Attributes; + WDF_IO_QUEUE_CONFIG TransferQueueConfig; + WDF_OBJECT_ATTRIBUTES TransferQueueAttributes; + WDF_IO_QUEUE_CONFIG CommandQueueConfig; + WDF_OBJECT_ATTRIBUTES CommandQueueAttributes; + UFXENDPOINT Endpoint; + PUFXENDPOINT_CONTEXT EpContext; + PUFXDEVICE_CONTEXT DeviceContext; + UFX_ENDPOINT_CALLBACKS Callbacks; + PENDPOINT_QUEUE_CONTEXT QueueContext; + WDFQUEUE Queue; + + TraceEntry(); + + DeviceContext = UfxDeviceGetContext(Device); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, UFXENDPOINT_CONTEXT); + Attributes.ExecutionLevel = WdfExecutionLevelPassive; + Attributes.EvtCleanupCallback = UfxEndpoint_Cleanup; + + // + // Note: Execution level needs to be passive to avoid deadlocks with WdfRequestComplete. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&TransferQueueAttributes, ENDPOINT_QUEUE_CONTEXT); + TransferQueueAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + WDF_IO_QUEUE_CONFIG_INIT(&TransferQueueConfig, WdfIoQueueDispatchManual); + TransferQueueConfig.AllowZeroLengthRequests = TRUE; + TransferQueueConfig.EvtIoStop = EndpointQueue_EvtIoStop; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&CommandQueueAttributes, ENDPOINT_QUEUE_CONTEXT); + CommandQueueAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + WDF_IO_QUEUE_CONFIG_INIT(&CommandQueueConfig, WdfIoQueueDispatchSequential); + CommandQueueConfig.EvtIoInternalDeviceControl = EvtEndpointCommandQueue; + + UFX_ENDPOINT_CALLBACKS_INIT(&Callbacks); + UfxEndpointInitSetEventCallbacks(EndpointInit, &Callbacks); + + Status = UfxEndpointCreate( + Device, + EndpointInit, + &Attributes, + &TransferQueueConfig, + &TransferQueueAttributes, + &CommandQueueConfig, + &CommandQueueAttributes, + &Endpoint); + CHK_NT_MSG(Status, "Failed to create ufxendpoint!"); + + Status = WdfCollectionAdd(DeviceContext->Endpoints, Endpoint); + CHK_NT_MSG(Status, "Failed to add endpoint to collection!"); + + EpContext = UfxEndpointGetContext(Endpoint); + EpContext->UfxDevice = Device; + EpContext->WdfDevice = DeviceContext->FdoWdfDevice; + RtlCopyMemory(&EpContext->Descriptor, Descriptor, sizeof(*Descriptor)); + + Queue = UfxEndpointGetTransferQueue(Endpoint); + QueueContext = EndpointQueueGetContext(Queue); + QueueContext->Endpoint = Endpoint; + + Queue = UfxEndpointGetCommandQueue(Endpoint); + QueueContext = EndpointQueueGetContext(Queue); + QueueContext->Endpoint = Endpoint; + + Status = TransferInitialize(Endpoint); + CHK_NT_MSG(Status, "Failed to initialize endpoint transfers"); + + // + // This can happen if we're handling a SetInterface command. + // + if (DeviceContext->UsbState == UsbfnDeviceStateConfigured) { + UfxEndpointConfigure(Endpoint); + } + + Status = WdfIoQueueReadyNotify( + UfxEndpointGetTransferQueue(Endpoint), + TransferReadyNotify, + Endpoint); + CHK_NT_MSG(Status, "Failed to register ready notify"); + +End: + TraceExit(); + return Status; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxEndpointConfigureHardware ( + _In_ UFXENDPOINT Endpoint, + _In_ BOOLEAN Modify + ) +/*++ +Routine Description: + + Configures the endpoint on the controller based on the + endpoint descriptor. If it is a control endpoint, configures + for both IN and OUT endpoints. + +Parameters Description: + + Endpoint - Endpoint to configure + + Modify - This is only TRUE for endpoint 0 on soft reset. + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + + TraceEntry(); + + UNREFERENCED_PARAMETER(Modify); + + EpContext = UfxEndpointGetContext(Endpoint); + + TraceInformation("CONFIGURE ENDPOINT: %08X Endpoint (%d)", (ULONG) Endpoint, EpContext->PhysicalEndpoint); + + // + // ControllerContext = DeviceGetControllerContext(EpContext->WdfDevice); + // + // The USB address is: + // EpContext->Descriptor.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK + // + // The maxPacketSize is: + // (Address == 0 && !Modify) ? 512 : EpContext->Descriptor.wMaxPacketSize; + // + // The Interval is: + // ((EpContext->Descriptor.bInterval > 0) && (ControllerContext->Speed != UsbFullSpeed)) ? + // EpContext->Descriptor.bInterval : + // 0; + // + + if (CONTROL_ENDPOINT(Endpoint)) { + // + // #### TODO: Configure both IN and OUT endpoints #### + // + } else { + if (DIRECTION_IN(Endpoint)) { + // + // #### TODO: Configure the IN endpoint #### + // + } else { + // + // #### TODO: Configure the OUT endpoint #### + // + } + } + + TraceExit(); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxEndpointConfigure ( + _In_ UFXENDPOINT Endpoint + ) +/*++ +Routine Description: + + Enables and configures the endpoint on the controller. + +Parameters Description: + + Endpoint - Endpoint to configure + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + ULONG EndpointMask; + ULONG Address; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + + EndpointMask = 1 << (EpContext->PhysicalEndpoint); + if (CONTROL_ENDPOINT(Endpoint)) { + EndpointMask |= 1 << (EpContext->PhysicalEndpoint + 1); + } + + Address = EpContext->Descriptor.bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK; + + // + // Configure the endpoint + // + UfxEndpointConfigureHardware(Endpoint, Address == 0); + + // + // #### TODO: Insert code to enable the endpoint on the controller #### + // + + if (Address != 0) { + TransferStart(Endpoint); + } + + TraceExit(); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +UfxEndpointDescriptorUpdate ( + _In_ UFXENDPOINT Endpoint, + _In_ PUSB_ENDPOINT_DESCRIPTOR Descriptor + ) +/*++ +Routine Description: + + Updates the descriptor and re-programs the endpoint. + If endpoint 0 is passed, starts a new configuration. + +Parameters Description: + + Endpoint - Endpoint to update. + + Descriptor - Endpoint descriptor for this endpoint. + +Return Value: + + STATUS_SUCCESS if successful, appropriate NTSTATUS message otherwise. + +--*/ +{ + PUFXENDPOINT_CONTEXT EpContext; + + TraceEntry(); + + EpContext = UfxEndpointGetContext(Endpoint); + + RtlCopyMemory(&EpContext->Descriptor, Descriptor, sizeof(USB_ENDPOINT_DESCRIPTOR)); + + if ((Descriptor->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK) == 0) { + UfxEndpointConfigure(Endpoint); + } + + TraceExit(); + return STATUS_SUCCESS; +} + +VOID +UfxEndpoint_Cleanup ( + _In_ WDFOBJECT Object + ) +/*++ +Routine Description: + + Cleanup routine for the UFX endpoint object. + +Parameters Description: + + Object - UFX endpoint object + +--*/ +{ + UFXENDPOINT Endpoint; + PUFXENDPOINT_CONTEXT EpContext; + ULONG EndpointMask; + PUFXDEVICE_CONTEXT DeviceContext; + NTSTATUS Status; + + TraceEntry(); + + Endpoint = (UFXENDPOINT) Object; + EpContext = UfxEndpointGetContext(Endpoint); + DeviceContext = UfxDeviceGetContext(EpContext->UfxDevice); + + // + // Release all references + // + WdfCollectionRemove(DeviceContext->Endpoints, Endpoint); + + // + // Disable the endpoint. Note queue should already be purged by UFX. + // + Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE); + CHK_NT_MSG(Status, "Failed to stop idle to disable endpoint"); + + EndpointMask = 1 << (EpContext->PhysicalEndpoint); + if (CONTROL_ENDPOINT(Endpoint)) { + EndpointMask |= 1 << (EpContext->PhysicalEndpoint + 1); + } + + // + // #### TODO: Add code to disable the endpoint on the controller #### + // + + WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice); + + // + // Delete allocated stuff + // + TransferDestroy(Endpoint); + +End: + TraceExit(); +} + +_Use_decl_annotations_ +VOID +EndpointQueue_EvtIoStop ( + WDFQUEUE Queue, + WDFREQUEST Request, + ULONG ActionFlags + ) +/*++ +Routine Description: + + EvtIoStop event handler + +Parameters Description: + + Queue - Handle to the queue object + + Request - The request to be completed, requeued, or suspended. + + ActionFlags - Bitmask indicating action to take and if request is cancelable. + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + TraceEntry(); + + TransferRequestCancel(Request, TRUE); + + TraceExit(); +} + +VOID +EvtEndpointCommandQueue ( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode + ) +/*++ +Routine Description: + + EvtIoInternalDeviceControl event handler + +Parameters Description: + + Queue - Handle to the queue object + + Request - Internal device control request. + + OutputBufferLength - size of the output buffer. + + InputBufferLength - size of the input buffer. + + IoControlCode - IOCTL for the request. + +--*/ + +{ + PVOID OutputBuffer; + PENDPOINT_QUEUE_CONTEXT QueueContext; + NTSTATUS Status; + PUFXENDPOINT_CONTEXT EpContext; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + TraceEntry(); + + QueueContext = EndpointQueueGetContext(Queue); + EpContext = UfxEndpointGetContext(QueueContext->Endpoint); + + Status = WdfRequestRetrieveOutputBuffer(Request, 0, &OutputBuffer, NULL); + CHK_NT_MSG(Status, "Failed to retrieve command output buffer"); + + switch(IoControlCode) { + case IOCTL_INTERNAL_USBFN_GET_PIPE_STATE: + TransferGetStall( + QueueContext->Endpoint, + (PBOOLEAN) OutputBuffer); + + WdfRequestComplete(Request, STATUS_SUCCESS); + break; + + case IOCTL_INTERNAL_USBFN_SET_PIPE_STATE: + if (*((PBOOLEAN) OutputBuffer)) { + EpContext->StallRequest = Request; + TransferCommandStallSet(QueueContext->Endpoint); + + } else { + EpContext->ClearRequest = Request; + TransferCommandStallClear(QueueContext->Endpoint); + } + break; + + case IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE: + Status = UfxEndpointDescriptorUpdate( + QueueContext->Endpoint, + (PUSB_ENDPOINT_DESCRIPTOR) OutputBuffer); + CHK_NT_MSG(Status, "Failed to update endpoint descriptor"); + WdfRequestComplete(Request, STATUS_SUCCESS); + break; + + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + goto End; + } + +End: + if (!NT_SUCCESS(Status)) { + WdfRequestComplete(Request, Status); + } + TraceExit(); +}
\ No newline at end of file diff --git a/usb/ufxclientsample/ufxendpoint.h b/usb/ufxclientsample/ufxendpoint.h new file mode 100644 index 00000000..7eb3a283 --- /dev/null +++ b/usb/ufxclientsample/ufxendpoint.h @@ -0,0 +1,73 @@ +/*++ + +Copyright (c) 1990-2013 Microsoft Corporation. All rights reserved. + +Module Name: + + ufxendpoint.h + +Abstract: + + Defines the structures and functions needed for UFXENDPOINT object + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#include <ufxclient.h> +#include "transfer.h" + +#define CONTROL_ENDPOINT(Endpoint) \ + ((UfxEndpointGetContext(Endpoint)->Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == \ + USB_ENDPOINT_TYPE_CONTROL) + +#define DIRECTION_IN(Endpoint) \ + (CONTROL_ENDPOINT(Endpoint) || \ + USB_ENDPOINT_DIRECTION_IN(UfxEndpointGetContext(Endpoint)->Descriptor.bEndpointAddress)) + +#define DIRECTION_OUT(Endpoint) \ + (CONTROL_ENDPOINT(Endpoint) || \ + USB_ENDPOINT_DIRECTION_OUT(UfxEndpointGetContext(Endpoint)->Descriptor.bEndpointAddress)) + +typedef struct _UFXENDPOINT_CONTEXT { + WDFDEVICE WdfDevice; + UFXDEVICE UfxDevice; + USB_ENDPOINT_DESCRIPTOR Descriptor; + ULONG PhysicalEndpoint; + WDFREQUEST StallRequest; + WDFREQUEST ClearRequest; +} UFXENDPOINT_CONTEXT, *PUFXENDPOINT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(UFXENDPOINT_CONTEXT, UfxEndpointGetContext); + +typedef struct _ENDPOINT_QUEUE_CONTEXT { + UFXENDPOINT Endpoint; +} ENDPOINT_QUEUE_CONTEXT, *PENDPOINT_QUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ENDPOINT_QUEUE_CONTEXT, EndpointQueueGetContext); + +_Must_inspect_result_ +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +UfxEndpointAdd ( + _In_ UFXDEVICE Device, + _In_ PUSB_ENDPOINT_DESCRIPTOR Descriptor, + _Inout_ PUFXENDPOINT_INIT EndpointInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxEndpointConfigure ( + _In_ UFXENDPOINT Endpoint + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +UfxEndpointConfigureHardware ( + _In_ UFXENDPOINT Endpoint, + _In_ BOOLEAN Modify + );
\ No newline at end of file diff --git a/usb/umdf2_fx2/ReadMe.md b/usb/umdf2_fx2/ReadMe.md index 4f825de5..291e91cb 100644 --- a/usb/umdf2_fx2/ReadMe.md +++ b/usb/umdf2_fx2/ReadMe.md @@ -1,326 +1,74 @@ -Sample UMDF Function Driver for OSR USB-FX2 (UMDF Version 1) -============================================================ +Sample Function Driver for OSR USB-FX2 (UMDF Version 2) +======================================================= -The umdf\_fx2 sample is a User-Mode Driver Framework (UMDF) driver for the OSR USB-FX2 device. It includes a test app and sample device metadata, and supports impersonation and idle power down. +The umdf2\_fx2 sample is a User-Mode Driver Framework (UMDF) version 2 driver for the OSR USB-FX2 device. + +The specification for the device is at <http://www.osronline.com/hardware/OSRFX2_32.pdf>. The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. ## Universal Windows Driver Compliant This sample builds a Universal Windows Driver. It uses only APIs and DDIs that are included in OneCoreUAP. -The sample can also be used with the CustomDeviceAccess MSDK sample. The sample demonstrates how to perform bulk and interrupt data transfers to an USB device. The specification for the device is at <http://www.osronline.com/hardware/OSRFX2_32.pdf>. The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. - -Starting in Windows 8.1, the osrusbfx2 sample has been divided into these samples: -* [WDF Sample Driver Learning Lab for OSR USB-FX2](http://msdn.microsoft.com/en-us/library/windows/hardware/): This sample is a series of iterative drivers that demonstrate how to write a "Hello World" driver and adds additional features in each step. -* [kmdf\_fx2](gallery_samples.123a_gallery#1): This sample is the final version of kernel-mode [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) driver. The sample demonstrates KMDF methods. -* umdf\_fx2: This sample is the final version of the user-mode driver [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/). The sample demonstrates UMDF methods. - -**Note** -Due to a known bug in the current Windows Driver Kit tools, when building this sample in Debug mode, the exe project may report some ApiValidator warnings. These can be safely ignored. - -Overview --------- - -Here is the overview of the device: - -- The device is based on the development board supplied with the Cypress EZ-USB FX2 Development Kit (CY3681). -- It contains 1 interface and 3 endpoints (Interrupt IN, Bulk Out, Bulk IN). -- Firmware supports vendor commands to query or set LED Bar graph display and 7-segment LED display, and to query toggle switch states. -- Interrupt Endpoint: - - Sends an 8-bit value that represents the state of the switches. - - Sent on startup, resume from suspend, and whenever the switch pack setting changes. - - Firmware does not de-bounce the switch pack. - - One switch change can result in multiple bytes being sent. - - Bits are in the reverse order of the labels on the pack (for example, bit 0x80 is labeled 1 on the pack). -- Bulk Endpoints are configured for loopback: - - The device moves data from IN endpoint to OUT endpoint. - - The device does not change the values of the data it receives nor does it internally create any data. - - Endpoints are always double buffered. - - Maximum packet size depends on speed (64 full speed, 512 high speed). - -Testing the driver ------------------- - -You can use the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample to test the umdf\_fx2 sample. - -This sample also includes a test application, osrusbfx2.exe, that you can use to test the device. This console application enumerates the interface registered by the driver and opens the device to send read, write, or IOCTL requests based on the command line options. - -Usage for Read/Write test: - -- -r [*n*], where *n* is number of bytes to read. -- -w [*n*], where *n* is number of bytes to write. -- -c [*n*], where *n* is number of iterations (default = 1). -- -v, shows verbose read data. -- -p, plays with Bar Display, Dip Switch, 7-Segment Display. -- -a, performs asynchronous I/O operation. -- -u, dumps USB configuration and pipe information. -- -f \<*filename*\> [*interval-seconds*], where *interval-seconds* is a delay in milliseconds, to send a text file to the seven-segment display (UMDF only) - -**Playing with the 7 segment display, toggle switches, and bar graph display** - -Use the command **osrusbfx2.exe -p** with options 1 through 9 to set and clear bar graph display, set and get 7 segment state, and read the toggle switch states. The following shows the function options: - -1. Light Bar -2. Clear Bar -3. Light entire Bar graph -4. Clear entire Bar graph -5. Get bar graph state -6. Get Switch state -7. Get Switch Interrupt Message -8. Get 7 segment state -9. Set 7 segment state -10. Reset the device -11. Re-enumerate the device - -0. Exit - -Selection: - -**Reset and re-enumerate the device** - -Use the command **osrusbfx2.exe -p** with options 10 and 11 to either reset the device or re-enumerate the device. - -**Read and write to bulk endpoints** - -The following commands send read and write requests to the device's bulk endpoint. - -- `osrusbfx2.exe -r 64` - - The preceding command reads 64 bytes to the bulk IN endpoint. - -- `osrusbfx2.exe -w 64 ` - - The preceding command writes 64 bytes to the bulk OUT endpoint. - -- `osrusbfx2.exe -r 64 -w 64 -c 100 -v` - - The preceding command first writes 64 bytes of data to bulk OUT endpoint (Pipe 1), then reads 64 bytes from bulk IN endpoint (Pipe 2), and then compares the read buffer with write buffer to see if they match. If the buffer contents match, it repeats this operation 100 times. - -- `osrusbfx2.exe -a` - - The preceding command reads and writes to the device asynchronously in an infinite loop. - -The bulk endpoints are double buffered. Depending on the operational speed (full or high), the buffer size is either 64 bytes or 512 bytes, respectively. A request to read data does not complete if the buffers are empty. If the buffers are full, a request to write data does not complete until the buffers are emptied. When you are doing a synchronous read, make sure the endpoint buffer has data (for example, when you send 512 bytes write request to the device operating in full speed mode). Because the endpoints are double buffered, the total buffer capacity is 256 bytes. The first 256 bytes fills the buffer and the write request waits in the USB stack until the buffers are emptied. If you run another instance of the application to read 512 bytes of data, both write and read requests complete successfully. - -**Displaying descriptors** - -The following command displays all the descriptors and endpoint information. - -**osrusbfx2.exe -u** - -If the device is operating in high speed mode, you get the following information: - -`===================` - -`USB_CONFIGURATION_DESCRIPTOR` - -`bLength = 0x9, decimal 9` - -`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` - -`wTotalLength = 0x27, decimal 39` - -`bNumInterfaces = 0x1, decimal 1` - -`bConfigurationValue = 0x1, decimal 1` - -`iConfiguration = 0x4, decimal 4` - -`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` - -`MaxPower = 0x32, decimal 50` - -`-----------------------------` - -`USB_INTERFACE_DESCRIPTOR #0` - -`bLength = 0x9` - -`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` - -`bInterfaceNumber = 0x0` - -`bAlternateSetting = 0x0` - -`bNumEndpoints = 0x3` - -`bInterfaceClass = 0xff` - -`bInterfaceSubClass = 0x0` - -`bInterfaceProtocol = 0x0` - -`bInterface = 0x0` - -`------------------------------` - -`USB_ENDPOINT_DESCRIPTOR for Pipe00` - -`bLength = 0x7` - -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` - -`bEndpointAddress= 0x81 ( INPUT )` - -`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` - -`wMaxPacketSize= 0x49, decimal 73` - -`bInterval = 0x1, decimal 1` - -`------------------------------` - -`USB_ENDPOINT_DESCRIPTOR for Pipe01` - -`bLength = 0x7` - -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` - -`bEndpointAddress= 0x6 ( OUTPUT )` - -`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` - -`wMaxPacketSize= 0x200, ` - -`decimal 512 bInterval = 0x0, ` - -`decimal 0` - -`------------------------------` - -`USB_ENDPOINT_DESCRIPTOR for Pipe02` - -`bLength = 0x7` - -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` - -`bEndpointAddress= 0x88 ( INPUT )` - -`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` - -`wMaxPacketSize= 0x200, decimal 512` - -`bInterval = 0x0, decimal 0` - -If the device is operating in low speed mode, you will get the following information: - -`===================` - -`USB_CONFIGURATION_DESCRIPTOR` - -`bLength = 0x9, decimal 9` - -`bDescriptorType = 0x2 ( USB_CONFIGURATION_DESCRIPTOR_TYPE )` - -`wTotalLength = 0x27, decimal 39` - -`bNumInterfaces = 0x1, decimal 1` - -`bConfigurationValue = 0x1, decimal 1` - -`iConfiguration = 0x3, decimal 3` - -`bmAttributes = 0xa0 ( USB_CONFIG_BUS_POWERED )` - -`MaxPower = 0x32, decimal 50 ` - -`-----------------------------` - -`USB_INTERFACE_DESCRIPTOR #0` - -`bLength = 0x9` - -`bDescriptorType = 0x4 ( USB_INTERFACE_DESCRIPTOR_TYPE )` - -`bInterfaceNumber = 0x0 bAlternateSetting = 0x0` - -`bNumEndpoints = 0x3` - -`bInterfaceClass = 0xff` - -`bInterfaceSubClass = 0x0` - -`bInterfaceProtocol = 0x0` - -`bInterface = 0x0` - -`------------------------------` - -`USB_ENDPOINT_DESCRIPTOR for Pipe00` - -`bLength = 0x7` - -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` - -`bEndpointAddress= 0x81 ( INPUT )` - -`bmAttributes= 0x3 ( USB_ENDPOINT_TYPE_INTERRUPT )` - -`wMaxPacketSize= 0x49, decimal 73` - -`bInterval = 0x1, decimal 1` +Set the configuration and platform in Visual Studio +--------------------------------------------------- -`------- -----------------------` +In Visual Studio, in Solution Explorer, right click **Solution**, and choose **Configuration Manager**. Set the configuration and the platform. Make sure that the configuration and platform are the same for both the driver project and the package project. Do not check the **Deploy** boxes. Because this solution uses UMDF version 2, you cannot select a configuration earlier than Windows 8.1. -`USB_ENDPOINT_DESCRIPTOR for Pipe01` +Build the sample using Visual Studio +------------------------------------ -`bLength = 0x7` +In Visual Studio, on the **Build** menu, choose **Build Solution**. -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` +For more information about using Visual Studio to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). -`bEndpointAddress= 0x6 ( OUTPUT )` +Locate the built driver package +------------------------------- -`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` +In File Explorer, navigate to the folder that contains your built driver package. The location of this folder varies depending on what you set for configuration and platform. For example, if your settings are Win8.1 Debug and x64, the package is in your solution folder under x64\\Win8.1Debug\\Package. -`wMaxPacketSize= 0x40, decimal 64` +Run the sample +-------------- -`bInterval = 0x0, decimal 0` +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. -`------------------------------` +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy a driver sample automatically or manually. -`USB_ENDPOINT_DESCRIPTOR for Pipe02` +### Automatic deployment (FX2 board) -`bLength = 0x7` +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). -`bDescriptorType = 0x5 ( USB_ENDPOINT_DESCRIPTOR_TYPE )` +1. Plug in the OSR USB-FX2 board to the target computer. +2. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +3. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Install and Verify**. Click **OK**. +4. On the **Build** menu, choose **Deploy Package** or **Build Solution**. -`bEndpointAddress= 0x88 ( INPUT )` +### Manual deployment (FX2 board) -`bmAttributes= 0x2 ( USB_ENDPOINT_TYPE_BULK )` +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). -`wMaxPacketSize= 0x40, decimal 64` +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\umdf2\_fx2). +2. Plug in the OSR USB-FX2 board to the target computer. Open a Command Prompt window and enter **dvmgmt** to open Device Manager. In Device Manager, locate the node for the OSR USB-FX2 board. Right click the node, and choose **Properties**. In the **Details** tab, under **Properties**, choose **Hardware Ids**. Note the hardware IDs listed for your FX2 board. One of these IDs should match one of the IDs in the osrusbfx2um.inf file. For example, Device Manager might show an ID of USB\\VID\_0547&PID\_1002, which matches one of the IDs in the [Microsoft.*xxx*] section of osrusbfx2um.inf. -`bInterval = 0x0, decimal 0 ` +3. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter this command: -Sample Contents ---------------- + **devcon update osrusbfx2um.inf"***HardwareID***"** -Folder + where *HardwareID* is the hardware ID of your FX2 board. Here is an example: -Description + **devcon update osrusbfx2um.inf "USB\\VID\_0547&PID\_1002"** -usb\\umdf\_fx2\\driver +View the driver for the OSR USB-FX2 board in Device Manager +----------------------------------------------------------- -This directory contains driver code that demonstrates the following functionality: +On the target computer, in your Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **UMDF 2.0 Sample Driver for OSR Fx2 Learning Kit** (for example, this might be under the **Sample Device** node). -- Loads the driver and responds to PnP and Power events. You can install, uninstall, disable, enable, suspend, and resume the system. -- Registers a PnP device interface so that application can open a handle to the device. -- Implements **IPnpCallbackHardware** interface and initializes USB I/O targets in **IPnpCallbackHardware::OnPrepareHardware** method. -- Creates a sequential queue for handling IOCTL requests. -- Adds code to handle the IOCTL to set bar graph display. -- Creates a parallel queue for handling read and write requests. -- Retrieves memory from read and write requests, format the requests, and sends them to a USB target. -- Supports additional IOCTLs to get and set the 7-segment display, get bar graph display, and get config descriptor. -- Sets power policy for the device. -- Adds code to indicate that the device is ready by lighting up the period on 7-segment display. -- Calls **SetupDi** functions to determine the "BusTypeGUID" of the device, and uses impersonation to access resources that only the caller has access to. -- Shows how to implement idle and wake functionality to make the driver the power policy owner (PPO). The sample achieves this using power-managed queues and UMDF DDIs, AssignS0IdleSettings, and AssignSxWakeSettings. -- Demonstrates implementation of a continuous reader. -- Demonstrates the use of impersonation. +In Device Manager, on the **View** menu, choose **Devices by connection**. Locate **UMDF 2.0 Sample Driver for OSR Fx2 Learning Kit** as a child of a USB hub node, which may be contained with the **ACPI x64-based PC** node. -usb\\umdf\_fx2\\exe +Build the sample using MSBuild +------------------------------ -This directory contains a test application that can be used to drive the UMDF driver and FX2 device. This is a modified version of the test application for the KMDF Fx2 driver. +As an alternative to building the driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, umdf2echo.sln. Use the MSBuild command to build the solution. Here is an example: -usb\\umdf\_fx2\\deviceMetadata +**msbuild /p:configuration=”Win8 Release” /p:platform=”Win32” umdf2\_fx2.sln** -This directory contains the device metadata package for the sample. You must copy the device metadata to the system before installing the device. For information on how to update and deploy device metadata, see [Custom driver access sample](http://go.microsoft.com/fwlink/p/?LinkID=248288). +For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.inx b/usb/umdf2_fx2/driver/osrusbfx2um.inx index ff535c15..4f445ae3 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.inx +++ b/usb/umdf2_fx2/driver/osrusbfx2um.inx @@ -20,14 +20,14 @@ Signature="$Windows NT$" Class=Sample ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} -Provider=%MSFTUMDF% +Provider=%ProviderName% DriverVer=03/25/2005,0.0.0.1 CatalogFile=wudf.cat [Manufacturer] -%MSFTUMDF%=Microsoft,NT$ARCH$ +%MfgName%=OSR,NT$ARCH$ -[Microsoft.NT$ARCH$] +[OSR.NT$ARCH$] %OsrUsbDeviceName%=OsrUsb_Install, USB\Vid_045e&Pid_94aa&mi_00 %OsrUsbDeviceName%=OsrUsb_Install, USB\VID_0547&PID_1002 @@ -78,8 +78,9 @@ osrusbfx2um.dll ; =================== Generic ================================== [Strings] -MSFTUMDF="Microsoft Internal (WDF:UMDF)" -MediaDescription="Microsoft Sample Driver Installation Media" +ProviderName="TODO-Set-Provider" +MfgName="OSR" +MediaDescription="Sample Driver Installation Media" ClassName="Sample Device" WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" OsrUsbDeviceName="UMDF v2 Sample Driver for OSR USB Fx2 Learning Kit with NativeUSB" diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj index baa0a411..b6b1e253 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj +++ b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj @@ -19,12 +19,12 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{6A48DB7E-DC78-493F-9923-DCB9321C7667}</ProjectGuid> + <ProjectGuid>{AC913FF4-1E9D-4666-BA65-BA9C3C6BDC7A}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{7FB8FEE0-972F-4454-9A05-425221DC87B6}</SampleGuid> + <SampleGuid>{C259646B-9566-4D0C-96B5-74D23C92DABF}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -202,7 +202,6 @@ <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" /> diff --git a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters index 160a48d9..cf5c627c 100644 --- a/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters +++ b/usb/umdf2_fx2/driver/osrusbfx2um.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{21B700F3-2B7F-4332-A55B-C436016AC536}</UniqueIdentifier> + <UniqueIdentifier>{043629B9-E054-4FF3-874E-548E7D4FFBB7}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{B93FCB80-AF61-4C1D-9534-6B6EB29B526A}</UniqueIdentifier> + <UniqueIdentifier>{C31DA020-0B3B-4F1A-919E-C366757C9957}</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>{4C88E4BA-E0F4-45C9-852B-F96E9C9E5883}</UniqueIdentifier> + <UniqueIdentifier>{0D5B6280-46CF-448E-ACA9-DF9F20586F0A}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{3893D068-C2BA-4785-B0AE-9EF13A8DE5BB}</UniqueIdentifier> + <UniqueIdentifier>{B23BCA35-0435-4D67-8FEB-818995B8239C}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> @@ -36,9 +36,6 @@ </ClCompile> </ItemGroup> <ItemGroup> - <FilesToPackage Include=".\Debug\\osrusbfx2um.inf"> - <Filter>Driver Files</Filter> - </FilesToPackage> <Inf Include=".\osrusbfx2um.inx"> <Filter>Driver Files</Filter> </Inf> diff --git a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj index 0a26c683..8ebd4c2b 100644 --- a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj +++ b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj @@ -19,11 +19,11 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{FAF22768-F07B-437A-BB6B-4CA77B19D705}</ProjectGuid> + <ProjectGuid>{9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{BD1E8570-B544-4A6C-BF30-70EBD4456E54}</SampleGuid> + <SampleGuid>{71E76691-6085-472A-AEE3-32F302D432A1}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -179,7 +179,6 @@ <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" /> diff --git a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters index f9eac4c7..189b77ca 100644 --- a/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters +++ b/usb/umdf2_fx2/exe/osrusbfx2.vcxproj.Filters @@ -3,15 +3,15 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{E08AB654-AE1F-42CF-AD59-772321BAD1ED}</UniqueIdentifier> + <UniqueIdentifier>{7FC48C4A-E699-452E-9AC1-B87A1398097A}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{60796E01-8594-4A2D-9395-F4D0D6B07875}</UniqueIdentifier> + <UniqueIdentifier>{4AB8E4FC-C777-4E53-B3B1-546910707A69}</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>{D37B1ED9-9240-47CA-BF91-6FD1F6C8572F}</UniqueIdentifier> + <UniqueIdentifier>{9A57DDF7-3E20-42F4-BE75-466CADEFA001}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/usb/umdf2_fx2/exe/testapp.c b/usb/umdf2_fx2/exe/testapp.c index a7d82915..fce915b5 100644 --- a/usb/umdf2_fx2/exe/testapp.c +++ b/usb/umdf2_fx2/exe/testapp.c @@ -191,7 +191,7 @@ Return Value: return INVALID_HANDLE_VALUE; } - printf("DeviceName = (%s)\n", completeDeviceName); + printf("DeviceName = (%S)\n", completeDeviceName); if(Synchronous) { hDev = CreateFile(completeDeviceName, diff --git a/usb/umdf2_fx2/umdf2_fx2.sln b/usb/umdf2_fx2/umdf2_fx2.sln index 780c0e7f..fd2f0eb1 100644 --- a/usb/umdf2_fx2/umdf2_fx2.sln +++ b/usb/umdf2_fx2/umdf2_fx2.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{CAFE3118-273C-43B1-9895-909D2132640C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{3868A978-E3AA-4A0C-B3CA-23BA75D19CF8}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{E1EEF412-A834-4B7C-B3CB-D22FA4FF52CC}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{60363E6C-E86C-42ED-8222-ACAC1F71D486}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2um", "driver\osrusbfx2um.vcxproj", "{6A48DB7E-DC78-493F-9923-DCB9321C7667}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2um", "driver\osrusbfx2um.vcxproj", "{C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "exe\osrusbfx2.vcxproj", "{FAF22768-F07B-437A-BB6B-4CA77B19D705}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "exe\osrusbfx2.vcxproj", "{9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|Win32.ActiveCfg = Debug|Win32 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|Win32.Build.0 = Debug|Win32 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|Win32.ActiveCfg = Release|Win32 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|Win32.Build.0 = Release|Win32 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|x64.ActiveCfg = Debug|x64 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Debug|x64.Build.0 = Debug|x64 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|x64.ActiveCfg = Release|x64 - {6A48DB7E-DC78-493F-9923-DCB9321C7667}.Release|x64.Build.0 = Release|x64 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|Win32.ActiveCfg = Debug|Win32 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|Win32.Build.0 = Debug|Win32 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|Win32.ActiveCfg = Release|Win32 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|Win32.Build.0 = Release|Win32 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|x64.ActiveCfg = Debug|x64 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Debug|x64.Build.0 = Debug|x64 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|x64.ActiveCfg = Release|x64 - {FAF22768-F07B-437A-BB6B-4CA77B19D705}.Release|x64.Build.0 = Release|x64 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Debug|Win32.ActiveCfg = Debug|Win32 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Debug|Win32.Build.0 = Debug|Win32 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Release|Win32.ActiveCfg = Release|Win32 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Release|Win32.Build.0 = Release|Win32 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Debug|x64.ActiveCfg = Debug|x64 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Debug|x64.Build.0 = Debug|x64 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Release|x64.ActiveCfg = Release|x64 + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326}.Release|x64.Build.0 = Release|x64 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Debug|Win32.Build.0 = Debug|Win32 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Release|Win32.ActiveCfg = Release|Win32 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Release|Win32.Build.0 = Release|Win32 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Debug|x64.ActiveCfg = Debug|x64 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Debug|x64.Build.0 = Debug|x64 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Release|x64.ActiveCfg = Release|x64 + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6A48DB7E-DC78-493F-9923-DCB9321C7667} = {CAFE3118-273C-43B1-9895-909D2132640C} - {FAF22768-F07B-437A-BB6B-4CA77B19D705} = {E1EEF412-A834-4B7C-B3CB-D22FA4FF52CC} + {C25F378C-3D8F-4AF2-AFBB-7D438CBAB326} = {3868A978-E3AA-4A0C-B3CA-23BA75D19CF8} + {9D6DB868-3478-4CD3-9C16-CE9E1FD04AA6} = {60363E6C-E86C-42ED-8222-ACAC1F71D486} EndGlobalSection EndGlobal diff --git a/usb/umdf_filter_kmdf/Package/package.VcxProj b/usb/umdf_filter_kmdf/Package/package.VcxProj new file mode 100644 index 00000000..4ca7636e --- /dev/null +++ b/usb/umdf_filter_kmdf/Package/package.VcxProj @@ -0,0 +1,87 @@ +<?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> + <ItemGroup> + <ProjectReference Include="..\kmdf_driver\osrusbfx2.vcxproj"> + <Project>{6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}</Project> + </ProjectReference> + <ProjectReference Include="..\umdf_filter\WUDFOsrUsbFilter.vcxproj"> + <Project>{BE14DB05-36A7-4ECE-88E1-FB8157CA568E}</Project> + </ProjectReference> + </ItemGroup> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Utility</ConfigurationType> + <DriverType>Package</DriverType> + <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck> + <Configuration>Debug</Configuration> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Globals"> + <ProjectGuid>{2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}</ProjectGuid> + <SampleGuid>{9515D06E-6666-40E0-BC9B-4D353B06AF3B}</SampleGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <PropertyGroup> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + <ImportToStore>False</ImportToStore> + <InstallMode>None</InstallMode> + <HardwareIdString /> + <CommandLine /> + <ScriptPath /> + <DeployFiles /> + <ScriptName /> + <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery> + <EnableVerifier>False</EnableVerifier> + <AllDrivers>False</AllDrivers> + <VerifyProjectOutput>True</VerifyProjectOutput> + <VerifyDrivers /> + <VerifyFlags>133563</VerifyFlags> + </PropertyGroup> + <ItemDefinitionGroup> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters b/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters new file mode 100644 index 00000000..9aaef831 --- /dev/null +++ b/usb/umdf_filter_kmdf/Package/package.VcxProj.Filters @@ -0,0 +1,21 @@ +<?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>{86971831-99C4-48F4-BA75-63AFA1FF01D6}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{49BD12DD-8C0A-47ED-9D86-487828F8E2E1}</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>{A74FBF55-5FC8-4073-89C5-B13BFE528197}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{71D5E423-057B-48A2-90E2-66C66E3CC18C}</UniqueIdentifier> + </Filter> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/umdf_filter_kmdf/ReadMe.md b/usb/umdf_filter_kmdf/ReadMe.md new file mode 100644 index 00000000..3906d751 --- /dev/null +++ b/usb/umdf_filter_kmdf/ReadMe.md @@ -0,0 +1,78 @@ +Sample UMDF Filter above KMDF Function Driver for OSR USB-FX2 (UMDF Version 1) +============================================================================== + +The umdf\_filter\_kmdf sample demonstrates how to load a UMDF filter driver as an upper filter driver above the kmdf\_fx2 sample driver. + +The sample includes Event Tracing for Windows (ETW) tracing support, and is written for the OSR USB-FX2 Learning Kit. The specification for the device is at <http://www.osronline.com/hardware/OSRFX2_32.pdf>. + + + +Build the sample +---------------- + +The default Solution build configuration is Windows 8.1 Debug and Win32. You can change the default configuration to build for Windows 8 or Windows 7 version of the operating system. + +**To select a configuration and build a driver** + +1. Open the driver project or solution in Visual Studio 2013 (find *filtername*.sln or *filtername*.vcxproj). +2. Right-click the solution in the **Solutions Explorer** and select **Configuration Manager**. +3. From the **Configuration Manager**, select the **Active Solution Configuration** (for example, Windows 8.1 Debug or Windows 8.1 Release) and the **Active Solution Platform** (for example, Win32) that correspond to the type of build you are interested in. +4. From the **Build** menu, click **Build Solution** (Ctrl+Shift+B). + +Overview +-------- + +Here is the overview of the device: + +- The device is based on the development board supplied with the Cypress EZ-USB FX2 Development Kit (CY3681). +- It contains 1 interface and 3 endpoints (Interrupt IN, Bulk Out, Bulk IN). +- Firmware supports vendor commands to query or set LED Bar graph display and 7-segment LED display, and to query toggle switch states. +- Interrupt Endpoint: + - Sends an 8-bit value that represents the state of the switches. + - Sent on startup, resume from suspend, and whenever the switch pack setting changes. + - Firmware does not de-bounce the switch pack. + - One switch change can result in multiple bytes being sent. + - Bits are in the reverse order of the labels on the pack (for example, bit 0x80 is labeled 1 on the pack). +- Bulk Endpoints are configured for loopback: + - The device moves data from IN endpoint to OUT endpoint. + - The device does not change the values of the data it receives nor does it internally create any data. + - Endpoints are always double buffered. + - Maximum packet size depends on speed (64 full speed, 512 high speed). +- ETW events: + - Included osrusbfx2.man, which describes events added. + - Three events are targeted to the event log: + - Failure during the add device routine. + - Failure to start the OSR device on a USB 1.1 controller. + - Invocation of the “re-enumerate device” IOCTL. + - Read/write start/stop events can be used to measure the time taken. + +Testing the driver +------------------ + +You can test this sample either by using the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample application, or by using the osrusbfx2.exe test application. For information on how to build and use the osrusbfx2.exe application, see the test instructions for the [kmdf\_fx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) sample. + +Sample Contents +--------------- + +<table> +<colgroup> +<col width="50%" /> +<col width="50%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">Folder +Description</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left">usb\umdf_filter_kmdf\kmdf_driver +This directory contains source code for the kmdf_fx2 sample driver.</td> +<td align="left">usb\umdf_filter_kmdf\umdf_filter +This directory contains the UMDF filter driver.</td> +</tr> +</tbody> +</table> + + diff --git a/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h b/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h new file mode 100644 index 00000000..6681fa14 --- /dev/null +++ b/usb/umdf_filter_kmdf/inc/WUDFOsrUsbPublic.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + WUDFOsrUsbPublic.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications for the UMDF OSR device sample. + + Note that this driver does NOT use the same device interface GUID + as the KMDF OSR USB sample. + +Environment: + + user and kernel + +--*/ + +#pragma once + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +// {573E8C73-0CB4-4471-A1BF-FAB26C31D384} +DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, + 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84); + diff --git a/usb/umdf_filter_kmdf/inc/list.h b/usb/umdf_filter_kmdf/inc/list.h new file mode 100644 index 00000000..38d0b1e9 --- /dev/null +++ b/usb/umdf_filter_kmdf/inc/list.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + list.h + +Abstract: + + This module contains doubly linked list macros + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + + +FORCEINLINE +VOID +InitializeListHead( + IN PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +FORCEINLINE +BOOLEAN +RemoveEntryList( + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + return (BOOLEAN)(Flink == Blink); +} + +FORCEINLINE +VOID +InsertHeadList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE +VOID +InsertTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} diff --git a/usb/umdf_filter_kmdf/inc/public.h b/usb/umdf_filter_kmdf/inc/public.h new file mode 100644 index 00000000..22f6cb6d --- /dev/null +++ b/usb/umdf_filter_kmdf/inc/public.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + public.h + +Abstract: + + Public definitions for the OSR_FX2 device operations. + +Environment: + + User & Kernel mode + +--*/ + +#ifndef _PUBLIC_H +#define _PUBLIC_H + +#include <initguid.h> + +#include "WudfOsrUsbPublic.h" + + +// +// Define the structures that will be used by the IOCTL +// interface to the driver +// + +// +// BAR_GRAPH_STATE +// +// BAR_GRAPH_STATE is a bit field structure with each +// bit corresponding to one of the bar graph on the +// OSRFX2 Development Board +// +#include <pshpack1.h> + +#pragma warning( push ) +#pragma warning( disable : 4201 ) // nameless struct/union +#pragma warning( disable : 4214 ) // bit-field type other than int + +typedef struct _BAR_GRAPH_STATE { + + union { + + struct { + // + // Individual bars starting from the + // top of the stack of bars + // + // NOTE: There are actually 10 bars, + // but the very top two do not light + // and are not counted here + // + UCHAR Bar1 : 1; + UCHAR Bar2 : 1; + UCHAR Bar3 : 1; + UCHAR Bar4 : 1; + UCHAR Bar5 : 1; + UCHAR Bar6 : 1; + UCHAR Bar7 : 1; + UCHAR Bar8 : 1; + }; + + // + // The state of all the bar graph as a single + // UCHAR + // + UCHAR BarsAsUChar; + + }; + +}BAR_GRAPH_STATE, *PBAR_GRAPH_STATE; + +// +// SWITCH_STATE +// +// SWITCH_STATE is a bit field structure with each +// bit corresponding to one of the switches on the +// OSRFX2 Development Board +// +typedef struct _SWITCH_STATE { + + union { + struct { + // + // Individual switches starting from the + // left of the set of switches + // + UCHAR Switch1 : 1; + UCHAR Switch2 : 1; + UCHAR Switch3 : 1; + UCHAR Switch4 : 1; + UCHAR Switch5 : 1; + UCHAR Switch6 : 1; + UCHAR Switch7 : 1; + UCHAR Switch8 : 1; + }; + + // + // The state of all the switches as a single + // UCHAR + // + UCHAR SwitchesAsUChar; + + }; + + +}SWITCH_STATE, *PSWITCH_STATE; + +// +// Seven segment display bit values. +// + +// +// Undefine conflicting MFC constant +// +#undef SS_CENTER +#undef SS_LEFT +#undef SS_RIGHT + +#define SS_TOP 0x01 +#define SS_TOP_LEFT 0x40 +#define SS_TOP_RIGHT 0x02 +#define SS_CENTER 0x20 +#define SS_BOTTOM_LEFT 0x10 +#define SS_BOTTOM_RIGHT 0x04 +#define SS_BOTTOM 0x80 +#define SS_DOT 0x08 + +// +// FILE_PLAYBACK +// +// FILE_PLAYBACK structure contains the parameters for the PLAY_FILE I/O Control. +// + +typedef struct _FILE_PLAYBACK +{ + // + // The delay between changes in the display, in milliseconds. + // + + USHORT Delay; + + // + // The data file path. + // + + WCHAR Path[1]; +} FILE_PLAYBACK, *PFILE_PLAYBACK; + +#include <poppack.h> + +#define IOCTL_INDEX 0x800 +#define FILE_DEVICE_OSRUSBFX2 0x65500 + +#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 1, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 3, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 4, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 5, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + + +#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 6, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 7, \ + METHOD_BUFFERED, \ + FILE_READ_ACCESS) + + +#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 8, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ + IOCTL_INDEX + 9, \ + METHOD_OUT_DIRECT, \ + FILE_READ_ACCESS) + +#define IOCTL_OSRUSBFX2_PLAY_FILE CTL_CODE(FILE_DEVICE_OSRUSBFX2, \ + IOCTL_INDEX + 10, \ + METHOD_BUFFERED, \ + FILE_WRITE_ACCESS) + +#pragma warning(pop) + +#endif + diff --git a/usb/umdf_filter_kmdf/inc/usb_hw.h b/usb/umdf_filter_kmdf/inc/usb_hw.h new file mode 100644 index 00000000..d6e983f1 --- /dev/null +++ b/usb/umdf_filter_kmdf/inc/usb_hw.h @@ -0,0 +1,233 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Usb.h + +Abstract: + + Contains prototypes for interfacing with a USB connected device. These + are copied from the KMDF WDFUSB.H header file (but with the WDF specific + portions removed) + +Environment: + + kernel mode only + +--*/ + +#pragma once + +typedef enum _WINUSB_BMREQUEST_DIRECTION { + BmRequestHostToDevice = BMREQUEST_HOST_TO_DEVICE, + BmRequestDeviceToHost = BMREQUEST_DEVICE_TO_HOST, +} WINUSB_BMREQUEST_DIRECTION; + +typedef enum _WINUSB_BMREQUEST_TYPE { + BmRequestStandard = BMREQUEST_STANDARD, + BmRequestClass = BMREQUEST_CLASS, + BmRequestVendor = BMREQUEST_VENDOR, +} WINUSB_BMREQUEST_TYPE; + +typedef enum _WINUSB_BMREQUEST_RECIPIENT { + BmRequestToDevice = BMREQUEST_TO_DEVICE, + BmRequestToInterface = BMREQUEST_TO_INTERFACE, + BmRequestToEndpoint = BMREQUEST_TO_ENDPOINT, + BmRequestToOther = BMREQUEST_TO_OTHER, +} WINUSB_BMREQUEST_RECIPIENT; + +typedef enum _WINUSB_DEVICE_TRAITS { + WINUSB_DEVICE_TRAIT_SELF_POWERED = 0x00000001, + WINUSB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE = 0x00000002, + WINUSB_DEVICE_TRAIT_AT_HIGH_SPEED = 0x00000004, +} WINUSB_DEVICE_TRAITS; + +typedef enum _WdfUsbTargetDeviceSelectInterfaceType { + WdfUsbTargetDeviceSelectInterfaceTypeInterface = 0x10, + WdfUsbTargetDeviceSelectInterfaceTypeUrb = 0x11, +} WdfUsbTargetDeviceSelectInterfaceType; + + + +typedef union _WINUSB_CONTROL_SETUP_PACKET { + struct { + union { + #pragma warning(disable:4214) // bit field types other than int + struct { + // + // Valid values are BMREQUEST_TO_DEVICE, BMREQUEST_TO_INTERFACE, + // BMREQUEST_TO_ENDPOINT, BMREQUEST_TO_OTHER + // + BYTE Recipient:2; + + BYTE Reserved:3; + + // + // Valid values are BMREQUEST_STANDARD, BMREQUEST_CLASS, + // BMREQUEST_VENDOR + // + BYTE Type:2; + + // + // Valid values are BMREQUEST_HOST_TO_DEVICE, + // BMREQUEST_DEVICE_TO_HOST + // + BYTE Dir:1; + } Request; + #pragma warning(default:4214) // bit field types other than int + BYTE Byte; + } bm; + + BYTE bRequest; + + union { + struct { + BYTE LowByte; + BYTE HiByte; + } Bytes; + USHORT Value; + } wValue; + + union { + struct { + BYTE LowByte; + BYTE HiByte; + } Bytes; + USHORT Value; + } wIndex; + + USHORT wLength; + } Packet; + + struct { + BYTE Bytes[8]; + } Generic; + + WINUSB_SETUP_PACKET WinUsb; + +} WINUSB_CONTROL_SETUP_PACKET, *PWINUSB_CONTROL_SETUP_PACKET; + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestClass; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_DIRECTION Direction, + WINUSB_BMREQUEST_RECIPIENT Recipient, + BYTE Request, + USHORT Value, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) Direction; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestVendor; + Packet->Packet.bm.Request.Recipient = (BYTE) Recipient; + + Packet->Packet.bRequest = Request; + Packet->Packet.wValue.Value = Value; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, + USHORT FeatureSelector, + USHORT Index, + BOOLEAN SetFeature + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) BmRequestHostToDevice; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; + + if (SetFeature) { + Packet->Packet.bRequest = USB_REQUEST_SET_FEATURE; + } + else { + Packet->Packet.bRequest = USB_REQUEST_CLEAR_FEATURE; + } + + Packet->Packet.wValue.Value = FeatureSelector; + Packet->Packet.wIndex.Value = Index; + + // Packet->Packet.wLength will be set by the formatting function +} + +VOID +FORCEINLINE +WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS( + PWINUSB_CONTROL_SETUP_PACKET Packet, + WINUSB_BMREQUEST_RECIPIENT BmRequestRecipient, + USHORT Index + ) +{ + RtlZeroMemory(Packet, sizeof(WINUSB_CONTROL_SETUP_PACKET)); + + Packet->Packet.bm.Request.Dir = (BYTE) BmRequestDeviceToHost; + Packet->Packet.bm.Request.Type = (BYTE) BmRequestStandard; + Packet->Packet.bm.Request.Recipient = (BYTE) BmRequestRecipient; + + Packet->Packet.bRequest = USB_REQUEST_GET_STATUS; + Packet->Packet.wIndex.Value = Index; + Packet->Packet.wValue.Value = 0; + + // Packet->Packet.wLength will be set by the formatting function +} + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/Device.c b/usb/umdf_filter_kmdf/kmdf_driver/Device.c new file mode 100644 index 00000000..87ead857 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/Device.c @@ -0,0 +1,1051 @@ +/*++ + +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: + + Device.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + + +--*/ + +#include <osrusbfx2.h> +#include <devpkey.h> + +#if defined(EVENT_TRACING) +#include "device.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, OsrFxEvtDeviceAdd) +#pragma alloc_text(PAGE, OsrFxEvtDevicePrepareHardware) +#pragma alloc_text(PAGE, OsrFxEvtDeviceD0Exit) +#pragma alloc_text(PAGE, SelectInterfaces) +#pragma alloc_text(PAGE, OsrFxSetPowerPolicy) +#pragma alloc_text(PAGE, OsrFxReadFdoRegistryKeyValue) +#pragma alloc_text(PAGE, GetDeviceEventLoggingNames) +#pragma alloc_text(PAGE, OsrFxValidateConfigurationDescriptor) +#endif + + +NTSTATUS +OsrFxEvtDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + PDEVICE_CONTEXT pDevContext; + WDFQUEUE queue; + GUID activity; + UNICODE_STRING symbolicLinkName; + WDFSTRING symbolicLinkString; + DEVPROP_BOOLEAN isRestricted; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + // + // For usb devices, PrepareHardware callback is the to place select the + // interface and configure the device. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; + + // + // These two callbacks start and stop the wdfusb pipe continuous reader + // as we go in and out of the D0-working state. + // + + pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); + + // + // Now specify the size of device extension where we track per device + // context.DeviceInit is completely initialized. So call the framework + // to create the device and attach it to the lower stack. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreate failed with Status code %!STATUS!\n", status); + return status; + } + + // + // Setup the activity ID so that we can log events using it. + // + + activity = DeviceToActivityId(device); + + // + // Get the DeviceObject context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. + // + pDevContext = GetDeviceContext(device); + + // + // Get the device's friendly name and location so that we can use it in + // error logging. If this fails then it will setup dummy strings. + // + + GetDeviceEventLoggingNames(device); + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode when you surprise remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // Create a parallel default queue and register an event callback to + // receive ioctl requests. We will create separate queues for + // handling read and write requests. All other requests will be + // completed with error status automatically by the framework. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests for + // long time or forward them to other drivers. + // If the EvtIoStop callback is not implemented, the framework waits for + // all driver-owned requests to be done before moving in the Dx/sleep + // states or before removing the device, which is the correct behavior + // for this type of driver. If the requests were taking an indeterminate + // amount of time to complete, or if the driver forwarded the requests + // to a lower driver/another stack, the queue should have an + // EvtIoStop/EvtIoResume. + // + __analysis_assume(ioQueueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue);// pointer to default queue + __analysis_assume(ioQueueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // We will create a separate sequential queue and configure it + // to receive read requests. We also need to register a EvtIoStop + // handler so that we can acknowledge requests that are pending + // at the target driver. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeRead); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + + // + // We will create another sequential queue and configure it + // to receive write requests. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; + ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; + + status = WdfIoQueueCreate( + device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + status = WdfDeviceConfigureRequestDispatching( + device, + queue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS (status)){ + NT_ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); + goto Error; + } + + // + // Register a manual I/O queue for handling Interrupt Message Read Requests. + // This queue will be used for storing Requests that need to wait for an + // interrupt to occur before they can be completed. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); + + // + // This queue is used for requests that dont directly access the device. The + // requests in this queue are serviced only when the device is in a fully + // powered state and sends an interrupt. So we can use a non-power managed + // queue to park the requests since we dont care whether the device is idle + // or fully powered up. + // + ioQueueConfig.PowerManaged = WdfFalse; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &pDevContext->InterruptMsgQueue + ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed 0x%x\n", status); + goto Error; + } + + // + // Register a device interface so that app can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL); // Reference String + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); + goto Error; + } + + // + // Create the lock that we use to serialize calls to ResetDevice(). As an + // alternative to using a WDFWAITLOCK to serialize the calls, a sequential + // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = device; + + status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfWaitLockCreate failed %!STATUS!\n", status); + goto Error; + } + + // + // Get the string for the device interface and set the restricted + // property on it to allow applications bound with device metadata + // to access the interface. + // + if (g_pIoSetDeviceInterfacePropertyData != NULL) { + + status = WdfStringCreate(NULL, + WDF_NO_OBJECT_ATTRIBUTES, + &symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfStringCreate failed %!STATUS!\n", status); + goto Error; + } + + status = WdfDeviceRetrieveDeviceInterfaceString(device, + (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, + NULL, + symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceRetrieveDeviceInterfaceString failed %!STATUS!\n", status); + goto Error; + } + + WdfStringGetUnicodeString(symbolicLinkString, &symbolicLinkName); + + isRestricted = DEVPROP_TRUE; + + status = g_pIoSetDeviceInterfacePropertyData(&symbolicLinkName, + &DEVPKEY_DeviceInterface_Restricted, + 0, + 0, + DEVPROP_TYPE_BOOLEAN, + sizeof(isRestricted), + &isRestricted ); + + WdfObjectDelete(symbolicLinkString); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "IoSetDeviceInterfacePropertyData failed %!STATUS!\n", status); + goto Error; + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); + + return status; + +Error: + + // + // Log fail to add device to the event log + // + EventWriteFailAddDevice(&activity, + pDevContext->DeviceName, + pDevContext->Location, + status); + + return status; +} + +NTSTATUS +OsrFxEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourceList, + WDFCMRESLIST ResourceListTranslated + ) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. In the case of a USB device, this involves + reading and selecting descriptors. + +Arguments: + + Device - handle to a device + + ResourceList - handle to a resource-list object that identifies the + raw hardware resources that the PnP manager assigned + to the device + + ResourceListTranslated - handle to a resource-list object that + identifies the translated hardware resources + that the PnP manager assigned to the device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + WDF_USB_DEVICE_INFORMATION deviceInfo; + ULONG waitWakeEnable; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + waitWakeEnable = FALSE; + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // Create a USB device handle so that we can communicate with the + // underlying USB stack. The WDFUSBDEVICE handle is used to query, + // configure, and manage all aspects of the USB device. + // These aspects include device properties, bus properties, + // and I/O creation and synchronization. We only create device the first + // the PrepareHardware is called. If the device is restarted by pnp manager + // for resource rebalance, we will use the same device handle but then select + // the interfaces again because the USB stack could reconfigure the device on + // restart. + // + if (pDeviceContext->UsbDevice == NULL) { + WDF_USB_DEVICE_CREATE_CONFIG config; + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, + USBD_CLIENT_CONTRACT_VERSION_602); + + status = WdfUsbTargetDeviceCreateWithParameters(Device, + &config, + WDF_NO_OBJECT_ATTRIBUTES, + &pDeviceContext->UsbDevice); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceCreateWithParameters failed with Status code %!STATUS!\n", status); + return status; + } + + // + // TODO: If you are fetching configuration descriptor from device for + // selecting a configuration or to parse other descriptors, call OsrFxValidateConfigurationDescriptor + // to do basic validation on the descriptors before you access them . + // + } + + // + // Retrieve USBD version information, port driver capabilites and device + // capabilites such as speed, power, etc. + // + WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); + + status = WdfUsbTargetDeviceRetrieveInformation( + pDeviceContext->UsbDevice, + &deviceInfo); + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceSelfPowered: %s\n", + (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); + + waitWakeEnable = deviceInfo.Traits & + WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "IsDeviceRemoteWakeable: %s\n", + waitWakeEnable ? "TRUE" : "FALSE"); + // + // Save these for use later. + // + pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; + } + else { + pDeviceContext->UsbDeviceTraits = 0; + } + + status = SelectInterfaces(Device); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "SelectInterfaces failed 0x%x\n", status); + return status; + } + + // + // Enable wait-wake and idle timeout if the device supports it + // + if (waitWakeEnable) { + status = OsrFxSetPowerPolicy(Device); + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxSetPowerPolicy failed %!STATUS!\n", status); + return status; + } + } + + status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Entry( + WDFDEVICE Device, + 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 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 + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + BOOLEAN isTargetStarted; + + pDeviceContext = GetDeviceContext(Device); + isTargetStarted = FALSE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(PreviousState)); + + // + // Since continuous reader is configured for this interrupt-pipe, we must explicitly start + // the I/O target to get the framework to post read requests. + // + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "Failed to start interrupt pipe %!STATUS!\n", status); + goto End; + } + + isTargetStarted = TRUE; + +End: + + if (!NT_SUCCESS(status)) { + // + // Failure in D0Entry will lead to device being removed. So let us stop the continuous + // reader in preparation for the ensuing remove. + // + if (isTargetStarted) { + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); + + return status; +} + + +NTSTATUS +OsrFxEvtDeviceD0Exit( + WDFDEVICE Device, + 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. + + + 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. + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->OsrFxEvtDeviceD0Exit - moving to %s\n", + DbgDevicePowerString(TargetState)); + + pDeviceContext = GetDeviceContext(Device); + + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe), WdfIoTargetCancelSentIo); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); + + return STATUS_SUCCESS; +} + +VOID +OsrFxEvtDeviceSelfManagedIoFlush( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine handles flush activity for the device's + self-managed I/O operations. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + // Service the interrupt message queue to drain any outstanding + // requests + OsrUsbIoctlGetInterruptMessage(Device, STATUS_DEVICE_REMOVED); +} + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ) +/*++ + +Routine Description: + + Validates a USB Configuration Descriptor + +Parameters: + + ConfigDesc: Pointer to the entire USB Configuration descriptor returned by the device + + BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) + + Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will + be set to the address within the ConfigDesc buffer where the failure occured. + +Return Value: + + USBD_STATUS + Success implies the configuration descriptor is valid. + +--*/ +{ + + + USBD_STATUS status = USBD_STATUS_SUCCESS; + USHORT ValidationLevel = 3; + + PAGED_CODE(); + + // + // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. + // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. + // It also checks for interface numbers, number of endpoints in an interface etc. + // Please refer to msdn documentation for this function for more information. + // + + status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); + if (!(NT_SUCCESS (status)) ){ + return status; + } + + // + // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor + // Check that all such descriptors have size >= sizeof(the descriptor they point to) + // Check for any association between them if required + // + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(Device, &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(Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignSxWakeSettings failed %x\n", status); + return status; + } + + return status; +} + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine selects the configuration, interface and + creates a context for every pipe (end point) in that interface. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_CONTEXT pDeviceContext; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + UCHAR index; + UCHAR numberConfiguredPipes; + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); + + status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, + WDF_NO_OBJECT_ATTRIBUTES, + &configParams); + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", + status); + + // + // Since the Osr USB fx2 device is capable of working at high speed, the only reason + // the device would not be working at high speed is if the port doesn't + // support it. If the port doesn't support high speed it is a 1.1 port + // + if ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { + GUID activity = DeviceToActivityId(Device); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " On a 1.1 USB port on Windows Vista" + " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" + " doesn't conform to the USB specification. Windows Vista detects this and" + " returns an error. \n" + ); + EventWriteSelectConfigFailure( + &activity, + pDeviceContext->DeviceName, + pDeviceContext->Location, + status + ); + } + + return status; + } + + pDeviceContext->UsbInterface = + configParams.Types.SingleInterface.ConfiguredUsbInterface; + + numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; + + // + // Get pipe handles + // + for(index=0; index < numberConfiguredPipes; index++) { + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + + pipe = WdfUsbInterfaceGetConfiguredPipe( + pDeviceContext->UsbInterface, + index, //PipeIndex, + &pipeInfo + ); + // + // Tell the framework that it's okay to read less than + // MaximumPacketSize + // + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); + + if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "Interrupt Pipe is 0x%p\n", pipe); + pDeviceContext->InterruptPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsInEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkInput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkReadPipe = pipe; + } + + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + WdfUsbTargetPipeIsOutEndpoint(pipe)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, + "BulkOutput Pipe is 0x%p\n", pipe); + pDeviceContext->BulkWritePipe = pipe; + } + + } + + // + // If we didn't find all the 3 pipes, fail the start. + // + if(!(pDeviceContext->BulkWritePipe + && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { + status = STATUS_INVALID_DEVICE_STATE; + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Device is not configured properly %!STATUS!\n", + status); + + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + Retrieve the friendly name and the location string into WDFMEMORY objects + and store them in the device context. + +Arguments: + +Return Value: + + None + +--*/ +{ + PDEVICE_CONTEXT pDevContext = GetDeviceContext(Device); + + WDF_OBJECT_ATTRIBUTES objectAttributes; + + WDFMEMORY deviceNameMemory = NULL; + WDFMEMORY locationMemory = NULL; + + NTSTATUS status; + + PAGED_CODE(); + + // + // We want both memory objects to be children of the device so they will + // be deleted automatically when the device is removed. + // + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); + objectAttributes.ParentObject = Device; + + // + // First get the length of the string. If the FriendlyName + // is not there then get the lenght of device description. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyFriendlyName, + NonPagedPool, + &objectAttributes, + &deviceNameMemory); + + if (!NT_SUCCESS(status)) + { + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyDeviceDescription, + NonPagedPool, + &objectAttributes, + &deviceNameMemory); + } + + if (NT_SUCCESS(status)) + { + pDevContext->DeviceNameMemory = deviceNameMemory; + pDevContext->DeviceName = WdfMemoryGetBuffer(deviceNameMemory, NULL); + } + else + { + pDevContext->DeviceNameMemory = NULL; + pDevContext->DeviceName = L"(error retrieving name)"; + } + + // + // Retrieve the device location string. + // + + status = WdfDeviceAllocAndQueryProperty(Device, + DevicePropertyLocationInformation, + NonPagedPool, + WDF_NO_OBJECT_ATTRIBUTES, + &locationMemory); + + if (NT_SUCCESS(status)) + { + pDevContext->LocationMemory = locationMemory; + pDevContext->Location = WdfMemoryGetBuffer(locationMemory, NULL); + } + else + { + pDevContext->LocationMemory = NULL; + pDevContext->Location = L"(error retrieving location)"; + } + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ) +{ + 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"; + } +} + + + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c b/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c new file mode 100644 index 00000000..eabda192 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/bulkrwr.c @@ -0,0 +1,436 @@ +/*++ + +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: + + bulkrwr.c + +Abstract: + + This file has routines to perform reads and writes. + The read and writes are targeted bulk to endpoints. + +Environment: + + Kernel mode + +--*/ + +#include <osrusbfx2.h> + + +#if defined(EVENT_TRACING) +#include "bulkrwr.tmh" +#endif + +#pragma warning(disable:4267) + +VOID +OsrFxEvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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: + + +--*/ +{ + WDFUSBPIPE pipe; + NTSTATUS status; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + // + // Log read start event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "-->OsrFxEvtIoRead\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkReadPipe; + + status = WdfRequestRetrieveOutputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfRequestRetrieveOutputMemory failed %!STATUS!\n", status); + goto Exit; + } + + // + // The format call validates to make sure that you are reading or + // writing to the right pipe type, sets the appropriate transfer flags, + // creates an URB and initializes the request. + // + status = WdfUsbTargetPipeFormatRequestForRead(pipe, + Request, + reqMemory, + NULL // Offsets + ); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfUsbTargetPipeFormatRequestForRead failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestReadCompletionRoutine, + pipe); + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + + +Exit: + if (!NT_SUCCESS(status)) { + // + // log event read failed + // + EventWriteReadFail(&activity, WdfIoQueueGetDevice(Queue), status); + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, "<-- OsrFxEvtIoRead\n"); + + return; +} + +VOID +EvtRequestReadCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesRead = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesRead = usbCompletionParams->Parameters.PipeRead.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "Number of bytes read: %I64d\n", (INT64)bytesRead); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "Read failed - request status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + + } + + // + // Log read stop event, using IRP activity ID if available or request + // handle otherwise. + // + + EventWriteReadStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesRead, + status, + usbCompletionParams->UsbdStatus); + + WdfRequestCompleteWithInformation(Request, status, bytesRead); + + return; +} + +VOID +OsrFxEvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read or Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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; + WDFUSBPIPE pipe; + WDFMEMORY reqMemory; + PDEVICE_CONTEXT pDeviceContext; + GUID activity = RequestToActivityId(Request); + + UNREFERENCED_PARAMETER(Queue); + + + // + // Log write start event, using IRP activity ID if available or request + // handle otherwise. + // + EventWriteWriteStart(&activity, WdfIoQueueGetDevice(Queue), (ULONG)Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "-->OsrFxEvtIoWrite\n"); + + // + // First validate input parameters. + // + if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", + TEST_BOARD_TRANSFER_BUFFER_SIZE); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + pipe = pDeviceContext->BulkWritePipe; + + status = WdfRequestRetrieveInputMemory(Request, &reqMemory); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestRetrieveInputBuffer failed\n"); + goto Exit; + } + + status = WdfUsbTargetPipeFormatRequestForWrite(pipe, + Request, + reqMemory, + NULL); // Offset + + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfUsbTargetPipeFormatRequestForWrite failed 0x%x\n", status); + goto Exit; + } + + WdfRequestSetCompletionRoutine( + Request, + EvtRequestWriteCompletionRoutine, + pipe); + + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + // + // Framework couldn't send the request for some reason. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "WdfRequestSend failed\n"); + status = WdfRequestGetStatus(Request); + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) { + // + // log event write failed + // + EventWriteWriteFail(&activity, WdfIoQueueGetDevice(Queue), status); + + WdfRequestCompleteWithInformation(Request, status, 0); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- OsrFxEvtIoWrite\n"); + + return; +} + +VOID +EvtRequestWriteCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + _In_ PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + NTSTATUS status; + size_t bytesWritten = 0; + GUID activity = RequestToActivityId(Request); + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + status = CompletionParams->IoStatus.Status; + + // + // For usb devices, we should look at the Usb.Completion param. + // + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + + bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; + + if (NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "Number of bytes written: %I64d\n", (INT64)bytesWritten); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "Write failed: request Status 0x%x UsbdStatus 0x%x\n", + status, usbCompletionParams->UsbdStatus); + } + + // + // Log write stop event, using IRP activtiy ID if available or request + // handle otherwise + // + EventWriteWriteStop(&activity, + WdfIoQueueGetDevice(WdfRequestGetIoQueue(Request)), + bytesWritten, + status, + usbCompletionParams->UsbdStatus); + + + WdfRequestCompleteWithInformation(Request, status, bytesWritten); + + return; +} + + +VOID +OsrFxEvtIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ + +Routine Description: + + This callback is invoked on every inflight request when the device + is suspended or removed. Since our inflight read and write requests + are actually pending in the target device, we will just acknowledge + its presence. Until we acknowledge, complete, or requeue the requests + framework will wait before allowing the device suspend or remove to + proceeed. When the underlying USB stack gets the request to suspend or + remove, it will fail all the pending requests. + +Arguments: + + Queue - handle to queue object that is associated with the I/O request + + Request - handle to a request object + + ActionFlags - bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS flags + +Return Value: + None + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(ActionFlags); + + if (ActionFlags & WdfRequestStopActionSuspend ) { + WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue + } else if(ActionFlags & WdfRequestStopActionPurge) { + WdfRequestCancelSentRequest(Request); + } + return; +} + + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/driver.c b/usb/umdf_filter_kmdf/kmdf_driver/driver.c new file mode 100644 index 00000000..d3b44573 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/driver.c @@ -0,0 +1,299 @@ +/*++ + +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: + + Driver.c + +Abstract: + + Main module. + + This driver is for Open System Resources USB-FX2 Learning Kit designed + and built by OSR specifically for use in teaching software developers how to write + drivers for USB devices. + + The board supports a single configuration. The board automatically + detects the speed of the host controller, and supplies either the + high or full speed configuration based on the host controller's speed. + + The firmware supports 3 endpoints: + + Endpoint number 1 is used to indicate the state of the 8-switch + switch-pack on the OSR USB-FX2 board. A single byte representing + the switch state is sent (a) when the board is first started, + (b) when the board resumes after selective-suspend, + (c) whenever the state of the switches is changed. + + Endpoints 6 and 8 perform an internal loop-back function. + Data that is sent to the board at EP6 is returned to the host on EP8. + + For further information on the endpoints, please refer to the spec + http://www.osronline.com/hardware/OSRFX2_32.pdf. + + Vendor ID of the device is 0x4705 and Product ID is 0x210. + +Environment: + + Kernel mode only + +--*/ + +#include <osrusbfx2.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 trace.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 "driver.tmh" +#else +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; +PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, OsrFxEvtDriverContextCleanup) +#endif + +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL or another NTSTATUS error code otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + UNICODE_STRING funcName; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n"); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Built %s %s\n", __DATE__, __TIME__); + + // + // IRP activity ID functions are available on some versions, save them into + // globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoGetActivityIdIrp"); + g_pIoGetActivityIdIrp = (PFN_IO_GET_ACTIVITY_ID_IRP) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // The Device interface property set is available on some version, save it + // into globals (or NULL if not available) + // + RtlInitUnicodeString(&funcName, L"IoSetDeviceInterfacePropertyData"); + g_pIoSetDeviceInterfacePropertyData = (PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) (ULONG_PTR) + MmGetSystemRoutineAddress(&funcName); + + // + // Register with ETW (unified tracing) + // + EventRegisterOSRUSBFX2(); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + OsrFxEvtDeviceAdd + ); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup; + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, // Driver Object Attributes + &config, // Driver Config Info + WDF_NO_HANDLE // hDriver + ); + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status 0x%x\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); + EventUnregisterOSRUSBFX2(); + } + + return status; +} + +VOID +OsrFxEvtDriverContextCleanup( + WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free resources allocated in DriverEntry that are not automatically + cleaned up by the framework. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PAGED_CODE (); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "--> OsrFxEvtDriverContextCleanup\n"); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver )); + + UNREFERENCED_PARAMETER(Driver); // For the case when WPP is not being used. + + EventUnregisterOSRUSBFX2(); +} + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + DebugPrintLevel - print level between 0 and 3, with 3 the most verbose + DebugPrintFlag - message mask + DebugMessage - format string of the message to print + ... - values used by the format string + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 1024 + 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 0x%x\n", status); + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { + DbgPrint("%s %s", _DRIVER_NAME_, debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + + + + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c b/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c new file mode 100644 index 00000000..00ea3550 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/interrupt.c @@ -0,0 +1,184 @@ +/*++ + +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: + + Interrupt.c + +Abstract: + + This modules has routines configure a continuous reader on an + interrupt pipe to asynchronously read toggle switch states. + +Environment: + + Kernel mode + +--*/ + +#include <osrusbfx2.h> + +#if defined(EVENT_TRACING) +#include "interrupt.tmh" +#endif + + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ) +/*++ + +Routine Description: + + This routine configures a continuous reader on the + interrupt endpoint. It's called from the PrepareHarware event. + +Arguments: + + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; + NTSTATUS status; + + WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, + OsrFxEvtUsbInterruptPipeReadComplete, + DeviceContext, // Context + sizeof(UCHAR)); // TransferLength + + contReaderConfig.EvtUsbTargetPipeReadersFailed = OsrFxEvtUsbInterruptReadersFailed; + + // + // Reader requests are not posted to the target automatically. + // Driver must explictly call WdfIoTargetStart to kick start the + // reader. In this sample, it's done in D0Entry. + // By defaut, framework queues two requests to the target + // endpoint. Driver can configure up to 10 requests with CONFIG macro. + // + status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe, + &contReaderConfig); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "OsrFxConfigContReaderForInterruptEndPoint failed %x\n", + status); + return status; + } + + return status; +} + +VOID +OsrFxEvtUsbInterruptPipeReadComplete( + WDFUSBPIPE Pipe, + WDFMEMORY Buffer, + size_t NumBytesTransferred, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This the completion routine of the continour reader. This can + called concurrently on multiprocessor system if there are + more than one readers configured. So make sure to protect + access to global resources. + +Arguments: + + Buffer - This buffer is freed when this call returns. + If the driver wants to delay processing of the buffer, it + can take an additional referrence. + + Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro + +Return Value: + + NT status value + +--*/ +{ + PUCHAR switchState = NULL; + WDFDEVICE device; + PDEVICE_CONTEXT pDeviceContext = Context; + + UNREFERENCED_PARAMETER(Pipe); + + device = WdfObjectContextGetObject(pDeviceContext); + + // + // Make sure that there is data in the read packet. Depending on the device + // specification, it is possible for it to return a 0 length read in + // certain conditions. + // + + if (NumBytesTransferred == 0) { + TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete Zero length read " + "occured on the Interrupt Pipe's Continuous Reader\n" + ); + return; + } + + + NT_ASSERT(NumBytesTransferred == sizeof(UCHAR)); + + switchState = WdfMemoryGetBuffer(Buffer, NULL); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "OsrFxEvtUsbInterruptPipeReadComplete SwitchState %x\n", + *switchState); + + pDeviceContext->CurrentSwitchState = *switchState; + + // + // Handle any pending Interrupt Message IOCTLs. Note that the OSR USB device + // will generate an interrupt message when the the device resumes from a low + // power state. So if the Interrupt Message IOCTL was sent after the device + // has gone to a low power state, the pending Interrupt Message IOCTL will + // get completed in the function call below, before the user twiddles the + // dip switches on the OSR USB device. If this is not the desired behavior + // for your driver, then you could handle this condition by maintaining a + // state variable on D0Entry to track interrupt messages caused by power up. + // + OsrUsbIoctlGetInterruptMessage(device, STATUS_SUCCESS); + +} + +BOOLEAN +OsrFxEvtUsbInterruptReadersFailed( + _In_ WDFUSBPIPE Pipe, + _In_ NTSTATUS Status, + _In_ USBD_STATUS UsbdStatus + ) +{ + WDFDEVICE device = WdfIoTargetGetDevice(WdfUsbTargetPipeGetIoTarget(Pipe)); + PDEVICE_CONTEXT pDeviceContext = GetDeviceContext(device); + + UNREFERENCED_PARAMETER(UsbdStatus); + + // + // Clear the current switch state. + // + pDeviceContext->CurrentSwitchState = 0; + + // + // Service the pending interrupt switch change request + // + OsrUsbIoctlGetInterruptMessage(device, Status); + + return TRUE; +} + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c b/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c new file mode 100644 index 00000000..0f29dc8c --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/ioctl.c @@ -0,0 +1,1057 @@ +/*++ + +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: + + Ioctl.c + +Abstract: + + USB device driver for OSR USB-FX2 Learning Kit + +Environment: + + Kernel mode only + +--*/ + +#include <osrusbfx2.h> + +#if defined(EVENT_TRACING) +#include "ioctl.tmh" +#endif + +#pragma alloc_text(PAGE, OsrFxEvtIoDeviceControl) +#pragma alloc_text(PAGE, ResetPipe) +#pragma alloc_text(PAGE, ResetDevice) +#pragma alloc_text(PAGE, ReenumerateDevice) +#pragma alloc_text(PAGE, GetBarGraphState) +#pragma alloc_text(PAGE, SetBarGraphState) +#pragma alloc_text(PAGE, GetSevenSegmentState) +#pragma alloc_text(PAGE, SetSevenSegmentState) +#pragma alloc_text(PAGE, GetSwitchState) + +VOID +OsrFxEvtIoDeviceControl( + _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 + +--*/ +{ + WDFDEVICE device; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PBAR_GRAPH_STATE barGraphState = NULL; + PSWITCH_STATE switchState = NULL; + PUCHAR sevenSegment = NULL; + BOOLEAN requestPending = FALSE; + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(InputBufferLength); + UNREFERENCED_PARAMETER(OutputBufferLength); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); + // + // initialize variables + // + device = WdfIoQueueGetDevice(Queue); + pDevContext = GetDeviceContext(device); + + switch(IoControlCode) { + + case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { + + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; + USHORT requiredSize = 0; + + // + // First get the size of the config descriptor + // + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + NULL, + &requiredSize); + + if (status != STATUS_BUFFER_TOO_SMALL) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + // + // Get the buffer - make sure the buffer is big enough + // + status = WdfRequestRetrieveOutputBuffer(Request, + (size_t)requiredSize, // MinimumRequired + &configurationDescriptor, + NULL); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); + break; + } + + status = WdfUsbTargetDeviceRetrieveConfigDescriptor( + pDevContext->UsbDevice, + configurationDescriptor, + &requiredSize); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); + break; + } + + bytesReturned = requiredSize; + + } + break; + + case IOCTL_OSRUSBFX2_RESET_DEVICE: + + status = ResetDevice(device); + break; + + case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: + + // + // Otherwise, call our function to reenumerate the + // device + // + status = ReenumerateDevice(pDevContext); + + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: + + // + // Make sure the caller's output buffer is large enough + // to hold the state of the bar graph + // + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + // + // Call our function to get the bar graph state + // + status = GetBarGraphState(pDevContext, barGraphState); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(BAR_GRAPH_STATE); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(BAR_GRAPH_STATE), + &barGraphState, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); + break; + } + + // + // Call our routine to set the bar graph state + // + status = SetBarGraphState(pDevContext, barGraphState); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting an UCHAR\n"); + break; + } + + // + // Call our function to get the 7 segment state + // + status = GetSevenSegmentState(pDevContext, sevenSegment); + + // + // If we succeeded return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(UCHAR); + + } else { + + bytesReturned = 0; + + } + break; + + case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: + + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(UCHAR), + &sevenSegment, + NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's input buffer is too small for this IOCTL, expecting an UCHAR\n"); + bytesReturned = sizeof(UCHAR); + break; + } + + // + // Call our routine to set the 7 segment state + // + status = SetSevenSegmentState(pDevContext, sevenSegment); + + // + // There's no data returned for this call + // + bytesReturned = 0; + break; + + case IOCTL_OSRUSBFX2_READ_SWITCHES: + + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + break; + + } + + // + // Call our routine to get the state of the switches + // + status = GetSwitchState(pDevContext, switchState); + + // + // If successful, return the user their data + // + if (NT_SUCCESS(status)) { + + bytesReturned = sizeof(SWITCH_STATE); + + } else { + // + // Don't return any data + // + bytesReturned = 0; + } + break; + + case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: + + // + // Forward the request to an interrupt message queue and dont complete + // the request until an interrupt from the USB device occurs. + // + status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); + if (NT_SUCCESS(status)) { + requestPending = TRUE; + } + + break; + + default : + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + if (requestPending == FALSE) { + WdfRequestCompleteWithInformation(Request, status, bytesReturned); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); + + return; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine resets the pipe. + +Arguments: + + Pipe - framework pipe handle + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + // + status = WdfUsbTargetPipeResetSynchronously(Pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL // PWDF_REQUEST_SEND_OPTIONS + ); + + if (NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "ResetPipe - success\n"); + status = STATUS_SUCCESS; + } + else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetPipe - failed\n"); + } + + return status; +} + +VOID +StopAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe), + WdfIoTargetCancelSentIo); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe), + WdfIoTargetCancelSentIo); +} + +NTSTATUS +StartAllPipes( + IN PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->InterruptPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkReadPipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(DeviceContext->BulkWritePipe)); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still + connected. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> ResetDevice\n"); + + pDeviceContext = GetDeviceContext(Device); + + // + // A NULL timeout indicates an infinite wake + // + status = WdfWaitLockAcquire(pDeviceContext->ResetDeviceWaitLock, NULL); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice - could not acquire lock\n"); + return status; + } + + StopAllPipes(pDeviceContext); + + status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->UsbDevice); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "ResetDevice failed - 0x%x\n", status); + } + + status = StartAllPipes(pDeviceContext); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "Failed to start all pipes - 0x%x\n", status); + } + + WdfWaitLockRelease(pDeviceContext->ResetDeviceWaitLock); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- ResetDevice\n"); + return status; +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ) +/*++ + +Routine Description + + This routine re-enumerates the USB device. + +Arguments: + + pDevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + GUID activity; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_REENUMERATE, // Request + 0, // Value + 0); // Index + + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + NULL, // MemoryDescriptor + NULL); // BytesTransferred + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n"); + + // + // Send event to eventlog + // + + activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext)); + EventWriteDeviceReenumerated(&activity, + DevContext->DeviceName, + DevContext->Location, + status); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine gets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that receives the bar graph's state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + BarGraphState->BarsAsUChar = 0; + + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + WDF_NO_HANDLE, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetBarGraphState: Failed to GetBarGraphState - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ) +/*++ + +Routine Description + + This routine sets the state of the bar graph on the board + +Arguments: + + DevContext - One of our device extensions + + BarGraphState - Struct that describes the bar graph's desired state + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_BARGRAPH_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + BarGraphState, + sizeof(BAR_GRAPH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetBarGraphState: Failed - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine gets the state of the 7 segment display on the board + by sending a synchronous control command. + + NOTE: It's not a good practice to send a synchronous request in the + context of the user thread because if the transfer takes long + time to complete, you end up holding the user thread. + + I'm choosing to do synchronous transfer because a) I know this one + completes immediately b) and for demonstration. + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - receives the state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + // + // Set the buffer to 0, the board will OR in everything that is set + // + *SevenSegment = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status); + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ) +/*++ + +Routine Description + + This routine sets the state of the 7 segment display on the board + +Arguments: + + DevContext - One of our device extensions + + SevenSegment - desired state of the 7 segment display + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n"); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestHostToDevice, + BmRequestToDevice, + USBFX2LK_SET_7SEGMENT_DISPLAY, // Request + 0, // Value + 0); // Index + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SevenSegment, + sizeof(UCHAR)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status); + + } else { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment); + + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n"); + + return status; + +} + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ) +/*++ + +Routine Description + + This routine gets the state of the switches on the board + +Arguments: + + DevContext - One of our device extensions + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; + WDF_REQUEST_SEND_OPTIONS sendOptions; + WDF_MEMORY_DESCRIPTOR memDesc; + ULONG bytesTransferred; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n"); + + PAGED_CODE(); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &sendOptions, + WDF_REQUEST_SEND_OPTION_TIMEOUT + ); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( + &sendOptions, + DEFAULT_CONTROL_TRANSFER_TIMEOUT + ); + + WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, + BmRequestDeviceToHost, + BmRequestToDevice, + USBFX2LK_READ_SWITCHES, // Request + 0, // Value + 0); // Index + + SwitchState->SwitchesAsUChar = 0; + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, + SwitchState, + sizeof(SWITCH_STATE)); + + status = WdfUsbTargetDeviceSendControlTransferSynchronously( + DevContext->UsbDevice, + NULL, // Optional WDFREQUEST + &sendOptions, + &controlSetupPacket, + &memDesc, + &bytesTransferred); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "GetSwitchState: Failed to Get switches - 0x%x \n", status); + + } else { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, + "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n"); + + return status; + +} + + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ) +/*++ + +Routine Description + + This method handles the completion of the pended request for the IOCTL + IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE. + +Arguments: + + Device - Handle to a framework device. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + WDFREQUEST request; + PDEVICE_CONTEXT pDevContext; + size_t bytesReturned = 0; + PSWITCH_STATE switchState = NULL; + + pDevContext = GetDeviceContext(Device); + + do { + + // + // Check if there are any pending requests in the Interrupt Message Queue. + // If a request is found then complete the pending request. + // + status = WdfIoQueueRetrieveNextRequest(pDevContext->InterruptMsgQueue, &request); + + if (NT_SUCCESS(status)) { + status = WdfRequestRetrieveOutputBuffer(request, + sizeof(SWITCH_STATE), + &switchState, + NULL);// BufferLength + + if (!NT_SUCCESS(status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, + "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); + bytesReturned = sizeof(SWITCH_STATE); + + } else { + + // + // Copy the state information saved by the continuous reader. + // + if (NT_SUCCESS(ReaderStatus)) { + switchState->SwitchesAsUChar = pDevContext->CurrentSwitchState; + bytesReturned = sizeof(SWITCH_STATE); + } else { + bytesReturned = 0; + } + } + + // + // Complete the request. If we failed to get the output buffer then + // complete with that status. Otherwise complete with the status from the reader. + // + WdfRequestCompleteWithInformation(request, + NT_SUCCESS(status) ? ReaderStatus : status, + bytesReturned); + status = STATUS_SUCCESS; + + } else if (status != STATUS_NO_MORE_ENTRIES) { + KdPrint(("WdfIoQueueRetrieveNextRequest status %08x\n", status)); + } + + request = NULL; + + } while (status == STATUS_SUCCESS); + + return; + +} + + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h new file mode 100644 index 00000000..909e347d --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.h @@ -0,0 +1,335 @@ +/*++ + +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: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#include <initguid.h> +#include <ntddk.h> +#include "usbdi.h" +#include "usbdlib.h" +#include "public.h" +#include "driverspecs.h" +#include <wdf.h> +#include <wdfusb.h> +#define NTSTRSAFE_LIB +#include <ntstrsafe.h> + +#include "trace.h" + +// +// Include auto-generated ETW event functions (created by MC.EXE from +// osrusbfx2.man) +// +#include "fx2Events.h" + +#ifndef _PRIVATE_H +#define _PRIVATE_H + +#define POOL_TAG (ULONG) 'FRSO' +#define _DRIVER_NAME_ "OSRUSBFX2" + +#define TEST_BOARD_TRANSFER_BUFFER_SIZE (64*1024) +#define DEVICE_DESC_LENGTH 256 + +extern const __declspec(selectany) LONGLONG DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; + +// +// Define the vendor commands supported by our device +// +#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4 +#define USBFX2LK_READ_SWITCHES 0xD6 +#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7 +#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8 +#define USBFX2LK_IS_HIGH_SPEED 0xD9 +#define USBFX2LK_REENUMERATE 0xDA +#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB + +// +// Define the features that we can clear +// and set on our device +// +#define USBFX2LK_FEATURE_EPSTALL 0x00 +#define USBFX2LK_FEATURE_WAKE 0x01 + +// +// Order of endpoints in the interface descriptor +// +#define INTERRUPT_IN_ENDPOINT_INDEX 0 +#define BULK_OUT_ENDPOINT_INDEX 1 +#define BULK_IN_ENDPOINT_INDEX 2 + +// +// A structure representing the instance information associated with +// this particular device. +// + +typedef struct _DEVICE_CONTEXT { + + WDFUSBDEVICE UsbDevice; + + WDFUSBINTERFACE UsbInterface; + + WDFUSBPIPE BulkReadPipe; + + WDFUSBPIPE BulkWritePipe; + + WDFUSBPIPE InterruptPipe; + + WDFWAITLOCK ResetDeviceWaitLock; + + UCHAR CurrentSwitchState; + + WDFQUEUE InterruptMsgQueue; + + ULONG UsbDeviceTraits; + + // + // The following fields are used during event logging to + // report the events relative to this specific instance + // of the device. + // + + WDFMEMORY DeviceNameMemory; + PCWSTR DeviceName; + + WDFMEMORY LocationMemory; + PCWSTR Location; + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) + +extern ULONG DebugLevel; + +typedef +NTSTATUS +(*PFN_IO_GET_ACTIVITY_ID_IRP) ( + _In_ PIRP Irp, + _Out_ LPGUID Guid + ); + +typedef +NTSTATUS +(*PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA) ( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ CONST DEVPROPKEY *PropertyKey, + _In_ LCID Lcid, + _In_ ULONG Flags, + _In_ DEVPROPTYPE Type, + _In_ ULONG Size, + _In_opt_ PVOID Data + ); + +// +// Global function pointer set in DriverEntry +// Check for NULL before using +// +extern PFN_IO_GET_ACTIVITY_ID_IRP g_pIoGetActivityIdIrp; + +extern PFN_IO_SET_DEVICE_INTERFACE_PROPERTY_DATA g_pIoSetDeviceInterfacePropertyData; + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP OsrFxEvtDriverContextCleanup; + +EVT_WDF_DRIVER_DEVICE_ADD OsrFxEvtDeviceAdd; + +EVT_WDF_DEVICE_PREPARE_HARDWARE OsrFxEvtDevicePrepareHardware; + +EVT_WDF_IO_QUEUE_IO_READ OsrFxEvtIoRead; + +EVT_WDF_IO_QUEUE_IO_WRITE OsrFxEvtIoWrite; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL OsrFxEvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestReadCompletionRoutine; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE EvtRequestWriteCompletionRoutine; + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +ReenumerateDevice( + _In_ PDEVICE_CONTEXT DevContext + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetBarGraphState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PBAR_GRAPH_STATE BarGraphState + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _Out_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +SetSevenSegmentState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PUCHAR SevenSegment + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +GetSwitchState( + _In_ PDEVICE_CONTEXT DevContext, + _In_ PSWITCH_STATE SwitchState + ); + +VOID +OsrUsbIoctlGetInterruptMessage( + _In_ WDFDEVICE Device, + _In_ NTSTATUS ReaderStatus + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxSetPowerPolicy( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +NTSTATUS +OsrFxConfigContReaderForInterruptEndPoint( + _In_ PDEVICE_CONTEXT DeviceContext + ); + +EVT_WDF_USB_READER_COMPLETION_ROUTINE OsrFxEvtUsbInterruptPipeReadComplete; + +EVT_WDF_USB_READERS_FAILED OsrFxEvtUsbInterruptReadersFailed; + +EVT_WDF_IO_QUEUE_IO_STOP OsrFxEvtIoStop; + +EVT_WDF_DEVICE_D0_ENTRY OsrFxEvtDeviceD0Entry; + +EVT_WDF_DEVICE_D0_EXIT OsrFxEvtDeviceD0Exit; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH OsrFxEvtDeviceSelfManagedIoFlush; + +_IRQL_requires_(PASSIVE_LEVEL) +BOOLEAN +OsrFxReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWCHAR Name, + _Out_ PULONG Value + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +OsrFxEnumerateChildren( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +VOID +GetDeviceEventLoggingNames( + _In_ WDFDEVICE Device + ); + +_IRQL_requires_(PASSIVE_LEVEL) +PCHAR +DbgDevicePowerString( + _In_ WDF_POWER_DEVICE_STATE Type + ); + + +_IRQL_requires_(PASSIVE_LEVEL) +USBD_STATUS +OsrFxValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ); + +FORCEINLINE +GUID +RequestToActivityId( + _In_ WDFREQUEST Request + ) +{ + GUID activity = {0}; + NTSTATUS status = STATUS_SUCCESS; + + if (g_pIoGetActivityIdIrp != NULL) { + + // + // Use activity ID generated by application (or IO manager) + // + status = g_pIoGetActivityIdIrp(WdfRequestWdmGetIrp(Request), &activity); + } + + if (g_pIoGetActivityIdIrp == NULL || !NT_SUCCESS(status)) { + + // + // Fall back to using the WDFREQUEST handle as the activity ID + // + RtlCopyMemory(&activity, &Request, sizeof(WDFREQUEST)); + } + + + return activity; +} + +FORCEINLINE +GUID +DeviceToActivityId( + _In_ WDFDEVICE Device + ) +{ + GUID activity = {0}; + RtlCopyMemory(&activity, &Device, sizeof(WDFDEVICE)); + return activity; +} + + +#endif + + diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man new file mode 100644 index 00000000..176dfc89 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.man @@ -0,0 +1,309 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes'?> +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" + > + <instrumentation> + <events> + <provider + guid="{69cd60e3-430f-4da4-b1b3-e3bdaf945875}" + messageFileName="%Systemroot%\System32\drivers\osrusbfx2.SYS" + name="OSRUSBFX2" + resourceFileName="%SystemRoot%\System32\drivers\osrusbfx2.SYS" + symbol="OSRUSBFX2_PROVIDER" + > + <channels> + <channel + chid="Analytic" + enabled="false" + name="OsrUsbfx2/Analytic" + symbol="OSRUSBFX2_ANALYTIC" + type="Analytic" + /> + <channel + chid="operational" + enabled="true" + isolation="System" + message="$(string.OSRUSBFX2_OPERATIONAL.Name)" + name="OsrUsbFx2/Operational" + symbol="OSRUSBFX2_OPERATIONAL" + type="Operational" + /> + </channels> + <keywords> + <keyword + mask="0x0000000000000010" + message="$(string.OSRUSBFX2_DEVICE_INFO_KEYWORD.message)" + name="deviceinfo" + symbol="OSRUSBFX2_DEVICE_INFO_KEYWORD" + /> + <keyword + mask="0x0000000000000040" + message="$(string.OSRUSBFX2_READ_WRITE_KEYWORD.message)" + name="readwrite" + symbol="OSRUSBFX2_READ_WRITE_KEYWORD" + /> + </keywords> + <opcodes> + <!-- Defining our own custom opcode instead of using standard opcodes defined by winmeta.xml --> + <opcode + name="add" + symbol="OSRUSBFX2_DEVICE_ADD" + value="10" + /> + <opcode + name="fail" + symbol="OSRUSBFX2_FAIL" + value="11" + /> + </opcodes> + <tasks> + <!-- Support for XP and W2K3 : MC.exe will create a MOF file --> + <!-- Requires an associated eventGUID attribute for each task that is defined --> + <!-- For the MOF file : --> + <!-- Semantically, the event GUID represents a set of logical events that are logged by the provider. --> + <task + eventGUID="{872c3c43-6899-4f1d-89b8-51a82f6db657}" + name="deviceInit" + symbol="OSRUSBFX2_DEVICE_INIT" + value="1" + /> + <task + eventGUID="{872c3c45-6899-4f1d-89b8-51a82f6db657}" + name="read" + symbol="OSRUSBFX2_READ" + value="2" + /> + <task + eventGUID="{872c3c46-6899-4f1d-89b8-51a82f6db657}" + name="write" + symbol="OSRUSBFX2_WRITE" + value="3" + /> + </tasks> + <templates> + <template tid="tid_DeviceStatus"> + <data + inType="win:UnicodeString" + name="FriendlyName" + outType="xs:string" + /> + <data + inType="win:UnicodeString" + name="Location" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + </template> + <template tid="tid_ReadWrite"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="Length" + outType="xs:unsignedInt" + /> + </template> + <template tid="tid_ReadWriteFail"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + </template> + <template tid="tid_ReadWriteCompletion"> + <data + inType="win:Pointer" + name="Device" + outType="win:HexInt64" + /> + <data + inType="win:UInt32" + name="Length" + outType="xs:unsignedInt" + /> + <data + inType="win:UInt32" + name="NTStatus" + outType="xs:HexInt32" + /> + <data + inType="win:UInt32" + name="UsbdStatus" + outType="xs:unsignedInt" + /> + </template> + </templates> + <events> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadStart.EventMessage)" + level="win:Informational" + opcode="win:Start" + symbol="ReadStart" + task="read" + template="tid_ReadWrite" + value="1" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadStop.EventMessage)" + level="win:Informational" + opcode="win:Stop" + symbol="ReadStop" + task="read" + template="tid_ReadWriteCompletion" + value="2" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.ReadFail.EventMessage)" + level="win:Error" + opcode="fail" + symbol="ReadFail" + task="read" + template="tid_ReadWriteFail" + value="3" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteStart.EventMessage)" + level="win:Informational" + opcode="win:Start" + symbol="WriteStart" + task="write" + template="tid_ReadWrite" + value="4" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteStop.EventMessage)" + level="win:Informational" + opcode="win:Stop" + symbol="WriteStop" + task="write" + template="tid_ReadWriteCompletion" + value="5" + /> + <event + channel="Analytic" + keywords="readwrite" + message="$(string.WriteFail.EventMessage)" + level="win:Error" + opcode="fail" + symbol="WriteFail" + task="write" + template="tid_ReadWriteFail" + value="6" + /> + <event + channel="operational" + keywords="deviceinfo" + level="win:Error" + message="$(string.DeviceFailAdd.EventMessage)" + opcode="add" + symbol="FailAddDevice" + task="deviceInit" + template="tid_DeviceStatus" + value="100" + /> + <event + channel="operational" + keywords="deviceinfo" + message="$(string.DeviceReenumerated.EventMessage)" + opcode="win:Start" + symbol="DeviceReenumerated" + task="deviceInit" + template="tid_DeviceStatus" + value="101" + /> + <event + channel="operational" + keywords="deviceinfo" + level="win:Error" + message="$(string.SelectConfigFailure.Message)" + opcode="fail" + symbol="SelectConfigFailure" + task="deviceInit" + template="tid_DeviceStatus" + value="102" + /> + </events> + </provider> + </events> + </instrumentation> + <localization xmlns="http://schemas.microsoft.com/win/2004/08/events"> + <resources culture="en-US"> + <stringTable> + <string + id="OSRUSBFX2_DEVICE_INFO_KEYWORD.message" + value="Device events: fail to load, reenumerate" + /> + <string + id="OSRUSBFX2_READ_WRITE_KEYWORD.message" + value="Read, Write events" + /> + <string + id="OSRUSBFX2_OPERATIONAL.Name" + value="Operational channel eventlog" + /> + <string + id="ReadStart.EventMessage" + value="Read. Device = %1, Length = %2" + /> + <string + id="ReadStop.EventMessage" + value="Read complete. Device = %1, Length = %2, Status = %3, UsbStatus = %4" + /> + <string + id="ReadFail.EventMessage" + value="Read error. Device = %1, Status = %2" + /> + <string + id="WriteStart.EventMessage" + value="Write. Device = %1, Length = %2" + /> + <string + id="WriteStop.EventMessage" + value="Write complete. Device = %1, Length = %2, Status = %3, UsbStatus = %4" + /> + <string + id="WriteFail.EventMessage" + value="Write error. Device = %1, Status = %2" + /> + <string + id="DeviceReenumerated.EventMessage" + value="Device %1 (location %2) was reenumerated" + /> + <string + id="DeviceFailAdd.EventMessage" + value="Fail to add device %1 (location %2), status %3" + /> + <string + id="SelectConfigFailure.Message" + value="This error occurs when an OSR USB Fx2 board is attached to a USB 1.1 port on a machine running Windows Vista. This error occurs because the OSR USB Fx2 board's Interrupt end-point descriptor does not conform to the USB specification. Windows Vista detects this and returns an error. You should plug the device into a USB 2.0 (or higher) port." + /> + </stringTable> + </resources> + </localization> +</instrumentationManifest> diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc new file mode 100644 index 00000000..092ec195 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.rc @@ -0,0 +1,18 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Sample Driver for OSR USB-FX2 Learning Kit" +#define VER_INTERNALNAME_STR "osrusbfx2.sys" +#define VER_ORIGINALFILENAME_STR "osrusbfx2.sys" + +#include "common.ver" + +// +// Include auto-generated string resources (created by MC.EXE from +// osrusbfx2.man) +// + +#include "fx2Events.rc" diff --git a/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj new file mode 100644 index 00000000..979852e9 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj @@ -0,0 +1,244 @@ +<?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>{6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <SupportsPackaging>false</SupportsPackaging> + <RequiresPackageProject>true</RequiresPackageProject> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{18C4C80D-74E9-4145-BD1A-9525E8F04FCF}</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="driver.c; device.c; ioctl.c; bulkrwr.c; Interrupt.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </ClCompile> + <MessageCompile Include="osrusbfx2.man"> + <GenerateKernelModeLoggingMacros>true</GenerateKernelModeLoggingMacros> + <GenerateMofFile>true</GenerateMofFile> + <HeaderFilePath>.\$(IntDir)</HeaderFilePath> + <GeneratedHeaderPath>true</GeneratedHeaderPath> + <RCFilePath>.\$(IntDir)</RCFilePath> + <GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath> + <GeneratedFilesBaseName>fx2Events</GeneratedFilesBaseName> + <UseBaseNameOfInput>true</UseBaseNameOfInput> + </MessageCompile> + <OtherWpp Include="osrusbfx2.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>osrusbfx2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\inc</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ALLOW_DATE_TIME>1</ALLOW_DATE_TIME> + </PropertyGroup> + <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> + <ResourceCompile Include="osrusbfx2.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </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/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters new file mode 100644 index 00000000..13f23acc --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/osrusbfx2.vcxproj.Filters @@ -0,0 +1,46 @@ +<?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>{7BBF30E5-9EE0-4544-BC21-3F9BBA4719F6}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F4DA0DF1-D522-4DE8-A128-0E3856D30A60}</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>{86AACBD7-6DA3-4FF9-850F-FD8BA69A2316}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{C3F34238-DF88-433F-9C43-9B4DA776DCB5}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="bulkrwr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Interrupt.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ioctl.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <MessageCompile Include="osrusbfx2.man"> + <Filter>Resource Files</Filter> + </MessageCompile> + <ResourceCompile Include="osrusbfx2.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/umdf_filter_kmdf/kmdf_driver/trace.h b/usb/umdf_filter_kmdf/kmdf_driver/trace.h new file mode 100644 index 00000000..518ff5f1 --- /dev/null +++ b/usb/umdf_filter_kmdf/kmdf_driver/trace.h @@ -0,0 +1,115 @@ +/*++ + +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. + +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_IOCTL 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 + + +VOID +TraceEvents ( + _In_ ULONG DebugPrintLevel, + _In_ ULONG DebugPrintFlag, + _Printf_format_string_ + _In_ PCSTR DebugMessage, + ... + ); + +#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. +// +// NOTE: If you are adopting this sample for your driver, please generate +// a new guid, using tools\other\i386\guidgen.exe present in the +// DDK. +// +// Name of the logger is OSRUSBFX2 and the guid is +// {D23A0C5A-D307-4f0e-AE8E-E2A355AD5DAB} +// (0xd23a0c5a, 0xd307, 0x4f0e, 0xae, 0x8e, 0xe2, 0xa3, 0x55, 0xad, 0x5d, 0xab); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid,(d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ + 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_IOCTL) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + /* 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) + + +#endif + + + diff --git a/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc b/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc new file mode 100644 index 00000000..cec032d9 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/OsrUsbFilter.rc @@ -0,0 +1,17 @@ +//--------------------------------------------------------------------------- +// OsrUsbFilter.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF OsrUsbFilter User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "OsrUsbFilter" +#define VER_ORIGINALFILENAME_STR "OsrUsbFilter.dll" + +#include "common.ver" diff --git a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj new file mode 100644 index 00000000..a0df5d88 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj @@ -0,0 +1,286 @@ +<?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>{BE14DB05-36A7-4ECE-88E1-FB8157CA568E}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <SupportsPackaging>false</SupportsPackaging> + <RequiresPackageProject>true</RequiresPackageProject> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{248CCFA9-D129-42B1-A548-A0C5CD4F8AFE}</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>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</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="dllsup.cpp; comsup.cpp; driver.cpp; device.cpp; queue.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="WUDFOsrUsbFilterOnKmDriver.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\WUDFOsrUsbFilterOnKmDriver.Inf</CopyOutput> + </Inf> + <OtherWpp Include="OsrUsbFilter.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>WUDFOsrUsbFilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>WUDFOsrUsbFilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>WUDFOsrUsbFilter</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>WUDFOsrUsbFilter</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="OsrUsbFilter.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </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/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters new file mode 100644 index 00000000..ebc49f02 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{80542188-20E5-48F5-9843-73E5C5357618}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{06DDFA1D-9B66-4847-90DA-9B47DAA6BB4D}</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>{CFF95FF0-CB6A-408A-BDEB-2EB542DABA61}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{9E1415BD-A138-4C82-9F05-75AAEFB9ADC2}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="comsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <Inf Include="WUDFOsrUsbFilterOnKmDriver.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="OsrUsbFilter.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx new file mode 100644 index 00000000..3ee5cd16 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/WUDFOsrUsbFilterOnKmDriver.inx @@ -0,0 +1,122 @@ +; +; INF for installing OSR USB user-mode filter driver on top of OSR USB KMDF (final) sample driver +; You will need to have the user-mode filter driver and KMDF function driver in one install location +; The KMDF files needed are: +; osrusbfx2.sys (final version) +; WdfCoInstallerxxxx.dll (the KMDF coinstaller) +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%ProviderName% +DriverVer=10/01/2002,6.0.5058.0 +CatalogFile=wudf.cat + + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + + +; ================= Device section ===================== + +[Manufacturer] +%ManufacturerName%=Standard,NT$ARCH$ + +; For XP and later +[Standard.NT$ARCH$] +%USB\VID_045E&PID_930A.DeviceDesc%=osrusbfx2, USB\VID_0547&PID_1002 + +[osrusbfx2.NT] +CopyFiles=osrusbfx2.Files.Ext,UMDriverCopy + +[osrusbfx2.NT.hw] +AddReg=OsrUsb_AddReg + + +[osrusbfx2.NT.CoInstallers] +AddReg=CoInstaller_AddReg +CopyFiles=CoInstaller_CopyFiles + +[osrusbfx2.NT.Services] +AddService=WUDFRd,0x000001f8,WUDFRD_ServiceInstall +AddService=osrusbfx2, 0x000001fa, osrusbfx2.AddService ;flag 0x2 sets this as the service for the device + +[osrusbfx2.NT.Wdf] +KmdfService=osrusbfx2, osrusbfx2_wdfsect +UmdfService="WUDFOsrUsbFilter", WudfOsrUsbFilter_Install +UmdfServiceOrder=WUDFOsrUsbFilter + +[OsrUsb_AddReg] +HKR,,"UpperFilters",0x00010008,"WUDFRd" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND + + +[WudfOsrUsbFilter_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID = "{422d8dbc-520d-4d7e-8f53-920e5c867e6c}" +ServiceBinary = "%12%\UMDF\WUDFOsrUsbFilter.dll" + +[osrusbfx2_wdfsect] +KmdfLibraryVersion=1.11 + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[osrusbfx2.AddService] +DisplayName = %osrusbfx2.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %10%\System32\Drivers\osrusbfx2.sys + +[osrusbfx2.Files.Ext] +osrusbfx2.sys + +[UMDriverCopy] +WudfOsrUsbFilter.dll + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +osrusbfx2.sys = 1 +WudfOsrUsbFilter.dll=1 +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\umdf +DefaultDestDir = 12 + +;-------------- WDF Coinstaller installation + +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[CoInstaller_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + +;---------------------------------------------------------------; + +[Strings] +ProviderName="TODO-Set-Provider" +ManufacturerName="TODO-Set-Manufacturer" +Disk_Description="OSRUSBFX2 Installation Disk" +USB\VID_045E&PID_930A.DeviceDesc="Microsoft UMDF OSR Usb Sample Device With Filter on kernel-mode Driver" +osrusbfx2.SvcDesc="WDF Sample Driver for OSR USB-FX2 Learning Kit" +ClassName = "Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" + diff --git a/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp b/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp new file mode 100644 index 00000000..31257f31 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/comsup.cpp @@ -0,0 +1,351 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.cpp + +Abstract: + + This module contains implementations for the functions and methods + used for providing COM support. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "comsup.tmh" + +// +// This is the number of characters in a GUID string including the trailing +// NULL. +// + +#define GUID_STRING_CCH (sizeof("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}")) + +// +// Implementation of CUnknown methods. +// + +CUnknown::CUnknown( + VOID + ) : m_ReferenceCount(1) +/*++ + + Routine Description: + + Constructor for an instance of the CUnknown class. This simply initializes + the reference count of the object to 1. The caller is expected to + call Release() if it wants to delete the object once it has been allocated. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + // do nothing. +} + +HRESULT +STDMETHODCALLTYPE +CUnknown::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method provides the basic support for query interface on CUnknown. + If the interface requested is IUnknown it references the object and + returns an interface pointer. Otherwise it returns an error. + + Arguments: + + InterfaceId - the IID being requested + + Object - a location to store the interface pointer to return. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) + { + *Object = QueryIUnknown(); + return S_OK; + } + else + { + *Object = NULL; + return E_NOINTERFACE; + } +} + +IUnknown * +CUnknown::QueryIUnknown( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IUnknown interface. + + This allows other methods to convert a CUnknown pointer into an IUnknown + pointer without a typecast and without calling QueryInterface and dealing + with the return value. + + Arguments: + + None + + Return Value: + + A pointer to the object's IUnknown interface. + +--*/ +{ + AddRef(); + return static_cast<IUnknown *>(this); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::AddRef( + VOID + ) +/*++ + + Routine Description: + + This method adds one to the object's reference count. + + Arguments: + + None + + Return Value: + + The new reference count. The caller should only use this for debugging + as the object's actual reference count can change while the caller + examines the return value. + +--*/ +{ + return InterlockedIncrement(&m_ReferenceCount); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::Release( + VOID + ) +/*++ + + Routine Description: + + This method subtracts one to the object's reference count. If the count + goes to zero, this method deletes the object. + + Arguments: + + None + + Return Value: + + The new reference count. If the caller uses this value it should only be + to check for zero (i.e. this call caused or will cause deletion) or + non-zero (i.e. some other call may have caused deletion, but this one + didn't). + +--*/ +{ + ULONG count = InterlockedDecrement(&m_ReferenceCount); + + if (count == 0) + { + delete this; + } + return count; +} + +// +// Implementation of CClassFactory methods. +// + +// +// Define storage for the factory's static lock count variable. +// + +LONG CClassFactory::s_LockCount = 0; + +IClassFactory * +CClassFactory::QueryIClassFactory( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IClassFactory interface. + + This allows other methods to convert a CClassFactory pointer into an + IClassFactory pointer without a typecast and without dealing with the + return value QueryInterface. + + Arguments: + + None + + Return Value: + + A referenced pointer to the object's IClassFactory interface. + +--*/ +{ + AddRef(); + return static_cast<IClassFactory *>(this); +} + +HRESULT +CClassFactory::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method attempts to retrieve the requested interface from the object. + + If the interface is found then the reference count on that interface (and + thus the object itself) is incremented. + + Arguments: + + InterfaceId - the interface the caller is requesting. + + Object - a location to store the interface pointer. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + // + // This class only supports IClassFactory so check for that. + // + + if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) + { + *Object = QueryIClassFactory(); + return S_OK; + } + else + { + // + // See if the base class supports the interface. + // + + return CUnknown::QueryInterface(InterfaceId, Object); + } +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::CreateInstance( + _In_opt_ IUnknown * /* OuterObject */, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This COM method is the factory routine - it creates instances of the driver + callback class and returns the specified interface on them. + + Arguments: + + OuterObject - only used for aggregation, which our driver callback class + does not support. + + InterfaceId - the interface ID the caller would like to get from our + new object. + + Object - a location to store the referenced interface pointer to the new + object. + + Return Value: + + Status. + +--*/ +{ + HRESULT hr; + + PCMyDriver driver; + + *Object = NULL; + + hr = CMyDriver::CreateInstance(&driver); + + if (SUCCEEDED(hr)) + { + hr = driver->QueryInterface(InterfaceId, Object); + driver->Release(); + } + + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::LockServer( + _In_ BOOL Lock + ) +/*++ + + Routine Description: + + This COM method can be used to keep the DLL in memory. However since the + driver's DllCanUnloadNow function always returns false, this has little + effect. Still it tracks the number of lock and unlock operations. + + Arguments: + + Lock - Whether the caller wants to lock or unlock the "server" + + Return Value: + + S_OK + +--*/ +{ + if (Lock) + { + InterlockedIncrement(&s_LockCount); + } + else + { + InterlockedDecrement(&s_LockCount); + } + return S_OK; +} + diff --git a/usb/umdf_filter_kmdf/umdf_filter/comsup.h b/usb/umdf_filter_kmdf/umdf_filter/comsup.h new file mode 100644 index 00000000..b96fd982 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/comsup.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.h + +Abstract: + + This module contains classes and functions use for providing COM support + code. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Forward type declarations. They are here rather than in internal.h as +// you only need them if you choose to use these support classes. +// + +typedef class CUnknown *PCUnknown; +typedef class CClassFactory *PCClassFactory; + +// +// Base class to implement IUnknown. You can choose to derive your COM +// classes from this class, or simply implement IUnknown in each of your +// classes. +// + +class CUnknown : public IUnknown +{ + +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The reference count for this object. Initialized to 1 in the + // constructor. + // + + LONG m_ReferenceCount; + +// +// Protected data members and methods. These are accessible by the subclasses +// but not by other classes. +// +protected: + + // + // The constructor and destructor are protected to ensure that only the + // subclasses of CUnknown can create and destroy instances. + // + + CUnknown( + VOID + ); + + // + // The destructor MUST be virtual. Since any instance of a CUnknown + // derived class should only be deleted from within CUnknown::Release, + // the destructor MUST be virtual or only CUnknown::~CUnknown will get + // invoked on deletion. + // + // If you see that your CMyDevice specific destructor is never being + // called, make sure you haven't deleted the virtual destructor here. + // + + virtual + ~CUnknown( + VOID + ) + { + // Do nothing + } + +// +// Public Methods. These are accessible by any class. +// +public: + + IUnknown * + QueryIUnknown( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ); + + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ); + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; + +// +// Class factory support class. Create an instance of this from your +// DllGetClassObject method and modify the implementation to create +// an instance of your driver event handler class. +// + +class CClassFactory : public CUnknown, public IClassFactory +{ +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The lock count. This is shared across all instances of IClassFactory + // and can be queried through the public IsLocked method. + // + + static LONG s_LockCount; + +// +// Public Methods. These are accessible by any class. +// +public: + + IClassFactory * + QueryIClassFactory( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IClassFactory methods. + // + + virtual + HRESULT + STDMETHODCALLTYPE + CreateInstance( + _In_opt_ IUnknown *OuterObject, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + virtual + HRESULT + STDMETHODCALLTYPE + LockServer( + _In_ BOOL Lock + ); +}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/device.cpp b/usb/umdf_filter_kmdf/umdf_filter/device.cpp new file mode 100644 index 00000000..126637ce --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/device.cpp @@ -0,0 +1,243 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF OSR USB Sample Filter driver's + device callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "device.tmh" + +HRESULT +CMyDevice::CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit, + _Out_ PCMyDevice *Device + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the OSR USB Sample Filter driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + PCMyDevice device; + HRESULT hr; + + // + // Allocate a new instance of the device class. + // + + device = new CMyDevice(); + + if (NULL == device) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + hr = device->Initialize(FxDriver, FxDeviceInit); + + if (SUCCEEDED(hr)) + { + *Device = device; + } + else + { + device->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver * FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + + Return Value: + + status. + +--*/ +{ + IWDFDevice *fxDevice; + HRESULT hr; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // We don't need device level locking since we do not keep any state + // across the requests + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // Mark ourselves as a filter + // + + FxDeviceInit->SetFilter(); + + + // + // We are a filter; we don't want to be the power policy owner + // + + FxDeviceInit->SetPowerPolicyOwnership(FALSE); + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + { + IUnknown *unknown = this->QueryIUnknown(); + + hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); + + unknown->Release(); + } + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + + // + // Drop the reference we got from CreateDevice. Since this object + // is partnered with the framework object they have the same + // lifespan - there is no need for an additional reference. + // + + fxDevice->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + PCMyQueue defaultQueue; + + HRESULT hr; + + hr = CMyQueue::CreateInstance(m_FxDevice, &defaultQueue); + + if (FAILED(hr)) + { + return hr; + } + + hr = defaultQueue->Configure(); + + defaultQueue->Release(); + + return hr; +} + +HRESULT +CMyDevice::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Since the OSR USB Sample Filter driver doesn't support any of the device events, this + method simply calls the base class's BaseQueryInterface. + + If OSR USB Sample Filter is extended to include device event interfaces then this + method must be changed to check the IID and return pointers to them as + appropriate. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + return CUnknown::QueryInterface(InterfaceId, Object); +} diff --git a/usb/umdf_filter_kmdf/umdf_filter/device.h b/usb/umdf_filter_kmdf/umdf_filter/device.h new file mode 100644 index 00000000..f7a50b1d --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/device.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF OSR USB Sample Filter + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Class for the iotrace driver. +// + +class CMyDevice : public CUnknown +{ + +// +// Private data members. +// +private: + + IWDFDevice *m_FxDevice; + +// +// Private methods. +// + +private: + + CMyDevice( + VOID + ) + { + m_FxDevice = NULL; + } + + HRESULT + Initialize( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit, + _Out_ PCMyDevice *Device + ); + + HRESULT + Configure( + VOID + ); + +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp b/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp new file mode 100644 index 00000000..10ef8a78 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/dllsup.cpp @@ -0,0 +1,183 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the OSR USB Sample Filter + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the skeleton uses + L"Microsoft\\UMDF\\Skeleton" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the OSR USB Sample Filter sample. If + you choose to use a different primary include file, you should ensure + they are defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +// +// Global variable to hold the module handle for this DLL. Initialized during +// DllMain and never cleared. This is used when registering and unregistering +// the driver's COM information. +// + +HINSTANCE g_ModuleHandle = NULL; + +BOOL +WINAPI +DllMain( + HINSTANCE /* ModuleHandle */, + DWORD Reason, + PVOID /* Reserved */ + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return TRUE; +} + +HRESULT +STDAPICALLTYPE +DllGetClassObject( + _In_ REFCLSID ClassId, + _In_ REFIID InterfaceId, + _Outptr_ LPVOID *Interface + ) +/*++ + + Routine Description: + + This routine is called by COM in order to instantiate the OSR USB Sample + Filter driver callback object and do an initial query interface on it. + + This method only creates an instance of the driver's class factory, as this + is the minimum required to support UMDF. + + Arguments: + + ClassId - the CLSID of the object being "gotten" + + InterfaceId - the interface the caller wants from that object. + + Interface - a location to store the referenced interface pointer + + Return Value: + + S_OK if the function succeeds or error indicating the cause of the + failure. + +--*/ +{ + PCClassFactory factory; + + HRESULT hr = S_OK; + + *Interface = NULL; + + // + // If the CLSID doesn't match that of our "coclass" (defined in the IDL + // file) then we can't create the object the caller wants. This may + // indicate that the COM registration is incorrect, and another CLSID + // is referencing this drvier. + // + + if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Called to create instance of unrecognized class (%!GUID!)", + &ClassId + ); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + // + // Create an instance of the class factory for the caller. + // + + factory = new CClassFactory(); + + if (NULL == factory) + { + hr = E_OUTOFMEMORY; + } + + // + // Query the object we created for the interface the caller wants. After + // that we release the object. This will drive the reference count to + // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). + // In the later case the object is automatically deleted. + // + + if (SUCCEEDED(hr)) + { + hr = factory->QueryInterface(InterfaceId, Interface); + factory->Release(); + } + + return hr; +} + diff --git a/usb/umdf_filter_kmdf/umdf_filter/driver.cpp b/usb/umdf_filter_kmdf/umdf_filter/driver.cpp new file mode 100644 index 00000000..c5910c05 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/driver.cpp @@ -0,0 +1,207 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF OSR USB Sample Filter + driver's core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +HRESULT +CMyDriver::CreateInstance( + _Out_ PCMyDriver *Driver + ) +/*++ + + Routine Description: + + This static method is invoked in order to create and initialize a new + instance of the driver class. The caller should arrange for the object + to be released when it is no longer in use. + + Arguments: + + Driver - a location to store a referenced pointer to the new instance + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ +{ + PCMyDriver driver; + HRESULT hr; + + // + // Allocate the callback object. + // + + driver = new CMyDriver(); + + if (NULL == driver) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the callback object. + // + + hr = driver->Initialize(); + + if (SUCCEEDED(hr)) + { + // + // Store a pointer to the new, initialized object in the output + // parameter. + // + + *Driver = driver; + } + else + { + + // + // Release the reference on the driver object to get it to delete + // itself. + // + + driver->Release(); + } + + return hr; +} + +HRESULT +CMyDriver::Initialize( + VOID + ) +/*++ + + Routine Description: + + This method is called to initialize a newly created driver callback object + before it is returned to the creator. Unlike the constructor, the + Initialize method contains operations which could potentially fail. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + return S_OK; +} + +HRESULT +CMyDriver::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Interface + ) +/*++ + + Routine Description: + + This method returns a pointer to the requested interface on the callback + object.. + + Arguments: + + InterfaceId - the IID of the interface to query/reference + + Interface - a location to store the interface pointer. + + Return Value: + + S_OK if the interface is supported. + E_NOINTERFACE if it is not supported. + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) + { + *Interface = QueryIDriverEntry(); + return S_OK; + } + else + { + return CUnknown::QueryInterface(InterfaceId, Interface); + } +} + +HRESULT +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + HRESULT hr; + + PCMyDevice device = NULL; + + // + // Create a new instance of our device callback object + // + + hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); + + // + // If that succeeded then call the device's construct method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference on the device callback object now that it's been + // associated with an fx device object. + // + + if (NULL != device) + { + device->Release(); + } + + return hr; +} diff --git a/usb/umdf_filter_kmdf/umdf_filter/driver.h b/usb/umdf_filter_kmdf/umdf_filter/driver.h new file mode 100644 index 00000000..08f36a71 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/driver.h @@ -0,0 +1,145 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF OSR USB Sample Filter + driver's callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the OSR USB Sample Filter driver. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +class CMyDriver : public CUnknown, public IDriverEntry +{ +// +// Private data members. +// +private: + +// +// Private methods. +// +private: + + // + // Returns a refernced pointer to the IDriverEntry interface. + // + + IDriverEntry * + QueryIDriverEntry( + VOID + ) + { + AddRef(); + return static_cast<IDriverEntry*>(this); + } + + HRESULT + Initialize( + VOID + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _Out_ PCMyDriver *Driver + ); + +// +// COM methods +// +public: + + // + // IDriverEntry methods + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnInitialize( + _In_ IWDFDriver* /*FxWdfDriver*/ + ) + { + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + virtual + VOID + STDMETHODCALLTYPE + OnDeinitialize( + _In_ IWDFDriver * /*FxWdfDriver*/ + ) + { + return; + } + + // + // IUnknown methods. + // + // We have to implement basic ones here that redirect to the + // base class becuase of the multiple inheritance. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; diff --git a/usb/umdf_filter_kmdf/umdf_filter/exports.def b/usb/umdf_filter_kmdf/umdf_filter/exports.def new file mode 100644 index 00000000..0fc42817 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/exports.def @@ -0,0 +1,4 @@ +; Skeleton.def : Declares the module parameters. + +EXPORTS + DllGetClassObject PRIVATE diff --git a/usb/umdf_filter_kmdf/umdf_filter/internal.h b/usb/umdf_filter_kmdf/umdf_filter/internal.h new file mode 100644 index 00000000..516f6d7f --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/internal.h @@ -0,0 +1,111 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF OSR USB Sample Filter + driver. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the WUDF headers +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Forward definitions of classes in the other header files. +// + +typedef class CMyDriver *PCMyDriver; +typedef class CMyDevice *PCMyDevice; +typedef class CMyQueue *PCMyQueue; + +// +// Define the tracing flags. +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (73cdcaa5,ce52,43f2,aa2d,5f5a84e22213), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\OsrUsbFilter" +#define MYDRIVER_COM_DESCRIPTION L"UMDF OSR USB Sample Filter Driver" +#define MYDRIVER_CLASS_ID {0x422d8dbc, 0x520d, 0x4d7e, {0x8f, 0x53, 0x92, 0x0e, 0x5c, 0x86, 0x7e, 0x6c}} + +// +// Include the type specific headers. +// + +#include "comsup.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_SAMPLE_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} diff --git a/usb/umdf_filter_kmdf/umdf_filter/queue.cpp b/usb/umdf_filter_kmdf/umdf_filter/queue.cpp new file mode 100644 index 00000000..5642ec74 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/queue.cpp @@ -0,0 +1,538 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Queue.cpp + +Abstract: + + This module contains the implementation of the OSR USB Filter Sample driver's + queue callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "queue.h" + +#include "queue.tmh" + +HRESULT +CMyQueue::CreateInstance( + _In_ IWDFDevice * FxDevice, + _Out_ CMyQueue **Queue + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the OSR USB Filter Sample driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + CMyQueue *queue; + + HRESULT hr = S_OK; + + // + // Allocate a new instance of the device class. + // + + queue = new CMyQueue(); + + if (NULL == queue) + { + hr = E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + if (SUCCEEDED(hr)) + { + hr = queue->Initialize(FxDevice); + } + + if (SUCCEEDED(hr)) + { + queue->AddRef(); + *Queue = queue; + } + + if (NULL != queue) + { + queue->Release(); + } + + return hr; +} + +HRESULT +CMyQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + HRESULT hr; + + + if(IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDefaultIoHandler))) + { + hr = S_OK; + *Object = QueryIQueueCallbackDefaultIoHandler(); + } + else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) + { + hr = S_OK; + *Object = QueryIQueueCallbackWrite(); + } + else if (IsEqualIID(InterfaceId, __uuidof(IRequestCallbackRequestCompletion))) + { + hr = S_OK; + *Object = QueryIRequestCallbackRequestCompletion(); + + } + else + { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +HRESULT +CMyQueue::Initialize( + _In_ IWDFDevice *FxDevice + ) +/*++ + + Routine Description: + + This method initializes the device callback object. Any operations which + need to be performed before the caller can use the callback object, but + which couldn't be done in the constructor becuase they could fail would + be placed here. + + Arguments: + + FxDevice - the device which this Queue is for. + + Return Value: + + status. + +--*/ +{ + IWDFIoQueue *fxQueue; + HRESULT hr; + + // + // Create the framework queue + // + + IUnknown *unknown = QueryIUnknown(); + hr = FxDevice->CreateIoQueue( + unknown, + TRUE, // bDefaultQueue + WdfIoQueueDispatchParallel, + FALSE, // bPowerManaged + TRUE, // bAllowZeroLengthRequests + &fxQueue + ); + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + "%!FUNC!: Could not create default I/O queue, %!hresult!", + hr + ); + } + + unknown->Release(); + + if (SUCCEEDED(hr)) + { + m_FxQueue = fxQueue; + + // + // m_FxQueue is kept as a Weak reference to framework Queue object to avoid + // circular reference. This object's lifetime is contained within + // framework Queue object's lifetime + // + + fxQueue->Release(); + } + + if (SUCCEEDED(hr)) + { + FxDevice->GetDefaultIoTarget(&m_FxIoTarget); + } + + return hr; +} + +void +CMyQueue::InvertBits( + _Inout_ IWDFMemory* FxMemory, + _In_ SIZE_T NumBytes + ) +/*++ + + Routine Description: + + This helper method inverts bits in the buffer of an FxMemory object + + Arguments: + + FxMemory - Framework memory object whose buffer's bits are to be inverted + + NumBytes - Number of bytes for which bits are to be inverted + + Return Value: + + None + +--*/ +{ + PBYTE Buffer = (PBYTE) + FxMemory->GetDataBuffer(NULL); + + for (SIZE_T i = 0; i < NumBytes; i++) + { + memset(Buffer + i, ~(Buffer[i]), sizeof(*Buffer)); + } +} + +void +CMyQueue::OnWrite( + _In_ IWDFIoQueue* FxQueue, + _In_ IWDFIoRequest* FxRequest, + _In_ SIZE_T NumOfBytesToWrite + ) +/*++ + + Routine Description: + + This method is called by Framework Queue object to deliver the Write request + This method inverts the bits in write buffer and forwards the request down the device stack + In case of any failure prior to ForwardRequest, it completets the request with failure + + Arguments: + + pWdfQueue - Framework Queue which is delivering the request + + pWdfRequest - Framework Request + + Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(FxQueue); + + IWDFMemory * FxInputMemory = NULL; + + FxRequest->GetInputMemory(&FxInputMemory); + + // + // Invert bits of the buffer to be written to device + // + + InvertBits(FxInputMemory, NumOfBytesToWrite); + + // + // Forward request down the stack + // When the device below completes the request we will get notified in OnComplete + // and then we will complete the request + // + + ForwardRequest(FxRequest); + + FxInputMemory->Release(); +} + +// +// IQueueCallbackDefaultIoHandler method +// + +void +CMyQueue::OnDefaultIoHandler( + _In_ IWDFIoQueue* FxQueue, + _In_ IWDFIoRequest* FxRequest + ) +/*++ + + Routine Description: + + This method is called by Framework Queue object to deliver all the I/O + Requests for which we do not have a specific handler + (In our case anything other than Write) + + Arguments: + + pWdfQueue - Framework Queue which is delivering the request + + pWdfRequest - Framework Request + + Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(FxQueue); + + // + // We just forward the request down the stack + // When the device below completes the request we will get notified in OnComplete + // and then we will complete the request + // + + ForwardRequest(FxRequest); +} + +void +CMyQueue::ForwardRequest( + _In_ IWDFIoRequest* FxRequest + ) +/*++ + + Routine Description: + + This helper method forwards the request down the stack + + Arguments: + + pWdfRequest - Request to be forwarded + + Return Value: + + None + + Remarks: + + The request gets forwarded to the next device in the stack which can be: + 1. Next device in user-mode stack + 2. Top device in kernel-mode stack (Redirector's Down Device) + + In this routine we: + 1. Set a completion callback + 2. Copy request parameters to next stack location + 3. Asynchronously send the request without any timeout + + When the lower request gets completed we will be notified via the + completion callback, where we will complete our request + + In case of failure this routine completes the request + +--*/ +{ + // + //First set the completion callback + // + + IRequestCallbackRequestCompletion *completionCallback = + QueryIRequestCallbackRequestCompletion(); + + FxRequest->SetCompletionCallback( + completionCallback, + NULL //pContext + ); + + completionCallback->Release(); + + // + //Copy current i/o stack locations parameters to the next stack location + // + + FxRequest->FormatUsingCurrentType( + ); + + // + //Send down the request + // + HRESULT hrSend = S_OK; + + hrSend = FxRequest->Send( + m_FxIoTarget, + 0, //No flag + 0 //No timeout + ); + + if (FAILED(hrSend)) + { + // + //If send failed we need to complete the request with failure + // + FxRequest->CompleteWithInformation(hrSend, 0); + } + + return; +} + +void +CMyQueue::HandleReadRequestCompletion( + IWDFIoRequest* FxRequest, + IWDFIoRequestCompletionParams* CompletionParams + ) +/*++ + + Routine Description: + + This helper method is called by OnCompletion method to complete Read request + We invert the bits in the read buffer + This is so that the client reads back the data it wrote since + we inverted bits during write to device + + Arguments: + + FxRequest - Request object of our layer + + CompletionParams - Parameters with which the lower Request got completed + + Return Value: + + None + + Remarks: + + This method always completes the request since no one else would get a chance to + complete the request + In case of failure it completes the request with failure + +--*/ +{ + HRESULT hrCompletion = CompletionParams->GetCompletionStatus(); + ULONG_PTR BytesRead = CompletionParams->GetInformation(); + + // + // Check + // 1. whether the lower device succeeded the Request (otherwise we will just complete + // the Request with failure + // 2. If data read is of non-zero length, for us to bother to invert its bits + // + + if (SUCCEEDED(hrCompletion) && + (0 != BytesRead) + ) + { + IWDFMemory *FxOutputMemory; + + FxRequest->GetOutputMemory(&FxOutputMemory ); + + InvertBits(FxOutputMemory, BytesRead); + + FxOutputMemory->Release(); + } + + // + // Complete the request + // + + FxRequest->CompleteWithInformation( + hrCompletion, + BytesRead + ); +} + + +void +CMyQueue::OnCompletion( + IWDFIoRequest* FxRequest, + IWDFIoTarget* FxIoTarget, + IWDFRequestCompletionParams* CompletionParams, + PVOID Context + ) +/*++ + + Routine Description: + + This method is called by Framework I/O Target object when + the lower device completets the Request + + Arguments: + + pWdfRequest - Request object of our layer + + pIoTarget - I/O Target object invoking this callback + + pParams - Parameters with which the lower Request got completed + + Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(FxIoTarget); + UNREFERENCED_PARAMETER(Context); + + // + // If it is a read request, we invert the bits read since we inverted them during write + // so that application would read the same data as it wrote + // + + if (WdfRequestRead == FxRequest->GetType()) + { + IWDFIoRequestCompletionParams * IoCompletionParams = NULL; + HRESULT hrQI = CompletionParams->QueryInterface(IID_PPV_ARGS(&IoCompletionParams)); + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + HandleReadRequestCompletion( + FxRequest, + IoCompletionParams + ); + + SAFE_RELEASE(IoCompletionParams); + } + else + { + + // + // Otherwise we just complete our Request object with the same parameters + // with which the lower Request got completed + // + + FxRequest->CompleteWithInformation( + CompletionParams->GetCompletionStatus(), + CompletionParams->GetInformation() + ); + } +} + diff --git a/usb/umdf_filter_kmdf/umdf_filter/queue.h b/usb/umdf_filter_kmdf/umdf_filter/queue.h new file mode 100644 index 00000000..216264e9 --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter/queue.h @@ -0,0 +1,253 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Queue.h + +Abstract: + + This module contains the type definitions for the OSR USB Filter Sample + driver's queue callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Class for the queue callbacks. +// It implements +// IQueueCallbackDeviceIoControl +// IRequestCallbackRequestCompletion +// Queue callbacks +// +// This class also implements IRequestCallbackRequestCompletion callback +// to get the request completion notification when request is sent down the +// stack. This callback can be implemented on a separate object as well. +// This callback is implemented here only for conenience. +// +class CMyQueue : + public CUnknown, + public IQueueCallbackWrite, + public IQueueCallbackDefaultIoHandler, + public IRequestCallbackRequestCompletion +{ + +// +// Private data members. +// +private: + + // + // Weak reference to framework Queue object which this object implements callbacks for + // This is kept as a weak reference to avoid circular reference + // This object's lifetime is contained within framework Queue object's lifetime + // + + IWDFIoQueue *m_FxQueue; + + // + // I/O Target to which we forward requests. Represents next device in the + // device stack + // + + IWDFIoTarget *m_FxIoTarget; + +// +// Private methods. +// + +private: + + CMyQueue() : + m_FxQueue(NULL), + m_FxIoTarget(NULL) + { + } + + virtual ~CMyQueue() + { + if (NULL != m_FxIoTarget) + { + m_FxIoTarget->Release(); + } + } + + // + // QueryInterface helpers + // + + IRequestCallbackRequestCompletion * + QueryIRequestCallbackRequestCompletion( + VOID + ) + { + AddRef(); + return static_cast<IRequestCallbackRequestCompletion*>(this); + } + + IQueueCallbackWrite * + QueryIQueueCallbackWrite( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackWrite *>(this); + } + + IQueueCallbackDefaultIoHandler * + QueryIQueueCallbackDefaultIoHandler( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackDefaultIoHandler *>(this); + } + + // + // Initialize + // + + HRESULT + Initialize( + _In_ IWDFDevice *FxDevice + ); + + // + // Helper method to forward request down the stack + // + + void + ForwardRequest( + _In_ IWDFIoRequest *pWdfRequest + ); + + // + // Helper method to inverts bits in the buffer of a framework Memory object + // + + void + InvertBits( + _Inout_ IWDFMemory* FxMemory, + _In_ SIZE_T NumBytes + ); + + // + // Helper method to handle Read request completion + // + + void + HandleReadRequestCompletion( + IWDFIoRequest* FxRequest, + IWDFIoRequestCompletionParams* CompletionParams + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this class + // + + static + HRESULT + CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ CMyQueue **Queue + ); + + + HRESULT + Configure( + VOID + ) + { + return S_OK; + } + +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IQueueCallbackWrite method + // + + virtual + void + STDMETHODCALLTYPE + OnWrite( + _In_ IWDFIoQueue* FxQueue, + _In_ IWDFIoRequest* FxRequest, + _In_ SIZE_T NumOfBytesToWrite + ); + + + // + // IQueueCallbackDefaultIoHandler method + // + + virtual + void + STDMETHODCALLTYPE + OnDefaultIoHandler( + _In_ IWDFIoQueue* FxQueue, + _In_ IWDFIoRequest* FxRequest + ); + + // + //IRequestCallbackRequestCompletion + // + + virtual + void + STDMETHODCALLTYPE + OnCompletion( + IWDFIoRequest* FxRequest, + IWDFIoTarget* FxIoTarget, + IWDFRequestCompletionParams* CompletionParams, + PVOID Context + ); +}; + diff --git a/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln b/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln new file mode 100644 index 00000000..3d7cb72a --- /dev/null +++ b/usb/umdf_filter_kmdf/umdf_filter_kmdf.sln @@ -0,0 +1,59 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{C1316664-1EF9-40B6-BB74-C6680FB441CA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{619F52B1-AE17-4645-9FDB-7B2D3D2679DD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf_driver", "Kmdf_driver", "{865605E4-9818-4413-9177-9330DA3B724B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{BE14DB05-36A7-4ECE-88E1-FB8157CA568E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "osrusbfx2", "kmdf_driver\osrusbfx2.vcxproj", "{6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}" +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 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Debug|Win32.ActiveCfg = Debug|Win32 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Debug|Win32.Build.0 = Debug|Win32 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Release|Win32.ActiveCfg = Release|Win32 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Release|Win32.Build.0 = Release|Win32 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Debug|x64.ActiveCfg = Debug|x64 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Debug|x64.Build.0 = Debug|x64 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Release|x64.ActiveCfg = Release|x64 + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D}.Release|x64.Build.0 = Release|x64 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Debug|Win32.Build.0 = Debug|Win32 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Release|Win32.ActiveCfg = Release|Win32 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Release|Win32.Build.0 = Release|Win32 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Debug|x64.ActiveCfg = Debug|x64 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Debug|x64.Build.0 = Debug|x64 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Release|x64.ActiveCfg = Release|x64 + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E}.Release|x64.Build.0 = Release|x64 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Debug|Win32.ActiveCfg = Debug|Win32 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Debug|Win32.Build.0 = Debug|Win32 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Release|Win32.ActiveCfg = Release|Win32 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Release|Win32.Build.0 = Release|Win32 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Debug|x64.ActiveCfg = Debug|x64 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Debug|x64.Build.0 = Debug|x64 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Release|x64.ActiveCfg = Release|x64 + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2BA68E64-0EBB-409C-937F-FDAC3FB7A39D} = {C1316664-1EF9-40B6-BB74-C6680FB441CA} + {BE14DB05-36A7-4ECE-88E1-FB8157CA568E} = {619F52B1-AE17-4645-9FDB-7B2D3D2679DD} + {6ABDB82A-B2BA-4EE3-A4CC-C0B00B7B5220} = {865605E4-9818-4413-9177-9330DA3B724B} + EndGlobalSection +EndGlobal diff --git a/usb/umdf_filter_umdf/Package/package.VcxProj b/usb/umdf_filter_umdf/Package/package.VcxProj index 9ce9102a..6bee13d5 100644 --- a/usb/umdf_filter_umdf/Package/package.VcxProj +++ b/usb/umdf_filter_umdf/Package/package.VcxProj @@ -18,6 +18,14 @@ <Platform>x64</Platform> </ProjectConfiguration> </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\umdf_driver\WUDFOsrUsbFx2.vcxproj"> + <Project>{23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}</Project> + </ProjectReference> + <ProjectReference Include="..\umdf_filter\WUDFOsrUsbFilter.vcxproj"> + <Project>{4BBB6EA2-FEE6-4951-8D63-BA71C959958F}</Project> + </ProjectReference> + </ItemGroup> <PropertyGroup Label="PropertySheets"> <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> <ConfigurationType>Utility</ConfigurationType> @@ -27,8 +35,8 @@ </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Globals"> - <ProjectGuid>{8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}</ProjectGuid> - <SampleGuid>{41DDE172-7368-4C23-A7CC-B858DDD69598}</SampleGuid> + <ProjectGuid>{7F3A9577-907F-41F9-A180-C7DFFA7C9F18}</ProjectGuid> + <SampleGuid>{5DD4B112-FC71-4CC4-BD6C-7A47B0C393EC}</SampleGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> @@ -73,18 +81,6 @@ </PropertyGroup> <ItemDefinitionGroup> </ItemDefinitionGroup> - <ItemGroup> - <!--Inf Include="DriverInf.inv" /--> - <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\umdf_driver\WUDFOsrUsbFx2.vcxproj"> - <Project>{81B31960-3EA8-4F43-B79A-5A851EC49CE8}</Project> - </ProjectReference> - <ProjectReference Include="..\umdf_filter\WUDFOsrUsbFilter.vcxproj"> - <Project>{F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}</Project> - </ProjectReference> - </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> diff --git a/usb/umdf_filter_umdf/Package/package.VcxProj.Filters b/usb/umdf_filter_umdf/Package/package.VcxProj.Filters index 16a8f2b2..338a8815 100644 --- a/usb/umdf_filter_umdf/Package/package.VcxProj.Filters +++ b/usb/umdf_filter_umdf/Package/package.VcxProj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{B88534C0-78F8-4BDC-8C08-67199D9AA05A}</UniqueIdentifier> + <UniqueIdentifier>{CAA3CB0A-784F-417B-ADA4-267FD26703A4}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{5F6982F6-3AF9-4722-83E0-A9D98AE5B91F}</UniqueIdentifier> + <UniqueIdentifier>{9BD249E8-2871-4C6B-8319-A14DDF0914A2}</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>{14281D5C-7E16-4447-BBF8-E89022F25A64}</UniqueIdentifier> + <UniqueIdentifier>{6DF09A8E-2B37-41C7-AD3E-DBFB1708CECA}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{EC6EE142-CF05-44A4-9FDC-01D842258F31}</UniqueIdentifier> + <UniqueIdentifier>{165858E4-F07F-4DBC-964A-A3E623018249}</UniqueIdentifier> </Filter> </ItemGroup> </Project>
\ No newline at end of file diff --git a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj index 278a29ee..bb103f8d 100644 --- a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj +++ b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj @@ -19,7 +19,7 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{81B31960-3EA8-4F43-B79A-5A851EC49CE8}</ProjectGuid> + <ProjectGuid>{23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> @@ -27,7 +27,7 @@ <RequiresPackageProject>true</RequiresPackageProject> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{2B42915F-EE92-4D87-A546-B050A53BCCB6}</SampleGuid> + <SampleGuid>{E4C6299E-8765-4C69-8CEB-B5F530F83D42}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -256,7 +256,6 @@ <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" /> diff --git a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters index 62f00807..0ff60758 100644 --- a/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters +++ b/usb/umdf_filter_umdf/umdf_driver/WUDFOsrUsbFx2.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{48ABB0A1-2EEB-4A52-A63E-E2CAAF57DDA7}</UniqueIdentifier> + <UniqueIdentifier>{8A850A2A-3EE0-48E3-9B10-C5D80ED01050}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{80693C76-07E2-41A9-BA81-3F4FC6E25DE9}</UniqueIdentifier> + <UniqueIdentifier>{2DE6E105-292A-4C7B-A2A0-7B39D9339979}</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>{46C21426-AD2F-493A-A1FA-BDD65A5BB6AF}</UniqueIdentifier> + <UniqueIdentifier>{D880698B-D054-49BC-B7B3-607606EAB71A}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{05DE7331-93CD-4B4C-8212-3510CFF88BC8}</UniqueIdentifier> + <UniqueIdentifier>{5CEFA42C-9FC9-4234-815F-4C86F8D5AE7D}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj index e7d128d9..99e4832d 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj @@ -19,7 +19,7 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}</ProjectGuid> + <ProjectGuid>{4BBB6EA2-FEE6-4951-8D63-BA71C959958F}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> @@ -27,7 +27,7 @@ <RequiresPackageProject>true</RequiresPackageProject> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{1A27CDB5-8D3E-47CE-B9F3-6A9C3E964175}</SampleGuid> + <SampleGuid>{D91D8948-9EF7-41ED-BBC4-7E870F5929F1}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -273,7 +273,6 @@ <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" /> diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters index 054dcbea..2845ce7f 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilter.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{5D7700E9-F17B-412A-AD01-7ABC0A91FC45}</UniqueIdentifier> + <UniqueIdentifier>{C8E8CD40-00CA-4946-BD15-35A6AE9BC653}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{6163CCCD-5DFB-441F-A144-DFAF53F65869}</UniqueIdentifier> + <UniqueIdentifier>{DAC345DC-1425-47B4-BC7A-F459FCFBEA26}</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>{C5FC49C2-D442-4645-9D78-BC6B98C60BBC}</UniqueIdentifier> + <UniqueIdentifier>{396BA632-D58C-49AC-B3C3-E85ED7BB478F}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{EE04D080-B627-4CBB-AD4E-2A9A70CEDE94}</UniqueIdentifier> + <UniqueIdentifier>{884CE389-18D3-452C-9FEA-9E5F512FC4E2}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx index db242508..2d61a186 100644 --- a/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx +++ b/usb/umdf_filter_umdf/umdf_filter/WUDFOsrUsbFilterOnUmFx2Driver.inx @@ -7,14 +7,14 @@ Signature="$Windows NT$" Class=Sample ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} -Provider=%MSFTUMDF% +Provider=%ProviderName% DriverVer=03/25/2005,0.0.0.1 CatalogFile=wudf.cat [Manufacturer] -%MSFTUMDF%=Microsoft,NT$ARCH$ +%ManufacturerName%=Standard,NT$ARCH$ -[Microsoft.NT$ARCH$] +[Standard.NT$ARCH$] %OsrUsbDeviceName%=OsrUsb_Install, USB\Vid_045e&Pid_94aa&mi_00 %OsrUsbDeviceName%=OsrUsb_Install, USB\VID_0547&PID_1002 @@ -107,9 +107,10 @@ WudfOsrUsbFx2.dll ; =================== Generic ================================== [Strings] -MSFTUMDF="Microsoft Internal (WDF:UMDF)" -MediaDescription="Microsoft UMDF OSR USB Sample Device Installation Media" +ProviderName="TODO-Set-Provider" +ManufacturerName="TODO-Set-Manufacturer" +MediaDescription="UMDF OSR USB Sample Device Installation Media" ClassName="Sample Device" -OsrUsbDeviceName="Microsoft UMDF OSR Usb Sample Device With Filter on User-mode Driver" +OsrUsbDeviceName="UMDF OSR Usb Sample Device With Filter on User-mode Driver" WinUsb_SvcDesc="WinUSB Driver" WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" diff --git a/usb/umdf_filter_umdf/umdf_filter_umdf.sln b/usb/umdf_filter_umdf/umdf_filter_umdf.sln index 0bdd1b1d..a26f3f52 100644 --- a/usb/umdf_filter_umdf/umdf_filter_umdf.sln +++ b/usb/umdf_filter_umdf/umdf_filter_umdf.sln @@ -3,17 +3,17 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{E1970392-D253-4054-9859-047E430EAF95}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{72DF351F-0D1A-4DC2-84E6-E71F93608A08}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{DEE88039-9FB9-401D-B13D-727CBF613BCB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_filter", "Umdf_filter", "{7B826E21-097E-4279-9B72-C812B012A2D9}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_driver", "Umdf_driver", "{2E02C638-E773-463D-918E-3A1FBA040E1D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Umdf_driver", "Umdf_driver", "{BF37E731-1A3F-4BA2-B71F-86BDC37D83F7}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{7F3A9577-907F-41F9-A180-C7DFFA7C9F18}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFilter", "umdf_filter\WUDFOsrUsbFilter.vcxproj", "{4BBB6EA2-FEE6-4951-8D63-BA71C959958F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "umdf_driver\WUDFOsrUsbFx2.vcxproj", "{81B31960-3EA8-4F43-B79A-5A851EC49CE8}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "umdf_driver\WUDFOsrUsbFx2.vcxproj", "{23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,37 +23,37 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|Win32.ActiveCfg = Debug|Win32 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|Win32.Build.0 = Debug|Win32 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|Win32.ActiveCfg = Release|Win32 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|Win32.Build.0 = Release|Win32 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|x64.ActiveCfg = Debug|x64 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Debug|x64.Build.0 = Debug|x64 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|x64.ActiveCfg = Release|x64 - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD}.Release|x64.Build.0 = Release|x64 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|Win32.ActiveCfg = Debug|Win32 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|Win32.Build.0 = Debug|Win32 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|Win32.ActiveCfg = Release|Win32 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|Win32.Build.0 = Release|Win32 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|x64.ActiveCfg = Debug|x64 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Debug|x64.Build.0 = Debug|x64 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|x64.ActiveCfg = Release|x64 - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF}.Release|x64.Build.0 = Release|x64 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|Win32.ActiveCfg = Debug|Win32 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|Win32.Build.0 = Debug|Win32 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|Win32.ActiveCfg = Release|Win32 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|Win32.Build.0 = Release|Win32 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|x64.ActiveCfg = Debug|x64 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Debug|x64.Build.0 = Debug|x64 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|x64.ActiveCfg = Release|x64 - {81B31960-3EA8-4F43-B79A-5A851EC49CE8}.Release|x64.Build.0 = Release|x64 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Debug|Win32.ActiveCfg = Debug|Win32 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Debug|Win32.Build.0 = Debug|Win32 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Release|Win32.ActiveCfg = Release|Win32 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Release|Win32.Build.0 = Release|Win32 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Debug|x64.ActiveCfg = Debug|x64 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Debug|x64.Build.0 = Debug|x64 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Release|x64.ActiveCfg = Release|x64 + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18}.Release|x64.Build.0 = Release|x64 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Debug|Win32.Build.0 = Debug|Win32 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Release|Win32.ActiveCfg = Release|Win32 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Release|Win32.Build.0 = Release|Win32 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Debug|x64.ActiveCfg = Debug|x64 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Debug|x64.Build.0 = Debug|x64 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Release|x64.ActiveCfg = Release|x64 + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F}.Release|x64.Build.0 = Release|x64 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Debug|Win32.ActiveCfg = Debug|Win32 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Debug|Win32.Build.0 = Debug|Win32 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Release|Win32.ActiveCfg = Release|Win32 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Release|Win32.Build.0 = Release|Win32 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Debug|x64.ActiveCfg = Debug|x64 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Debug|x64.Build.0 = Debug|x64 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Release|x64.ActiveCfg = Release|x64 + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {8D2391A3-43B4-4B9F-89E2-A4024B35FBAD} = {E1970392-D253-4054-9859-047E430EAF95} - {F7387F7F-59AF-4963-9D6E-8626E9E4D2EF} = {DEE88039-9FB9-401D-B13D-727CBF613BCB} - {81B31960-3EA8-4F43-B79A-5A851EC49CE8} = {2E02C638-E773-463D-918E-3A1FBA040E1D} + {7F3A9577-907F-41F9-A180-C7DFFA7C9F18} = {72DF351F-0D1A-4DC2-84E6-E71F93608A08} + {4BBB6EA2-FEE6-4951-8D63-BA71C959958F} = {7B826E21-097E-4279-9B72-C812B012A2D9} + {23F6BB7E-4FB3-4584-8972-5048C2C1CAEE} = {BF37E731-1A3F-4BA2-B71F-86BDC37D83F7} EndGlobalSection EndGlobal diff --git a/usb/umdf_fx2/ReadMe.md b/usb/umdf_fx2/ReadMe.md index e27415cc..8b04f98e 100644 --- a/usb/umdf_fx2/ReadMe.md +++ b/usb/umdf_fx2/ReadMe.md @@ -5,13 +5,6 @@ The umdf\_fx2 sample is a User-Mode Driver Framework (UMDF) driver for the OSR U The sample can also be used with the CustomDeviceAccess MSDK sample. The sample demonstrates how to perform bulk and interrupt data transfers to an USB device. The specification for the device is at <http://www.osronline.com/hardware/OSRFX2_32.pdf>. The driver and sample device metadata also work with the [Custom driver access](http://go.microsoft.com/fwlink/p/?LinkID=248288) sample. -Starting in Windows 8.1, the osrusbfx2 sample has been divided into these samples: - -- [WDF Sample Driver Learning Lab for OSR USB-FX2](http://msdn.microsoft.com/en-us/library/windows/hardware/): This sample is a series of iterative drivers that demonstrate how to write a "Hello World" driver and adds additional features in each step. - -- [kmdf\_fx2](gallery_samples.123a_gallery#1): This sample is the final version of kernel-mode [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/) driver. The sample demonstrates KMDF methods. - -- umdf\_fx2: This sample is the final version of the user-mode driver [wdf\_osrfx2](http://msdn.microsoft.com/en-us/library/windows/hardware/). The sample demonstrates UMDF methods. Related topics -------------- diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx index 1ade7da6..529515c6 100644 --- a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.inx @@ -6,14 +6,14 @@ Signature="$Windows NT$" Class=Sample ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} -Provider=%MSFTUMDF% +Provider=%ProviderName% DriverVer=03/25/2005,0.0.0.1 CatalogFile=wudf.cat [Manufacturer] -%MSFTUMDF%=Microsoft,NT$ARCH$ +%ManufacturerName%=Standard,NT$ARCH$ -[Microsoft.NT$ARCH$] +[Standard.NT$ARCH$] %OsrUsbDeviceName%=OsrUsb_Install, USB\Vid_045e&Pid_94aa&mi_00 %OsrUsbDeviceName%=OsrUsb_Install, USB\VID_0547&PID_1002 @@ -107,8 +107,9 @@ WUDFOsrUsbFx2.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME ; =================== Generic ================================== [Strings] -MSFTUMDF="Microsoft Internal (WDF:UMDF)" -MediaDescription="Microsoft Sample Driver Installation Media" +ProviderName="TODO-Set-Provider" +ManufacturerName="TODO-Set-Manufacturer" +MediaDescription="Sample Driver Installation Media" ClassName="Sample Device" WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" OsrUsbDeviceName="UMDF Sample Driver for OSR USB Fx2 Learning Kit" diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj index 78e68710..4960ba7c 100644 --- a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj @@ -19,13 +19,13 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}</ProjectGuid> + <ProjectGuid>{BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{DD1D49D1-69A2-4BF2-9EE8-34692D0104FB}</SampleGuid> + <SampleGuid>{CB79CACC-78FE-4BD1-8CEF-F304F7B06047}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -287,7 +287,6 @@ <ItemGroup> <Inf Exclude="@(Inf)" Include="*.inf" /> <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> - <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> </ItemGroup> <ItemGroup> <None Include="*.txt" Exclude="@(None)" /> diff --git a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters index 1e50204c..2d50f351 100644 --- a/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters +++ b/usb/umdf_fx2/driver/WUDFOsrUsbFx2.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{23E0CA5E-560F-46BF-8A5D-0C9892A60610}</UniqueIdentifier> + <UniqueIdentifier>{E1664368-3424-45A1-AF32-AAACC488825D}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{DE2D9516-18E4-493F-8E49-245A3A552F1A}</UniqueIdentifier> + <UniqueIdentifier>{137984AA-C7C2-452A-9DA3-3FCF41A038C9}</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>{0D7905F4-200D-4439-A264-543F6CC50803}</UniqueIdentifier> + <UniqueIdentifier>{B2A97895-8C0E-4645-AF01-3C7522D5A567}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{622540FC-F451-4D00-B0A6-DED0A2B5BDBA}</UniqueIdentifier> + <UniqueIdentifier>{9B29C0A6-BE4B-4116-8FF9-8E8894F2055D}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> @@ -45,9 +45,6 @@ </None> </ItemGroup> <ItemGroup> - <FilesToPackage Include=".\Debug\\WUDFOsrUsbFx2.inf"> - <Filter>Driver Files</Filter> - </FilesToPackage> <Inf Include="WUDFOsrUsbFx2.inx"> <Filter>Driver Files</Filter> </Inf> diff --git a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj index 0b2f09fd..b79ca2a3 100644 --- a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj +++ b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj @@ -19,11 +19,11 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}</ProjectGuid> + <ProjectGuid>{24745B15-B6D2-4D1A-AB27-C0F38B1C0086}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{A76B918B-D92F-4EA3-8BA4-6D560CCAB575}</SampleGuid> + <SampleGuid>{9D5B23F4-B6A2-45BC-92DA-A299F0812254}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -198,7 +198,6 @@ <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" /> diff --git a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters index b101faa4..c7c570ef 100644 --- a/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters +++ b/usb/umdf_fx2/exe/WudfOsrUsbFx2Test.vcxproj.Filters @@ -3,15 +3,15 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{70899A87-F630-4585-8B67-E7450F161ADD}</UniqueIdentifier> + <UniqueIdentifier>{89C25BE5-A406-421D-A03E-1829A2E96921}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{01515B55-99D7-41ED-9B4E-F4E8971BB851}</UniqueIdentifier> + <UniqueIdentifier>{C1755921-6CDF-4C5E-A16F-564D80D9C88C}</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>{DC48D49A-F703-4F8E-95F8-ED4DE2603606}</UniqueIdentifier> + <UniqueIdentifier>{91D70E33-BE1D-40E5-B28D-65555B5DF102}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/usb/umdf_fx2/umdf_fx2.sln b/usb/umdf_fx2/umdf_fx2.sln index 9e363469..bfaee1d4 100644 --- a/usb/umdf_fx2/umdf_fx2.sln +++ b/usb/umdf_fx2/umdf_fx2.sln @@ -3,13 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B339DBBB-24B4-45D7-9F00-655FFD2AA012}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{8367199C-3B22-414B-BD8D-780BB74E06C6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{2869A0EF-34B9-45CF-9E14-01A016B8FC6E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{002D6001-0177-4A2D-8CDF-6F2F6A9CAAB6}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "driver\WUDFOsrUsbFx2.vcxproj", "{6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFOsrUsbFx2", "driver\WUDFOsrUsbFx2.vcxproj", "{BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WudfOsrUsbFx2Test", "exe\WudfOsrUsbFx2Test.vcxproj", "{D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WudfOsrUsbFx2Test", "exe\WudfOsrUsbFx2Test.vcxproj", "{24745B15-B6D2-4D1A-AB27-C0F38B1C0086}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,28 +19,28 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|Win32.ActiveCfg = Debug|Win32 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|Win32.Build.0 = Debug|Win32 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|Win32.ActiveCfg = Release|Win32 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|Win32.Build.0 = Release|Win32 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|x64.ActiveCfg = Debug|x64 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Debug|x64.Build.0 = Debug|x64 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|x64.ActiveCfg = Release|x64 - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E}.Release|x64.Build.0 = Release|x64 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|Win32.ActiveCfg = Debug|Win32 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|Win32.Build.0 = Debug|Win32 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|Win32.ActiveCfg = Release|Win32 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|Win32.Build.0 = Release|Win32 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|x64.ActiveCfg = Debug|x64 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Debug|x64.Build.0 = Debug|x64 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|x64.ActiveCfg = Release|x64 - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F}.Release|x64.Build.0 = Release|x64 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Debug|Win32.ActiveCfg = Debug|Win32 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Debug|Win32.Build.0 = Debug|Win32 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Release|Win32.ActiveCfg = Release|Win32 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Release|Win32.Build.0 = Release|Win32 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Debug|x64.ActiveCfg = Debug|x64 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Debug|x64.Build.0 = Debug|x64 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Release|x64.ActiveCfg = Release|x64 + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53}.Release|x64.Build.0 = Release|x64 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Debug|Win32.ActiveCfg = Debug|Win32 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Debug|Win32.Build.0 = Debug|Win32 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Release|Win32.ActiveCfg = Release|Win32 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Release|Win32.Build.0 = Release|Win32 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Debug|x64.ActiveCfg = Debug|x64 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Debug|x64.Build.0 = Debug|x64 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Release|x64.ActiveCfg = Release|x64 + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6C6B5C2D-F192-4C22-B8ED-A90C10FB9A1E} = {B339DBBB-24B4-45D7-9F00-655FFD2AA012} - {D567DDDD-4EC8-40B4-AE8F-58B2D41F837F} = {2869A0EF-34B9-45CF-9E14-01A016B8FC6E} + {BCB0C08D-E6FC-4FE6-BFDE-723B3706FA53} = {8367199C-3B22-414B-BD8D-780BB74E06C6} + {24745B15-B6D2-4D1A-AB27-C0F38B1C0086} = {002D6001-0177-4A2D-8CDF-6F2F6A9CAAB6} EndGlobalSection EndGlobal diff --git a/usb/usbsamp/ReadMe.md b/usb/usbsamp/ReadMe.md new file mode 100644 index 00000000..ddab8159 --- /dev/null +++ b/usb/usbsamp/ReadMe.md @@ -0,0 +1,187 @@ +Usbsamp Generic USB Driver +========================== + +The USBSAMP sample demonstrates how to perform full speed, high speed, and SuperSpeed transfers to and from bulk and isochronous endpoints of a generic USB device. USBSAMP is based on the [Kernel Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff557405) (KMDF). Superspeed bulk and isochronous transfers only work when the Microsoft USB 3.0 stack is loaded. + +The sample also contains a console test application that initiates bulk (including stream) and isochronous transfers and obtains data from the device's I/O endpoints. The application also demonstrates how to use GUID-based device names and pipe names generated by the operating system using the **SetupDiXXX** user-mode APIs. + +For information about USB, see [Universal Serial Bus (USB) Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff538930). + +## Universal Windows Driver Compliant +This sample builds a Universal Windows Driver. It uses only APIs and DDIs that are included in OneCoreUAP. + +**Hardware requirements** + +The sample driver can be loaded as the function driver for any of these devices: + +- OSR FX2 learning kit. You can get the kit from [OSR Online](http://www.osronline.com/). +- [MUTT devices](http://msdn.microsoft.com/en-us/library/windows/hardware/dn376873). To order those devices, see [How to get MUTT devices](buses.microsoft_usb_test_tool__mutt__devices#howto). +- Intel 82930 USB test board. + +If you have a different USB device, you can still use the driver by adding the device's hardware ID to the INX file. Note that the data transfer scenarios will work only with the endpoints supported by the device. + +Set the configuration and platform in Visual Studio +--------------------------------------------------- + +In Visual Studio, in Solution Explorer, right click **Solution ‘usbsamp’ (3 projects)**, and choose **Configuration Manager**. Set the configuration and the platform. Make sure that the configuration and platform are the same for both the driver project and the package project. Do not check the **Deploy** boxes. Here are some examples of configuration and platform settings. + +<table> +<colgroup> +<col width="33%" /> +<col width="33%" /> +<col width="33%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">Configuration +Platform +Description</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left">Win8.1 Debug +x64 +The driver will run on an x64 hardware platform that is running Windows 8.1. The driver will not run on any earlier versions of Windows.</td> +<td align="left">Win7 Debug +x64 +The driver will run on an x64 hardware platform that is running Windows 7 or a later version of Windows.</td> +</tr> +</tbody> +</table> + +Build the sample using Visual Studio +------------------------------------ + +In Visual Studio, on the **Build** menu, choose **Build Solution**. + +For more information about using Visual Studio to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + +Locate the built driver package +------------------------------- + +In File Explorer, navigate to the folder that contains your built driver package. The location of this folder varies depending on what you set for configuration and platform. For example, if your settings are Win7 Debug and x64, the package is in your solution folder under x64\\Win7Debug\\Package. + +The package contains these files: + +<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">usbsamp.sys +The driver file.</td> +<td align="left">WdfCoinstaller010<em>xx</em>.dll +The coinstaller for version 1.<em>xx</em> of KMDF.</td> +</tr> +</tbody> +</table> + +Run the sample +-------------- + +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. + +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy the USBSAMP sample automatically or manually. + +Automatic deployment +-------------------- + +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). + +1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Install and Verify**. Click **OK**. +3. On the **Build** menu, choose **Deploy Package** or **Build Solution**. + +Manual deployment +----------------- + +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). + +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\Usbsamp). +2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command: + + **devcon install usbsamp.inf USB\\VID\_045E&PID\_078F** + +View the device in Device Manager +--------------------------------- + +On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate the device. For example the device name might be **WDF Sample for FX2 MUTT device** under the**Sample Device** node. + +Build the sample using MSBuild +------------------------------ + +As an alternative to building the USBSAMP sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, Usbsamp.sln. Use the MSBuild command to build the solution. Here are some examples: + +**msbuild /p:configuration=”Win7 Debug” /p:platform=”x64” Usbsamp.sln** + +**msbuild /p:configuration=”Win8 Release” /p:platform=”Win32” Usbsamp.sln** + +For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + +Testing the sample +------------------ + +The sample includes a test application, usbsamp.exe. This console application enumerates the interface registered by the driver and opens the device to send Read, Write, or DeviceIoControl requests based on the command line options. To test the sample, + +1. In Visual Studio, choose **Solution Explorer** from the **View** menu. Locate the application project named **usbsamp**, under the **Exe** folder. +2. Right-click and choose **Build**. For example, if your settings are Win8.1 Debug and x64, the application executable is in your solution folder under the exe\\x64\\Win8.1Debug\\usbsamp.exe. +3. Run the executable on the target machine. + +- To view all descriptors and endpoint information, use the following command. + + **usbsamp.exe -u** + + You can use the preceding command to view pipe numbers for read and write requests. + +- To send a Read-Write request, use the following command. + + **usbsamp.exe -r 1024 -w 1024 -c 100 -v** + + The preceding command first writes 1024 bytes of data to bulk out endpoint (pipe 1), then reads 1024 bytes from bulk in endpoint (pipe 0), and compares the read buffer with write buffer to see if they match. If the buffer contents match, it performs this operation 100 times. + +- To send Read-Write requests to bulk endpoints, use any of the following commands, simultaneously. If Read-Write requests are sent to a SuperSpeed bulk endpoint with streams, the sample driver always uses the first underlying stream associated with that endpoint. The driver is multi-thread safe so it can handle multiple requests at a time. + + **usbsamp.exe -r 65536** + + The preceding command reads 65536 bytes from pipe 0. + + **usbsamp.exe -w 65536** + + The preceding command writes 65536 bytes to pipe 1. + + **usbsamp.exe -r 65536 -i pipe02** + + The preceding command reads 65536 bytes from pipe 2. + + **usbsamp.exe -w 65536 -o pipe03** + + The preceding command writes 65536 bytes to pipe 3. + +- To send Read and Write requests to isochronous endpoints you can use one or more of these commands simultaneously. + + **usbsamp.exe -r 512 -i pipe04** + + The preceding command reads 512 bytes from pipe 4. + + **usbsamp.exe -w 512 -o pipe05** + + The preceding command writes 512 bytes to pipe 5. + + **usbsamp.exe -w 1024 -o pipe05 -r 1024 -i pipe04 -c 100 -v** + + The preceding command writes 1024 bytes to pipe 5, then reads 1024 bytes from pipe 4, and compares the buffers to see if they match. If the buffer contents match, it performs this operation 100 times. + +- To skip validation of the data to be read or written in a particular request, use the command with **-x** option as follows: + + **usbsamp.exe -r 1024 -w 1024 -c 100 -x** + + diff --git a/usb/usbsamp/exe/testapp.c b/usb/usbsamp/exe/testapp.c new file mode 100644 index 00000000..e4429726 --- /dev/null +++ b/usb/usbsamp/exe/testapp.c @@ -0,0 +1,1307 @@ +/*++ + +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: + + Console test app for usbsamp.SYS driver + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#include <windows.h> + +#include <conio.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <time.h> + +#include "devioctl.h" +#include "public.h" +#include "strsafe.h" + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include <setupapi.h> +#include <basetyps.h> +#include "usbdi.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + + +#define NOISY(_x_) printf _x_ ; +#define MAX_LENGTH 256 + +char inPipe[MAX_LENGTH] = "PIPE00"; // pipe name for bulk input pipe on our test board +char outPipe[MAX_LENGTH] = "PIPE01"; // pipe name for bulk output pipe on our test board +char completeDeviceName[MAX_LENGTH] = ""; //generated from the GUID registered by the driver itself + +BOOL fDumpUsbConfig = FALSE; // flags set in response to console command line switches +BOOL fDumpReadData = FALSE; +BOOL fRead = FALSE; +BOOL fWrite = FALSE; +BOOL fCompareData = TRUE; + +int gDebugLevel = 1; // higher == more verbose, default is 1, 0 turns off all + +ULONG IterationCount = 1; //count of iterations of the test we are to perform +int WriteLen = 0; // #bytes to write +int ReadLen = 0; // #bytes to read + +// functions + + +HANDLE +OpenOneDevice ( + _In_ HDEVINFO HardwareDeviceInfo, + _In_ PSP_DEVICE_INTERFACE_DATA DeviceInfoData, + _In_ PSTR devName + ) +/*++ +Routine Description: + + Given the HardwareDeviceInfo, representing a handle to the plug and + play information, and deviceInfoData, representing a specific usb device, + open that device and fill in all the relevant information in the given + USB_DEVICE_DESCRIPTOR structure. + +Arguments: + + HardwareDeviceInfo: handle to info obtained from Pnp mgr via SetupDiGetClassDevs() + DeviceInfoData: ptr to info obtained via SetupDiEnumDeviceInterfaces() + +Return Value: + + return HANDLE if the open and initialization was successfull, + else INVLAID_HANDLE_VALUE. + +--*/ +{ + PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + HANDLE hOut = INVALID_HANDLE_VALUE; + + // + // allocate a function class device data structure to receive the + // goods about this particular device. + // + SetupDiGetDeviceInterfaceDetail ( + HardwareDeviceInfo, + DeviceInfoData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL); // not interested in the specific dev-node + + + predictedLength = requiredLength; + // sizeof (SP_FNCLASS_DEVICE_DATA) + 512; + + functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc (predictedLength); + if(NULL == functionClassDeviceData) { + return INVALID_HANDLE_VALUE; + } + functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + + // + // Retrieve the information from Plug and Play. + // + if (! SetupDiGetDeviceInterfaceDetail ( + HardwareDeviceInfo, + DeviceInfoData, + functionClassDeviceData, + predictedLength, + &requiredLength, + NULL)) { + free( functionClassDeviceData ); + return INVALID_HANDLE_VALUE; + } + + (void)StringCchCopy( devName, MAX_LENGTH, functionClassDeviceData->DevicePath) ; + printf( "Attempting to open %s\n", devName ); + + hOut = CreateFile ( + functionClassDeviceData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); // No template file + + if (INVALID_HANDLE_VALUE == hOut) { + printf( "FAILED to open %s\n", devName ); + } + free( functionClassDeviceData ); + return hOut; +} + + +HANDLE +OpenUsbDevice( + _In_ LPGUID pGuid, + _In_ PSTR outNameBuf + ) +/*++ +Routine Description: + + Do the required PnP things in order to find + the next available proper device in the system at this time. + +Arguments: + + pGuid: ptr to GUID registered by the driver itself + outNameBuf: the generated name for this device + +Return Value: + + return HANDLE if the open and initialization was successful, + else INVLAID_HANDLE_VALUE. +--*/ +{ + ULONG NumberDevices; + HANDLE hOut = INVALID_HANDLE_VALUE; + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInfoData; + ULONG i; + BOOLEAN done; + PUSB_DEVICE_DESCRIPTOR usbDeviceInst; + PUSB_DEVICE_DESCRIPTOR *UsbDevices = &usbDeviceInst; + PUSB_DEVICE_DESCRIPTOR tempDevDesc; + + *UsbDevices = NULL; + tempDevDesc = NULL; + NumberDevices = 0; + + // + // Open a handle to the plug and play dev node. + // SetupDiGetClassDevs() returns a device information set that contains + // info on all installed devices of a specified class. + // + hardwareDeviceInfo = + SetupDiGetClassDevs ( pGuid, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + + if (hardwareDeviceInfo == INVALID_HANDLE_VALUE) { + return INVALID_HANDLE_VALUE ; + } + // + // Take a wild guess at the number of devices we have; + // Be prepared to realloc and retry if there are more than we guessed + // + NumberDevices = 4; + done = FALSE; + deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + i=0; + while (!done) { + NumberDevices *= 2; + + if (*UsbDevices) { + tempDevDesc = (PUSB_DEVICE_DESCRIPTOR) + realloc (*UsbDevices, (NumberDevices * sizeof (USB_DEVICE_DESCRIPTOR))); + if(tempDevDesc) { + *UsbDevices = tempDevDesc; + tempDevDesc = NULL; + } + else { + free(*UsbDevices); + *UsbDevices = NULL; + } + } else { + *UsbDevices = (PUSB_DEVICE_DESCRIPTOR)calloc (NumberDevices, sizeof (USB_DEVICE_DESCRIPTOR)); + } + + if (NULL == *UsbDevices) { + + // SetupDiDestroyDeviceInfoList destroys a device information set + // and frees all associated memory. + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return INVALID_HANDLE_VALUE; + } + + for (; i < NumberDevices; i++) { + // SetupDiEnumDeviceInterfaces() returns information about device + // interfaces exposed by one or more devices. Each call returns + // information about one interface; the routine can be called + // repeatedly to get information about several interfaces exposed + // by one or more devices. + + if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // We don't care about specific PDOs + pGuid, + i, + &deviceInfoData)) { + + hOut = OpenOneDevice (hardwareDeviceInfo, &deviceInfoData, outNameBuf); + if ( hOut != INVALID_HANDLE_VALUE ) { + done = TRUE; + break; + } + } else { + if (ERROR_NO_MORE_ITEMS == GetLastError()) { + done = TRUE; + break; + } + } + } + } + + // SetupDiDestroyDeviceInfoList() destroys a device information set + // and frees all associated memory. + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + free ( *UsbDevices ); + return hOut; +} + + + + +BOOL +GetUsbDeviceFileName( + _In_ LPGUID pGuid, + _In_ PSTR outNameBuf + ) +/*++ +Routine Description: + + Given a ptr to a driver-registered GUID, give us a string with the device name + that can be used in a CreateFile() call. + Actually briefly opens and closes the device and sets outBuf if successfull; + returns FALSE if not + +Arguments: + + pGuid: ptr to GUID registered by the driver itself + outNameBuf: the generated zero-terminated name for this device + +Return Value: + + TRUE on success else FALSE + +--*/ +{ + HANDLE hDev = OpenUsbDevice( pGuid, outNameBuf ); + + if ( hDev != INVALID_HANDLE_VALUE ) { + CloseHandle( hDev ); + return TRUE; + } + return FALSE; +} + +HANDLE +open_dev() +/*++ +Routine Description: + + Called by dumpUsbConfig() to open an instance of our device + +Arguments: + + None + +Return Value: + + Device handle on success else NULL + +--*/ +{ + HANDLE hDEV = OpenUsbDevice( (LPGUID)&GUID_CLASS_USBSAMP_USB, + completeDeviceName); + + if (hDEV == INVALID_HANDLE_VALUE) { + printf("Failed to open (%s) = %u", completeDeviceName, GetLastError()); + } else { + printf("DeviceName = (%s)\n", completeDeviceName); + } + + return hDEV; + +} + + +HANDLE +open_file( + _In_ PSTR filename + ) +/*++ +Routine Description: + + Called by main() to open an instance of our device after obtaining its name + +Arguments: + + None + +Return Value: + + Device handle on success else NULL + +--*/ +{ + int success = 1; + HANDLE h; + + if ( !GetUsbDeviceFileName( + (LPGUID) &GUID_CLASS_USBSAMP_USB, + completeDeviceName) ) + { + NOISY(("Failed to GetUsbDeviceFileName err - %u\n", GetLastError())); + return INVALID_HANDLE_VALUE; + } + + (void) StringCchCat (completeDeviceName, MAX_LENGTH, "\\" ); + + if(FAILED(StringCchCat (completeDeviceName, MAX_LENGTH, filename))) { + NOISY(("Failed to open handle - possibly long filename\n")); + return INVALID_HANDLE_VALUE; + } + + printf("completeDeviceName = (%s)\n", completeDeviceName); + + h = CreateFile(completeDeviceName, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (h == INVALID_HANDLE_VALUE) { + NOISY(("Failed to open (%s) = %u", completeDeviceName, GetLastError())); + success = 0; + } else { + NOISY(("Opened successfully.\n")); + } + + return h; +} + +void +usage() +/*++ +Routine Description: + + Called by main() to dump usage info to the console when + the app is called with no parms or with an invalid parm + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + static int i=1; + + if (i) { + printf("Usage for Read/Write test:\n"); + printf("-r [n] where n is number of bytes to read\n"); + printf("-w [n] where n is number of bytes to write\n"); + printf("-c [n] where n is number of iterations (default = 1)\n"); + printf("-i [s] where s is the input pipe\n"); + printf("-o [s] where s is the output pipe\n"); + printf("-v verbose -- dumps read data\n"); + printf("-x to skip validation of read and write data\n"); + + printf("\nUsage for USB and Endpoint info:\n"); + printf("-u to dump USB configuration and pipe info \n"); + i = 0; + } +} + + +void +parse( + _In_ int argc, + _In_reads_(argc) char *argv[] + ) +/*++ +Routine Description: + + Called by main() to parse command line parms + +Arguments: + + argc and argv that was passed to main() + +Return Value: + + Sets global flags as per user function request + +--*/ +{ + int i; + + if ( argc < 2 ) // give usage if invoked with no parms + usage(); + + for (i=0; i<argc; i++) { + if (argv[i][0] == '-' || + argv[i][0] == '/') { + switch(argv[i][1]) { + case 'r': + case 'R': + if (i+1 >= argc) { + usage(); + exit(1); + } + else { +#pragma warning(suppress: 6385) + ReadLen = atoi(&argv[i+1][0]); + if (ReadLen == 0) { + usage(); + exit(1); + } + fRead = TRUE; + } + i++; + break; + case 'w': + case 'W': + if (i+1 >= argc) { + usage(); + exit(1); + } + else { + WriteLen = atoi(&argv[i+1][0]); + if (WriteLen == 0) { + usage(); + exit(1); + } + fWrite = TRUE; + } + i++; + break; + case 'c': + case 'C': + if (i+1 >= argc) { + usage(); + exit(1); + } + else { + IterationCount = atoi(&argv[i+1][0]); + if (IterationCount == 0) { + usage(); + exit(1); + } + } + i++; + break; + case 'i': + case 'I': + if (i+1 >= argc) { + usage(); + exit(1); + } + else { + (void)StringCchCopy(inPipe, MAX_LENGTH, &argv[i+1][0]); + } + i++; + break; + case 'u': + case 'U': + fDumpUsbConfig = TRUE; + i++; + break; + case 'v': + case 'V': + fDumpReadData = TRUE; + i++; + break; + case 'x': + case 'X': + fCompareData = FALSE; + i++; + break; + case 'o': + case 'O': + if (i+1 >= argc) { + usage(); + exit(1); + } + else { + (void)StringCchCopy(outPipe, MAX_LENGTH, &argv[i+1][0]); + } + i++; + break; + default: + usage(); + } + } + } +} + +BOOL +compare_buffs( + _In_reads_bytes_(length) char *buff1, + _In_reads_bytes_(length) char *buff2, + _In_ int length + ) +/*++ +Routine Description: + + Called to verify read and write buffers match for loopback test + +Arguments: + + buffers to compare and length + +Return Value: + + TRUE if buffers match, else FALSE + +--*/ +{ + int ok = 1; + + if (memcmp(buff1, buff2, length )) { + // Edi, and Esi point to the mismatching char and ecx indicates the + // remaining length. + ok = 0; + } + + return ok; +} + +#define NPERLN 8 + +void +dump( + UCHAR *b, + int len +) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of the io buffer + +Arguments: + + buffer and length + +Return Value: + + none + +--*/ +{ + ULONG i; + ULONG longLen = (ULONG)len / sizeof( ULONG ); + PULONG pBuf = (PULONG) b; + + // dump an ordinal ULONG for each sizeof(ULONG)'th byte + printf("\n****** BEGIN DUMP LEN decimal %d, 0x%x\n", len,len); + for (i=0; i<longLen; i++) { + printf("%04X ", *pBuf++); + if (i % NPERLN == (NPERLN - 1)) { + printf("\n"); + } + } + if (i % NPERLN != 0) { + printf("\n"); + } + printf("\n****** END DUMP LEN decimal %d, 0x%x\n", len,len); +} + + +// Begin, routines for USB configuration dump (Cmdline "rwbulk -u" ) + + +char +*usbDescriptorTypeString(UCHAR bDescriptorType ) +/*++ +Routine Description: + + Called to get ascii string of USB descriptor + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bDescriptorType or + PUSB_DEVICE_DESCRIPTOR->bDescriptorType or + PUSB_INTERFACE_DESCRIPTOR->bDescriptorType or + PUSB_STRING_DESCRIPTOR->bDescriptorType or + PUSB_POWER_DESCRIPTOR->bDescriptorType or + PUSB_CONFIGURATION_DESCRIPTOR->bDescriptorType + +Return Value: + + ptr to string + +--*/{ + + switch(bDescriptorType) { + + case USB_DEVICE_DESCRIPTOR_TYPE: + return "USB_DEVICE_DESCRIPTOR_TYPE"; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + return "USB_CONFIGURATION_DESCRIPTOR_TYPE"; + + + case USB_STRING_DESCRIPTOR_TYPE: + return "USB_STRING_DESCRIPTOR_TYPE"; + + + case USB_INTERFACE_DESCRIPTOR_TYPE: + return "USB_INTERFACE_DESCRIPTOR_TYPE"; + + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + return "USB_ENDPOINT_DESCRIPTOR_TYPE"; + + case USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE: + return "USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE"; + + +#ifdef USB_POWER_DESCRIPTOR_TYPE // this is the older definintion which is actually obsolete + // workaround for temporary bug in 98ddk, older USB100.h file + case USB_POWER_DESCRIPTOR_TYPE: + return "USB_POWER_DESCRIPTOR_TYPE"; +#endif + +#ifdef USB_RESERVED_DESCRIPTOR_TYPE // this is the current version of USB100.h as in NT5DDK + + case USB_RESERVED_DESCRIPTOR_TYPE: + return "USB_RESERVED_DESCRIPTOR_TYPE"; + + case USB_CONFIG_POWER_DESCRIPTOR_TYPE: + return "USB_CONFIG_POWER_DESCRIPTOR_TYPE"; + + case USB_INTERFACE_POWER_DESCRIPTOR_TYPE: + return "USB_INTERFACE_POWER_DESCRIPTOR_TYPE"; +#endif // for current nt5ddk version of USB100.h + + default: + return "??? UNKNOWN!!"; + } +} + + +char +*usbEndPointTypeString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of endpt descriptor type + +Arguments: + + PUSB_ENDPOINT_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_ENDPOINT_TYPE_MASK; + + + switch( typ) { + case USB_ENDPOINT_TYPE_INTERRUPT: + return "USB_ENDPOINT_TYPE_INTERRUPT"; + + case USB_ENDPOINT_TYPE_BULK: + return "USB_ENDPOINT_TYPE_BULK"; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + return "USB_ENDPOINT_TYPE_ISOCHRONOUS"; + + case USB_ENDPOINT_TYPE_CONTROL: + return "USB_ENDPOINT_TYPE_CONTROL"; + + default: + return "??? UNKNOWN!!"; + } +} + + +char +*usbConfigAttributesString(UCHAR bmAttributes) +/*++ +Routine Description: + + Called to get ascii string of USB_CONFIGURATION_DESCRIPTOR attributes + +Arguments: + + PUSB_CONFIGURATION_DESCRIPTOR->bmAttributes + +Return Value: + + ptr to string + +--*/ +{ + UINT typ = bmAttributes & USB_CONFIG_POWERED_MASK; + + + switch( typ) { + + case USB_CONFIG_BUS_POWERED: + return "USB_CONFIG_BUS_POWERED"; + + case USB_CONFIG_SELF_POWERED: + return "USB_CONFIG_SELF_POWERED"; + + case USB_CONFIG_REMOTE_WAKEUP: + return "USB_CONFIG_REMOTE_WAKEUP"; + + + default: + return "??? UNKNOWN!!"; + } +} + + +void +print_USB_CONFIGURATION_DESCRIPTOR(PUSB_CONFIGURATION_DESCRIPTOR cd) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB config descriptor + +Arguments: + + ptr to USB configuration descriptor + +Return Value: + + none + +--*/ +{ + printf("\n===================\nUSB_CONFIGURATION_DESCRIPTOR\n"); + + printf( + "bLength = 0x%x, decimal %u\n", cd->bLength, cd->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", cd->bDescriptorType, usbDescriptorTypeString( cd->bDescriptorType ) + ); + + printf( + "wTotalLength = 0x%x, decimal %u\n", cd->wTotalLength, cd->wTotalLength + ); + + printf( + "bNumInterfaces = 0x%x, decimal %u\n", cd->bNumInterfaces, cd->bNumInterfaces + ); + + printf( + "bConfigurationValue = 0x%x, decimal %u\n", cd->bConfigurationValue, cd->bConfigurationValue + ); + + printf( + "iConfiguration = 0x%x, decimal %u\n", cd->iConfiguration, cd->iConfiguration + ); + + printf( + "bmAttributes = 0x%x ( %s )\n", cd->bmAttributes, usbConfigAttributesString( cd->bmAttributes ) + ); + + printf( + "MaxPower = 0x%x, decimal %u\n", cd->MaxPower, cd->MaxPower + ); +} + + +void +print_USB_INTERFACE_DESCRIPTOR(PUSB_INTERFACE_DESCRIPTOR id, UINT ix) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB interface descriptor + +Arguments: + + ptr to USB interface descriptor + +Return Value: + + none + +--*/ +{ + printf("\n-----------------------------\nUSB_INTERFACE_DESCRIPTOR #%u\n", ix); + + + printf( + "bLength = 0x%x\n", id->bLength + ); + + + printf( + "bDescriptorType = 0x%x ( %s )\n", id->bDescriptorType, usbDescriptorTypeString( id->bDescriptorType ) + ); + + + printf( + "bInterfaceNumber = 0x%x\n", id->bInterfaceNumber + ); + printf( + "bAlternateSetting = 0x%x\n", id->bAlternateSetting + ); + printf( + "bNumEndpoints = 0x%x\n", id->bNumEndpoints + ); + printf( + "bInterfaceClass = 0x%x\n", id->bInterfaceClass + ); + printf( + "bInterfaceSubClass = 0x%x\n", id->bInterfaceSubClass + ); + printf( + "bInterfaceProtocol = 0x%x\n", id->bInterfaceProtocol + ); + printf( + "bInterface = 0x%x\n", id->iInterface + ); +} + + +void +print_USB_ENDPOINT_DESCRIPTOR(PUSB_ENDPOINT_DESCRIPTOR ed, int i) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB endpoint descriptor + +Arguments: + + ptr to USB endpoint descriptor, + index of this endpt in interface desc + +Return Value: + + none + +--*/ +{ + printf( + "------------------------------\nUSB_ENDPOINT_DESCRIPTOR for Pipe%02d\n", i + ); + + printf( + "bLength = 0x%x\n", ed->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", ed->bDescriptorType, usbDescriptorTypeString( ed->bDescriptorType ) + ); + + if ( USB_ENDPOINT_DIRECTION_IN( ed->bEndpointAddress ) ) { + printf( + "bEndpointAddress= 0x%x ( INPUT )\n", ed->bEndpointAddress + ); + } else { + printf( + "bEndpointAddress= 0x%x ( OUTPUT )\n", ed->bEndpointAddress + ); + } + + printf( + "bmAttributes= 0x%x ( %s )\n", ed->bmAttributes, usbEndPointTypeString ( ed->bmAttributes ) + ); + + printf( + "wMaxPacketSize= 0x%x, decimal %u\n", ed->wMaxPacketSize, ed->wMaxPacketSize + ); + + printf( + "bInterval = 0x%x, decimal %u\n", ed->bInterval, ed->bInterval + ); +} + + +void +print_USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR(PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR secd, int i) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of a USB super speed endpoint companion descriptor + +Arguments: + + secd - ptr to USB endpoint descriptor, + i - index of this endpt in interface desc + +Return Value: + + none + +--*/ +{ + printf( + "------------------------------\nUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR for Pipe%02d\n", i + ); + + printf( + "bLength = 0x%x\n", secd->bLength + ); + + printf( + "bDescriptorType = 0x%x ( %s )\n", secd->bDescriptorType, usbDescriptorTypeString( secd->bDescriptorType ) + ); + + printf( + "bMaxBurst = 0x%x, decimal %u\n", secd->bMaxBurst, secd->bMaxBurst + ); + + printf( + "bmAttributes = 0x%x \n", secd->bmAttributes.AsUchar + ); + + printf( + "wBytesPerInterval = 0x%x, decimal %u\n", secd->wBytesPerInterval, secd->wBytesPerInterval + ); + +} + + +void +rw_dev( HANDLE hDEV ) +/*++ +Routine Description: + + Called to do formatted ascii dump to console of USB + configuration, interface, and endpoint descriptors + (Cmdline "rwbulk -u" ) + +Arguments: + + handle to device + +Return Value: + + none + +--*/ +{ + UINT success; + int siz, nBytes; + UCHAR buf[256] = {0}; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUSB_CONFIGURATION_DESCRIPTOR cd; + BOOL displayUnknown; + + siz = sizeof(buf); + + if (hDEV == INVALID_HANDLE_VALUE) { + NOISY(("DEV not open")); + return; + } + + success = DeviceIoControl(hDEV, + IOCTL_USBSAMP_GET_CONFIG_DESCRIPTOR, + buf, + siz, + buf, + siz, + (PULONG) &nBytes, + NULL); + + NOISY(("request complete, success = %u nBytes = %d\n", success, nBytes)); + + if (success) { + + UINT j = 0, k = 0, n; + PUCHAR pch; + PUCHAR descEnd; + + pch = buf; + n = 0; + + cd = (PUSB_CONFIGURATION_DESCRIPTOR) pch; + + descEnd = (PUCHAR)cd + cd->wTotalLength; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)cd; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + displayUnknown = FALSE; + + switch (commonDesc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + NOISY(("Configuration Descriptor's bLength filed does not match its size\n")); + displayUnknown = TRUE; + break; + } + n = 0; + print_USB_CONFIGURATION_DESCRIPTOR((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc); + break; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) + { + NOISY(("Interface Descriptor's bLength filed does not match its size\n")); + displayUnknown = TRUE; + break; + } + j = 0; + k = 0; + print_USB_INTERFACE_DESCRIPTOR((PUSB_INTERFACE_DESCRIPTOR)commonDesc, n++); + break; + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) + { + NOISY(("Endpoint Descriptor's bLength filed does not match its size\n")); + displayUnknown = TRUE; + break; + } + print_USB_ENDPOINT_DESCRIPTOR((PUSB_ENDPOINT_DESCRIPTOR)commonDesc, j++); + break; + + case USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR)) + { + NOISY(("SuperSpeed Endpoint Companion Descriptor's bLength field does not match its size\n")); + displayUnknown = TRUE; + break; + } + print_USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR((PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR)commonDesc, k++); + break; + + default: + displayUnknown = TRUE; + break; + } + + if (displayUnknown) + { + NOISY(("Test application finds a unknown descriptor.\n")); + } + + commonDesc = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)commonDesc + commonDesc->bLength); + + } + + } + + return; +} + + +int dumpUsbConfig() +/*++ +Routine Description: + + Called to do formatted ascii dump to console of USB + configuration, interface, and endpoint descriptors + (Cmdline "rwbulk -u" ) + +Arguments: + + none + +Return Value: + + none + +--*/ +{ + HANDLE hDEV = open_dev(); + + if (hDEV != INVALID_HANDLE_VALUE) + { + rw_dev( hDEV ); + CloseHandle(hDEV); + } + + return 0; + +} +// End, routines for USB configuration and pipe info dump (Cmdline "rwbulk -u" ) + + + +int +_cdecl +main( + _In_ int argc, + _In_reads_(argc) char *argv[] + ) +/*++ +Routine Description: + + Entry point to rwbulk.exe + Parses cmdline, performs user-requested tests + +Arguments: + + argc, argv standard console 'c' app arguments + +Return Value: + + Zero + +--*/ + +{ + char * pinBuf = NULL; + char * poutBuf = NULL; + int nBytesRead; + int nBytesWrite; + ULONG i; + ULONG j; + int ok; + UINT success; + HANDLE hRead = INVALID_HANDLE_VALUE; + HANDLE hWrite = INVALID_HANDLE_VALUE; + ULONG fail = 0L; + + parse(argc, argv ); + + // dump USB configuation and pipe info + if( fDumpUsbConfig ) { + dumpUsbConfig(); + } + + // doing a read, write, or both test + if ((fRead) || (fWrite)) { + + if (fRead) { + // + // open the output file + // + if ( fDumpReadData ) { // round size to sizeof ULONG for readable dumping + + while( ReadLen % sizeof( ULONG ) ) { + ReadLen++; + } + } + + hRead = open_file( inPipe); + pinBuf = (char*) malloc(ReadLen); + + } + + if (fWrite) { + if ( fDumpReadData ) { // round size to sizeof ULONG for readable dumping + while( WriteLen % sizeof( ULONG ) ) { + WriteLen++; + } + } + + hWrite = open_file( outPipe); + poutBuf = (char*)malloc(WriteLen); + } + + for (i=0; i<IterationCount; i++) { + + if (fWrite && poutBuf && hWrite != INVALID_HANDLE_VALUE) { + + PULONG pOut = (PULONG) poutBuf; + ULONG numLongs = WriteLen / sizeof( ULONG ); + + // + // put some data in the output buffer + // + for (j=0; j<numLongs; j++) { + *(pOut+j) = j; + } + + // + // send the write + // + WriteFile(hWrite, poutBuf, WriteLen, (PULONG) &nBytesWrite, NULL); + + printf("<%s> W (%04.4u) : request %06.6d bytes -- %06.6d bytes written\n", + outPipe, i, WriteLen, nBytesWrite); + + //assert(nBytesWrite == WriteLen); + } + + if (fRead && pinBuf) { + + success = ReadFile(hRead, pinBuf, ReadLen, (PULONG) &nBytesRead, NULL); + + if (success) { + printf("<%s> R (%04.4u) : request %06.6d bytes -- %06.6d bytes read\n", + inPipe, i, ReadLen, nBytesRead); + + if (fWrite && fCompareData) { + + // + // validate the input buffer against what + // we sent to the device (loopback test) + // +#pragma warning(suppress: 26053) + ok = compare_buffs(pinBuf, poutBuf, nBytesRead); + + if( fDumpReadData ) { + printf("Dumping read buffer\n"); + dump( (PUCHAR) pinBuf, nBytesRead ); + printf("Dumping write buffer\n"); + dump( (PUCHAR) poutBuf, nBytesRead ); + } + assert(ok); + + if(ok != 1) { + fail++; + } + + assert(ReadLen == WriteLen); + assert(nBytesRead == ReadLen); + } + } + } + } + + if (pinBuf) { + free(pinBuf); + } + + if (poutBuf) { + free(poutBuf); + } + + // close devices if needed + if(hRead != INVALID_HANDLE_VALUE) + CloseHandle(hRead); + + if(hWrite != INVALID_HANDLE_VALUE) + CloseHandle(hWrite); + } + + return 0; +} diff --git a/usb/usbsamp/exe/testapp.rc b/usb/usbsamp/exe/testapp.rc new file mode 100644 index 00000000..3fa81211 --- /dev/null +++ b/usb/usbsamp/exe/testapp.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "UsbSamp Bulk & Isoch Read and Write test App" +#define VER_INTERNALNAME_STR "usbsamp.exe" +#define VER_ORIGINALFILENAME_STR "usbsamp.exe" + +#include <common.ver> + diff --git a/usb/usbsamp/exe/usbsamp.vcxproj b/usb/usbsamp/exe/usbsamp.vcxproj new file mode 100644 index 00000000..5c27d51c --- /dev/null +++ b/usb/usbsamp/exe/usbsamp.vcxproj @@ -0,0 +1,179 @@ +<?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>{82B15C8E-818A-41C0-AE62-1AEA7270E8B6}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{D84698F9-5D22-4B3F-ADC9-A65171DA8464}</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>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="testapp.c" /> + <ResourceCompile Include="testapp.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </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/usb/usbsamp/exe/usbsamp.vcxproj.Filters b/usb/usbsamp/exe/usbsamp.vcxproj.Filters new file mode 100644 index 00000000..d838bfe3 --- /dev/null +++ b/usb/usbsamp/exe/usbsamp.vcxproj.Filters @@ -0,0 +1,27 @@ +<?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>{EE38233A-C328-44AC-A845-0B8F28FBE8F3}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F6CE757F-951D-4785-A12E-D52DE74A7231}</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>{9044173D-AE9F-4798-9138-C397123B741F}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <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/usb/usbsamp/sys/bulkrwr.c b/usb/usbsamp/sys/bulkrwr.c new file mode 100644 index 00000000..475c89ed --- /dev/null +++ b/usb/usbsamp/sys/bulkrwr.c @@ -0,0 +1,907 @@ +/*++ + +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: + + bulkrwr.c + +Abstract: + + This file has routines to perform reads and writes. + The read and writes are for bulk transfers. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" + +#if !defined(BUFFERED_READ_WRITE) // if doing DIRECT_IO + +VOID +ReadWriteBulkEndPoints( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG Length, + _In_ WDF_REQUEST_TYPE RequestType + ) +/*++ + +Routine Description: + + This callback is invoked when the framework received WdfRequestTypeRead or + WdfRequestTypeWrite request. This read/write is performed in stages of + maximum transfer size. Once a stage of transfer is complete, then the + request is circulated again, until the requested length of transfer is + performed. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + + Request - Handle to a framework request object. This one represents + the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. + + Length - Length of the input/output buffer. + +Return Value: + + VOID + +--*/ +{ + PMDL newMdl=NULL, requestMdl = NULL; + PURB urb = NULL; + WDFMEMORY urbMemory; + ULONG totalLength = Length; + ULONG stageLength = 0; + ULONG urbFlags = 0; + NTSTATUS status; + ULONG_PTR virtualAddress = 0; + PREQUEST_CONTEXT rwContext = NULL; + PFILE_CONTEXT fileContext = NULL; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + WDF_OBJECT_ATTRIBUTES objectAttribs; + USBD_PIPE_HANDLE usbdPipeHandle; + PDEVICE_CONTEXT deviceContext; + ULONG maxTransferSize; + PPIPE_CONTEXT pipeContext; + + UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); + + // + // First validate input parameters. + // + deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + if (totalLength > deviceContext->MaximumTransferSize) { + UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + if ((RequestType != WdfRequestTypeRead) && + (RequestType != WdfRequestTypeWrite)) { + UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + pipeContext = GetPipeContext(pipe); + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); + + if ((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && + (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { + UsbSamp_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + goto Exit; + + } + + rwContext = GetRequestContext(Request); + + if (RequestType == WdfRequestTypeRead) { + + status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); + goto Exit; + } + + urbFlags |= USBD_TRANSFER_DIRECTION_IN; + rwContext->Read = TRUE; + UsbSamp_DbgPrint(3, ("Read operation\n")); + + } + else { + status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status)); + goto Exit; + } + + urbFlags |= USBD_TRANSFER_DIRECTION_OUT; + rwContext->Read = FALSE; + UsbSamp_DbgPrint(3, ("Write operation\n")); + } + + urbFlags |= USBD_SHORT_TRANSFER_OK; + virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); + + // + // The transfer request is for totalLength. + // We can perform a max of maxTransfersize in each stage. + // + maxTransferSize = GetMaxTransferSize(pipe, deviceContext); + + if (totalLength > maxTransferSize) { + stageLength = maxTransferSize; + } + else { + stageLength = totalLength; + } + + newMdl = IoAllocateMdl((PVOID) virtualAddress, + totalLength, + FALSE, + FALSE, + NULL); + + if (newMdl == NULL) { + UsbSamp_DbgPrint(1, ("Failed to alloc mem for mdl\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + // + // map the portion of user-buffer described by an mdl to another mdl + // + IoBuildPartialMdl(requestMdl, + newMdl, + (PVOID) virtualAddress, + stageLength); + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); + objectAttribs.ParentObject = Request; + + status = WdfUsbTargetDeviceCreateUrb(deviceContext->WdfUsbTargetDevice, + &objectAttribs, + &urbMemory, + &urb); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateUrb failed %x\n", status)); + goto Exit; + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + pipeContext->StreamConfigured == TRUE) { + // + // For super speed bulk pipe with streams, we specify one of its associated + // usbd pipe handles to format an URB for sending or receiving data. + // The usbd pipe handle is returned by the HCD via sucessful open-streams request + // + usbdPipeHandle = GetStreamPipeHandleFromBulkPipe(pipe); + } + else { + usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); + } +#else + usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); +#endif + + UsbBuildInterruptOrBulkTransferRequest(urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + usbdPipeHandle, + NULL, + newMdl, + stageLength, + urbFlags, + NULL); + + status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL ); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); + + // + // set REQUEST_CONTEXT parameters. + // + rwContext->UrbMemory = urbMemory; + rwContext->Mdl = newMdl; + rwContext->Length = totalLength - stageLength; + rwContext->Numxfer = 0; + rwContext->VirtualAddress = virtualAddress + stageLength; + + if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { + status = WdfRequestGetStatus(Request); + NT_ASSERT(!NT_SUCCESS(status)); + } + +Exit: + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, 0); + + if (newMdl != NULL) { + IoFreeMdl(newMdl); + } + } + + UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); + + return; +} + + +VOID +UsbSamp_EvtReadWriteCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads/writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + PMDL requestMdl; + WDFUSBPIPE pipe; + ULONG stageLength; + NTSTATUS status; + PREQUEST_CONTEXT rwContext; + PURB urb; + PCHAR operation; + ULONG bytesReadWritten; + ULONG maxTransferSize; + PDEVICE_CONTEXT deviceContext; + + rwContext = GetRequestContext(Request); + deviceContext = Context; + + if (rwContext->Read) { + operation = "Read"; + } + else { + operation = "Write"; + } + + pipe = (WDFUSBPIPE) Target ; + status = CompletionParams->IoStatus.Status; + + if (!NT_SUCCESS(status)){ + // + // Queue a workitem to reset the pipe because the completion could be + // running at DISPATCH_LEVEL. + // + QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); + goto End; + } + + urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); + bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; + rwContext->Numxfer += bytesReadWritten; + + // + // If there is anything left to transfer. + // + if (rwContext->Length == 0) { + // + // this is the last transfer + // + WdfRequestSetInformation(Request, rwContext->Numxfer); + goto End; + } + + // + // Start another transfer + // + UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation)); + + // + // The transfer request is for totalLength. + // We can perform a max of maxTransfersize in each stage. + // + maxTransferSize = GetMaxTransferSize(pipe, deviceContext); + + if (rwContext->Length > maxTransferSize) { + stageLength = maxTransferSize; + } + else { + stageLength = rwContext->Length; + } + + // + // Following call is required to free any mapping made on the partial MDL + // and reset internal MDL state. + // + MmPrepareMdlForReuse(rwContext->Mdl); + + if (rwContext->Read) { + status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed %x\n", status)); + goto End; + } + } + else { + status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed %x\n", status)); + goto End; + } + } + + IoBuildPartialMdl(requestMdl, + rwContext->Mdl, + (PVOID) rwContext->VirtualAddress, + stageLength); + + // + // reinitialize the urb + // + urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; + + rwContext->VirtualAddress += stageLength; + rwContext->Length -= stageLength; + + // + // Format the request to send a URB to a USB pipe. + // + status = WdfUsbTargetPipeFormatRequestForUrb(pipe, + Request, + rwContext->UrbMemory, + NULL); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); + status = STATUS_INSUFFICIENT_RESOURCES; + goto End; + } + + WdfRequestSetCompletionRoutine(Request, UsbSamp_EvtReadWriteCompletion, deviceContext); + + // + // Send the request asynchronously. + // + if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { + UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); + status = WdfRequestGetStatus(Request); + goto End; + } + + // + // Else when the request completes, this completion routine will be + // called again. + // + return; + +End: + // + // We are here because the request failed or some other call failed. + // Dump the request context, complete the request and return. + // + DbgPrintRWContext(rwContext); + + IoFreeMdl(rwContext->Mdl); + + UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n", + operation, status)); + + WdfRequestComplete(Request, status); + + return; +} + +#else + +VOID +ReadWriteBulkEndPoints( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG Length, + _In_ WDF_REQUEST_TYPE RequestType + ) +/*++ + +Routine Description: + + This callback is invoked when the framework received WdfRequestTypeRead or + RP_MJ_WRITE request. This read/write is performed in stages of + maximum transfer size. Once a stage of transfer is complete, then the + request is circulated again, until the requested length of transfer is + performed. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + + Request - Handle to a framework request object. This one represents + the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. + + Length - Length of the input/output buffer. + +Return Value: + + VOID + +--*/ +{ + size_t totalLength = Length; + size_t stageLength = 0; + NTSTATUS status; + PVOID virtualAddress = 0; + PREQUEST_CONTEXT rwContext = NULL; + PFILE_CONTEXT fileContext = NULL; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + WDFMEMORY reqMemory; + WDFMEMORY_OFFSET offset; + WDF_OBJECT_ATTRIBUTES objectAttribs; + PDEVICE_CONTEXT deviceContext; + PPIPE_CONTEXT pipeContext; + + ULONG maxTransferSize; + + UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - begins\n")); + + // + // First validate input parameters. + // + deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + + if (totalLength > deviceContext->MaximumTransferSize) { + UsbSamp_DbgPrint(1, ("Transfer length > circular buffer\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + if ((RequestType != WdfRequestTypeRead) && + (RequestType != WdfRequestTypeWrite)) { + UsbSamp_DbgPrint(1, ("RequestType has to be either Read or Write\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + pipeContext = GetPipeContext(pipe); + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); + + rwContext = GetRequestContext(Request); + + if (RequestType == WdfRequestTypeRead) { + status = WdfRequestRetrieveOutputBuffer(Request, Length, &virtualAddress, &totalLength); + rwContext->Read = TRUE; + + } + else { //Write + + status = WdfRequestRetrieveInputBuffer(Request, Length, &virtualAddress, &totalLength); + rwContext->Read = FALSE; + } + + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); + goto Exit; + } + + // + // The transfer request is for totalLength. + // We can perform a max of maxTransfersize in each stage. + // + maxTransferSize = GetMaxTransferSize(pipe, deviceContext); + + if (totalLength > maxTransferSize) { + stageLength = maxTransferSize; + } + else { + stageLength = totalLength; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); + objectAttribs.ParentObject = Request; + status = WdfMemoryCreatePreallocated(&objectAttribs, + virtualAddress, + totalLength, + &reqMemory); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfMemoryCreatePreallocated failed\n")); + goto Exit; + } + + offset.BufferOffset = 0; + offset.BufferLength = stageLength; + + // + // The framework format call validates to make sure that you are reading or + // writing to the right pipe type, sets the appropriate transfer flags, + // creates an URB and initializes the request. + // + if (RequestType == WdfRequestTypeRead) { + + UsbSamp_DbgPrint(3, ("Read operation\n")); + status = WdfUsbTargetPipeFormatRequestForRead(pipe, + Request, + reqMemory, + &offset); + } + else { + + UsbSamp_DbgPrint(3, ("Write operation\n")); + status = WdfUsbTargetPipeFormatRequestForWrite(pipe, + Request, + reqMemory, + &offset); + } + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormatRequest failed 0x%x\n", status)); + goto Exit; + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + // + // If the request is for a super speed bulk pipe with streams, + // configure its urb's PipeHandle with its associated stream's PipeHandle + // + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + pipeContext->StreamConfigured == TRUE) { + ConfigureStreamPipeHandleForRequest(Request, pipe); + } +#endif + + WdfRequestSetCompletionRoutine( + Request, + UsbSamp_EvtReadWriteCompletion, + deviceContext); + // + // set REQUEST_CONTEXT parameters. + // + rwContext->Length = (ULONG)totalLength - (ULONG)stageLength; + rwContext->Numxfer = 0; + + // + // Send the request asynchronously. + // + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + UsbSamp_DbgPrint(1, ("WdfRequestSend failed\n")); + status = WdfRequestGetStatus(Request); + goto Exit; + } + + +Exit: + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, 0); + } + + UsbSamp_DbgPrint(3, ("UsbSamp_DispatchReadWrite - ends\n")); + + return; +} + +// TODO: Use mouser sample trick to avoid stack recursion + +VOID +UsbSamp_EvtReadWriteCompletion( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This is the completion routine for reads/writes + If the irp completes with success, we check if we + need to recirculate this irp for another stage of + transfer. + +Arguments: + + Context - Driver supplied context + Device - Device handle + Request - Request handle + Params - request completion params + +Return Value: + None + +--*/ +{ + WDFUSBPIPE pipe; + ULONG stageLength = 0; + NTSTATUS status; + PREQUEST_CONTEXT rwContext; + ULONG bytesReadWritten; + WDFMEMORY_OFFSET offset; + PCHAR operation; + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + PPIPE_CONTEXT pipeContext; + WDF_USB_PIPE_INFORMATION pipeInfo; + ULONG maxTransferSize; + PDEVICE_CONTEXT deviceContext; + + usbCompletionParams = CompletionParams->Parameters.Usb.Completion; + rwContext = GetRequestContext(Request); + deviceContext = Context; + + if (rwContext->Read) { + operation = "Read"; + bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeRead.Length; + } + else { + operation = "Write"; + bytesReadWritten = (ULONG)usbCompletionParams->Parameters.PipeWrite.Length; + } + + pipe = (WDFUSBPIPE) Target; + pipeContext = GetPipeContext(pipe); + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe,&pipeInfo); + status = CompletionParams->IoStatus.Status; + + if (!NT_SUCCESS(status)){ + // + // Queue a workitem to reset the pipe because the completion could be + // running at DISPATCH_LEVEL. + // TODO: preallocate per pipe workitem to avoid allocation failure. + QueuePassiveLevelCallback(WdfIoTargetGetDevice(Target), pipe); + goto End; + } + + rwContext->Numxfer += bytesReadWritten; + + // + // If there is anything left to transfer. + // + if (rwContext->Length == 0) { + // + // this is the last transfer + // + WdfRequestSetInformation(Request, rwContext->Numxfer); + goto End; + } + + // + // Start another transfer + // + UsbSamp_DbgPrint(3, ("Stage next %s transfer...\n", operation)); + + // + // The transfer request is for totalLength. + // We can perform a max of maxTransfersize in each stage. + // + maxTransferSize = GetMaxTransferSize(pipe, deviceContext); + + if (rwContext->Length > maxTransferSize) { + stageLength = maxTransferSize; + } + else + { + stageLength = rwContext->Length; + } + + offset.BufferOffset = rwContext->Numxfer; + offset.BufferLength = stageLength; + + rwContext->Length -= stageLength; + + if (rwContext->Read) { + + status = WdfUsbTargetPipeFormatRequestForRead( + pipe, + Request, + usbCompletionParams->Parameters.PipeRead.Buffer, + &offset); + + } + else { + + status = WdfUsbTargetPipeFormatRequestForWrite( + pipe, + Request, + usbCompletionParams->Parameters.PipeWrite.Buffer, + &offset); + + } + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeFormat%sRequest failed 0x%x\n", + operation, status)); + goto End; + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + // + // If the request is for a super speed bulk pipe with streams, + // configure its urb's PipeHandle with its associated stream's PipeHandle + // + if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && + pipeContext->StreamConfigured == TRUE) { + ConfigureStreamPipeHandleForRequest(Request, pipe); + } +#endif + + WdfRequestSetCompletionRoutine( + Request, + UsbSamp_EvtReadWriteCompletion, + deviceContext); + + // + // Send the request asynchronously. + // + if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { + UsbSamp_DbgPrint(1, ("WdfRequestSend for %s failed\n", operation)); + status = WdfRequestGetStatus(Request); + goto End; + } + + // + // Else when the request completes, this completion routine will be + // called again. + // + return; + +End: + // + // We are here because the request failed or some other call failed. + // Dump the request context, complete the request and return. + // + DbgPrintRWContext(rwContext); + + UsbSamp_DbgPrint(3, ("%s request completed with status 0x%x\n", + operation, status)); + + WdfRequestComplete(Request, status); + + return; +} + +#endif + +VOID +UsbSamp_EvtReadWriteWorkItem( + _In_ WDFWORKITEM WorkItem + ) +{ + PWORKITEM_CONTEXT pItemContext; + NTSTATUS status; + + UsbSamp_DbgPrint(3, ("ReadWriteWorkItem called\n")); + + pItemContext = GetWorkItemContext(WorkItem); + + status = ResetPipe(pItemContext->Pipe); + if (!NT_SUCCESS(status)) { + + UsbSamp_DbgPrint(1, ("ResetPipe failed 0x%x\n", status)); + + status = ResetDevice(pItemContext->Device); + if (!NT_SUCCESS(status)){ + + UsbSamp_DbgPrint(1, ("ResetDevice failed 0x%x\n", status)); + } + } + + WdfObjectDelete(WorkItem); + + return; +} + +NTSTATUS +QueuePassiveLevelCallback( + _In_ WDFDEVICE Device, + _In_ WDFUSBPIPE Pipe + ) +/*++ + +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: + + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PWORKITEM_CONTEXT context; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_WORKITEM_CONFIG workitemConfig; + WDFWORKITEM hWorkItem; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes, WORKITEM_CONTEXT); + attributes.ParentObject = Device; + + WDF_WORKITEM_CONFIG_INIT(&workitemConfig, UsbSamp_EvtReadWriteWorkItem); + + status = WdfWorkItemCreate( &workitemConfig, + &attributes, + &hWorkItem); + + if (!NT_SUCCESS(status)) { + return status; + } + + context = GetWorkItemContext(hWorkItem); + + context->Device = Device; + context->Pipe = Pipe; + + // + // Execute this work item. + // + WdfWorkItemEnqueue(hWorkItem); + + return STATUS_SUCCESS; +} + +VOID +DbgPrintRWContext( + PREQUEST_CONTEXT rwContext + ) +{ + UNREFERENCED_PARAMETER(rwContext); + + UsbSamp_DbgPrint(3, ("rwContext->UrbMemory = %p\n", + rwContext->UrbMemory)); + UsbSamp_DbgPrint(3, ("rwContext->Mdl = %p\n", + rwContext->Mdl)); + UsbSamp_DbgPrint(3, ("rwContext->Length = %d\n", + rwContext->Length)); + UsbSamp_DbgPrint(3, ("rwContext->Numxfer = %d\n", + rwContext->Numxfer)); + UsbSamp_DbgPrint(3, ("rwContext->VirtualAddress = %p\n", + (PVOID)rwContext->VirtualAddress)); + return; +} + diff --git a/usb/usbsamp/sys/device.c b/usb/usbsamp/sys/device.c new file mode 100644 index 00000000..a710a476 --- /dev/null +++ b/usb/usbsamp/sys/device.c @@ -0,0 +1,1674 @@ +/*++ + + 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: + + Device.c + +Abstract: + + Bulk USB device driver for Intel 82930 USB test board + Plug and Play module. This file contains routines to handle pnp requests. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, UsbSamp_EvtDeviceAdd) +#pragma alloc_text(PAGE, UsbSamp_EvtDevicePrepareHardware) +#pragma alloc_text(PAGE, UsbSamp_EvtDeviceContextCleanup) +#pragma alloc_text(PAGE, ReadAndSelectDescriptors) +#pragma alloc_text(PAGE, ConfigureDevice) +#pragma alloc_text(PAGE, SelectInterfaces) +#pragma alloc_text(PAGE, SetPowerPolicy) +#pragma alloc_text(PAGE, AbortPipes) +#pragma alloc_text(PAGE, ReadFdoRegistryKeyValue) +#pragma alloc_text(PAGE, RetrieveDeviceInformation) +#pragma alloc_text(PAGE, UsbSamp_ValidateConfigurationDescriptor) +#if (NTDDI_VERSION >= NTDDI_WIN8) +#pragma alloc_text(PAGE, UsbSamp_EvtPipeContextCleanup) +#pragma alloc_text(PAGE, InitializePipeContextForSuperSpeedDevice) +#pragma alloc_text(PAGE, GetEndpointDescriptorForEndpointAddress) +#pragma alloc_text(PAGE, InitializePipeContextForSuperSpeedIsochPipe) +#endif +#pragma alloc_text(PAGE, InitializePipeContextForHighSpeedDevice) +#pragma alloc_text(PAGE, InitializePipeContextForFullSpeedDevice) +#endif + +NTSTATUS +UsbSamp_EvtDeviceAdd( + WDFDRIVER Driver, + PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_FILEOBJECT_CONFIG fileConfig; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + WDFDEVICE device; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + PDEVICE_CONTEXT pDevContext; + WDFQUEUE queue; + ULONG maximumTransferSize; + + UNREFERENCED_PARAMETER(Driver); + + UsbSamp_DbgPrint (3, ("UsbSamp_EvtDeviceAdd routine\n")); + + PAGED_CODE(); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + pnpPowerCallbacks.EvtDevicePrepareHardware = UsbSamp_EvtDevicePrepareHardware; + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Initialize the request attributes to specify the context size and type + // for every request created by framework for this device. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); + + WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes); + + // + // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the + // framework whether you are interested in handle Create, Close and + // Cleanup requests that gets genereate when an application or another + // kernel component opens an handle to the device. If you don't register + // the framework default behaviour would be complete these requests + // with STATUS_SUCCESS. A driver might be interested in registering these + // events if it wants to do security validation and also wants to maintain + // per handle (fileobject) context. + // + + WDF_FILEOBJECT_CONFIG_INIT( + &fileConfig, + UsbSamp_EvtDeviceFileCreate, + WDF_NO_EVENT_CALLBACK, + WDF_NO_EVENT_CALLBACK + ); + + // + // Specify a context for FileObject. If you register FILE_EVENT callbacks, + // the framework by default creates a framework FILEOBJECT corresponding + // to the WDM fileobject. If you want to track any per handle context, + // use the context for FileObject. Driver that typically use FsContext + // field should instead use Framework FileObject context. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FILE_CONTEXT); + + WdfDeviceInitSetFileObjectConfig(DeviceInit, + &fileConfig, + &attributes); + +#if !defined(BUFFERED_READ_WRITE) + // + // I/O type is Buffered by default. We want to do direct I/O for Reads + // and Writes so set it explicitly. Please note that this sample + // can do isoch transfer only if the io type is directio. + // + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); + +#endif + + // + // Now specify the size of device extension where we track per device + // context.DeviceInit is completely initialized. So call the framework + // to create the device and attach it to the lower stack. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + attributes.EvtCleanupCallback = UsbSamp_EvtDeviceContextCleanup; + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfDeviceCreate failed with Status code 0x%x\n", status)); + return status; + } + + // + // Get the DeviceObject context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. + // + + pDevContext = GetDeviceContext(device); + + // + //Get MaximumTransferSize from registry + // + maximumTransferSize = 0; + + ReadFdoRegistryKeyValue(Driver, + L"MaximumTransferSize", + &maximumTransferSize); + + if (maximumTransferSize){ + pDevContext->MaximumTransferSize = maximumTransferSize; + } + else { + pDevContext->MaximumTransferSize = DEFAULT_REGISTRY_TRANSFER_SIZE; + } + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode (on Win2K) when you surprise + // remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // Register I/O callbacks to tell the framework that you are interested + // in handling WdfRequestTypeRead, WdfRequestTypeWrite, and + // IRP_MJ_DEVICE_CONTROL requests. + // WdfIoQueueDispatchParallel means that we are capable of handling + // all the I/O request simultaneously and we are responsible for protecting + // data that could be accessed by these callbacks simultaneously. + // This queue will be, by default, automanaged by the framework with + // respect to PNP and Power events. That is, framework will take care + // of queuing, failing, dispatching incoming requests based on the current + // pnp/power state of the device. + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + ioQueueConfig.EvtIoRead = UsbSamp_EvtIoRead; + ioQueueConfig.EvtIoWrite = UsbSamp_EvtIoWrite; + ioQueueConfig.EvtIoDeviceControl = UsbSamp_EvtIoDeviceControl; + ioQueueConfig.EvtIoStop = UsbSamp_EvtIoStop; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue);// pointer to default queue + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfIoQueueCreate failed for Default Queue 0x%x\n", status)); + return status; + } + + // + // Create a synchronized manual queue so we can retrieve one read request at a + // time and dispatch it to the lower driver with the right StartFrame number. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, + WdfIoQueueDispatchManual); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.SynchronizationScope=WdfSynchronizationScopeQueue; + + ioQueueConfig.EvtIoStop = UsbSamp_EvtIoStop; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + &attributes, + &pDevContext->IsochReadQueue); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfIoQueueCreate failed for isoch 0x%x\n", status)); + return status; + } + + // + // Register a ready notification routine so we get notified whenever the queue transitions + // from empty to non-empty state. + // + status = WdfIoQueueReadyNotify(pDevContext->IsochReadQueue, + UsbSamp_EvtIoQueueReadyNotification, + (WDFCONTEXT)pDevContext); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfIoQueueReadyNotify failed for isoch 0x%x\n", status)); + return status; + } + + // + // Create a synchronized manual queue so we can retrieve one write request at a + // time and dispatch it to the lower driver with the right StartFrame number. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, + WdfIoQueueDispatchManual); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.SynchronizationScope=WdfSynchronizationScopeQueue; + + ioQueueConfig.EvtIoStop = UsbSamp_EvtIoStop; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + &attributes, + &pDevContext->IsochWriteQueue); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfIoQueueCreate failed for isoch 0x%x\n", status)); + return status; + } + + // + // Register a ready notification routine so we get notified whenever the queue transitions + // from empty to non-empty state. + // + status = WdfIoQueueReadyNotify(pDevContext->IsochWriteQueue, + UsbSamp_EvtIoQueueReadyNotification, + (WDFCONTEXT)pDevContext); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfIoQueueReadyNotify failed for isoch 0x%x\n", status)); + return status; + } + + // + // Register a device interface so that app can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface(device, + (LPGUID) &GUID_CLASS_USBSAMP_USB, + NULL);// Reference String + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); + return status; + } + + status = USBD_CreateHandle(WdfDeviceWdmGetDeviceObject(device), + WdfDeviceWdmGetAttachedDevice(device), + USBD_CLIENT_CONTRACT_VERSION_602, + POOL_TAG, + &pDevContext->UsbdHandle); + if(!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("USBD_CreateHandle failed 0x%x", status)); + return status; + } + + UsbSamp_DbgPrint(3, ("EvtDriverDeviceAdd - ends\n")); + + return status; +} + +NTSTATUS +UsbSamp_EvtDevicePrepareHardware( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourceList, + _In_ WDFCMRESLIST ResourceListTranslated + ) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. In the case of a USB device, this involves + reading and selecting descriptors. + + //TODO: + +Arguments: + + Device - handle to a device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + + UsbSamp_DbgPrint(3, ("EvtDevicePrepareHardware - begins\n")); + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + // + // Read the device descriptor, configuration descriptor + // and select the interface descriptors + // + status = ReadAndSelectDescriptors(Device); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("ReadandSelectDescriptors failed\n")); + return status; + } + + // + // Enable wait-wake and idle timeout if the device supports it + // + if (pDeviceContext->WaitWakeEnable){ + status = SetPowerPolicy(Device); + if (!NT_SUCCESS (status)) { + UsbSamp_DbgPrint(3, ("UsbSampSetPowerPolicy failed\n")); + return status; + } + } + + UsbSamp_DbgPrint(3, ("EvtDevicePrepareHardware - ends\n")); + + return status; +} + +NTSTATUS +SetPowerPolicy( + _In_ WDFDEVICE Device + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IDLE_CAPS_TYPE); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); + if ( !NT_SUCCESS(status)) { + UsbSamp_DbgPrint(3, ("WdfDeviceSetPowerPolicyS0IdlePolicy failed 0x%x\n", status)); + return status; + } + + // + // Init wait-wake policy structure. + // + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + + status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(3, ("WdfDeviceAssignSxWakeSettings failed 0x%x\n", status)); + return status; + } + + return status; +} + + +NTSTATUS +ReadAndSelectDescriptors( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine configures the USB device. + In this routines we get the device descriptor, + the configuration descriptor and select the + configuration. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NTSTATUS - NT status value. + +--*/ +{ + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + + PAGED_CODE(); + + // + // initialize variables + // + pDeviceContext = GetDeviceContext(Device); + + // + // Create a USB device handle so that we can communicate with the + // underlying USB stack. The WDFUSBDEVICE handle is used to query, + // configure, and manage all aspects of the USB device. + // These aspects include device properties, bus properties, + // and I/O creation and synchronization. We only create device the first + // the PrepareHardware is called. If the device is restarted by pnp manager + // for resource rebalance, we will use the same device handle but then select + // the interfaces again because the USB stack could reconfigure the device on + // restart. + // + if (pDeviceContext->WdfUsbTargetDevice == NULL) { + WDF_USB_DEVICE_CREATE_CONFIG config; + + WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, + USBD_CLIENT_CONTRACT_VERSION_602); + + status = WdfUsbTargetDeviceCreateWithParameters(Device, + &config, + WDF_NO_OBJECT_ATTRIBUTES, + &pDeviceContext->WdfUsbTargetDevice); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateWithParameters failed with Status code %x\n", status)); + return status; + } + } + + WdfUsbTargetDeviceGetDeviceDescriptor(pDeviceContext->WdfUsbTargetDevice, + &pDeviceContext->UsbDeviceDescriptor); + + NT_ASSERT(pDeviceContext->UsbDeviceDescriptor.bNumConfigurations); + + status = ConfigureDevice(Device); + + return status; +} + +NTSTATUS +ConfigureDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine reads the configuration descriptor + for the device in couple of steps. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NTSTATUS - NT status value + +--*/ +{ + USHORT size = 0; + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor; + WDF_OBJECT_ATTRIBUTES attributes; + WDFMEMORY memory; + PUCHAR Offset = NULL; + + PAGED_CODE(); + + // + // initialize the variables + // + configurationDescriptor = NULL; + pDeviceContext = GetDeviceContext(Device); + + // + // Read the first configuration descriptor + // This requires two steps: + // 1. Ask the WDFUSBDEVICE how big it is + // 2. Allocate it and get it from the WDFUSBDEVICE + // + status = WdfUsbTargetDeviceRetrieveConfigDescriptor(pDeviceContext->WdfUsbTargetDevice, + NULL, + &size); + + if (status != STATUS_BUFFER_TOO_SMALL || size == 0) { + return status; + } + + // + // Create a memory object and specify usbdevice as the parent so that + // it will be freed automatically. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + attributes.ParentObject = pDeviceContext->WdfUsbTargetDevice; + + status = WdfMemoryCreate(&attributes, + NonPagedPool, + POOL_TAG, + size, + &memory, + &configurationDescriptor); + if (!NT_SUCCESS(status)) { + return status; + } + + status = WdfUsbTargetDeviceRetrieveConfigDescriptor(pDeviceContext->WdfUsbTargetDevice, + configurationDescriptor, + &size); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Check if the descriptors are valid + // + status = UsbSamp_ValidateConfigurationDescriptor(configurationDescriptor, size , &Offset); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("Descriptor validation failed with Status code %x and at the offset %p\n", status , Offset )); + return status; + } + + pDeviceContext->UsbConfigurationDescriptor = configurationDescriptor; + + status = SelectInterfaces(Device); + + return status; +} + +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This helper routine selects the configuration, interface and + creates a context for every pipe (end point) in that interface. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; + NTSTATUS status; + PDEVICE_CONTEXT pDeviceContext; + UCHAR i; + WDF_OBJECT_ATTRIBUTES pipeAttributes; + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams; + UCHAR numberAlternateSettings = 0; + UCHAR numberConfiguredPipes; + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + // + // The device has only one interface and the interface may have multiple + // alternate settings. It will try to use alternate setting zero if it has + // non-zero endpoints, otherwise it will try to search an alternate + // setting with non-zero endpoints. + // + + WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pipeAttributes, PIPE_CONTEXT); + +#if (NTDDI_VERSION >= NTDDI_WIN8) + pipeAttributes.EvtCleanupCallback = UsbSamp_EvtPipeContextCleanup; +#endif + + status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->WdfUsbTargetDevice, + &pipeAttributes, + &configParams); + + + if (NT_SUCCESS(status) && + WdfUsbTargetDeviceGetNumInterfaces(pDeviceContext->WdfUsbTargetDevice) > 0) { + + status = RetrieveDeviceInformation(Device); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("RetrieveDeviceInformation failed %x\n", status)); + return status; + } + + pDeviceContext->UsbInterface = + configParams.Types.SingleInterface.ConfiguredUsbInterface; + + // + // This is written to work with Intel 82930 board, OSRUSBFX2, FX2 MUTT and FX3 MUTT + // devices. The alternate setting zero of MUTT devices don't have any endpoints. So + // in the code below, we will walk through the list of alternate settings until we + // find one that has non-zero endpoints. + // + + numberAlternateSettings = WdfUsbInterfaceGetNumSettings(pDeviceContext->UsbInterface); + + NT_ASSERT(numberAlternateSettings > 0); + + numberConfiguredPipes = 0; + + for (i = 0; i < numberAlternateSettings && numberConfiguredPipes == 0; i++) { + + WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams, i); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pipeAttributes, PIPE_CONTEXT); + +#if (NTDDI_VERSION >= NTDDI_WIN8) + pipeAttributes.EvtCleanupCallback = UsbSamp_EvtPipeContextCleanup; +#endif + + status = WdfUsbInterfaceSelectSetting(pDeviceContext->UsbInterface, + &pipeAttributes, + &selectSettingParams + ); + + if (NT_SUCCESS(status)) { + + numberConfiguredPipes = WdfUsbInterfaceGetNumConfiguredPipes(pDeviceContext->UsbInterface); + + if (numberConfiguredPipes > 0){ + + pDeviceContext->SelectedAlternateSetting = i; + + } + + } + + } + + pDeviceContext->NumberConfiguredPipes = numberConfiguredPipes; + + for (i = 0; i < pDeviceContext->NumberConfiguredPipes; i++) { + WDFUSBPIPE pipe; + + pipe = WdfUsbInterfaceGetConfiguredPipe(pDeviceContext->UsbInterface, + i, //PipeIndex, + NULL + ); +#if (NTDDI_VERSION >= NTDDI_WIN8) + if (pDeviceContext->IsDeviceSuperSpeed) { + status = InitializePipeContextForSuperSpeedDevice(pDeviceContext, + pipe); + } + else if (pDeviceContext->IsDeviceHighSpeed) { + status = InitializePipeContextForHighSpeedDevice(pipe); + } + else { + status = InitializePipeContextForFullSpeedDevice(pipe); + } +#else + if (pDeviceContext->IsDeviceHighSpeed) { + status = InitializePipeContextForHighSpeedDevice(pipe); + } + else { + status = InitializePipeContextForFullSpeedDevice(pipe); + } +#endif + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("InitializePipeContext failed %x\n", status)); + break; + } + } + + } + + return status; +} + + +NTSTATUS +AbortPipes( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description + + sends an abort pipe request on all open pipes. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + UCHAR i; + ULONG count; + NTSTATUS status; + PDEVICE_CONTEXT pDevContext; + + PAGED_CODE(); + + // + // initialize variables + // + pDevContext = GetDeviceContext(Device); + + UsbSamp_DbgPrint(3, ("AbortPipes - begins\n")); + + count = pDevContext->NumberConfiguredPipes; + + for (i = 0; i < count; i++) { + WDFUSBPIPE pipe; + pipe = WdfUsbInterfaceGetConfiguredPipe(pDevContext->UsbInterface, + i, //PipeIndex, + NULL + ); + + UsbSamp_DbgPrint(3, ("Aborting open pipe %d\n", i)); + + status = WdfUsbTargetPipeAbortSynchronously(pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL);//PWDF_REQUEST_SEND_OPTIONS + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetPipeAbortSynchronously failed %x\n", status)); + break; + } + } + + UsbSamp_DbgPrint(3, ("AbortPipes - ends\n")); + + return STATUS_SUCCESS; +} + + +#if (NTDDI_VERSION >= NTDDI_WIN8) +NTSTATUS +InitializePipeContextForSuperSpeedDevice( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description + + This function initialize pipe context for super speed isoch and + bulk endpoints. + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_PIPE_INFORMATION pipeInfo; + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(Pipe, &pipeInfo); + + // + // We only use pipe context for super speed isoch and bulk speed bulk endpoints. + // + if ((WdfUsbPipeTypeIsochronous == pipeInfo.PipeType)) { + + status = InitializePipeContextForSuperSpeedIsochPipe(DeviceContext, + WdfUsbInterfaceGetInterfaceNumber(DeviceContext->UsbInterface), + Pipe); + + } else if (WdfUsbPipeTypeBulk == pipeInfo.PipeType) { + + status = InitializePipeContextForSuperSpeedBulkPipe(DeviceContext, + WdfUsbInterfaceGetInterfaceNumber(DeviceContext->UsbInterface), + Pipe); + + } + + return status; + +} + + +PUSB_ENDPOINT_DESCRIPTOR +GetEndpointDescriptorForEndpointAddress( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ UCHAR EndpointAddress, + _Out_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR *ppEndpointCompanionDescriptor + ) +/*++ + +Routine Description: + + The helper routine gets the Endpoint Descriptor matched with EndpointAddress and return + its Endpoint Companion Descriptor if it has. + + UsbSamp_ValidateConfigurationDescriptor already validates that descriptors lie within + allocated buffer. + +Arguments: + + DeviceContext - pointer to the device context which includes configuration descriptor + + InterfaceNumber - InterfaceNumber of selected interface + + EndpointAddress - EndpointAddress of the Pipe + + ppEndpointCompanionDescriptor - pointer to the Endpoint Companioin Descroptor pointer + +Return Value: + + Pointer to Endpoint Descriptor + +--*/ +{ + + PUSB_COMMON_DESCRIPTOR pCommonDescriptorHeader = NULL; + PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor = NULL; + PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor = NULL; + PUSB_ENDPOINT_DESCRIPTOR pEndpointDescriptor = NULL; + PUCHAR startingPosition; + ULONG index; + BOOLEAN found = FALSE; + + PAGED_CODE(); + + pConfigurationDescriptor = DeviceContext->UsbConfigurationDescriptor; + + *ppEndpointCompanionDescriptor = NULL; + + // + // Parse the ConfigurationDescriptor (including all Interface and + // Endpoint Descriptors) and locate a Interface Descriptor which + // matches the InterfaceNumber, AlternateSetting, InterfaceClass, + // InterfaceSubClass, and InterfaceProtocol parameters. + // + pInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( + pConfigurationDescriptor, + pConfigurationDescriptor, + InterfaceNumber, + DeviceContext->SelectedAlternateSetting, + -1, // InterfaceClass, don't care + -1, // InterfaceSubClass, don't care + -1 // InterfaceProtocol, don't care + ); + + if (pInterfaceDescriptor == NULL ) { + + UsbSamp_DbgPrint(1, ("USBD_ParseConfigurationDescriptorEx failed to retrieve Interface Descriptor.\n")); + goto End; + + } + + startingPosition = (PUCHAR) pInterfaceDescriptor; + + for(index = 0; index < pInterfaceDescriptor->bNumEndpoints; index++) { + + pCommonDescriptorHeader = USBD_ParseDescriptors(pConfigurationDescriptor, + pConfigurationDescriptor->wTotalLength, + startingPosition, + USB_ENDPOINT_DESCRIPTOR_TYPE); + + if (pCommonDescriptorHeader == NULL) { + + UsbSamp_DbgPrint(1, ("USBD_ParseDescriptors failed to retrieve SuperSpeed Endpoint Descriptor unexpectedly\n")); + goto End; + + } + + // + // UsbSamp_ValidateConfigurationDescriptor validates all descriptors. + // This means that the descriptor pointed to by pCommonDescriptorHeader( received above ) is completely + // contained within the buffer representing ConfigurationDescriptor and + // it also verifies that pCommonDescriptorHeader->bLength is equal to sizeof(USB_ENDPOINT_DESCRIPTOR). + // + + pEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pCommonDescriptorHeader; + + // + // Search an Endpoint Descriptor that matches the EndpointAddress + // + if (pEndpointDescriptor->bEndpointAddress == EndpointAddress){ + + found = TRUE; + + break; + + } + + // + // Skip the current Endpoint Descriptor and search for the next. + // + startingPosition = (PUCHAR)pCommonDescriptorHeader + pCommonDescriptorHeader->bLength; + + } + + if (found) { + // + // Locate the SuperSpeed Endpoint Companion Descriptor associated with the endpoint descriptor + // + pCommonDescriptorHeader = USBD_ParseDescriptors(pConfigurationDescriptor, + pConfigurationDescriptor->wTotalLength, + pEndpointDescriptor, + USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE); + + if (pCommonDescriptorHeader != NULL) { + + // + // UsbSamp_ValidateConfigurationDescriptor validates all descriptors. + // This means that the descriptor pointed to by pCommonDescriptorHeader( received above ) is completely + // contained within the buffer representing ConfigurationDescriptor and + // it also verifies that pCommonDescriptorHeader->bLength is >= sizeof(USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR) + // + + *ppEndpointCompanionDescriptor = + (PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR) pCommonDescriptorHeader; + + } else { + + UsbSamp_DbgPrint(3, ("USBD_ParseDescriptors failed to retrieve SuperSpeed Endpoint Companion Descriptor unexpectedly\n")); + + } + + } + + +End: + return pEndpointDescriptor; +} + + +NTSTATUS +InitializePipeContextForSuperSpeedIsochPipe( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description + + This function validates all the isoch related fields in the endpoint descriptor + to make sure it's in comformance with the spec and Microsoft core stack + implementation and intializes the pipe context. + + The TransferSizePerMicroframe and TransferSizePerFrame values will be + used in the I/O path to do read and write transfers. + +Return Value: + + NT status value + +-*/ +{ + WDF_USB_PIPE_INFORMATION pipeInfo; + PPIPE_CONTEXT pipeContext; + UCHAR endpointAddress; + PUSB_ENDPOINT_DESCRIPTOR pEndpointDescriptor; + PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR pEndpointCompanionDescriptor; + USHORT wMaxPacketSize; + UCHAR bMaxBurst; + UCHAR bMult; + USHORT wBytesPerInterval; + + + PAGED_CODE(); + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(Pipe, &pipeInfo); + + // + // We use the pipe context only for isoch endpoints. + // + if ((WdfUsbPipeTypeIsochronous != pipeInfo.PipeType)) { + + return STATUS_SUCCESS; + + } + + pipeContext = GetPipeContext(Pipe); + + endpointAddress = pipeInfo.EndpointAddress; + + pEndpointDescriptor = GetEndpointDescriptorForEndpointAddress( + DeviceContext, + InterfaceNumber, + endpointAddress, + &pEndpointCompanionDescriptor); + + if (pEndpointDescriptor == NULL || pEndpointCompanionDescriptor == NULL ){ + + UsbSamp_DbgPrint(1, ("pEndpointDescriptor or pEndpointCompanionDescriptor is invalid (NULL)\n")); + return STATUS_INVALID_PARAMETER; + + } + + // + // For SuperSpeed isoch endpoint, it uses wBytesPerInterval from its + // endpoint companion descriptor. If bMaxBurst field in its endpoint + // companion descriptor is greater than zero, wMaxPacketSize must be + // 1024. If the value in the bMaxBurst field is set to zero then + // wMaxPacketSize can have any value from 0 to 1024. + // + wBytesPerInterval = pEndpointCompanionDescriptor->wBytesPerInterval; + wMaxPacketSize = pEndpointDescriptor->wMaxPacketSize; + bMaxBurst = pEndpointCompanionDescriptor->bMaxBurst; + bMult = pEndpointCompanionDescriptor->bmAttributes.Isochronous.Mult; + + if (wBytesPerInterval > (wMaxPacketSize * (bMaxBurst + 1) * (bMult + 1))){ + + UsbSamp_DbgPrint(1, ("SuperSpeed isochronouse endpoints's wBytesPerInterval value (%d) is greater than wMaxPacketSize * (bMaxBurst+1) * (Mult +1) (%d) \n", + wBytesPerInterval, (wMaxPacketSize * (bMaxBurst + 1) * (bMult + 1)))); + return STATUS_INVALID_PARAMETER; + + } + + if (bMaxBurst > 0){ + + if (wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE){ + + UsbSamp_DbgPrint(1, ("SuperSpeed isochronouse endpoints must have wMaxPacketSize value of %d bytes when bMaxpBurst is %d \n", + USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE, bMaxBurst)); + return STATUS_INVALID_PARAMETER; + + } + + } else { + + if (wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE){ + + UsbSamp_DbgPrint(1, ("SuperSpeed isochronouse endpoints must have wMaxPacketSize value no more than %d bytes when bMaxpBurst is %d \n", + USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE, bMaxBurst)); + return STATUS_INVALID_PARAMETER; + + } + + } + + + // + // This sample demos how to use wBytesPerInterval from its Endpoint + // Companion Descriptor. Actaully, for Superspeed isochronous endpoints, + // MaximumPacketSize in WDF_USB_PIPE_INFORMATION and USBD_PIPE_INFORMATION + // is returned with the value of wBytesPerInterval in the endpoint + // companion descriptor. This is different than the true MaxPacketSize of + // the endpoint descriptor. + // + NT_ASSERT(pipeInfo.MaximumPacketSize == wBytesPerInterval); + pipeContext->TransferSizePerMicroframe = wBytesPerInterval; + + // + // Microsoft USB 3.0 stack only supports bInterval value of 1, 2, 3 and 4 + // (or polling period of 1, 2, 4 and 8). + // For super-speed isochronous endpoints, the bInterval value is used as + // the exponent for a 2^(bInterval-1) value expressed in microframes; + // e.g., a bInterval of 4 means a period of 8 (2^(4-1)) microframes. + // + if (pipeInfo.Interval == 0 || pipeInfo.Interval > 4) { + + UsbSamp_DbgPrint(1, ("bInterval value in pipeInfo is invalid (0 or > 4)\n")); + return STATUS_INVALID_PARAMETER; + + } + + switch (pipeInfo.Interval) { + case 1: + // + // Transfer period is every microframe (8 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 8; + break; + + case 2: + // + // Transfer period is every 2 microframes (4 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 4; + break; + + case 3: + // + // Transfer period is every 4 microframes (2 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 2; + break; + + case 4: + // + // Transfer period is every 8 microframes (1 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe; + break; + } + + UsbSamp_DbgPrint(1, ("MaxPacketSize = %d, bInterval = %d\n", + pipeInfo.MaximumPacketSize, + pipeInfo.Interval)); + + UsbSamp_DbgPrint(1, ("TransferSizePerFrame = %d, TransferSizePerMicroframe = %d\n", + pipeContext->TransferSizePerFrame, + pipeContext->TransferSizePerMicroframe)); + + return STATUS_SUCCESS; +} + +#endif + +NTSTATUS +InitializePipeContextForHighSpeedDevice( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description + + This function validates all the isoch related fields in the endpoint descriptor + to make sure it's in comformance with the spec and Microsoft core stack + implementation and intializes the pipe context. + + The TransferSizePerMicroframe and TransferSizePerFrame values will be + used in the I/O path to do read and write transfers. + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_PIPE_INFORMATION pipeInfo; + PPIPE_CONTEXT pipeContext; + + PAGED_CODE(); + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(Pipe, &pipeInfo); + + // + // We use the pipe context only for isoch endpoints. + // + if ((WdfUsbPipeTypeIsochronous != pipeInfo.PipeType)) { + return STATUS_SUCCESS; + } + + pipeContext = GetPipeContext(Pipe); + + if (pipeInfo.MaximumPacketSize == 0) { + UsbSamp_DbgPrint(1, ("MaximumPacketSize in the pipeInfo is invalid (zero)\n")); + return STATUS_INVALID_PARAMETER; + } + + // + // Universal Serial Bus Specification Revision 2.0 5.6.3 Isochronous Transfer + // Packet Size Constraints: High-speed endpoints are allowed up to 1024-byte data + // payloads per microframe and allowed up to a maximum of 3 transactions per microframe. + // + // For highspeed isoch endpoints, bits 12-11 of wMaxPacketSize in the endpoint descriptor + // specify the number of additional transactions oppurtunities per microframe. + // 00 - None (1 transaction per microframe) + // 01 - 1 additional (2 per microframe) + // 10 - 2 additional (3 per microframe) + // 11 - Reserved. + // + // Note: MaximumPacketSize of WDF_USB_PIPE_INFORMATION is already adjusted to include + // additional transactions if it is a high bandwidth pipe. + // + + if (pipeInfo.MaximumPacketSize > 1024 * 3) { + UsbSamp_DbgPrint(1, ("MaximumPacketSize in the endpoint descriptor is invalid (>1024*3)\n")); + return STATUS_INVALID_PARAMETER; + } + + // + // Microsoft USB stack only supports bInterval value of 1, 2, 3 and 4 (or polling period of 1, 2, 4 and 8). + // + if (pipeInfo.Interval == 0 || pipeInfo.Interval > 4) { + UsbSamp_DbgPrint(1, ("bInterval value in pipeInfo is invalid (0 or > 4)\n")); + return STATUS_INVALID_PARAMETER; + } + + pipeContext->TransferSizePerMicroframe = pipeInfo.MaximumPacketSize; + + // + // For high-speed isochronous endpoints, the bInterval value is used + // as the exponent for a 2^(bInterval-1) value expressed in + // microframes; e.g., a bInterval of 4 means a period of 8 (2^(4-1)) + // microframes. The bInterval value must be from 1 to 16. NOTE: The + // USBPORT.SYS driver only supports high-speed isochronous bInterval + // values of {1, 2, 3, 4}. + // + switch (pipeInfo.Interval) { + case 1: + // + // Transfer period is every microframe (8 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 8; + break; + + case 2: + // + // Transfer period is every 2 microframes (4 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 4; + break; + + case 3: + // + // Transfer period is every 4 microframes (2 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe * 2; + break; + + case 4: + // + // Transfer period is every 8 microframes (1 times a frame). + // + pipeContext->TransferSizePerFrame = pipeContext->TransferSizePerMicroframe; + break; + } + + UsbSamp_DbgPrint(1, ("MaxPacketSize = %d, bInterval = %d\n", + pipeInfo.MaximumPacketSize, + pipeInfo.Interval)); + + UsbSamp_DbgPrint(1, ("TransferSizePerFrame = %d, TransferSizePerMicroframe = %d\n", + pipeContext->TransferSizePerFrame, + pipeContext->TransferSizePerMicroframe)); + + return STATUS_SUCCESS; +} + +NTSTATUS +InitializePipeContextForFullSpeedDevice( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description + + This function validates all the isoch related fields in the endpoint descriptor + to make sure it's in comformance with the spec and Microsoft core stack + implementation and intializes the pipe context. + + The TransferSizePerMicroframe and TransferSizePerFrame values will be + used in the I/O path to do read and write transfers. + +Return Value: + + NT status value + +--*/ +{ + WDF_USB_PIPE_INFORMATION pipeInfo; + PPIPE_CONTEXT pipeContext; + + PAGED_CODE(); + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(Pipe, &pipeInfo); + + // + // We use the pipe context only for isoch endpoints. + // + if ((WdfUsbPipeTypeIsochronous != pipeInfo.PipeType)) { + return STATUS_SUCCESS; + } + + pipeContext = GetPipeContext(Pipe); + + if (pipeInfo.MaximumPacketSize == 0) { + UsbSamp_DbgPrint(1, ("MaximumPacketSize in the endpoint descriptor is invalid\n")); + return STATUS_INVALID_PARAMETER; + } + + // + // Universal Serial Bus Specification Revision 2.0 + // 5.6.3 Isochronous Transfer Packet Size Constraints + // + // The USB limits the maximum data payload size to 1,023 bytes + // for each full-speed isochronous endpoint. + // + if (pipeInfo.MaximumPacketSize > 1023) { + UsbSamp_DbgPrint(1, ("MaximumPacketSize in the endpoint descriptor is invalid\n")); + return STATUS_INVALID_PARAMETER; + } + + // + // Microsoft USB stack only supports bInterval value of 1 for + // full-speed isochronous endpoints. + // + if (pipeInfo.Interval != 1) { + UsbSamp_DbgPrint(1, ("bInterval value in endpoint descriptor is invalid\n")); + return STATUS_INVALID_PARAMETER; + } + + pipeContext->TransferSizePerFrame = pipeInfo.MaximumPacketSize; + pipeContext->TransferSizePerMicroframe = 0; + + UsbSamp_DbgPrint(1, ("TransferSizePerFrame = %d\n", pipeContext->TransferSizePerFrame)); + + return STATUS_SUCCESS; +} + +NTSTATUS +RetrieveDeviceInformation( + _In_ WDFDEVICE Device + ) +{ + PDEVICE_CONTEXT pDeviceContext; + WDF_USB_DEVICE_INFORMATION info; + NTSTATUS status; + USHORT numberOfStreams = 0; + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + WDF_USB_DEVICE_INFORMATION_INIT(&info); + + // + // Retrieve USBD version information, port driver capabilites and device + // capabilites such as speed, power, etc. + // + status = WdfUsbTargetDeviceRetrieveInformation(pDeviceContext->WdfUsbTargetDevice, + &info); + if (!NT_SUCCESS(status)) { + return status; + } + + pDeviceContext->IsDeviceHighSpeed = + (info.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? TRUE : FALSE; + + UsbSamp_DbgPrint(3, ("DeviceIsHighSpeed: %s\n", + pDeviceContext->IsDeviceHighSpeed ? "TRUE" : "FALSE")); + + UsbSamp_DbgPrint(3, ("IsDeviceSelfPowered: %s\n", + (info.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE")); + + pDeviceContext->WaitWakeEnable = + info.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + + UsbSamp_DbgPrint(3, ("IsDeviceRemoteWakeable: %s\n", + (info.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE) ? "TRUE" : "FALSE")); + + status = GetStackCapability(Device, + &GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE, + 0, + NULL); + if (NT_SUCCESS(status)) { + pDeviceContext->IsDeviceSuperSpeed = TRUE; + } + + UsbSamp_DbgPrint(3, ("DeviceIsSuperSpeed: %s\n", + pDeviceContext->IsDeviceSuperSpeed ? "TRUE" : "FALSE")); + + if (pDeviceContext->IsDeviceSuperSpeed == TRUE) { + status = GetStackCapability(Device, + &GUID_USB_CAPABILITY_STATIC_STREAMS, + sizeof(numberOfStreams), + (PUCHAR)&numberOfStreams); + if (NT_SUCCESS(status)) { + pDeviceContext->IsStaticStreamsSupported = TRUE; + pDeviceContext->NumberOfStreamsSupportedByController = numberOfStreams; + } + + if (pDeviceContext->IsStaticStreamsSupported) { + UsbSamp_DbgPrint(3, ("Number of Streams supported by the controller: %d\n", numberOfStreams)); + } + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +ReadFdoRegistryKeyValue( + _In_ WDFDRIVER Driver, + _In_ LPWSTR Name, + _Out_ PULONG Value + ) +/*++ + +Routine Description: + + Can be used to read any REG_DWORD registry value stored + under Device Parameter. + +Arguments: + + Driver - pointer to the device object + Name - Name of the registry value + Value - + + +Return Value: + + NTSTATUS + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + UNICODE_STRING valueName; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + *Value = 0; + + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (NT_SUCCESS (status)) { + + RtlInitUnicodeString(&valueName,Name); + + status = WdfRegistryQueryULong (hKey, + &valueName, + Value); + + WdfRegistryClose(hKey); + } + + return status; +} + +VOID +UsbSamp_EvtDeviceContextCleanup( + IN WDFOBJECT WdfDevice + ) +/*++ + +Routine Description: + + In this callback, it cleans up device context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + NULL + +--*/ +{ + WDFDEVICE device; + PDEVICE_CONTEXT pDevContext; + + PAGED_CODE(); + + device = (WDFDEVICE)WdfDevice; + + pDevContext = GetDeviceContext(device); + + if (pDevContext->UsbdHandle != NULL) { + USBD_CloseHandle(pDevContext->UsbdHandle); + } + +} + +USBD_STATUS +UsbSamp_ValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ) +/*++ + +Routine Description: + + Validates a USB Configuration Descriptor + +Parameters: + + ConfigDesc: Pointer to the entire USB Configuration descriptor returned by + the device + + BufferLength: Known size of buffer pointed to by ConfigDesc (Not wTotalLength) + + Offset: if the USBD_STATUS returned is not USBD_STATUS_SUCCESS, offet will + be set to the address within the ConfigDesc buffer where the failure + occured. + +Return Value: + + USBD_STATUS + Success implies the configuration descriptor is valid. + +--*/ +{ + USBD_STATUS status = USBD_STATUS_SUCCESS; + PUCHAR offset, end; + PUCHAR index = NULL; + USHORT ValidationLevel = 3; + + PAGED_CODE(); + + // + // Call USBD_ValidateConfigurationDescriptor to validate the descriptors which are present in this supplied configuration descriptor. + // USBD_ValidateConfigurationDescriptor validates that all descriptors are completely contained within the configuration descriptor buffer. + // It also checks for interface numbers, number of endpoints in an interface etc. + // Please refer to msdn documentation for this function for more information. + // + + status = USBD_ValidateConfigurationDescriptor( ConfigDesc, BufferLength , ValidationLevel , Offset , POOL_TAG ); + if (!(NT_SUCCESS (status)) ){ + return status; + } + + // + // TODO: You should validate the correctness of other descriptors which are not taken care by USBD_ValidateConfigurationDescriptor + // The below code loops through the configuration descriptor and verifies that all instances of + // USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR have a size of >= USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR + // You should put in more validations as per requirement + // + + + offset = ((PUCHAR)ConfigDesc) + ConfigDesc->bLength; + end = ((PUCHAR)ConfigDesc) + ConfigDesc->wTotalLength; + + while(offset < end){ + PUSB_COMMON_DESCRIPTOR commonDesc; + // + // Ensure the descriptor header is in bounds. We always + // need to ensure we have enough data to look at the descriptor + // header fields. Sometimes descriptors are zeroed at the end, + // this is OK. + // + commonDesc = (PUSB_COMMON_DESCRIPTOR)offset; + + + switch(commonDesc->bDescriptorType){ + + case USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE: + + // + // basic validation. + // + if(commonDesc->bLength < sizeof(USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR)) { + status = USBD_STATUS_BAD_DESCRIPTOR; + index = (PUCHAR)commonDesc; + goto ValidateConfigurationDescriptor_Done; + } + break; + + // + // TODO: Add validation for any other descriptor your device will return. + // + default: + break; + } + offset += commonDesc->bLength; + + } + +ValidateConfigurationDescriptor_Done: + + if(!USBD_SUCCESS(status)){ + NT_ASSERT(index); + *Offset = index; + } + else{ + *Offset = NULL; + } + return status; +} + +#if (NTDDI_VERSION >= NTDDI_WIN8) +VOID +UsbSamp_EvtPipeContextCleanup( + IN WDFOBJECT WdfObject + ) +/*++ + +Routine Description: + + In this callback, it cleans up pipe context. + +Arguments: + + WdfObject - WDFUSBPIPE object + +Return Value: + + NULL + +--*/ +{ + WDFUSBPIPE pipe; + PPIPE_CONTEXT pPipeContext = NULL; + PUSBSAMP_STREAM_INFO pStreamInfo = NULL; + + PAGED_CODE(); + + pipe = (WDFUSBPIPE)WdfObject; + pPipeContext = GetPipeContext(pipe); + + pPipeContext->StreamConfigured = FALSE; + pStreamInfo = &pPipeContext->StreamInfo; + pStreamInfo->NumberOfStreams = 0; + if(pStreamInfo->StreamList != NULL){ + ExFreePool(pStreamInfo->StreamList); + pStreamInfo->StreamList = NULL; + } + +} +#endif diff --git a/usb/usbsamp/sys/driver.c b/usb/usbsamp/sys/driver.c new file mode 100644 index 00000000..26d61477 --- /dev/null +++ b/usb/usbsamp/sys/driver.c @@ -0,0 +1,108 @@ +/*++ + +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: + + Driver.c + +Abstract: + + Bulk USB device driver for Intel 82930 USB test board. + Main module. + +Environment: + + Kernel mode only + +--*/ + +#include "private.h" + +// +// Globals +// + +ULONG DebugLevel = 1; + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#endif + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + UsbSamp_DbgPrint(3, ("UsbSamp Driver Sample - Driver Framework Edition.\n")); + UsbSamp_DbgPrint(3, ("Built %s %s\n", __DATE__, __TIME__)); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + UsbSamp_EvtDeviceAdd + ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE // hDriver + ); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + return status; +} + + + diff --git a/usb/usbsamp/sys/driver/usbsamp.inx b/usb/usbsamp/sys/driver/usbsamp.inx new file mode 100644 index 00000000..88db6c19 --- /dev/null +++ b/usb/usbsamp/sys/driver/usbsamp.inx @@ -0,0 +1,115 @@ +;/*++ +; +;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: +; +; USBSamp.INF +; +;Abstract: +; Installation inf for the Intel 82930 USB Test Board, OSR USB-FX device, +; FX2 MUTT and FX3 MUTT device +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%ProviderName% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=KmdfSamples.cat + + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Device section ===================== + +[Manufacturer] +%MfgName%=IntelOSR,NT$ARCH$ + +[IntelOSR.NT$ARCH$] +%USB\VID_0547&PID_1002.DeviceDesc%=usbsamp.Dev, USB\VID_0547&PID_1002 ; OSR USB-FX +%USB\VID_045E&PID_930A.DeviceDesc%=usbsamp.Dev, USB\VID_045E&PID_930A ; Intel 82930 +%USB\VID_045E&PID_078E.DeviceDesc%=usbsamp.Dev, USB\VID_045E&PID_078E ; FX2 MUTT +%USB\VID_045E&PID_078F.DeviceDesc%=usbsamp.Dev, USB\VID_045E&PID_078F ; FX3 MUTT + + +[usbsamp.Dev.NT] +CopyFiles=usbsamp.Files.Ext + +[usbsamp.Dev.NT.Services] +Addservice = usbsamp, 0x00000002, usbsamp.AddService + +[usbsamp.AddService] +DisplayName = %usbsamp.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %10%\System32\Drivers\usbsamp.sys +AddReg = usbsamp.AddReg + +[usbsamp.AddReg] +HKR,"Parameters","MaximumTransferSize",0x10001,65536 +HKR,"Parameters","DebugLevel",0x10001,2 + +[usbsamp.Files.Ext] +usbsamp.sys + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +usbsamp.sys = 1 + +;-------------- WDF Coinstaller installation +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[usbsamp.Dev.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" + +[usbsamp.Dev.NT.Wdf] +KmdfService = usbsamp, usbsamp_wdfsect + +[usbsamp_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +;---------------------------------------------------------------; + +[Strings] +ProviderName = "TODO-Set-Provider" +MfgName = "Intel/OSR" +Disk_Description= "usbsamp Installation Disk" +usbsamp.SvcDesc = "WDF Sample Driver for Intel 82930 USB Test Board" +ClassName = "Sample Device" +USB\VID_0547&PID_1002.DeviceDesc="WDF Sample for OSR USB-FX2 Learning Kit" +USB\VID_045E&PID_930A.DeviceDesc="WDF Sample for Intel 82930 USB Test Board" +USB\VID_045E&PID_078E.DeviceDesc="WDF Sample for FX2 MUTT device" +USB\VID_045E&PID_078F.DeviceDesc="WDF Sample for FX3 MUTT device" + diff --git a/usb/usbsamp/sys/driver/usbsamp.vcxproj b/usb/usbsamp/sys/driver/usbsamp.vcxproj new file mode 100644 index 00000000..0d96425a --- /dev/null +++ b/usb/usbsamp/sys/driver/usbsamp.vcxproj @@ -0,0 +1,203 @@ +<?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>{6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{D2F4B3C2-A1FA-433C-A698-DEF22D5B8A75}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</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>Universal</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>Universal</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>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\usbsamp.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\usbsamp.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>usbsamp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\usbdex.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\usbdex.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\usbdex.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\usbdex.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\bulkrwr.c" /> + <ClCompile Include="..\device.c" /> + <ClCompile Include="..\driver.c" /> + <ClCompile Include="..\isorwr.c" /> + <ClCompile Include="..\queue.c" /> + <ClCompile Include="..\stream.c" /> + <ResourceCompile Include="..\usbsamp.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </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/usb/usbsamp/sys/driver/usbsamp.vcxproj.Filters b/usb/usbsamp/sys/driver/usbsamp.vcxproj.Filters new file mode 100644 index 00000000..18f603d0 --- /dev/null +++ b/usb/usbsamp/sys/driver/usbsamp.vcxproj.Filters @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{D6BF3D48-CBBA-42B5-B745-30ECADE8EC41}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{DB8B8A2E-77FA-4567-8AA8-B36DE48FDC76}</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>{122D039B-46C3-41E1-AC33-2B0AFE33A066}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{EA2F6E70-5FFD-4177-A858-FCEA368FFBB1}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <Inf Include=".\usbsamp.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\bulkrwr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\isorwr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\queue.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\stream.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="..\usbsamp.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/usb/usbsamp/sys/isorwr.c b/usb/usbsamp/sys/isorwr.c new file mode 100644 index 00000000..ad780c38 --- /dev/null +++ b/usb/usbsamp/sys/isorwr.c @@ -0,0 +1,565 @@ +/*++ + +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: + + isorwr.c + +Abstract: + + This file has dispatch routines for read and write. + +Environment: + + Kernel mode + +Notes: + +--*/ + +#include "private.h" + +VOID +ReadWriteIsochEndPoints( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG Length, + _In_ WDF_REQUEST_TYPE RequestType + ) +/*++ + +Routine Description: + + This routine does some validation and invokes appropriate function to perform Isoch transfer + +--*/ +{ + NTSTATUS status; + WDF_USB_PIPE_INFORMATION pipeInfo; + PFILE_CONTEXT fileContext; + WDFUSBPIPE pipe; + PDEVICE_CONTEXT deviceContext; + PREQUEST_CONTEXT rwContext; + + UNREFERENCED_PARAMETER(Length); + + UsbSamp_DbgPrint(3, ("ReadWriteIsochEndPoints - begins\n")); + + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); + + if ((WdfUsbPipeTypeIsochronous != pipeInfo.PipeType)) { + UsbSamp_DbgPrint(1, ("Pipe type is not Isochronous\n")); + status = STATUS_INVALID_DEVICE_REQUEST; + goto Exit; + + } + + if (RequestType == WdfRequestTypeRead && WdfUsbTargetPipeIsInEndpoint(pipe) == FALSE) { + UsbSamp_DbgPrint(1, ("Invalid pipe - not an input pipe\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + if (RequestType == WdfRequestTypeWrite && WdfUsbTargetPipeIsOutEndpoint(pipe) == FALSE) { + UsbSamp_DbgPrint(1, ("Invalid pipe - not an output pipe\n")); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); + rwContext = GetRequestContext(Request); + + if (RequestType == WdfRequestTypeRead) { + rwContext->Read = TRUE; + status = WdfRequestForwardToIoQueue(Request, deviceContext->IsochReadQueue); + } + else { + rwContext->Read = FALSE; + status = WdfRequestForwardToIoQueue(Request, deviceContext->IsochWriteQueue); + } + + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestForwardToIoQueue failed with status 0x%x\n", status)); + goto Exit; + } + + return; + +Exit: + WdfRequestCompleteWithInformation(Request, status, 0); + return; +} + +VOID +UsbSamp_EvtIoQueueReadyNotification( + WDFQUEUE Queue, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + This function is called when the WDF queue transitions from 0 to 1 requests in the + queue. Because we are using queue level synchronization, the framework will not + call this routine concurrently if another request is received while this routine is + handling the previously retrieved request. That way we can compute the StartFrame + and dispatch requests without being concerned about two requests racing through + this routine and using StartFrame numbers that overlap each other. + + This is common routine for both read and write requests. + +--*/ +{ + NTSTATUS status; + WDF_REQUEST_PARAMETERS requestParams; + WDFREQUEST request; + PREQUEST_CONTEXT rwContext; + + do { + + status = WdfIoQueueRetrieveNextRequest(Queue, &request); + + if (!NT_SUCCESS(status)) { + return; + } + + rwContext = GetRequestContext(request); + + WDF_REQUEST_PARAMETERS_INIT(&requestParams); + WdfRequestGetParameters(request, &requestParams); + + if (rwContext->Read) { + PerformIsochTransfer((PDEVICE_CONTEXT)Context, + request, + (ULONG)requestParams.Parameters.Read.Length); + } + else { + PerformIsochTransfer((PDEVICE_CONTEXT)Context, + request, + (ULONG)requestParams.Parameters.Write.Length); + + } + + } while (status == STATUS_SUCCESS); + + return; +} + + +VOID +PerformIsochTransfer( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ WDFREQUEST Request, + _In_ ULONG TotalLength + ) +/*++ + +Routine Description: + + Common routine to perform isoch transfer to fullspeed and highspeed device. + +Arguments: + + Device - Device handle + Queue - Queue the request is delivered from + Request - Read/Write Request received from the user app. + TotalLength - Length of the user buffer. + Request - Read or Write request + +Return Value: + + VOID +--*/ +{ + ULONG numberOfPackets; + NTSTATUS status; + PREQUEST_CONTEXT rwContext; + WDFUSBPIPE pipe; + PFILE_CONTEXT fileContext; + WDF_OBJECT_ATTRIBUTES attributes; + ULONG j; + USBD_PIPE_HANDLE usbdPipeHandle; + PMDL requestMdl; + WDFMEMORY urbMemory; + PURB urb; + size_t urbSize; + ULONG offset; + ULONG frameNumber, numberOfFrames; + PPIPE_CONTEXT pipeContext; + + rwContext = GetRequestContext(Request); + + UsbSamp_DbgPrint(3, ("PerformIsochTransfer %s for Length %d - begins\n", + rwContext->Read ? "Read":"Write", TotalLength)); + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + pipeContext = GetPipeContext(pipe); + + if ((TotalLength % pipeContext->TransferSizePerFrame) != 0) { + UsbSamp_DbgPrint(1, ("The transfer must evenly start and end on whole frame boundaries.\n")); + UsbSamp_DbgPrint(1, ("Transfer length should be multiples of %d\n", pipeContext->TransferSizePerFrame)); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + if (DeviceContext->IsDeviceSuperSpeed) { + + numberOfFrames = TotalLength / pipeContext->TransferSizePerFrame; + numberOfPackets = TotalLength / pipeContext->TransferSizePerMicroframe; + + // + // Then make sure the buffer doesn't exceed maximum allowed packets per transfer + // + + if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_SUPER_SPEED) { + UsbSamp_DbgPrint(1, ("NumberOfPackets %d required to transfer exceeds the limit %d\n", + numberOfPackets, MAX_SUPPORTED_PACKETS_FOR_SUPER_SPEED)); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + UsbSamp_DbgPrint(3, ("Will send %d packets of %d bytes in %d frames\n", + numberOfPackets, pipeContext->TransferSizePerMicroframe, numberOfFrames)); + + } else if (DeviceContext->IsDeviceHighSpeed) { + + + numberOfFrames = TotalLength / pipeContext->TransferSizePerFrame; + numberOfPackets = TotalLength / pipeContext->TransferSizePerMicroframe; + + // + // Then make sure the buffer doesn't exceed maximum allowed packets per transfer + // + + if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_SPEED) { + UsbSamp_DbgPrint(1, ("NumberOfPackets %d required to transfer exceeds the limit %d\n", + numberOfPackets, MAX_SUPPORTED_PACKETS_FOR_HIGH_SPEED)); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + UsbSamp_DbgPrint(3, ("Will send %d packets of %d bytes in %d frames\n", + numberOfPackets, pipeContext->TransferSizePerMicroframe, numberOfFrames)); + + } + else { + + numberOfPackets = TotalLength / pipeContext->TransferSizePerFrame; + numberOfFrames = numberOfPackets; + + // + // Then make sure the buffer doesn't exceed maximum allowed packets per transfer + // + + if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED) { + UsbSamp_DbgPrint(1, ("NumberOfPackets %d required to transfer exceeds the limit %d\n", + numberOfPackets, MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED)); + status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + UsbSamp_DbgPrint(3, ("Will send %d packets of %d bytes in %d frames\n", + numberOfPackets, pipeContext->TransferSizePerFrame, numberOfFrames)); + } + + if (rwContext->Read == TRUE) { + status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed %x\n", status)); + goto Exit; + } + } + else { + status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed %x\n", status)); + goto Exit; + } + } + + urbSize = GET_ISO_URB_SIZE(numberOfPackets); + + // + // Allocate memory for URB. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Request; + + status = WdfUsbTargetDeviceCreateIsochUrb(DeviceContext->WdfUsbTargetDevice, + &attributes, + numberOfPackets, + &urbMemory, + NULL); + + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("WdfUsbTargetDeviceCreateIsochUrb failed 0x%x\n", status)); + goto Exit; + } + + urb = WdfMemoryGetBuffer(urbMemory, NULL); + + usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); + urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize; + urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER; + urb->UrbIsochronousTransfer.PipeHandle = usbdPipeHandle; + + if (rwContext->Read) { + urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN; + } + else { + urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT; + } + + urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength; + urb->UrbIsochronousTransfer.TransferBufferMDL = requestMdl; + urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets; + urb->UrbIsochronousTransfer.UrbLink = NULL; + + // + // Set the offsets for every packet for reads/writes + // + offset = 0; + + for (j = 0; j < numberOfPackets; j++) { + + if (DeviceContext->IsDeviceHighSpeed || + DeviceContext->IsDeviceSuperSpeed) { + urb->UrbIsochronousTransfer.IsoPacket[j].Offset = j * pipeContext->TransferSizePerMicroframe; + } + else { + urb->UrbIsochronousTransfer.IsoPacket[j].Offset = j * pipeContext->TransferSizePerFrame; + } + + // + // Length is a return value on Isoch IN. It is ignored on Isoch OUT. + // + urb->UrbIsochronousTransfer.IsoPacket[j].Length = 0; + urb->UrbIsochronousTransfer.IsoPacket[j].Status = 0; + + UsbSamp_DbgPrint(3, ("IsoPacket[%d].Offset = %X IsoPacket[%d].Length = %X\n", + j, urb->UrbIsochronousTransfer.IsoPacket[j].Offset, + j, urb->UrbIsochronousTransfer.IsoPacket[j].Length)); + } + + // + // Calculate the StartFrame number: + // When the client driver sets the ASAP flag, it basically guarantees that + // it will make data available to the host controller (HC) and that the + // HC should transfer it in the next transfer frame for the endpoint. + // (The HC maintains a next transfer frame state variable for each endpoint). + // If the data does not get to the HC fast enough, the USBD_ISO_PACKET_DESCRIPTOR - + // Status is USBD_STATUS_BAD_START_FRAME on uhci. On ohci it is 0xC000000E. + // + + //urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP; + + // + // Instead of using ASAP, we will explicitly set start frame since we cannot control the + // response time of application that's sending request to us. + // + status = WdfUsbTargetDeviceRetrieveCurrentFrameNumber(DeviceContext->WdfUsbTargetDevice, + &frameNumber); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("Failed to get frame number urb\n")); + goto Exit; + } + + if (frameNumber < pipeContext->NextFrameNumber) { + // + // Controller hasn't finished sending perivously scheduled request. So we will use + // the NextFrameNumber that we calculated for this one. + // + urb->UrbIsochronousTransfer.StartFrame = pipeContext->NextFrameNumber; + } + else { + // + // Controller frame number has advanced beyond the NextFrameNumber we calculated. + // + urb->UrbIsochronousTransfer.StartFrame = frameNumber; + } + + // + // Let us add a small latency to account for the time delay in reaching the controller + // from here. + // + urb->UrbIsochronousTransfer.StartFrame += DISPATCH_LATENCY_IN_MS; + + // + // Calculate the NextFrameNumber. + // + pipeContext->NextFrameNumber = urb->UrbIsochronousTransfer.StartFrame + numberOfFrames; + + // + // Associate the URB with the request. + // + status = WdfUsbTargetPipeFormatRequestForUrb(pipe, + Request, + urbMemory, + NULL ); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("Failed to format requset for urb\n")); + goto Exit; + } + + WdfRequestSetCompletionRoutine(Request, + UsbSamp_EvtIsoRequestCompletionRoutine, + rwContext); + + rwContext->UrbMemory = urbMemory; + rwContext->Mdl = requestMdl; + rwContext->Length = TotalLength; + rwContext->Numxfer = 0; + rwContext->VirtualAddress = (ULONG_PTR)MmGetMdlVirtualAddress(requestMdl); + + if (WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS) == FALSE) { + status = WdfRequestGetStatus(Request); + UsbSamp_DbgPrint(1, ("WdfRequestSend failed with status code 0x%x\n", status)); + goto Exit; + } + +Exit: + + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, 0); + } + + UsbSamp_DbgPrint(3, ("PerformHighSpeedIsochTransfer -- ends status 0x%x\n", status)); + return; +} + + +VOID +UsbSamp_EvtIsoRequestCompletionRoutine( + _In_ WDFREQUEST Request, + _In_ WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + _In_ WDFCONTEXT Context + ) +/*++ + +Routine Description: + + Completion Routine + +Arguments: + + Context - Driver supplied context + Target - Target handle + Request - Request handle + Params - request completion params + + +Return Value: + + VOID + +--*/ +{ + PURB urb; + NTSTATUS status; + ULONG length, i, totalPacketLenght; + PREQUEST_CONTEXT rwContext; + + UNREFERENCED_PARAMETER(Target); + + UsbSamp_DbgPrint(3, ("UsbSampEvtIsoRequestCompletionRoutine - begins\n")); + + rwContext = (PREQUEST_CONTEXT)Context; + + urb = (PURB) WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); + + length = urb->UrbIsochronousTransfer.TransferBufferLength; + + status = CompletionParams->IoStatus.Status; + + totalPacketLenght = 0; + + for (i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) { + + UsbSamp_DbgPrint(3, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %X\n", + i, + urb->UrbIsochronousTransfer.IsoPacket[i].Length, + i, + urb->UrbIsochronousTransfer.IsoPacket[i].Status)); + + totalPacketLenght += urb->UrbIsochronousTransfer.IsoPacket[i].Length; + } + + if (NT_SUCCESS(status) && USBD_SUCCESS(urb->UrbHeader.Status)) { + // + // For iosch out, IsoPacket[].Length field is not updated by the USB stack. + // + if (rwContext->Read == TRUE) { + NT_ASSERT(totalPacketLenght == length); + } + + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, length); + + UsbSamp_DbgPrint(3, ("Request completed with success, TransferBufferLength = %d, TotalPacketLength = %d\n", + length, totalPacketLenght)); + } + else { + + UsbSamp_DbgPrint(1, ("Read or write irp failed with NTSTATUS 0x%x, USBD_STATUS 0x%x\n", + status, urb->UrbHeader.Status)); + + WdfRequestCompleteWithInformation(Request, status, 0); + } + + UsbSamp_DbgPrint(3, ("UsbSampEvtIsoRequestCompletionRoutine - ends\n")); + + return; +} + +VOID +UsbSamp_EvtIoStop( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG ActionFlags + ) +/*++ + +Routine Description: + + This callback is invoked on every inflight request when the device + is suspended or removed. Since our inflight read and write requests + are actually pending in the target device, we will just acknowledge + its presence. Until we acknowledge, complete, or requeue the requests + framework will wait before allowing the device suspend or remove to + proceeed. When the underlying USB stack gets the request to suspend or + remove, it will fail all the pending requests. + +Arguments: + +Return Value: + None + +--*/ +{ + UNREFERENCED_PARAMETER(Queue); + + if (ActionFlags & WdfRequestStopActionSuspend ) { + WdfRequestStopAcknowledge(Request, FALSE); // Don't requeue + } + else if (ActionFlags & WdfRequestStopActionPurge) { + WdfRequestCancelSentRequest(Request); + } + + return; +} diff --git a/usb/usbsamp/sys/private.h b/usb/usbsamp/sys/private.h new file mode 100644 index 00000000..ef164908 --- /dev/null +++ b/usb/usbsamp/sys/private.h @@ -0,0 +1,391 @@ +/*++ + +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: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include <initguid.h> +#include <ntddk.h> +#include <ntintsafe.h> +#include "usbdi.h" +#include "usbdlib.h" + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +#include <wdf.h> +#include <wdfusb.h> +#include "public.h" + + +#ifndef _H +#define _H + +#define POOL_TAG (ULONG) 'SBSU' + +#define MAX_SUPPORTED_PACKETS_FOR_SUPER_SPEED 1024 +#define MAX_SUPPORTED_PACKETS_FOR_HIGH_SPEED 1024 +#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255 + +#define DISPATCH_LATENCY_IN_MS 10 + + +#undef ExAllocatePool +#define ExAllocatePool(type, size) \ + ExAllocatePoolWithTag(type, size, POOL_TAG); + +#if DBG + +#define UsbSamp_DbgPrint(level, _x_) \ + if((level) <= DebugLevel) { \ + DbgPrint("UsbSamp: "); DbgPrint _x_; \ + } + +#else + +#define UsbSamp_DbgPrint(level, _x_) + +#endif + +#define MAX_FULL_SPEED_TRANSFER_SIZE 64 +#define MAX_HIGH_SPEED_TRANSFER_SIZE 512 +#define MAX_SUPER_SPEED_TRANSFER_SIZE 1024 +#define MAX_STREAM_VALID_PACKET_SIZE 1024 +#define REMOTE_WAKEUP_MASK 0x20 + +#define DEFAULT_REGISTRY_TRANSFER_SIZE 65536 + +#define IDLE_CAPS_TYPE IdleUsbSelectiveSuspend + + +// +// A structure representing the instance information associated with +// this particular device. +// + +typedef struct _DEVICE_CONTEXT { + + USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor; + + PUSB_CONFIGURATION_DESCRIPTOR UsbConfigurationDescriptor; + + WDFUSBDEVICE WdfUsbTargetDevice; + + ULONG WaitWakeEnable; + + BOOLEAN IsDeviceHighSpeed; + + BOOLEAN IsDeviceSuperSpeed; + + WDFUSBINTERFACE UsbInterface; + + UCHAR SelectedAlternateSetting; + + UCHAR NumberConfiguredPipes; + + ULONG MaximumTransferSize; + + WDFQUEUE IsochReadQueue; + + WDFQUEUE IsochWriteQueue; + + BOOLEAN IsStaticStreamsSupported; + + USHORT NumberOfStreamsSupportedByController; + + USBD_HANDLE UsbdHandle; + + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) +// +// This context is associated with every open handle. +// +typedef struct _FILE_CONTEXT { + + WDFUSBPIPE Pipe; + +} FILE_CONTEXT, *PFILE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILE_CONTEXT, GetFileContext) + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +typedef struct _USBSAMP_STREAM_INFO { + + // Number of enabled streams on this pipe + ULONG NumberOfStreams; + + // Array of stream information structures representing streams on this pipe + PUSBD_STREAM_INFORMATION StreamList; + +} USBSAMP_STREAM_INFO, *PUSBSAMP_STREAM_INFO; + +#endif + +// +// This context is associated with every pipe handle. In this sample, +// it used for isoch transfers. +// +typedef struct _PIPE_CONTEXT { + + ULONG NextFrameNumber; + + ULONG TransferSizePerMicroframe; + + ULONG TransferSizePerFrame; + + BOOLEAN StreamConfigured; + +#if (NTDDI_VERSION >= NTDDI_WIN8) + USBSAMP_STREAM_INFO StreamInfo; +#endif + +} PIPE_CONTEXT, *PPIPE_CONTEXT; + + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PIPE_CONTEXT, GetPipeContext) + + +// +// This context is associated with every request recevied by the driver +// from the app. +// +typedef struct _REQUEST_CONTEXT { + + WDFMEMORY UrbMemory; + PMDL Mdl; + ULONG Length; // remaining to xfer + ULONG Numxfer; + ULONG_PTR VirtualAddress; // va for next segment of xfer. + BOOLEAN Read; // TRUE if Read +} REQUEST_CONTEXT, * PREQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext) + +typedef struct _WORKITEM_CONTEXT { + WDFDEVICE Device; + WDFUSBPIPE Pipe; +} WORKITEM_CONTEXT, *PWORKITEM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKITEM_CONTEXT, GetWorkItemContext) +extern ULONG DebugLevel; + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD UsbSamp_EvtDeviceAdd; +EVT_WDF_DEVICE_PREPARE_HARDWARE UsbSamp_EvtDevicePrepareHardware; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP UsbSamp_EvtDeviceContextCleanup; + +#if (NTDDI_VERSION >= NTDDI_WIN8) +EVT_WDF_OBJECT_CONTEXT_CLEANUP UsbSamp_EvtPipeContextCleanup; +#endif + +EVT_WDF_DEVICE_FILE_CREATE UsbSamp_EvtDeviceFileCreate; + +EVT_WDF_IO_QUEUE_IO_READ UsbSamp_EvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE UsbSamp_EvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL UsbSamp_EvtIoDeviceControl; + +EVT_WDF_REQUEST_COMPLETION_ROUTINE UsbSamp_EvtReadWriteCompletion; +EVT_WDF_REQUEST_COMPLETION_ROUTINE UsbSamp_EvtIsoRequestCompletionRoutine; + +EVT_WDF_IO_QUEUE_IO_STOP UsbSamp_EvtIoStop; + +EVT_WDF_IO_QUEUE_STATE UsbSamp_EvtIoQueueReadyNotification; + +EVT_WDF_WORKITEM UsbSamp_EvtReadWriteWorkItem; + +WDFUSBPIPE +GetPipeFromName( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ PUNICODE_STRING FileName + ); + +VOID +ReadWriteIsochEndPoints( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG Length, + _In_ WDF_REQUEST_TYPE RequestType + ); + +VOID +ReadWriteBulkEndPoints( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ ULONG Length, + _In_ WDF_REQUEST_TYPE RequestType + ); + +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ); + +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ); + +NTSTATUS +ReadAndSelectDescriptors( + _In_ WDFDEVICE Device + ); + +NTSTATUS +ConfigureDevice( + _In_ WDFDEVICE Device + ); + +NTSTATUS +SelectInterfaces( + _In_ WDFDEVICE Device + ); + +NTSTATUS +SetPowerPolicy( + _In_ WDFDEVICE Device + ); + +NTSTATUS +AbortPipes( + _In_ WDFDEVICE Device + ); + + +NTSTATUS +QueuePassiveLevelCallback( + _In_ WDFDEVICE Device, + _In_ WDFUSBPIPE Pipe + ); + +VOID +PerformIsochTransfer( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ WDFREQUEST Request, + _In_ ULONG TotalLength + ); + +VOID +DbgPrintRWContext( + PREQUEST_CONTEXT rwContext + ); + +NTSTATUS +ReadFdoRegistryKeyValue( + _In_ WDFDRIVER Driver, + _In_ LPWSTR Name, + _Out_ PULONG Value + ); + +NTSTATUS +InitializePipeContextForHighSpeedDevice( + _In_ WDFUSBPIPE Pipe + ); + +NTSTATUS +InitializePipeContextForFullSpeedDevice( + _In_ WDFUSBPIPE Pipe + ); + +NTSTATUS +RetrieveDeviceInformation( + _In_ WDFDEVICE Device + ); + + +USBD_STATUS +UsbSamp_ValidateConfigurationDescriptor( + _In_reads_bytes_(BufferLength) PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + _In_ ULONG BufferLength, + _Inout_ PUCHAR *Offset + ); + + +NTSTATUS +GetStackCapability( + _In_ WDFDEVICE Device, + _In_ const GUID* CapabilityType, + _In_ ULONG OutputBufferLength, + _When_(OutputBufferLength == 0, _Pre_null_) + _When_(OutputBufferLength != 0, _Out_writes_bytes_(OutputBufferLength)) + PUCHAR OutputBuffer + ); + +#if (NTDDI_VERSION >= NTDDI_WIN8) +NTSTATUS +InitializePipeContextForSuperSpeedDevice( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ WDFUSBPIPE Pipe + ); + +NTSTATUS +InitializePipeContextForSuperSpeedIsochPipe( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ WDFUSBPIPE Pipe + ); + +PUSB_ENDPOINT_DESCRIPTOR +GetEndpointDescriptorForEndpointAddress( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ UCHAR EndpointAddress, + _Out_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR *ppEndpointCompanionDescriptor + ); + +NTSTATUS +InitializePipeContextForSuperSpeedBulkPipe( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ WDFUSBPIPE Pipe + ); + +USBD_PIPE_HANDLE +GetStreamPipeHandleFromBulkPipe( + _In_ WDFUSBPIPE Pipe + ); + +VOID +ConfigureStreamPipeHandleForRequest( + _In_ WDFREQUEST Request, + _In_ WDFUSBPIPE Pipe + ); + +#endif + +ULONG +GetMaxTransferSize( + _In_ WDFUSBPIPE Pipe, + _In_ PDEVICE_CONTEXT DeviceContext +); + + +#endif + diff --git a/usb/usbsamp/sys/public.h b/usb/usbsamp/sys/public.h new file mode 100644 index 00000000..765a5732 --- /dev/null +++ b/usb/usbsamp/sys/public.h @@ -0,0 +1,49 @@ +/*++ + +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: + + BulkUsr.h + +Abstract: + +Environment: + + User & Kernel mode + +--*/ + +#ifndef _USER_H +#define _USER_H + +#include <initguid.h> + +// {6068EB61-98E7-4c98-9E20-1F068295909A} +DEFINE_GUID(GUID_CLASS_USBSAMP_USB, +0x873fdf, 0x61a8, 0x11d1, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0x8b); + +#define IOCTL_INDEX 0x0000 + + +#define IOCTL_USBSAMP_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define IOCTL_USBSAMP_RESET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, \ + IOCTL_INDEX + 1, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define IOCTL_USBSAMP_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, \ + IOCTL_INDEX + 2, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#endif diff --git a/usb/usbsamp/sys/queue.c b/usb/usbsamp/sys/queue.c new file mode 100644 index 00000000..5047d24c --- /dev/null +++ b/usb/usbsamp/sys/queue.c @@ -0,0 +1,595 @@ +/*++ + +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: + + Queue.c + +Abstract: + + This file contains dispatch routines for create, + close, device-control, read & write. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, UsbSamp_EvtDeviceFileCreate) +#pragma alloc_text(PAGE, UsbSamp_EvtIoDeviceControl) +#pragma alloc_text(PAGE, UsbSamp_EvtIoRead) +#pragma alloc_text(PAGE, UsbSamp_EvtIoWrite) +#pragma alloc_text(PAGE, GetPipeFromName) +#pragma alloc_text(PAGE, ResetPipe) +#pragma alloc_text(PAGE, ResetDevice) +#endif + + +VOID +UsbSamp_EvtDeviceFileCreate( + _In_ WDFDEVICE Device, + _In_ WDFREQUEST Request, + _In_ WDFFILEOBJECT FileObject + ) +/*++ + +Routine Description: + + The framework calls a driver's EvtDeviceFileCreate callback + when the framework receives an IRP_MJ_CREATE request. + The system sends this request when a user application opens the + device to perform an I/O operation, such as reading or writing a file. + This callback is called synchronously, in the context of the thread + that created the IRP_MJ_CREATE request. + +Arguments: + + Device - Handle to a framework device object. + FileObject - Pointer to fileobject that represents the open handle. + CreateParams - copy of the create IO_STACK_LOCATION + +Return Value: + + NT status code + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PUNICODE_STRING fileName; + PFILE_CONTEXT pFileContext; + PDEVICE_CONTEXT pDevContext; + WDFUSBPIPE pipe; + + UsbSamp_DbgPrint(3, ("EvtDeviceFileCreate - begins\n")); + + PAGED_CODE(); + + // + // initialize variables + // + pDevContext = GetDeviceContext(Device); + pFileContext = GetFileContext(FileObject); + + + fileName = WdfFileObjectGetFileName(FileObject); + + if (0 == fileName->Length) { + // + // opening a device as opposed to pipe. + // + status = STATUS_SUCCESS; + } + else { + pipe = GetPipeFromName(pDevContext, fileName); + + if (pipe != NULL) { + // + // found a match + // + pFileContext->Pipe = pipe; + + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); + + status = STATUS_SUCCESS; + } + else { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + WdfRequestComplete(Request, status); + + UsbSamp_DbgPrint(3, ("EvtDeviceFileCreate - ends\n")); + + return; +} + +VOID +UsbSamp_EvtIoDeviceControl( + _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 + +--*/ +{ + WDFDEVICE device; + PVOID ioBuffer; + size_t bufLength; + NTSTATUS status; + PDEVICE_CONTEXT pDevContext; + PFILE_CONTEXT pFileContext; + ULONG length = 0; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + UsbSamp_DbgPrint(3, ("Entered UsbSamp_DispatchDevCtrl\n")); + + PAGED_CODE(); + + // + // initialize variables + // + device = WdfIoQueueGetDevice(Queue); + pDevContext = GetDeviceContext(device); + + switch(IoControlCode) { + + case IOCTL_USBSAMP_RESET_PIPE: + + pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); + + if (pFileContext->Pipe == NULL) { + status = STATUS_INVALID_PARAMETER; + } + else { + status = ResetPipe(pFileContext->Pipe); + } + + break; + + case IOCTL_USBSAMP_GET_CONFIG_DESCRIPTOR: + + + if (pDevContext->UsbConfigurationDescriptor) { + + length = pDevContext->UsbConfigurationDescriptor->wTotalLength; + + status = WdfRequestRetrieveOutputBuffer(Request, length, &ioBuffer, &bufLength); + if (!NT_SUCCESS(status)){ + UsbSamp_DbgPrint(1, ("WdfRequestRetrieveInputBuffer failed\n")); + break; + } + + RtlCopyMemory(ioBuffer, + pDevContext->UsbConfigurationDescriptor, + length); + + status = STATUS_SUCCESS; + } + else { + status = STATUS_INVALID_DEVICE_STATE; + } + + break; + + case IOCTL_USBSAMP_RESET_DEVICE: + + status = ResetDevice(device); + break; + + default : + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + WdfRequestCompleteWithInformation(Request, status, length); + + UsbSamp_DbgPrint(3, ("Exit UsbSamp_DispatchDevCtrl\n")); + + return; +} + +VOID +UsbSamp_EvtIoRead( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Read requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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: + + +--*/ +{ + PFILE_CONTEXT fileContext = NULL; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + + PAGED_CODE(); + + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + if (pipe == NULL) { + UsbSamp_DbgPrint(1, ("pipe handle is NULL\n")); + WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); + return; + } + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); + + if ((WdfUsbPipeTypeBulk == pipeInfo.PipeType) || + (WdfUsbPipeTypeInterrupt == pipeInfo.PipeType)) { + + ReadWriteBulkEndPoints(Queue, Request, (ULONG) Length, WdfRequestTypeRead); + return; + + } + else if (WdfUsbPipeTypeIsochronous == pipeInfo.PipeType){ + +#if !defined(BUFFERED_READ_WRITE) // if doing DIRECT_IO + ReadWriteIsochEndPoints(Queue, Request, (ULONG) Length, WdfRequestTypeRead); + return; +#endif + + } + + UsbSamp_DbgPrint(1, ("ISO transfer is not supported for buffered I/O transfer\n")); + WdfRequestCompleteWithInformation(Request, STATUS_INVALID_DEVICE_REQUEST, 0); + + return; +} + +VOID +UsbSamp_EvtIoWrite( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t Length + ) +/*++ + +Routine Description: + + Called by the framework when it receives Write requests. + +Arguments: + + Queue - Default queue handle + Request - Handle to the read/write request + Lenght - Length of the data buffer associated with the request. + 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: + + +--*/ +{ + PFILE_CONTEXT fileContext = NULL; + WDFUSBPIPE pipe; + WDF_USB_PIPE_INFORMATION pipeInfo; + + PAGED_CODE(); + + // + // Get the pipe associate with this request. + // + fileContext = GetFileContext(WdfRequestGetFileObject(Request)); + pipe = fileContext->Pipe; + if (pipe == NULL) { + UsbSamp_DbgPrint(1, ("pipe handle is NULL\n")); + WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); + return; + } + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); + + if ((WdfUsbPipeTypeBulk == pipeInfo.PipeType) || + (WdfUsbPipeTypeInterrupt == pipeInfo.PipeType)) { + + ReadWriteBulkEndPoints(Queue, Request, (ULONG) Length, WdfRequestTypeWrite); + return; + + } + else if (WdfUsbPipeTypeIsochronous == pipeInfo.PipeType){ + +#if !defined(BUFFERED_READ_WRITE) // if doing DIRECT_IO + ReadWriteIsochEndPoints(Queue, Request, (ULONG) Length, WdfRequestTypeWrite); + return; +#endif + + } + + UsbSamp_DbgPrint(1, ("ISO transfer is not supported for buffered I/O transfer\n")); + WdfRequestCompleteWithInformation(Request, STATUS_INVALID_DEVICE_REQUEST, 0); + + return; +} + +WDFUSBPIPE +GetPipeFromName( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ PUNICODE_STRING FileName + ) +/*++ + +Routine Description: + + This routine will pass the string pipe name and + fetch the pipe handle. + +Arguments: + + DeviceContext - pointer to Device Context + + FileName - string pipe name + +Return Value: + + The device extension maintains a pipe context for + the pipes on 82930 board. + +--*/ +{ + LONG ix; + ULONG uval; + ULONG nameLength; + ULONG umultiplier; + WDFUSBPIPE pipe = NULL; + + PAGED_CODE(); + + // + // typedef WCHAR *PWSTR; + // + nameLength = (FileName->Length / sizeof(WCHAR)); + + UsbSamp_DbgPrint(3, ("UsbSamp_PipeWithName - begins\n")); + + if (nameLength != 0) { + + UsbSamp_DbgPrint(3, ("Filename = %wZ nameLength = %d\n", FileName, nameLength)); + + // + // Parse the pipe# + // + ix = nameLength - 1; + + // if last char isn't digit, decrement it. + while((ix > -1) && + ((FileName->Buffer[ix] < (WCHAR) '0') || + (FileName->Buffer[ix] > (WCHAR) '9'))) { + + ix--; + } + + if (ix > -1) { + + uval = 0; + umultiplier = 1; + + // traversing least to most significant digits. + + while((ix > -1) && + (FileName->Buffer[ix] >= (WCHAR) '0') && + (FileName->Buffer[ix] <= (WCHAR) '9')) { + + uval += (umultiplier * + (ULONG) (FileName->Buffer[ix] - (WCHAR) '0')); + + ix--; + umultiplier *= 10; + } + pipe = WdfUsbInterfaceGetConfiguredPipe( + DeviceContext->UsbInterface, + (UCHAR)uval, //PipeIndex, + NULL + ); + + } + } + + UsbSamp_DbgPrint(3, ("UsbSamp_PipeWithName - ends\n")); + + return pipe; +} + +NTSTATUS +ResetPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine resets the pipe. + +Arguments: + + Pipe - framework pipe handle + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + + PAGED_CODE(); + + // + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + // + status = WdfUsbTargetPipeResetSynchronously(Pipe, + WDF_NO_HANDLE, // WDFREQUEST + NULL // PWDF_REQUEST_SEND_OPTIONS + ); + + if (NT_SUCCESS(status)) { + UsbSamp_DbgPrint(3, ("ResetPipe - success\n")); + status = STATUS_SUCCESS; + } + else { + UsbSamp_DbgPrint(1, ("ResetPipe - failed\n")); + } + + return status; +} + +VOID +StopAllPipes( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + UCHAR count,i; + + count = DeviceContext->NumberConfiguredPipes; + for (i = 0; i < count; i++) { + WDFUSBPIPE pipe; + pipe = WdfUsbInterfaceGetConfiguredPipe(DeviceContext->UsbInterface, + i, //PipeIndex, + NULL + ); + WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pipe), + WdfIoTargetCancelSentIo); + } +} + + +VOID +StartAllPipes( + _In_ PDEVICE_CONTEXT DeviceContext + ) +{ + NTSTATUS status; + UCHAR count,i; + + count = DeviceContext->NumberConfiguredPipes; + for (i = 0; i < count; i++) { + WDFUSBPIPE pipe; + pipe = WdfUsbInterfaceGetConfiguredPipe(DeviceContext->UsbInterface, + i, //PipeIndex, + NULL + ); + status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pipe)); + if (!NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("StartAllPipes - failed pipe #%d\n", i)); + } + } +} + +NTSTATUS +ResetDevice( + _In_ WDFDEVICE Device + ) +/*++ + +Routine Description: + + This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still + connected. + +Arguments: + + Device - Handle to a framework device + +Return Value: + + NT status value + +--*/ +{ + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS status; + + UsbSamp_DbgPrint(3, ("ResetDevice - begins\n")); + + PAGED_CODE(); + + pDeviceContext = GetDeviceContext(Device); + + // + // A reset-device + // request will be stuck in the USB until the pending transactions + // have been canceled. Similarly, if there are pending tranasfers on the BULK + // _In_/OUT pipe cancel them. + // To work around this issue, the driver should stop the continuous reader + // (by calling WdfIoTargetStop) before resetting the device, and restart the + // continuous reader (by calling WdfIoTargetStart) after the request completes. + // + StopAllPipes(pDeviceContext); + + // + // It may not be necessary to check whether device is connected before + // resetting the port. + // + status = WdfUsbTargetDeviceIsConnectedSynchronous(pDeviceContext->WdfUsbTargetDevice); + + if (NT_SUCCESS(status)) { + status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->WdfUsbTargetDevice); + } + + StartAllPipes(pDeviceContext); + + UsbSamp_DbgPrint(3, ("ResetDevice - ends\n")); + + return status; +} diff --git a/usb/usbsamp/sys/stream.c b/usb/usbsamp/sys/stream.c new file mode 100644 index 00000000..37067f0a --- /dev/null +++ b/usb/usbsamp/sys/stream.c @@ -0,0 +1,433 @@ + /*++ + +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: + + stream.c + +Abstract: + + This files contain routines for Streams. + +Environment: + + Kernel mode only + +Notes: + + +--*/ + +#include "private.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, GetStackCapability) +#if (NTDDI_VERSION >= NTDDI_WIN8) +#pragma alloc_text(PAGE, InitializePipeContextForSuperSpeedBulkPipe) +#endif +#endif + +NTSTATUS +GetStackCapability( + _In_ WDFDEVICE Device, + _In_ const GUID* CapabilityType, + _In_ ULONG OutputBufferLength, + _When_(OutputBufferLength == 0, _Pre_null_) + _When_(OutputBufferLength != 0, _Out_writes_bytes_(OutputBufferLength)) + PUCHAR OutputBuffer + ) +/*++ + +Routine Description: + + The helper routine gets stack's capability. + +Arguments: + + Device - WDF Device Object + + CapabilityType - Pointer to capability type GUID + + OutputBufferLength - Length of output buffer + + OutPutBuffer - Output buffer + +Return Value: + + NTSTATUS + +--*/ + +{ + PDEVICE_CONTEXT pDevContext; + NTSTATUS status; + + PAGED_CODE(); + + pDevContext = GetDeviceContext(Device); + + // + // Note: All super speed bulk stream I/O transfers use USBD Handle obtained in + // UsbSamp_EvtDeviceAdd. If you call WdfUsbTargetDeviceQueryUsbCapability + // method instead of USBD_QueryUsbCapability here, it will not set stream + // capabilites for USBD Handle used by stream transfer in which case + // the open streams request will fail in this example. + // + status = USBD_QueryUsbCapability(pDevContext->UsbdHandle, + CapabilityType, + OutputBufferLength, + OutputBuffer, + NULL); + if (NT_SUCCESS(status)) { + UsbSamp_DbgPrint(1, ("USBD_QueryUsbCapability %x\n", status)); + } + + return status; +} + +#if (NTDDI_VERSION >= NTDDI_WIN8) + +NTSTATUS +InitializePipeContextForSuperSpeedBulkPipe( + _In_ PDEVICE_CONTEXT DeviceContext, + _In_ UCHAR InterfaceNumber, + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine initialize pipe's streams context. + +Arguments: + + DeviceContext - pointer to device context + + InterfaceNumber - InterfaceNumber of selected interface + + Pipe - Bullk Pipe + +Return Value: + + NTSTATUS + +--*/ + +{ + WDF_USB_PIPE_INFORMATION pipeInfo; + PPIPE_CONTEXT pipeContext; + PUSB_ENDPOINT_DESCRIPTOR pEndpointDescriptor; + PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR pEndpointCompanionDescriptor; + + UCHAR endpointAddress; + ULONG maxStreams; + ULONG supportedStreams; + PUSBSAMP_STREAM_INFO pStreamInfo; + NTSTATUS status; + PURB pUrb = NULL; + ULONG i; + + PAGED_CODE(); + + WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); + WdfUsbTargetPipeGetInformation(Pipe, &pipeInfo); + pipeContext = GetPipeContext(Pipe); + pStreamInfo = &pipeContext->StreamInfo; + + pStreamInfo->NumberOfStreams = 0; + pStreamInfo->StreamList = NULL; + + pipeContext->StreamConfigured = FALSE; + + // + // Validate that the endpoint/pipe is of type BULK. + // Streams are only allowed on a SS BULK endpoint. + // Also ensure that the bus actually supports streams + // before proceeding + // + if (pipeInfo.PipeType != WdfUsbPipeTypeBulk || + DeviceContext->NumberOfStreamsSupportedByController == 0) { + status = STATUS_SUCCESS; + goto End; + } + + endpointAddress = pipeInfo.EndpointAddress; + + pEndpointDescriptor = GetEndpointDescriptorForEndpointAddress( + DeviceContext, + InterfaceNumber, + endpointAddress, + &pEndpointCompanionDescriptor); + + if (pEndpointDescriptor != NULL && + pEndpointCompanionDescriptor != NULL) { + + maxStreams = pEndpointCompanionDescriptor->bmAttributes.Bulk.MaxStreams; + + if (maxStreams == 0) { + + supportedStreams = 0; + + } else { + + supportedStreams = 1 << maxStreams; + } + + } else { + + UsbSamp_DbgPrint(1, ("Endpoint Descriptor or Endpoint Companion Descriptor is NULL.\n")); + status = STATUS_INVALID_PARAMETER; + goto End; + + } + + if (supportedStreams == 0) { + status = STATUS_SUCCESS; + goto End; + } + + if (supportedStreams > DeviceContext->NumberOfStreamsSupportedByController) { + supportedStreams = DeviceContext->NumberOfStreamsSupportedByController; + } + + pStreamInfo->NumberOfStreams = supportedStreams; + + pStreamInfo->StreamList = ExAllocatePoolWithTag( + NonPagedPool, + supportedStreams * sizeof(USBD_STREAM_INFORMATION), + POOL_TAG); + + if (pStreamInfo->StreamList == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto End; + } + + for(i = 0; i < supportedStreams; i++) + { + pStreamInfo->StreamList[i].StreamID = i + 1; + } + + status = USBD_UrbAllocate(DeviceContext->UsbdHandle, &pUrb); + + if (!NT_SUCCESS(status)){ + pUrb = NULL; + status = STATUS_INSUFFICIENT_RESOURCES; + goto End; + } + + pUrb->UrbOpenStaticStreams.Hdr.Length = sizeof(struct _URB_OPEN_STATIC_STREAMS); + pUrb->UrbOpenStaticStreams.Hdr.Function = URB_FUNCTION_OPEN_STATIC_STREAMS; + pUrb->UrbOpenStaticStreams.PipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(Pipe); + pUrb->UrbOpenStaticStreams.NumberOfStreams = pStreamInfo->NumberOfStreams; + pUrb->UrbOpenStaticStreams.StreamInfoSize = sizeof(USBD_STREAM_INFORMATION); + pUrb->UrbOpenStaticStreams.Streams = pStreamInfo->StreamList; + + // Send the URB down the stack + status = WdfUsbTargetPipeSendUrbSynchronously( + Pipe, + NULL, + NULL, + pUrb + ); + + if (NT_SUCCESS(status)) { + + pipeContext->StreamConfigured = TRUE; + + } +End: + if (!NT_SUCCESS(status)) { + + pipeContext->StreamConfigured = FALSE; + pStreamInfo->NumberOfStreams = 0; + + if (pStreamInfo->StreamList != NULL) { + ExFreePool(pStreamInfo->StreamList); + pStreamInfo->StreamList = NULL; + } + + } + + if(pUrb != NULL) { + USBD_UrbFree(DeviceContext->UsbdHandle, pUrb); + } + + return status; +} + + +USBD_PIPE_HANDLE +GetStreamPipeHandleFromBulkPipe( + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + This routine gets a stream USBD_PIPE_HANDLE from a super speed bulk pipe + +Arguments: + + Pipe - Bullk Pipe + +Return Value: + + A stream's USBD_PIPE_HANDLE + +--*/ +{ + PPIPE_CONTEXT pipeContext; + + PUSBSAMP_STREAM_INFO pStreamInfo; + USBD_PIPE_HANDLE streamPipeHandle; + ULONG index; + + pipeContext = GetPipeContext(Pipe); + + if (pipeContext->StreamConfigured == FALSE) + { + streamPipeHandle = NULL; + goto End; + } + + pStreamInfo = &pipeContext->StreamInfo; + + if (pStreamInfo->NumberOfStreams == 0 || + pStreamInfo->StreamList == NULL) + { + streamPipeHandle = NULL; + goto End; + } + + // + // Specify one associate stream's PipeHandle as the super speed bulk endpoint's PipeHandle + // + index = 1; + + streamPipeHandle = pStreamInfo->StreamList[index].PipeHandle; + +End: + return streamPipeHandle; + +} + +VOID +ConfigureStreamPipeHandleForRequest( + _In_ WDFREQUEST Request, + _In_ WDFUSBPIPE Pipe + ) +/*++ + +Routine Description: + + The framework has formated request for super speed bulk pipe. + For stream transfer, use the associated stream's PipeHandle for transfer. + +Arguments: + + Request - Read/Write Request. + + Pipe - Bullk Pipe + +Return Value: + + NULL + +--*/ +{ + PIRP irp; + PIO_STACK_LOCATION irpSp; + PURB urb; + + // + // Get the IRP that is associated with the framework request object. + // + irp = WdfRequestWdmGetIrp(Request); + + // + // Obtain the next-lower driver's I/O stack location in the IRP + // + irpSp = IoGetNextIrpStackLocation(irp); + + // + // The framework uses pipe's Pipehandle for data transfer by default. + // For stream transfer, we should use the associated stream's PipeHandle of + // the super speed bulk pipe for transfer. Replace the PipeHandle with + // its associated stream's PipeHandle . + // + urb = irpSp->Parameters.Others.Argument1; + urb->UrbBulkOrInterruptTransfer.PipeHandle = GetStreamPipeHandleFromBulkPipe(Pipe); + +} + + +#endif + +ULONG +GetMaxTransferSize( + _In_ WDFUSBPIPE Pipe, + _In_ PDEVICE_CONTEXT DeviceContext +) +/*++ + +Routine Description: + + This routine returns maximum packet size of a bulk pipe + +Arguments: + + Pipe - Bullk Pipe + +Return Value: + + Maximum Packet Size + +--*/ +{ + ULONG maxTransferSize; + PPIPE_CONTEXT pipeContext; + + pipeContext = GetPipeContext(Pipe); + + if (pipeContext->StreamConfigured == TRUE) { + + // + // For super speed bulk stream pipe, the max transfer size is + // MAX_STREAM_VALID_PACKET_SIZE which depends on the implementation + // of super speed bulk stream endpoint + // + maxTransferSize = MAX_STREAM_VALID_PACKET_SIZE; + + } + else{ + if (DeviceContext->IsDeviceSuperSpeed == TRUE) + { + maxTransferSize = MAX_SUPER_SPEED_TRANSFER_SIZE; + } + else if (DeviceContext->IsDeviceHighSpeed == TRUE) + { + maxTransferSize = MAX_HIGH_SPEED_TRANSFER_SIZE; + } + else + { + maxTransferSize = MAX_FULL_SPEED_TRANSFER_SIZE; + } + + } + + return maxTransferSize; +} + + + + + + + diff --git a/usb/usbsamp/sys/usbsamp.rc b/usb/usbsamp/sys/usbsamp.rc new file mode 100644 index 00000000..c0861673 --- /dev/null +++ b/usb/usbsamp/sys/usbsamp.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Framework Sample for Intel 82930 USB Test Board" +#define VER_INTERNALNAME_STR "usbsamp.sys" +#define VER_ORIGINALFILENAME_STR "usbsamp.sys" + +#include "common.ver" + diff --git a/usb/usbsamp/usbsamp.htm b/usb/usbsamp/usbsamp.htm new file mode 100644 index 00000000..015e7f28 --- /dev/null +++ b/usb/usbsamp/usbsamp.htm @@ -0,0 +1,92 @@ +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows- +1252"> +<META NAME="Generator" CONTENT="Microsoft FrontPage 5.0"> +<TITLE>Bulk Usb</TITLE> +</HEAD> +<BODY LINK="#0000ff"> + +<FONT FACE="Verdana" SIZE=5><H2>USBSAMP</H2> +</FONT><FONT FACE="Verdana" SIZE=2> + +<P> +<FONT FACE="Verdana" SIZE=5><H3>Summary</H3> +</FONT><FONT FACE="Verdana" SIZE=2> + +<p>The USBSAMP sample demonstrates how to perform full and high speed bulk and isochronous, and super speed bulk stream data transfers to a generic USB device using Windows Kernel Mode Driver Framework (KMDF). Super speed bulk transfer only works on Microsoft USB 3.0 stack. The sample also contains a console test application to initiate bulk, bulk stream & isochronouse transfers and +obtain information on the device's I/O endpoints. The application also +demonstrates how to use GUID-based device names and pipe names generated by the +operating system using the SetupDiXXX user-mode APIs.</p> + + +<H3><A NAME="build"></A>Building the sample</H3></FONT><FONT FACE="Verdana" +SIZE=2><P> +To build the sample driver and exe, you must first set up the DDK build environment on your host machine. The �Installation and Release Notes� in the Windows DDK has a complete description on how to do this. + + <OL> + + + <LI> + Run the build �ceZ command in the usbsamp directory to build <I>usbsamp.sys</I> and <I>usbsamp.exe</I>. + + + + <LI> + Copy <I>KMDF coinstaller (wdfcoinstallerMMmmm.dll)</I>, <I>usbsamp.sys</I>, <I>usbsamp.exe</I>, and <I>usbsamp.inf</I> to a floppy disk or a temporary directory on the target system. +</OL> + <P> + + +<H3>Installing the Driver</H3> + + Make sure your device has been programmed with the device VID/PID in the + USBSAMP.inf file. If not, edit the device VID, PID, and description text in the INF to + match your test board/device. <p> + After you plug the device: + <p><b>On Windows 7 and later:</b></p> + <ul> + <li>Bring up the device manager, find the device, right click on the device to "Update Driver Software.." +<li>Choose the "Browse my computer for driver software" option +<li>Click on "Let me pick from a list of device drivers on my computer" +<li>In the "Select your device's type from the list below", pick the "Show All Devices" +<li>Click on "Have Disk" and specify the target media or the directory where the INF and SYS files are copied and then hit the "Next" button. +<li>The system will scan the directory and pick up the matching INF and start the installation. You will get a Hardware Installation Warning dialog stating that your driver has not passed Windows Logo Testing. Hit "Continue Anyway" button. +<li>The system will copy the KMDF coinstaller (wdfcoinstallerMMmmm.dll), driver, INF file, load the driver and start the device. If every thing goes fine, you will get "Completing the Found New Hardware Wizard". Hit the "Finish" button and the installation is complete. +<li> You should be able to see the device in the Device manager under "Samples" device type + </ul> + + +<h3>Testing</h3> + +You can use usbsamp.exe to test the device. This console application enumerates the interface registered by the driver and opens the device to send read, write or ioctl requests based on the command line options. +<p> +usbsamp.exe -u <-- Will dump all the descriptors and endpoint information. Always use it to dump the endpoint information to get correct pipe number for read and write +</P> +<p> +usbsamp.exe -r 1024 -w 1024 -c 100 -v <-- This command first writes 1024 bytes of data to bulk out endpoint (pipe1), and then reads 1024 bytes from bulk in endpoint (pipe0), and compares the read buffer with write buffer to see if they match. If the buffer contents match, it performs this operation 100 times. +</P> +<p> +To read and write to bulk endpoints you can run one or more of these commands simultaneously. When it reads or writes to super speed bulk endpoints with streams, the sample driver always uses the first underlying stream in that super speed bulk endpoints. The driver is multi-thread safe so it can handle multiple request at a time. +<p> +usbsamp.exe -r 65536 <--- by default, the device reads pipe0 +<p> +usbsamp.exe -w 65536 <--- by default, the device write to pipe1 +<p> +usbsamp.exe -r 65536 -i pipe02 <--- read 65536 bytes from pipe02 +<p> +usbsamp.exe -w 65536 -o pipe03 <--- write 65536 bytes to pipe03 + +<p> +To read and write to Isochronous endpoints you can run one or more of these commands simultaneously. +<p> +usbsamp.exe -r 510 -i pipe04 +<p> +usbsamp.exe -w 510 -o pipe05 +<p> +usbsamp.exe -w 1024 -o pipe05 -r 1024 -i pipe04 -c 100 -v + +<p> +When run with "-x" option for read and write, it skips validation of read and write data. +</BODY> +</HTML>
\ No newline at end of file diff --git a/usb/usbsamp/usbsamp.sln b/usb/usbsamp/usbsamp.sln new file mode 100644 index 00000000..8be6bd1a --- /dev/null +++ b/usb/usbsamp/usbsamp.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}") = "Exe", "Exe", "{49A076C1-4A83-4A1D-9D0B-71543A6621D0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{B3E94C51-B2D9-4787-95EF-4E9DFDEE5A6E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{4305B583-BDD8-4C8B-BA67-EAD701F97A92}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbsamp", "exe\usbsamp.vcxproj", "{82B15C8E-818A-41C0-AE62-1AEA7270E8B6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbsamp", "sys\driver\usbsamp.vcxproj", "{6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}" +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 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Debug|Win32.Build.0 = Debug|Win32 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Release|Win32.ActiveCfg = Release|Win32 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Release|Win32.Build.0 = Release|Win32 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Debug|x64.ActiveCfg = Debug|x64 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Debug|x64.Build.0 = Debug|x64 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Release|x64.ActiveCfg = Release|x64 + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6}.Release|x64.Build.0 = Release|x64 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Debug|Win32.ActiveCfg = Debug|Win32 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Debug|Win32.Build.0 = Debug|Win32 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Release|Win32.ActiveCfg = Release|Win32 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Release|Win32.Build.0 = Release|Win32 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Debug|x64.ActiveCfg = Debug|x64 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Debug|x64.Build.0 = Debug|x64 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Release|x64.ActiveCfg = Release|x64 + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {82B15C8E-818A-41C0-AE62-1AEA7270E8B6} = {49A076C1-4A83-4A1D-9D0B-71543A6621D0} + {6395CFC7-A0E1-40D8-A744-D1DC7B6513BA} = {B3E94C51-B2D9-4787-95EF-4E9DFDEE5A6E} + {B3E94C51-B2D9-4787-95EF-4E9DFDEE5A6E} = {4305B583-BDD8-4C8B-BA67-EAD701F97A92} + EndGlobalSection +EndGlobal diff --git a/usb/usbview/display.c b/usb/usbview/display.c index 67c215e4..9ee63a14 100644 --- a/usb/usbview/display.c +++ b/usb/usbview/display.c @@ -213,10 +213,19 @@ DisplayConfigDesc ( VOID DisplayBosDescriptor ( - PUSB_BOS_DESCRIPTOR BosDesc + PUSBDEVICEINFO info, + PUSB_BOS_DESCRIPTOR BosDesc, + PSTRING_DESCRIPTOR_NODE StringDescs ); VOID +DisplayBillboardCapabilityDescriptor ( + PUSBDEVICEINFO info, + PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc, + PSTRING_DESCRIPTOR_NODE StringDescs +); + +VOID DisplayDeviceQualifierDescriptor ( PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc ); @@ -926,7 +935,9 @@ UpdateTreeItemDeviceInfo( if (BosDesc) { - DisplayBosDescriptor((PUSB_BOS_DESCRIPTOR)(BosDesc + 1)); + DisplayBosDescriptor((PUSBDEVICEINFO) info, + (PUSB_BOS_DESCRIPTOR) (BosDesc + 1), + StringDescs); } } @@ -1535,6 +1546,15 @@ DisplayConnectionInfo ( else {AppendTextBuffer("\r\n");} break; + case USB_DEVICE_CLASS_BILLBOARD: + tog = 0; + if (gDoAnnotation) + { + AppendTextBuffer(" -> This is a billboard class device\r\n"); + } + else { AppendTextBuffer("\r\n"); } + break; + case USB_MISCELLANEOUS_DEVICE: tog = 0; //@@TestCase A1.3 @@ -2381,7 +2401,12 @@ DisplayDeviceQualifierDescriptor ( AppendTextBuffer(" -> This is a Vendor Specific Device\r\n"); } break; - + case USB_DEVICE_CLASS_BILLBOARD: + if (gDoAnnotation) + { + AppendTextBuffer(" -> This is a billboard class device\r\n"); + } + break; default: //@@TestCase A3.1 //@@ERROR @@ -2675,6 +2700,131 @@ DisplayContainerIdCapabilityExtensionDescriptor ( pGuid->Data4[7]); } +VOID +DisplayBillboardCapabilityDescriptor ( + PUSBDEVICEINFO info, + PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR billboardCapDesc, + PSTRING_DESCRIPTOR_NODE StringDescs + ) +{ + UCHAR i = 0; + UCHAR bNumAlternateModes = 0; + UCHAR alternateModeConfiguration = 0; + UCHAR adjustedBLength = 0; + + AppendTextBuffer("\r\n ===>Billboard Capability Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X", + billboardCapDesc->bLength); + + adjustedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) + + sizeof(billboardCapDesc->AlternateMode[0]) * (billboardCapDesc->bNumberOfAlternateModes - 1); + AppendTextBuffer(" -> Actual Length: 0x%02X\r\n", adjustedBLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + billboardCapDesc->bDescriptorType); + AppendTextBuffer("bDevCapabilityType: 0x%02X -> Billboard capability\r\n", + billboardCapDesc->bDevCapabilityType); + AppendTextBuffer("iAdditionalInfoURL: 0x%02X ->", + billboardCapDesc->iAddtionalInfoURL); + if (billboardCapDesc->iAddtionalInfoURL && gDoAnnotation) { + DisplayStringDescriptor(billboardCapDesc->iAddtionalInfoURL, + StringDescs, + info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified); + } + AppendTextBuffer("bNumberOfAlternateModes: 0x%02X\r\n", + billboardCapDesc->bNumberOfAlternateModes); + + if (billboardCapDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) + { + AppendTextBuffer("*!*ERROR: Invalid bNumberofAlternateModes\r\n"); + } + AppendTextBuffer("bPreferredAlternateMode: 0x%02X\r\n", + billboardCapDesc->bPreferredAlternateMode); + + AppendTextBuffer("VCONN Power: 0x%04X", + billboardCapDesc->VconnPower); + + if (billboardCapDesc->VconnPower.NoVconnPowerRequired) + { + AppendTextBuffer(" -> The adapter does not require Vconn Power. Bits 2..0 ignored\r\n"); + } + else + { + switch (billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality) + { + case 0: + AppendTextBuffer(" -> 1W needed by adapter for full functionality\r\n"); + break; + case 1: + AppendTextBuffer(" -> 1.5W needed by adapter for full functionality\r\n"); + break; + case 7: + AppendTextBuffer(" -> *!*ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used\r\n"); + break; + default: + AppendTextBuffer(" -> %2XW needed by adapter for full functionality\r\n", billboardCapDesc->VconnPower.VConnPowerNeededForFullFunctionality); + } + } + + if (billboardCapDesc->VconnPower.Reserved) + { + AppendTextBuffer("*!*ERROR: Reserved bits in VCONN Power being used\r\n"); + } + if (billboardCapDesc->bReserved) + { + AppendTextBuffer("*!*ERROR: bReserved being used\r\n"); + } + + + bNumAlternateModes = billboardCapDesc->bNumberOfAlternateModes; + if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) + { + bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE; + } + if (bNumAlternateModes > 0) + { + AppendTextBuffer("\r\nAlternate Modes Identified:\r\n"); + } + for (i = 0; i < bNumAlternateModes; i++) + { + alternateModeConfiguration = ((billboardCapDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3; + AppendTextBuffer("wSVID - 0x%04X bAlternateMode - 0x%02X ->", + billboardCapDesc->AlternateMode[i].wSVID, + billboardCapDesc->AlternateMode[i].bAlternateMode, + billboardCapDesc->AlternateMode[i].iAlternateModeSetting); + + switch (alternateModeConfiguration) + { + case 0: + AppendTextBuffer("Unspecified Error\r\n"); + break; + case 1: + AppendTextBuffer("Alternate Mode configuration not attempted\r\n"); + break; + case 2: + AppendTextBuffer("Alternate Mode configuration attempted but unsuccessful\r\n"); + break; + case 3: + AppendTextBuffer("Alternate Mode configuration successful\r\n"); + break; + } + AppendTextBuffer("iAlternateModeString - 0x%02X ", billboardCapDesc->AlternateMode[i].iAlternateModeSetting); + if (billboardCapDesc->AlternateMode[i].iAlternateModeSetting && gDoAnnotation) + { + DisplayStringDescriptor(billboardCapDesc->AlternateMode[i].iAlternateModeSetting, + StringDescs, + info->DeviceInfoNode != NULL ? info->DeviceInfoNode->LatestDevicePowerState : PowerDeviceUnspecified); + } + else + { + AppendTextBuffer("\r\n"); + } + AppendTextBuffer("\r\n"); + } +} + + /***************************************************************************** DisplayBosDescriptor() @@ -2685,7 +2835,9 @@ BosDesc - The Binary Object Store (BOS) Descriptor, and associated Descriptors VOID DisplayBosDescriptor ( - PUSB_BOS_DESCRIPTOR BosDesc + PUSBDEVICEINFO info, + PUSB_BOS_DESCRIPTOR BosDesc, + PSTRING_DESCRIPTOR_NODE StringDescs ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; @@ -2726,6 +2878,9 @@ DisplayBosDescriptor ( case USB_DEVICE_CAPABILITY_CONTAINER_ID: DisplayContainerIdCapabilityExtensionDescriptor((PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc); break; + case USB_DEVICE_CAPABILITY_BILLBOARD: + DisplayBillboardCapabilityDescriptor((PUSBDEVICEINFO) info, (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc, StringDescs); + break; default: AppendTextBuffer("\r\n ===>Unknown Capability Descriptor<===\r\n"); @@ -3183,6 +3338,19 @@ DisplayInterfaceDescriptor ( AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", InterfaceDesc->bInterfaceSubClass); break; + case USB_DEVICE_CLASS_BILLBOARD: + AppendTextBuffer(" -> Billboard Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X", InterfaceDesc->bInterfaceSubClass); + switch (InterfaceDesc->bInterfaceSubClass) + { + case 0: + AppendTextBuffer(" -> Billboard Subclass\r\n"); + break; + default: + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); + break; + } + break; default: if(gDoAnnotation) diff --git a/usb/usbview/usbdesc.h b/usb/usbview/usbdesc.h index 5b2622a2..23420cfe 100644 --- a/usb/usbview/usbdesc.h +++ b/usb/usbview/usbdesc.h @@ -34,6 +34,7 @@ Revision History: #define USB_INTERFACE_CLASS_DEVICE 0x00 #define USB_COMMUNICATION_DEVICE 0x02 #define USB_HUB_DEVICE 0x09 +#define USB_DEVICE_CLASS_BILLBOARD 0x11 #define USB_DIAGNOSTIC_DEVICE 0xDC #define USB_WIRELESS_CONTROLLER_DEVICE 0xE0 #define USB_MISCELLANEOUS_DEVICE 0xEF @@ -70,6 +71,11 @@ Revision History: #define USB_IAD_PROTOCOL 0x01 // +//Device class specific values +// +#define BILLBOARD_MAX_NUM_ALT_MODE 0x34 + +// //USB 2.0 Specification Changes - New Descriptors // #define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE 0x07 diff --git a/usb/usbview/usbview.sln b/usb/usbview/usbview.sln index d06846d8..5993209e 100644 --- a/usb/usbview/usbview.sln +++ b/usb/usbview/usbview.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbview", "usbview.vcxproj", "{53F7289B-2210-4DCD-9A41-D83DE76A7372}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbview", "usbview.vcxproj", "{3C291787-8A37-4E8C-86D5-0B739A1CEA74}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|Win32.ActiveCfg = Debug|Win32 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|Win32.Build.0 = Debug|Win32 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|Win32.ActiveCfg = Release|Win32 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|Win32.Build.0 = Release|Win32 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|x64.ActiveCfg = Debug|x64 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Debug|x64.Build.0 = Debug|x64 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|x64.ActiveCfg = Release|x64 - {53F7289B-2210-4DCD-9A41-D83DE76A7372}.Release|x64.Build.0 = Release|x64 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Debug|Win32.ActiveCfg = Debug|Win32 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Debug|Win32.Build.0 = Debug|Win32 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Release|Win32.ActiveCfg = Release|Win32 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Release|Win32.Build.0 = Release|Win32 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Debug|x64.ActiveCfg = Debug|x64 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Debug|x64.Build.0 = Debug|x64 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Release|x64.ActiveCfg = Release|x64 + {3C291787-8A37-4E8C-86D5-0B739A1CEA74}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/usb/usbview/usbview.vcxproj b/usb/usbview/usbview.vcxproj index 2b1fe15d..bccb6d76 100644 --- a/usb/usbview/usbview.vcxproj +++ b/usb/usbview/usbview.vcxproj @@ -19,11 +19,11 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{53F7289B-2210-4DCD-9A41-D83DE76A7372}</ProjectGuid> + <ProjectGuid>{3C291787-8A37-4E8C-86D5-0B739A1CEA74}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{5310F3E1-F715-4C85-8EEE-BD30F52FD176}</SampleGuid> + <SampleGuid>{0B5874D8-CA5A-4459-9471-A4D9CBD82977}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -168,7 +168,6 @@ <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" /> diff --git a/usb/usbview/usbview.vcxproj.Filters b/usb/usbview/usbview.vcxproj.Filters index 0688fd3e..ee2d7801 100644 --- a/usb/usbview/usbview.vcxproj.Filters +++ b/usb/usbview/usbview.vcxproj.Filters @@ -3,15 +3,15 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{902F6120-4AA1-4898-A1FD-6A44ADCFA148}</UniqueIdentifier> + <UniqueIdentifier>{24B15DD5-41FB-4742-A3C7-A074316B3FFD}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{B764DF51-5FA0-4F05-B3AE-E7ABC15ABE89}</UniqueIdentifier> + <UniqueIdentifier>{52B35399-50CE-420D-B0C6-D6D79A82EF43}</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>{1B5253D4-F3D5-4321-9E40-0E3E74955606}</UniqueIdentifier> + <UniqueIdentifier>{5DBEED0A-531F-4DD9-8C19-89D7EF22449E}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/usb/usbview/xmlhelper.cpp b/usb/usbview/xmlhelper.cpp index 4221aeb0..cf39a87d 100644 --- a/usb/usbview/xmlhelper.cpp +++ b/usb/usbview/xmlhelper.cpp @@ -200,7 +200,10 @@ array < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors( PUSBDEVICEINFO deviceInfo, PUSB_CONFIGURATION_DESCRIPTOR configDescs, PSTRING_DESCRIPTOR_NODE stringDesc); -UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc); +UsbBosDescriptorType ^ XmlGetBosDescriptor( + PUSB_BOS_DESCRIPTOR bosDesc, + PSTRING_DESCRIPTOR_NODE stringDesc + ); UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR deviceClass, UCHAR deviceSubClass, UCHAR deviceProtocol); UsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor( PUSB_COMMON_DESCRIPTOR unknownDesc @@ -214,6 +217,10 @@ UsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescri UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor( PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc ); +UsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor( + PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc, + PSTRING_DESCRIPTOR_NODE stringDesc + ); /***************************************************************************** D E F I N I T I O N S @@ -1525,7 +1532,18 @@ UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR bInterfaceClass, UCHAR bInterfaceSu deviceSubclass += bInterfaceSubclass; } break; - + case USB_DEVICE_CLASS_BILLBOARD: + deviceClass = gcnew String("Billboard Class"); + switch (bInterfaceSubclass) + { + case 0: + deviceSubclass = gcnew String("Billboard Subclass"); + break; + default: + deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubClass"); + break; + } + break; default: deviceClass = gcnew String("Interface Class unknown : "); @@ -2118,6 +2136,10 @@ String ^ XmlGetDeviceClassString(UCHAR deviceClass) deviceClassStr = gcnew String("Vendor specific device"); break; + case USB_DEVICE_CLASS_BILLBOARD: + deviceClassStr = gcnew String("Billboard class device"); + break; + default: deviceClassStr= gcnew String("ERROR: unknown bDeviceClass" + deviceClass); break; @@ -2186,6 +2208,13 @@ bool XmlAddDeviceClassDetails( { deviceDetails->DeviceType = XmlGetDeviceClassString(connectionInfo->DeviceDescriptor.bDeviceClass); + if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_BILLBOARD && + (connectionInfo->DeviceDescriptor.bDeviceSubClass != 0x0 || + connectionInfo->DeviceDescriptor.bDeviceProtocol != 0x0)) + { + deviceDetails->DeviceTypeError = gcnew String("ERROR: Billboard device has invalid bDeviceSubclass/bDeviceProtocol"); + } + if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) { deviceDetails->DeviceTypeError = gcnew String("ERROR: Multi-interface Function code " + @@ -2443,7 +2472,7 @@ HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo) // Add BOS descriptor if (NULL != ehInfo->BosDesc) { - exHub->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (ehInfo->BosDesc + 1)); + exHub->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (ehInfo->BosDesc + 1), ehInfo->StringDescs); } gXmlStack->Push(exHub); @@ -2461,7 +2490,10 @@ HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo) Gets the Bos descriptor object for given BOS descriptor *****************************************************************************/ -UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc) +UsbBosDescriptorType ^ XmlGetBosDescriptor( + PUSB_BOS_DESCRIPTOR bosDesc, + PSTRING_DESCRIPTOR_NODE stringDesc + ) { PUSB_COMMON_DESCRIPTOR commonDesc = NULL; PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL; @@ -2470,6 +2502,7 @@ UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc) ArrayList ^usbSuperSpeedExtDescList = gcnew ArrayList(); ArrayList ^usbContIdCapExtDescList = gcnew ArrayList(); ArrayList ^usbUnknownDescList = gcnew ArrayList(); + ArrayList ^usbBillboardDescList = gcnew ArrayList(); if(NULL == bosDesc) { @@ -2517,6 +2550,14 @@ UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc) ) ); break; + case USB_DEVICE_CAPABILITY_BILLBOARD: + usbBillboardDescList->Add( + XmlGetBillboardCapabilityDescriptor( + (PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) capDesc, + stringDesc + ) + ); + break; default: usbUnknownDescList->Add( XmlGetUnknownDescriptor( @@ -2545,6 +2586,9 @@ UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc) bosXmlDesc->UsbDispContIdCapExtDescriptor = reinterpret_cast<array<UsbDispContIdCapExtDescriptorType ^>^> ( usbContIdCapExtDescList->ToArray(UsbDispContIdCapExtDescriptorType::typeid) ); + bosXmlDesc->UsbBillboardCapabilityDescriptor = reinterpret_cast<array<UsbBillboardCapabilityDescriptorType ^>^> ( + usbBillboardDescList->ToArray(UsbBillboardCapabilityDescriptorType::typeid) + ); return bosXmlDesc; } @@ -2733,6 +2777,125 @@ UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescript return capXmlDesc; } + +/***************************************************************************** + +XmlGetBillboardCapabilityDescriptor() + +Gets a billboard capability descriptor from a given descriptor +*****************************************************************************/ +UsbBillboardCapabilityDescriptorType ^ XmlGetBillboardCapabilityDescriptor( + PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR capDesc, + PSTRING_DESCRIPTOR_NODE stringDesc + ) +{ + UCHAR i = 0; + UCHAR bNumAlternateModes = 0; + UCHAR alternateModeConfiguration = 0; + UsbBillboardCapabilityDescriptorType ^ capXmlDesc = nullptr; + UsbBillboardSVIDType ^ svidXmlDesc = nullptr; + ArrayList ^ usbSVIDDescList = gcnew ArrayList(); + + + if (NULL == capDesc) + { + return nullptr; + } + + capXmlDesc = gcnew UsbBillboardCapabilityDescriptorType(); + + + capXmlDesc->BLength = capDesc->bLength; + capXmlDesc->BDescriptorType = capDesc->bDescriptorType; + capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; + capXmlDesc->IAddtionalInfoURL = capDesc->iAddtionalInfoURL; + capXmlDesc->BNumberOfAlternateModes = capDesc->bNumberOfAlternateModes; + capXmlDesc->BPreferredAlternateMode = capDesc->bPreferredAlternateMode; + capXmlDesc->CalculatedBLength = sizeof(USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR) + + sizeof(capDesc->AlternateMode[0]) * (capDesc->bNumberOfAlternateModes - 1); + capXmlDesc->BillboardDescriptorErrors = gcnew String(""); + capXmlDesc->AddtionalInfoURL = XmlGetStringDescriptor( + capDesc->iAddtionalInfoURL, + stringDesc, + false + ); + + if (capDesc->VconnPower.NoVconnPowerRequired) + { + capXmlDesc->VConnPower = gcnew String("The adapter does not require Vconn Power. Bits 2..0 ignored"); + } + else + { + switch (capDesc->VconnPower.VConnPowerNeededForFullFunctionality) + { + case 0: + capXmlDesc->VConnPower = gcnew String("1W needed by adapter for full functionality"); + break; + case 1: + capXmlDesc->VConnPower = gcnew String("1.5W needed by adapter for full functionality"); + break; + case 7: + capXmlDesc->BillboardDescriptorErrors += "ERROR: VConnPowerNeededForFullFunctionality - Reserved value being used"; + break; + default: + capXmlDesc->VConnPower = gcnew String(String::Format("{0} W needed by adapter for full functionality", capDesc->VconnPower.VConnPowerNeededForFullFunctionality)); + } + } + + if (capDesc->bNumberOfAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) + { + capXmlDesc->BillboardDescriptorErrors += "ERROR: Invalid bNumberofAlternateModes; "; + } + if (capDesc->VconnPower.Reserved) + { + capXmlDesc->BillboardDescriptorErrors += "ERROR: Reserved bits in VCONN Power being used; "; + } + if (capDesc->bReserved) + { + capXmlDesc->BillboardDescriptorErrors += "ERROR: bReserved being used; "; + } + + bNumAlternateModes = capDesc->bNumberOfAlternateModes; + if (bNumAlternateModes > BILLBOARD_MAX_NUM_ALT_MODE) + { + bNumAlternateModes = BILLBOARD_MAX_NUM_ALT_MODE; + } + for (i = 0; i < bNumAlternateModes; i++) + { + svidXmlDesc = gcnew UsbBillboardSVIDType(); + alternateModeConfiguration = ((capDesc->bmConfigured[i / 4]) >> ((i % 4) * 2)) & 0x3; + svidXmlDesc->WSVID = capDesc->AlternateMode[i].wSVID; + svidXmlDesc->BAlternateMode = capDesc->AlternateMode[i].bAlternateMode; + svidXmlDesc->IAlternateModeString = capDesc->AlternateMode[i].iAlternateModeSetting; + svidXmlDesc->AlternateModeString = XmlGetStringDescriptor( + capDesc->AlternateMode[i].iAlternateModeSetting, + stringDesc, + false + ); + + switch (alternateModeConfiguration) + { + case 0: + svidXmlDesc->Description = gcnew String("Unspecified Error"); + break; + case 1: + svidXmlDesc->Description = gcnew String("Alternate Mode configuration not attempted"); + break; + case 2: + svidXmlDesc->Description = gcnew String("Alternate Mode configuration attempted but unsuccessful"); + break; + case 3: + svidXmlDesc->Description = gcnew String("Alternate Mode configuration successful"); + break; + } + usbSVIDDescList->Add(svidXmlDesc); + } + capXmlDesc->UsbBillboardSVID = reinterpret_cast<array<UsbBillboardSVIDType ^>^> ( + usbSVIDDescList->ToArray(UsbBillboardSVIDType::typeid)); + + return capXmlDesc; +} + /***************************************************************************** XmlAddUsbDevice() @@ -2852,7 +3015,10 @@ HRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo) // Add BOS descriptor if (NULL != deviceInfo->BosDesc) { - usbDevice->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (deviceInfo->BosDesc + 1)); + usbDevice->BosDescriptor = XmlGetBosDescriptor( + (PUSB_BOS_DESCRIPTOR) (deviceInfo->BosDesc + 1), + deviceInfo->StringDescs + ); } } else |
