From 96015c3cf0c1a37de5bb1a713f9dfbb8f41200bd Mon Sep 17 00:00:00 2001 From: KyungWoon Cho Date: Tue, 30 Jun 2020 22:09:15 +0900 Subject: [PATCH] new vhci driver based on kmdf UDE The old WDM-based vhci could not fully support USB libraries and applications such as #111 because it did not implement many USB host contoller & hub functionalities. They were impossible to be properly developed with poor MS documents. However, MS has already implemented most things via USB device emulation(UDE). Now, usbip-win provides a vhci driver using UDE. It is experimental and more tests are required. --- README.md | 56 ++-- driver/vhci_ude/custom_wpp.ini | 15 + driver/vhci_ude/gencat.bat | 11 + driver/vhci_ude/usbip_vhci_ude.inf | 86 +++++ driver/vhci_ude/usbip_vhci_ude.vcxproj | 260 +++++++++++++++ .../vhci_ude/usbip_vhci_ude.vcxproj.filters | 132 ++++++++ driver/vhci_ude/vhci_dbg.c | 157 +++++++++ driver/vhci_ude/vhci_dbg.h | 16 + driver/vhci_ude/vhci_dev.h | 65 ++++ driver/vhci_ude/vhci_driver.c | 44 +++ driver/vhci_ude/vhci_driver.h | 21 ++ driver/vhci_ude/vhci_ep.c | 188 +++++++++++ driver/vhci_ude/vhci_hc.c | 150 +++++++++ driver/vhci_ude/vhci_ioctl.c | 140 ++++++++ driver/vhci_ude/vhci_plugin.c | 165 ++++++++++ driver/vhci_ude/vhci_plugout.c | 126 +++++++ driver/vhci_ude/vhci_proto.c | 48 +++ driver/vhci_ude/vhci_queue_ep.c | 62 ++++ driver/vhci_ude/vhci_queue_hc.c | 35 ++ driver/vhci_ude/vhci_read.c | 121 +++++++ driver/vhci_ude/vhci_trace.h | 55 ++++ driver/vhci_ude/vhci_urbr.c | 276 ++++++++++++++++ driver/vhci_ude/vhci_urbr.h | 57 ++++ driver/vhci_ude/vhci_urbr_fetch.c | 119 +++++++ driver/vhci_ude/vhci_urbr_fetch_bulk.c | 20 ++ driver/vhci_ude/vhci_urbr_fetch_control.c | 32 ++ driver/vhci_ude/vhci_urbr_fetch_dscr.c | 17 + driver/vhci_ude/vhci_urbr_fetch_iso.c | 71 ++++ driver/vhci_ude/vhci_urbr_fetch_status.c | 17 + driver/vhci_ude/vhci_urbr_fetch_vendor.c | 23 ++ driver/vhci_ude/vhci_urbr_store.c | 184 +++++++++++ driver/vhci_ude/vhci_urbr_store_bulk.c | 66 ++++ driver/vhci_ude/vhci_urbr_store_control.c | 156 +++++++++ driver/vhci_ude/vhci_urbr_store_dscr.c | 70 ++++ driver/vhci_ude/vhci_urbr_store_iso.c | 110 +++++++ driver/vhci_ude/vhci_urbr_store_select.c | 48 +++ driver/vhci_ude/vhci_urbr_store_status.c | 53 +++ driver/vhci_ude/vhci_urbr_store_vendor.c | 103 ++++++ driver/vhci_ude/vhci_write.c | 75 +++++ include/usbip_vhci_api.h | 15 +- usbip_win.sln | 14 + userspace/lib/usbip_forward.c | 3 + userspace/src/usbip/usbip.c | 18 + userspace/src/usbip/usbip.h | 3 + userspace/src/usbip/usbip.vcxproj | 4 + userspace/src/usbip/usbip_attach_ude.c | 244 ++++++++++++++ userspace/src/usbip/usbip_dscr.c | 86 +++++ userspace/src/usbip/usbip_dscr.h | 11 + userspace/src/usbip/usbip_install_ude.c | 308 ++++++++++++++++++ userspace/src/usbip/usbip_vhci.c | 16 +- userspace/src/usbip/usbip_vhci.h | 2 + 51 files changed, 4150 insertions(+), 24 deletions(-) create mode 100644 driver/vhci_ude/custom_wpp.ini create mode 100644 driver/vhci_ude/gencat.bat create mode 100644 driver/vhci_ude/usbip_vhci_ude.inf create mode 100644 driver/vhci_ude/usbip_vhci_ude.vcxproj create mode 100644 driver/vhci_ude/usbip_vhci_ude.vcxproj.filters create mode 100644 driver/vhci_ude/vhci_dbg.c create mode 100644 driver/vhci_ude/vhci_dbg.h create mode 100644 driver/vhci_ude/vhci_dev.h create mode 100644 driver/vhci_ude/vhci_driver.c create mode 100644 driver/vhci_ude/vhci_driver.h create mode 100644 driver/vhci_ude/vhci_ep.c create mode 100644 driver/vhci_ude/vhci_hc.c create mode 100644 driver/vhci_ude/vhci_ioctl.c create mode 100644 driver/vhci_ude/vhci_plugin.c create mode 100644 driver/vhci_ude/vhci_plugout.c create mode 100644 driver/vhci_ude/vhci_proto.c create mode 100644 driver/vhci_ude/vhci_queue_ep.c create mode 100644 driver/vhci_ude/vhci_queue_hc.c create mode 100644 driver/vhci_ude/vhci_read.c create mode 100644 driver/vhci_ude/vhci_trace.h create mode 100644 driver/vhci_ude/vhci_urbr.c create mode 100644 driver/vhci_ude/vhci_urbr.h create mode 100644 driver/vhci_ude/vhci_urbr_fetch.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_bulk.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_control.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_dscr.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_iso.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_status.c create mode 100644 driver/vhci_ude/vhci_urbr_fetch_vendor.c create mode 100644 driver/vhci_ude/vhci_urbr_store.c create mode 100644 driver/vhci_ude/vhci_urbr_store_bulk.c create mode 100644 driver/vhci_ude/vhci_urbr_store_control.c create mode 100644 driver/vhci_ude/vhci_urbr_store_dscr.c create mode 100644 driver/vhci_ude/vhci_urbr_store_iso.c create mode 100644 driver/vhci_ude/vhci_urbr_store_select.c create mode 100644 driver/vhci_ude/vhci_urbr_store_status.c create mode 100644 driver/vhci_ude/vhci_urbr_store_vendor.c create mode 100644 driver/vhci_ude/vhci_write.c create mode 100644 userspace/src/usbip/usbip_attach_ude.c create mode 100644 userspace/src/usbip/usbip_dscr.c create mode 100644 userspace/src/usbip/usbip_dscr.h create mode 100644 userspace/src/usbip/usbip_install_ude.c diff --git a/README.md b/README.md index aa30a298..f92d8c77 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ - Tested on Ubuntu 16.04 - Kernel 4.15.0-29 (USB/IP kernel module crash was observed on some other version) - `# modprobe vhci-hcd` - - Install USB/IP test certificate - Install `driver/usbip_test.pfx` (password: usbip) - Certificate should be installed into @@ -70,7 +69,6 @@ usbip.exe list -l - Run `usbipd.exe` - `> usbipd.exe -d -4` - TCP port `3240` should be allowed by firewall - - Attach USB/IP device on linux machine - `# usbip attach -r -b 1-59` @@ -80,10 +78,8 @@ usbip.exe list -l - tested on Ubuntu 16.04 (Kernerl 4.15.0-29) - `# modprobe usbip-host` - You can use virtual [usbip-vstub](https://github.com/cezanne/usbip-vstub) as a stub server - - Run usbipd on a USB/IP server (Linux) - `# usbipd -4 -d` - - Install USB/IP test certificate - Install `driver/usbip_test.pfx` (password: usbip) - Certificate should be installed into @@ -92,27 +88,44 @@ usbip.exe list -l - Enable test signing - `> bcdedit.exe /set TESTSIGNING ON` - reboot the system to apply -- Copy `usbip.exe`, `usbip_vhci.sys`, `usbip_vhci.inf`, `usbip_root.inf`, `usbip_vhci.cat` into a folder in target machine +- Copy vhci driver files into a folder in target machine + - Currently, there are 2 versions for a vhci driver: vhci(old) and vhci(ude) + - vhci(ude) is newly developed to fully support USB applications using MS UDE framework. + - If you're testing vhci(ude), copy `usbip.exe`, `usbip_vhci_udf.sys`, `usbip_vhci_udf.inf`, `usbip_vhci_udf.cat` into a folder in target machine + - If you're testing vhci(old), copy `usbip.exe`, `usbip_vhci.sys`, `usbip_vhci.inf`, `usbip_root.inf`, `usbip_vhci.cat` into a folder in target machine - You can find all files in output folder after build or on [release](https://github.com/cezanne/usbip-win/releases) page. - Install USB/IP VHCI driver - You can install using usbip.exe or manually - - Using usbip.exe install command - - Run PowerShell or CMD as an Administrator - - `PS> usbip.exe install` - - Install manually - - Run PowerShell or CMD as an Administrator - - `PS> pnputil /add-driver usbip_vhci.inf` - - Start Device manager - - Choose "Add Legacy Hardware" from the "Action" menu. - - Select "Install the hardware that I manually select from the list". - - Click "Next". - - Click "Have Disk", click "Browse", choose the copied folder, and click "OK". - - Click on the "USB/IP VHCI Root", and then click "Next". - - Click Finish at "Completing the Add/Remove Hardware Wizard". + - Using usbip.exe install command + - Run PowerShell or CMD as an Administrator + - if using vhci(ude), `PS> usbip.exe install_ude` + - if using vhci(old), `PS> usbip.exe install` + - Install manually(new ude vhci) + - Run PowerShell or CMD as an Administrator + - `PS> pnputil /add-driver usbip_vhci_ude.inf` + - Start Device manager + - Choose "Add Legacy Hardware" from the "Action" menu. + - Select "Install the hardware that I manually select from the list". + - Click "Next". + - Click "Have Disk", click "Browse", choose the copied folder, and click "OK". + - Click on the "usbip-win VHCI(ude)", and then click "Next". + - Click Finish at "Completing the Add/Remove Hardware Wizard". + - Install manually(old vhci) + - Run PowerShell or CMD as an Administrator + - `PS> pnputil /add-driver usbip_vhci.inf` + - Start Device manager + - Choose "Add Legacy Hardware" from the "Action" menu. + - Select "Install the hardware that I manually select from the list". + - Click "Next". + - Click "Have Disk", click "Browse", choose the copied folder, and click "OK". + - Click on the "USB/IP VHCI Root", and then click "Next". + - Click Finish at "Completing the Add/Remove Hardware Wizard". - Attach a remote USB device - - `> usbip.exe attach -r -b 2-2` + - if using vhci(ude), `> usbip.exe attach_ude -r -b 2-2` + - if using vhci(old), `> usbip.exe attach -r -b 2-2` - Uninstall driver - - `PS> usbip.exe uninstall` + - if using vhci(ude), `PS> usbip.exe uninstall_ude` + - if using vhci(old),`PS> usbip.exe uninstall` ### Reporting Bug - usbip-win is not yet ready for production use. We could find problems with more detailed logs. @@ -143,8 +156,9 @@ Windows Registry Editor Version 5.00 #### How to get linux kernel log - Sometimes linux kernel log is required + ``` -# dmesg --follow | tee kernel_log.txt +\# dmesg --follow | tee kernel_log.txt ```
diff --git a/driver/vhci_ude/custom_wpp.ini b/driver/vhci_ude/custom_wpp.ini new file mode 100644 index 00000000..21bca30b --- /dev/null +++ b/driver/vhci_ude/custom_wpp.ini @@ -0,0 +1,15 @@ +DEFINE_CPLX_TYPE(SETUPPKT, DBG_SETUPPKT, PCUCHAR, ItemString, "s", _SETUPPKT_, 0, 1); +WPP_FLAGS(-DDBG_SETUPPKT(x) WPP_LOGPAIR(1024, dbg_usb_setup_packet(x))); +DEFINE_CPLX_TYPE(URBR, WPP_URBR, purb_req_t, ItemString, "s", _URBR_, 0, 1); +WPP_FLAGS(-DWPP_URBR(x) WPP_LOGPAIR((128), (dbg_urbr(x)))); +DEFINE_CPLX_TYPE(URBFUNC, WPP_URBFUNC, USHORT, ItemString, "s", _URBFUNC_, 0, 1); +WPP_FLAGS(-DWPP_URBFUNC(x) WPP_LOGPAIR((256), (dbg_urbfunc(x)))); +DEFINE_CPLX_TYPE(IOCTL, WPP_IOCTL, unsigned int, ItemString, "s", _IOCTL_, 0, 1); +WPP_FLAGS(-DWPP_IOCTL(x) WPP_LOGPAIR((256), (dbg_vhci_ioctl_code(x)))); +USEPREFIX (TRD, " %!FUNC!:"); +USEPREFIX (TRW, "(WW)%!FUNC!:"); +USEPREFIX (TRE, "(EE)%!FUNC!:"); +FUNC TRD{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS, MSG, ...); +FUNC TRW{LEVEL=TRACE_LEVEL_WARNING}(FLAGS, MSG, ...); +FUNC TRE{LEVEL=TRACE_LEVEL_ERROR}(FLAGS, MSG, ...); +CUSTOM_TYPE(epconf, ItemEnum(_UDECX_ENDPOINTS_CONFIGURE_TYPE)); \ No newline at end of file diff --git a/driver/vhci_ude/gencat.bat b/driver/vhci_ude/gencat.bat new file mode 100644 index 00000000..32880d13 --- /dev/null +++ b/driver/vhci_ude/gencat.bat @@ -0,0 +1,11 @@ +cd %1 +if exist vhci_ude_cat del /s /q vhci_ude_cat +mkdir vhci_ude_cat +cd vhci_ude_cat +copy ..\usbip_vhci_ude.sys +copy ..\usbip_vhci_ude.inf +inf2cat /driver:.\ /os:%2 /uselocaltime +signtool sign /f %3 /p usbip usbip_vhci_ude.cat +copy /y usbip_vhci_ude.cat .. +cd .. +del /s /q vhci_ude_cat diff --git a/driver/vhci_ude/usbip_vhci_ude.inf b/driver/vhci_ude/usbip_vhci_ude.inf new file mode 100644 index 00000000..74544826 --- /dev/null +++ b/driver/vhci_ude/usbip_vhci_ude.inf @@ -0,0 +1,86 @@ +; +; usbip_vhci_ude.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=USB +ClassGuid={36FC9E60-C465-11CF-8056-444553540000} +Provider=%ManufacturerName% +CatalogFile=usbip_vhci_ude.cat +DriverVer= + +[DestinationDirs] +DefaultDestDir = 12 +vhci_Device_CoInstaller_CopyFiles = 11 + +[SourceDisksNames] +1 = %DiskName%,,,"" + +[SourceDisksFiles] +usbip_vhci_ude.sys = 1,, +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +;***************************************** +; Install Section +;***************************************** + +[Manufacturer] +%ManufacturerName%=Standard,NT$ARCH$ + +[Standard.NT$ARCH$] +%vhci.DeviceDesc%=vhci_Device, ROOT\VHCI_ude + +[vhci_Device.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +usbip_vhci_ude.sys + +[vhci_Device.NT.HW] +AddReg=vhci_AddReg + +[vhci_AddReg] +; By default, USBDevice class uses iProduct descriptor to name the device in +; Device Manager on Windows 8 and higher. +; Uncomment for this device to use %DeviceName% on Windows 8 and higher: +;HKR,,FriendlyName,,%vhci.DeviceDesc% + +;-------------- Service installation +[vhci_Device.NT.Services] +AddService = usbip_vhci_ude,%SPSVCINST_ASSOCSERVICE%, vhci_Service_Inst + +; -------------- vhci driver install sections +[vhci_Service_Inst] +DisplayName = %vhci.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\usbip_vhci_ude.sys + +; +;--- vhci_Device Coinstaller installation ------ +; + +[vhci_Device.NT.CoInstallers] +AddReg=vhci_Device_CoInstaller_AddReg +CopyFiles=vhci_Device_CoInstaller_CopyFiles + +[vhci_Device_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[vhci_Device_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[vhci_Device.NT.Wdf] +KmdfService = usbip_vhci_ude, usbip_vhci_wdfsect +[usbip_vhci_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +ManufacturerName="usbip-win project" +DiskName = "usbip-win VHCI(ude) Disk" +vhci.DeviceDesc = "usbip-win VHCI(ude)" +vhci.SVCDESC = "usbip-win vhci(ude) Service" +REG_MULTI_SZ = 0x00010000 diff --git a/driver/vhci_ude/usbip_vhci_ude.vcxproj b/driver/vhci_ude/usbip_vhci_ude.vcxproj new file mode 100644 index 00000000..07b3fc00 --- /dev/null +++ b/driver/vhci_ude/usbip_vhci_ude.vcxproj @@ -0,0 +1,260 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA} + {8c0e3d8b-df43-455b-815a-4a0e72973bc6} + v4.5 + 12.0 + Debug + Win32 + kmdf + usbip_vhci_ude + $(LatestTargetPlatformVersion) + + + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + + Windows10 + true + true + 1 + 0 + + + Windows10 + false + true + 1 + 0 + + + Windows10 + true + true + 1 + 0 + + + Windows10 + false + true + 1 + 0 + + + + + + + + + + + DbgengKernelDebugger + $(SolutionDir)$(ConfigurationName)\$(Platform)\ + $(SolutionDir)$(ConfigurationName)\$(Platform)\$(ProjectName)\ + $(TargetName.Replace(' ','')) + true + false + + + DbgengKernelDebugger + $(SolutionDir)$(ConfigurationName)\$(Platform)\ + $(SolutionDir)$(ConfigurationName)\$(Platform)\$(ProjectName)\ + $(TargetName.Replace(' ','')) + true + false + + + DbgengKernelDebugger + $(SolutionDir)$(ConfigurationName)\$(Platform)\ + $(SolutionDir)$(ConfigurationName)\$(Platform)\$(ProjectName)\ + $(TargetName.Replace(' ','')) + true + false + + + DbgengKernelDebugger + $(SolutionDir)$(ConfigurationName)\$(Platform)\ + $(SolutionDir)$(ConfigurationName)\$(Platform)\$(ProjectName)\ + $(TargetName.Replace(' ','')) + true + false + + + + true + true + vhci_trace.h + true + ..\..\include;..\lib;$(IntDir);%(AdditionalIncludeDirectories) + %(WppPreprocessorDefinitions) + custom_wpp.ini + + + %(AdditionalDependencies);ntstrsafe.lib + + + gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)\driver\usbip_test.pfx + + + 0.5.0.0 + + + + + true + true + vhci_trace.h + true + ..\..\include;..\lib;$(IntDir);%(AdditionalIncludeDirectories) + %(WppPreprocessorDefinitions) + custom_wpp.ini + + + %(AdditionalDependencies);ntstrsafe.lib + + + gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)\driver\usbip_test.pfx + + + 0.5.0.0 + + + + + true + true + vhci_trace.h + true + ..\..\include;..\lib;$(IntDir);%(AdditionalIncludeDirectories) + %(WppPreprocessorDefinitions) + custom_wpp.ini + + + %(AdditionalDependencies);ntstrsafe.lib + $(OutDir)$(TargetName)$(TargetExt) + + + gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)\driver\usbip_test.pfx + + + 0.5.0.0 + + + + + true + true + vhci_trace.h + true + ..\..\include;..\lib;$(IntDir);%(AdditionalIncludeDirectories) + %(WppPreprocessorDefinitions) + custom_wpp.ini + + + %(AdditionalDependencies);ntstrsafe.lib + + + gencat.bat $(OutDir) 10_$(DDKPlatform) $(SolutionDir)\driver\usbip_test.pfx + + + 0.5.0.0 + + + + + + + + {27ab4325-4980-4634-9818-ae6bd61de532} + + + + + + + + + \ No newline at end of file diff --git a/driver/vhci_ude/usbip_vhci_ude.vcxproj.filters b/driver/vhci_ude/usbip_vhci_ude.vcxproj.filters new file mode 100644 index 00000000..69cdc756 --- /dev/null +++ b/driver/vhci_ude/usbip_vhci_ude.vcxproj.filters @@ -0,0 +1,132 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + Driver Files + + + \ No newline at end of file diff --git a/driver/vhci_ude/vhci_dbg.c b/driver/vhci_ude/vhci_dbg.c new file mode 100644 index 00000000..3d7e4f56 --- /dev/null +++ b/driver/vhci_ude/vhci_dbg.c @@ -0,0 +1,157 @@ +#include "vhci_driver.h" + +#include "dbgcode.h" + +#include +#include + +#include "strutil.h" +#include "usbip_vhci_api.h" + +#include "vhci_urbr.h" + +#ifdef DBG + +static namecode_t namecodes_vhci_ioctl[] = { + K_V(IOCTL_USBIP_VHCI_PLUGIN_HARDWARE) + K_V(IOCTL_USBIP_VHCI_UNPLUG_HARDWARE) + K_V(IOCTL_USBIP_VHCI_EJECT_HARDWARE) + K_V(IOCTL_USBIP_VHCI_GET_PORTS_STATUS) + K_V(IOCTL_INTERNAL_USB_CYCLE_PORT) + K_V(IOCTL_INTERNAL_USB_ENABLE_PORT) + K_V(IOCTL_INTERNAL_USB_GET_BUS_INFO) + K_V(IOCTL_INTERNAL_USB_GET_BUSGUID_INFO) + K_V(IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME) + K_V(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE) + K_V(IOCTL_INTERNAL_USB_GET_HUB_COUNT) + K_V(IOCTL_INTERNAL_USB_GET_HUB_NAME) + K_V(IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO) + K_V(IOCTL_INTERNAL_USB_GET_PORT_STATUS) + K_V(IOCTL_INTERNAL_USB_RESET_PORT) + K_V(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO) + K_V(IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION) + K_V(IOCTL_INTERNAL_USB_SUBMIT_URB) + K_V(IOCTL_INTERNAL_USB_GET_TOPOLOGY_ADDRESS) + K_V(IOCTL_USB_DIAG_IGNORE_HUBS_ON) + K_V(IOCTL_USB_DIAG_IGNORE_HUBS_OFF) + K_V(IOCTL_USB_DIAGNOSTIC_MODE_OFF) + K_V(IOCTL_USB_DIAGNOSTIC_MODE_ON) + K_V(IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION) + K_V(IOCTL_USB_GET_HUB_CAPABILITIES) + K_V(IOCTL_USB_GET_ROOT_HUB_NAME) + K_V(IOCTL_GET_HCD_DRIVERKEY_NAME) + K_V(IOCTL_USB_GET_NODE_INFORMATION) + K_V(IOCTL_USB_GET_NODE_CONNECTION_INFORMATION) + K_V(IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES) + K_V(IOCTL_USB_GET_NODE_CONNECTION_NAME) + K_V(IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME) + K_V(IOCTL_USB_HCD_DISABLE_PORT) + K_V(IOCTL_USB_HCD_ENABLE_PORT) + K_V(IOCTL_USB_HCD_GET_STATS_1) + K_V(IOCTL_USB_HCD_GET_STATS_2) + K_V(IOCTL_USB_GET_HUB_CAPABILITIES) + K_V(IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES) + K_V(IOCTL_USB_HUB_CYCLE_PORT) + K_V(IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX) + K_V(IOCTL_USB_RESET_HUB) + K_V(IOCTL_USB_GET_HUB_CAPABILITIES_EX) + K_V(IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES) + K_V(IOCTL_USB_GET_HUB_INFORMATION_EX) + K_V(IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES) + K_V(IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2) + {0,0} +}; + +struct namecode namecodes_urb_func[] = { + K_V(URB_FUNCTION_SELECT_CONFIGURATION) + K_V(URB_FUNCTION_SELECT_INTERFACE) + K_V(URB_FUNCTION_ABORT_PIPE) + K_V(URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL) + K_V(URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL) + K_V(URB_FUNCTION_GET_FRAME_LENGTH) + K_V(URB_FUNCTION_SET_FRAME_LENGTH) + K_V(URB_FUNCTION_GET_CURRENT_FRAME_NUMBER) + K_V(URB_FUNCTION_CONTROL_TRANSFER) + K_V(URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) + K_V(URB_FUNCTION_ISOCH_TRANSFER) + K_V(URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL) + K_V(URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE) + K_V(URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT) + K_V(URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE) + K_V(URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE) + K_V(URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT) + K_V(URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE) + K_V(URB_FUNCTION_SET_FEATURE_TO_DEVICE) + K_V(URB_FUNCTION_SET_FEATURE_TO_INTERFACE) + K_V(URB_FUNCTION_SET_FEATURE_TO_ENDPOINT) + K_V(URB_FUNCTION_SET_FEATURE_TO_OTHER) + K_V(URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE) + K_V(URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE) + K_V(URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT) + K_V(URB_FUNCTION_CLEAR_FEATURE_TO_OTHER) + K_V(URB_FUNCTION_GET_STATUS_FROM_DEVICE) + K_V(URB_FUNCTION_GET_STATUS_FROM_INTERFACE) + K_V(URB_FUNCTION_GET_STATUS_FROM_ENDPOINT) + K_V(URB_FUNCTION_GET_STATUS_FROM_OTHER) + K_V(URB_FUNCTION_RESERVED0) + K_V(URB_FUNCTION_VENDOR_DEVICE) + K_V(URB_FUNCTION_VENDOR_INTERFACE) + K_V(URB_FUNCTION_VENDOR_ENDPOINT) + K_V(URB_FUNCTION_VENDOR_OTHER) + K_V(URB_FUNCTION_CLASS_DEVICE) + K_V(URB_FUNCTION_CLASS_INTERFACE) + K_V(URB_FUNCTION_CLASS_ENDPOINT) + K_V(URB_FUNCTION_CLASS_OTHER) + K_V(URB_FUNCTION_RESERVED) + K_V(URB_FUNCTION_GET_CONFIGURATION) + K_V(URB_FUNCTION_GET_INTERFACE) + K_V(URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE) + K_V(URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE) + K_V(URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR) + K_V(URB_FUNCTION_RESERVE_0X002B) + K_V(URB_FUNCTION_RESERVE_0X002C) + K_V(URB_FUNCTION_RESERVE_0X002D) + K_V(URB_FUNCTION_RESERVE_0X002E) + K_V(URB_FUNCTION_RESERVE_0X002F) + K_V(URB_FUNCTION_SYNC_RESET_PIPE) + K_V(URB_FUNCTION_SYNC_CLEAR_STALL) + K_V(URB_FUNCTION_CONTROL_TRANSFER_EX) + {0,0} +}; + +const char * +dbg_vhci_ioctl_code(unsigned int ioctl_code) +{ + return dbg_namecode(namecodes_vhci_ioctl, "ioctl", ioctl_code); +} + +const char * +dbg_urbfunc(USHORT urbfunc) +{ + return dbg_namecode(namecodes_urb_func, "urb function", (unsigned int)urbfunc); +} + +const char * +dbg_usb_setup_packet(PCUCHAR packet) +{ + static char buf[1024]; + PUSB_DEFAULT_PIPE_SETUP_PACKET pkt = (PUSB_DEFAULT_PIPE_SETUP_PACKET)packet; + + libdrv_snprintf(buf, 1024, "rqtype:%02x,req:%02x,wIndex:%hu,wLength:%hu,wValue:%hu", + pkt->bmRequestType, pkt->bRequest, pkt->wIndex, pkt->wLength, pkt->wValue); + + return buf; +} + +const char * +dbg_urbr(purb_req_t urbr) +{ + static char buf[128]; + + if (urbr == NULL) + return "[null]"; + libdrv_snprintf(buf, 128, "[%s,seq:%u]", urbr->urb ? "urb": urbr->req ? "sel": "ulk", urbr->seq_num); + return buf; +} + +#endif \ No newline at end of file diff --git a/driver/vhci_ude/vhci_dbg.h b/driver/vhci_ude/vhci_dbg.h new file mode 100644 index 00000000..06472000 --- /dev/null +++ b/driver/vhci_ude/vhci_dbg.h @@ -0,0 +1,16 @@ +#pragma once + +#include "dbgcommon.h" + +#ifdef DBG + +#include "vhci_dev.h" +#include "vhci_urbr.h" +#include "dbgcode.h" + +extern const char *dbg_vhci_ioctl_code(unsigned int ioctl_code); +extern const char *dbg_urbfunc(USHORT urbfunc); +extern const char *dbg_usb_setup_packet(PCUCHAR packet); +extern const char *dbg_urbr(purb_req_t urbr); + +#endif diff --git a/driver/vhci_ude/vhci_dev.h b/driver/vhci_ude/vhci_dev.h new file mode 100644 index 00000000..dbaa2a0b --- /dev/null +++ b/driver/vhci_ude/vhci_dev.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +EXTERN_C_START + +struct _ctx_vusb; + +typedef struct +{ + WDFDEVICE hdev; + ULONG n_max_ports; + WDFQUEUE queue; + struct _ctx_vusb **vusbs; + WDFWAITLOCK lock; +} ctx_vhci_t, *pctx_vhci_t; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ctx_vhci_t, TO_VHCI) +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(pctx_vhci_t, TO_PVHCI) + +struct _urb_req; +struct _ctx_ep; + +typedef struct _ctx_vusb +{ + ULONG port; + pctx_vhci_t vhci; + UDECXUSBDEVICE ude_usbdev; + + BOOLEAN invalid; + // pending req which doesn't find an available urbr + WDFREQUEST pending_req_read; + // a partially transferred urbr + struct _urb_req *urbr_sent_partial; + // a partially transferred length of urbr_sent_partial + ULONG len_sent_partial; + // all urbr's. This list will be used for clear or cancellation. + LIST_ENTRY head_urbr; + // pending urbr's which are not transferred yet + LIST_ENTRY head_urbr_pending; + // urbr's which had been sent and have waited for response + LIST_ENTRY head_urbr_sent; + ULONG devid; + ULONG seq_num; + struct _ctx_ep *ep_default; + WDFLOOKASIDE lookaside_urbr; + WDFWAITLOCK lock; +} ctx_vusb_t, *pctx_vusb_t; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ctx_vusb_t, TO_VUSB) +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(pctx_vusb_t, TO_PVUSB) + +typedef struct _ctx_ep +{ + pctx_vusb_t vusb; + UCHAR type, addr, interval; + UDECXUSBENDPOINT ude_ep; + WDFQUEUE queue; +} ctx_ep_t, *pctx_ep_t; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ctx_ep_t, TO_EP) +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(pctx_ep_t, TO_PEP) + +EXTERN_C_END \ No newline at end of file diff --git a/driver/vhci_ude/vhci_driver.c b/driver/vhci_ude/vhci_driver.c new file mode 100644 index 00000000..8f604855 --- /dev/null +++ b/driver/vhci_ude/vhci_driver.c @@ -0,0 +1,44 @@ +#include "vhci_driver.h" +#include "vhci_driver.tmh" + +extern NTSTATUS +evt_add_vhci(_In_ WDFDRIVER drv, _Inout_ PWDFDEVICE_INIT dinit); + +static PAGEABLE VOID +vhci_EvtDriverContextCleanup(_In_ WDFOBJECT drvobj) +{ + PAGED_CODE(); + + TRD(DRIVER, "Enter"); + + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)drvobj)); +} + +INITABLE NTSTATUS +DriverEntry(_In_ PDRIVER_OBJECT drvobj, _In_ PUNICODE_STRING regpath) +{ + WDF_DRIVER_CONFIG conf; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attrs; + + WPP_INIT_TRACING(drvobj, regpath); + + TRD(DRIVER, "Enter"); + + WDF_OBJECT_ATTRIBUTES_INIT(&attrs); + attrs.EvtCleanupCallback = vhci_EvtDriverContextCleanup; + + WDF_DRIVER_CONFIG_INIT(&conf, evt_add_vhci); + conf.DriverPoolTag = VHCI_POOLTAG; + + status = WdfDriverCreate(drvobj, regpath, &attrs, &conf, WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + TRE(DRIVER, "WdfDriverCreate failed: %!STATUS!", status); + WPP_CLEANUP(drvobj); + return status; + } + + TRD(DRIVER, "Leave: %!STATUS!", status); + + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_driver.h b/driver/vhci_ude/vhci_driver.h new file mode 100644 index 00000000..fdf38fd9 --- /dev/null +++ b/driver/vhci_ude/vhci_driver.h @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "vhci_dev.h" +#include "vhci_dbg.h" +#include "vhci_trace.h" + +EXTERN_C_START + +#define INITABLE __declspec(code_seg("INIT")) +#define PAGEABLE __declspec(code_seg("PAGE")) + +#define VHCI_POOLTAG 'ichv' + +EXTERN_C_END diff --git a/driver/vhci_ude/vhci_ep.c b/driver/vhci_ude/vhci_ep.c new file mode 100644 index 00000000..05ee093c --- /dev/null +++ b/driver/vhci_ude/vhci_ep.c @@ -0,0 +1,188 @@ +#include "vhci_driver.h" +#include "vhci_ep.tmh" + +extern WDFQUEUE +create_queue_ep(pctx_ep_t ep); + +static VOID +ep_start(_In_ UDECXUSBENDPOINT ude_ep) +{ + pctx_ep_t ep = TO_EP(ude_ep); + + TRD(VUSB, "Enter"); + WdfIoQueueStart(ep->queue); + TRD(VUSB, "Leave"); +} + +static VOID +ep_purge_done(_In_ WDFQUEUE queue, _In_ WDFCONTEXT ctx) +{ + UNREFERENCED_PARAMETER(queue); + + UdecxUsbEndpointPurgeComplete((UDECXUSBENDPOINT)ctx); + + TRD(VUSB, "purge completed"); +} + +static VOID +ep_purge(_In_ UDECXUSBENDPOINT ude_ep) +{ + pctx_ep_t ep = TO_EP(ude_ep); + + TRD(VUSB, "Enter"); + + WdfIoQueuePurge(ep->queue, ep_purge_done, ude_ep); + + TRD(VUSB, "Leave"); +} + +static VOID +ep_reset(_In_ UDECXUSBENDPOINT ep, _In_ WDFREQUEST req) +{ + UNREFERENCED_PARAMETER(ep); + UNREFERENCED_PARAMETER(req); + + TRE(VUSB, "Enter"); +} + +static void +setup_ep_from_dscr(pctx_ep_t ep, PUSB_ENDPOINT_DESCRIPTOR dscr_ep) +{ + if (dscr_ep == NULL) { + ep->type = USB_ENDPOINT_TYPE_CONTROL; + ep->addr = USB_DEFAULT_DEVICE_ADDRESS; + ep->interval = 0; + } + else { + ep->type = dscr_ep->bmAttributes & USB_ENDPOINT_TYPE_MASK; + ep->addr = dscr_ep->bEndpointAddress; + ep->interval = dscr_ep->bInterval; + } +} + +static NTSTATUS +add_ep(pctx_vusb_t vusb, PUDECXUSBENDPOINT_INIT *pepinit, PUSB_ENDPOINT_DESCRIPTOR dscr_ep) +{ + pctx_ep_t ep; + UDECXUSBENDPOINT ude_ep; + UDECX_USB_ENDPOINT_CALLBACKS callbacks; + WDFQUEUE queue; + UCHAR ep_addr; + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status; + + ep_addr = dscr_ep ? dscr_ep->bEndpointAddress : USB_DEFAULT_DEVICE_ADDRESS; + UdecxUsbEndpointInitSetEndpointAddress(*pepinit, ep_addr); + + UDECX_USB_ENDPOINT_CALLBACKS_INIT(&callbacks, ep_reset); + callbacks.EvtUsbEndpointStart = ep_start; + callbacks.EvtUsbEndpointPurge = ep_purge; + + UdecxUsbEndpointInitSetCallbacks(*pepinit, &callbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, ctx_ep_t); + attrs.ParentObject = vusb->ude_usbdev; + status = UdecxUsbEndpointCreate(pepinit, &attrs, &ude_ep); + if (NT_ERROR(status)) { + TRE(VUSB, "failed to create endpoint: %!STATUS!", status); + return status; + } + + ep = TO_EP(ude_ep); + ep->vusb = vusb; + ep->ude_ep = ude_ep; + setup_ep_from_dscr(ep, dscr_ep); + + queue = create_queue_ep(ep); + if (queue == NULL) { + WdfObjectDelete(ude_ep); + return STATUS_UNSUCCESSFUL; + } + UdecxUsbEndpointSetWdfIoQueue(ude_ep, queue); + + ep->queue = queue; + if (dscr_ep == NULL) { + vusb->ep_default = ep; + } + return STATUS_SUCCESS; +} + +static NTSTATUS +default_ep_add(_In_ UDECXUSBDEVICE udev, _In_ PUDECXUSBENDPOINT_INIT epinit) +{ + pctx_vusb_t vusb = TO_VUSB(udev); + NTSTATUS status; + + TRD(VUSB, "Enter"); + + status = add_ep(vusb, &epinit, NULL); + + TRD(VUSB, "Leave: %!STATUS!", status); + + return status; +} + +static NTSTATUS +ep_add(_In_ UDECXUSBDEVICE udev, _In_ PUDECX_USB_ENDPOINT_INIT_AND_METADATA epcreate) +{ + pctx_vusb_t vusb = TO_VUSB(udev); + NTSTATUS status; + + TRD(VUSB, "Enter: epaddr: 0x%x, interval: 0x%x", (ULONG)epcreate->EndpointDescriptor->bEndpointAddress, + (ULONG)epcreate->EndpointDescriptor->bInterval); + + status = add_ep(vusb, &epcreate->UdecxUsbEndpointInit, epcreate->EndpointDescriptor); + + TRD(VUSB, "Leave: %!STATUS!", status); + + return status; +} + +static VOID +release_ep(PUDECX_ENDPOINTS_CONFIGURE_PARAMS params, WDFREQUEST req) +{ + for (ULONG i = 0; i < params->ReleasedEndpointsCount; i++) { + pctx_ep_t ep = TO_EP(params->ReleasedEndpoints[i]); + WdfIoQueuePurgeSynchronously(ep->queue); + } + WdfRequestComplete(req, STATUS_SUCCESS); +} + +static VOID +ep_configure(_In_ UDECXUSBDEVICE udev, _In_ WDFREQUEST req, _In_ PUDECX_ENDPOINTS_CONFIGURE_PARAMS params) +{ + pctx_vusb_t vusb = TO_VUSB(udev); + NTSTATUS status = STATUS_SUCCESS; + + TRD(VUSB, "Enter: %!epconf!", params->ConfigureType); + + switch (params->ConfigureType) { + case UdecxEndpointsConfigureTypeDeviceInitialize: + break; + case UdecxEndpointsConfigureTypeDeviceConfigurationChange: + status = submit_req_select(vusb->ep_default, req, 1, params->NewConfigurationValue, 0, 0); + break; + case UdecxEndpointsConfigureTypeInterfaceSettingChange: + status = submit_req_select(vusb->ep_default, req, 0, 0, params->InterfaceNumber, params->NewInterfaceSetting); + break; + case UdecxEndpointsConfigureTypeEndpointsReleasedOnly: + release_ep(params, req); + status = STATUS_PENDING; + break; + default: + TRE(VUSB, "unhandled configure type: %!epconf!", params->ConfigureType); + break; + } + + if (status != STATUS_PENDING) + WdfRequestComplete(req, status); + TRD(VUSB, "Leave: %!STATUS!", status); +} + +VOID +setup_ep_callbacks(PUDECX_USB_DEVICE_STATE_CHANGE_CALLBACKS pcallbacks) +{ + pcallbacks->EvtUsbDeviceDefaultEndpointAdd = default_ep_add; + pcallbacks->EvtUsbDeviceEndpointAdd = ep_add; + pcallbacks->EvtUsbDeviceEndpointsConfigure = ep_configure; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_hc.c b/driver/vhci_ude/vhci_hc.c new file mode 100644 index 00000000..0f235f2f --- /dev/null +++ b/driver/vhci_ude/vhci_hc.c @@ -0,0 +1,150 @@ +#include "vhci_driver.h" +#include "vhci_hc.tmh" + +#define MAX_HUB_PORTS 2 + +#include "usbip_vhci_api.h" + +extern VOID create_queue_hc(pctx_vhci_t vhci); + +static NTSTATUS +controller_query_usb_capability(WDFDEVICE UdecxWdfDevice, PGUID CapabilityType, + ULONG OutputBufferLength, PVOID OutputBuffer, PULONG ResultLength) +{ + UNREFERENCED_PARAMETER(UdecxWdfDevice); + UNREFERENCED_PARAMETER(CapabilityType); + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(OutputBuffer); + UNREFERENCED_PARAMETER(ResultLength); + + TRD(VHCI, "not supported"); + + return STATUS_NOT_SUPPORTED; +} + +static VOID +controller_reset(WDFDEVICE UdecxWdfDevice) +{ + UNREFERENCED_PARAMETER(UdecxWdfDevice); + + TRD(VHCI, "controller reset"); +} + +static PAGEABLE BOOLEAN +create_ucx_controller(WDFDEVICE hdev) +{ + UDECX_WDF_DEVICE_CONFIG conf; + NTSTATUS status; + + UDECX_WDF_DEVICE_CONFIG_INIT(&conf, controller_query_usb_capability); + /* FIXME: is this callback required ? */ +#if 0 + conf.EvtUdecxWdfDeviceReset = controller_reset; +#endif + status = UdecxWdfDeviceAddUsbDeviceEmulation(hdev, &conf); + if (NT_ERROR(status)) { + TRE(VHCI, "failed to create controller: %!STATUS!", status); + return FALSE; + } + + return TRUE; +} + +static PAGEABLE VOID +setup_fileobject(PWDFDEVICE_INIT dinit) +{ + WDF_OBJECT_ATTRIBUTES attrs; + WDF_FILEOBJECT_CONFIG conf; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, pctx_vusb_t); + WDF_FILEOBJECT_CONFIG_INIT(&conf, NULL, NULL, NULL); + WdfDeviceInitSetFileObjectConfig(dinit, &conf, &attrs); +} + +static PAGEABLE VOID +reg_devintf(WDFDEVICE hdev) +{ + NTSTATUS status; + + status = WdfDeviceCreateDeviceInterface(hdev, &GUID_DEVINTERFACE_VHCI_USBIP, NULL); + if (NT_ERROR(status)) { + TRE(VHCI, "failed to register usbip device interface: %!STATUS!", status); + } + status = WdfDeviceCreateDeviceInterface(hdev, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL); + if (NT_ERROR(status)) { + TRE(VHCI, "failed to register host controller device interface: %!STATUS!", status); + } +} + +static BOOLEAN +setup_vhci(pctx_vhci_t vhci) +{ + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status; + + WDF_OBJECT_ATTRIBUTES_INIT(&attrs); + attrs.ParentObject = vhci->hdev; + status = WdfWaitLockCreate(&attrs, &vhci->lock); + if (NT_ERROR(status)) { + TRE(VHCI, "failed to create wait lock: %!STATUS!", status); + return FALSE; + } + vhci->n_max_ports = MAX_HUB_PORTS; + + vhci->vusbs = ExAllocatePoolWithTag(PagedPool, sizeof(pctx_vusb_t) * vhci->n_max_ports, VHCI_POOLTAG); + if (vhci->vusbs == NULL) { + TRE(VHCI, "failed to allocate ports: out of memory"); + return FALSE; + } + RtlZeroMemory(vhci->vusbs, sizeof(pctx_vusb_t) * vhci->n_max_ports); + + return TRUE; +} + +PAGEABLE NTSTATUS +evt_add_vhci(_In_ WDFDRIVER drv, _Inout_ PWDFDEVICE_INIT dinit) +{ + pctx_vhci_t vhci; + WDFDEVICE hdev; + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + UNREFERENCED_PARAMETER(drv); + + PAGED_CODE(); + + TRD(VHCI, "Enter"); + + status = UdecxInitializeWdfDeviceInit(dinit); + if (!NT_SUCCESS(status)) { + TRE(VHCI, "failed to initialize UDE: %!STATUS!", status); + goto out; + } + + setup_fileobject(dinit); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, ctx_vhci_t); + status = WdfDeviceCreate(&dinit, &attrs, &hdev); + if (!NT_SUCCESS(status)) { + TRE(VHCI, "failed to create wdf device: %!STATUS!", status); + goto out; + } + + if (!create_ucx_controller(hdev)) + goto out; + + reg_devintf(hdev); + + vhci = TO_VHCI(hdev); + vhci->hdev = hdev; + if (!setup_vhci(vhci)) + goto out; + + create_queue_hc(vhci); + + status = STATUS_SUCCESS; +out: + TRD(VHCI, "Leave: %!STATUS!", status); + + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_ioctl.c b/driver/vhci_ude/vhci_ioctl.c new file mode 100644 index 00000000..c8fa4ae4 --- /dev/null +++ b/driver/vhci_ude/vhci_ioctl.c @@ -0,0 +1,140 @@ +#include "vhci_driver.h" +#include "vhci_ioctl.tmh" + +#include "usbip_vhci_api.h" + +NTSTATUS +plugin_vusb(pctx_vhci_t vhci, WDFREQUEST req, pvhci_pluginfo_t pluginfo); +NTSTATUS +plugout_vusb(pctx_vhci_t vhci, ULONG port); + +static VOID +get_ports_status(pctx_vhci_t vhci, ioctl_usbip_vhci_get_ports_status *ports_status) +{ + ULONG i; + + TRD(IOCTL, "Enter\n"); + + RtlZeroMemory(ports_status, sizeof(ioctl_usbip_vhci_get_ports_status)); + + WdfWaitLockAcquire(vhci->lock, NULL); + + for (i = 0; i != vhci->n_max_ports; i++) { + pctx_vusb_t vusb = vhci->vusbs[i]; + if (vusb != NULL) + ports_status->u.port_status[i] = 1; + } + + WdfWaitLockRelease(vhci->lock); + + TRD(IOCTL, "Leave\n"); +} + +static NTSTATUS +ioctl_get_ports_status(WDFQUEUE queue, WDFREQUEST req) +{ + pctx_vhci_t vhci; + ioctl_usbip_vhci_get_ports_status *ports_status; + NTSTATUS status; + + status = WdfRequestRetrieveOutputBuffer(req, sizeof(ioctl_usbip_vhci_get_ports_status), &ports_status, NULL); + if (NT_ERROR(status)) + return status; + + vhci = *TO_PVHCI(queue); + + get_ports_status(vhci, ports_status); + WdfRequestSetInformation(req, sizeof(ioctl_usbip_vhci_get_ports_status)); + + return STATUS_SUCCESS; +} + +static NTSTATUS +ioctl_plugin_vusb(WDFQUEUE queue, WDFREQUEST req, size_t inlen) +{ + pctx_vhci_t vhci; + pvhci_pluginfo_t pluginfo; + PUSHORT pdscr_fullsize; + size_t len; + NTSTATUS status; + + if (inlen < sizeof(vhci_pluginfo_t)) { + TRE(IOCTL, "too small input length: %lld < %lld", inlen, sizeof(vhci_pluginfo_t)); + return STATUS_INVALID_PARAMETER; + } + status = WdfRequestRetrieveInputBuffer(req, sizeof(vhci_pluginfo_t), &pluginfo, &len); + if (NT_ERROR(status)) { + TRE(IOCTL, "failed to get pluginfo buffer: %!STATUS!", status); + return status; + } + pdscr_fullsize = (PUSHORT)pluginfo->dscr_conf + 1; + if (len != sizeof(vhci_pluginfo_t) + *pdscr_fullsize - 9) { + TRE(IOCTL, "invalid pluginfo format: %lld != %lld", len, sizeof(vhci_pluginfo_t) + *pdscr_fullsize - 9); + return STATUS_INVALID_PARAMETER; + } + vhci = *TO_PVHCI(queue); + if (pluginfo->port < 0 || (ULONG)pluginfo->port > vhci->n_max_ports) + return STATUS_INVALID_PARAMETER; + return plugin_vusb(vhci, req, pluginfo); +} + +static NTSTATUS +ioctl_plugout_vusb(WDFQUEUE queue, WDFREQUEST req, size_t inlen) +{ + pvhci_unpluginfo_t unpluginfo; + pctx_vhci_t vhci; + ULONG port; + NTSTATUS status; + + if (inlen != sizeof(ioctl_usbip_vhci_unplug)) { + TRE(IOCTL, "invalid unplug input size: %lld < %lld", inlen, sizeof(ioctl_usbip_vhci_unplug)); + return STATUS_INVALID_PARAMETER; + } + + status = WdfRequestRetrieveInputBuffer(req, sizeof(ioctl_usbip_vhci_unplug), &unpluginfo, NULL); + if (NT_ERROR(status)) { + TRE(IOCTL, "failed to get unplug buffer: %!STATUS!", status); + return status; + } + + port = (ULONG)unpluginfo->addr; + vhci = *TO_PVHCI(queue); + if (port != 0 && port >= vhci->n_max_ports) + return STATUS_INVALID_PARAMETER; + + return plugout_vusb(vhci, port); +} + +VOID +io_device_control(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, + _In_ size_t outlen, _In_ size_t inlen, _In_ ULONG ioctl_code) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(outlen); + + TRD(IOCTL, "Enter: %!IOCTL!", ioctl_code); + + switch (ioctl_code) { + case IOCTL_USBIP_VHCI_GET_PORTS_STATUS: + status = ioctl_get_ports_status(queue, req); + break; + case IOCTL_USBIP_VHCI_PLUGIN_HARDWARE: + status = ioctl_plugin_vusb(queue, req, inlen); + break; + case IOCTL_USBIP_VHCI_UNPLUG_HARDWARE: + status = ioctl_plugout_vusb(queue, req, inlen); + break; + default: + if (UdecxWdfDeviceTryHandleUserIoctl((*TO_PVHCI(queue))->hdev, req)) { + TRD(IOCTL, "Leave: handled by Udecx"); + return; + } + TRE(IOCTL, "unhandled IOCTL: %!IOCTL!", ioctl_code); + break; + } + + WdfRequestComplete(req, status); + + TRD(IOCTL, "Leave: %!STATUS!", status); +} diff --git a/driver/vhci_ude/vhci_plugin.c b/driver/vhci_ude/vhci_plugin.c new file mode 100644 index 00000000..f7614982 --- /dev/null +++ b/driver/vhci_ude/vhci_plugin.c @@ -0,0 +1,165 @@ +#include "vhci_driver.h" +#include "vhci_plugin.tmh" + +#include "usbip_vhci_api.h" + +extern VOID +setup_ep_callbacks(PUDECX_USB_DEVICE_STATE_CHANGE_CALLBACKS pcallbacks); + +static BOOLEAN +setup_vusb(UDECXUSBDEVICE ude_usbdev) +{ + pctx_vusb_t vusb = TO_VUSB(ude_usbdev); + WDF_OBJECT_ATTRIBUTES attrs, attrs_hmem; + NTSTATUS status; + + WDF_OBJECT_ATTRIBUTES_INIT(&attrs); + attrs.ParentObject = ude_usbdev; + + status = WdfWaitLockCreate(&attrs, &vusb->lock); + if (NT_ERROR(status)) { + TRE(VUSB, "failed to create wait lock: %!STATUS!", status); + return FALSE; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs_hmem, urb_req_t); + attrs_hmem.ParentObject = ude_usbdev; + + status = WdfLookasideListCreate(&attrs, sizeof(urb_req_t), PagedPool, &attrs_hmem, 0, &vusb->lookaside_urbr); + if (NT_ERROR(status)) { + TRE(VUSB, "failed to create urbr memory: %!STATUS!", status); + return FALSE; + } + + vusb->ude_usbdev = ude_usbdev; + vusb->pending_req_read = NULL; + vusb->urbr_sent_partial = NULL; + vusb->len_sent_partial = 0; + vusb->seq_num = 0; + vusb->invalid = FALSE; + vusb->ep_default = NULL; + + InitializeListHead(&vusb->head_urbr); + InitializeListHead(&vusb->head_urbr_pending); + InitializeListHead(&vusb->head_urbr_sent); + + return TRUE; +} + +static PUDECXUSBDEVICE_INIT +build_vusb_pdinit(pctx_vhci_t vhci) +{ + PUDECXUSBDEVICE_INIT pdinit; + UDECX_USB_DEVICE_STATE_CHANGE_CALLBACKS callbacks; + + pdinit = UdecxUsbDeviceInitAllocate(vhci->hdev); + + UDECX_USB_DEVICE_CALLBACKS_INIT(&callbacks); + + setup_ep_callbacks(&callbacks); + + UdecxUsbDeviceInitSetStateChangeCallbacks(pdinit, &callbacks); + UdecxUsbDeviceInitSetSpeed(pdinit, UdecxUsbFullSpeed); + UdecxUsbDeviceInitSetEndpointsType(pdinit, UdecxEndpointTypeDynamic); + + return pdinit; +} + +static void +setup_descriptors(PUDECXUSBDEVICE_INIT pdinit, pvhci_pluginfo_t pluginfo) +{ + NTSTATUS status; + USHORT conf_dscr_fullsize; + + status = UdecxUsbDeviceInitAddDescriptor(pdinit, pluginfo->dscr_dev, 18); + if (NT_ERROR(status)) { + TRW(VUSB, "failed to add a device descriptor to device init"); + } + conf_dscr_fullsize = *((PUSHORT)pluginfo->dscr_conf + 1); + status = UdecxUsbDeviceInitAddDescriptor(pdinit, pluginfo->dscr_conf, conf_dscr_fullsize); + if (NT_ERROR(status)) { + TRW(VUSB, "failed to add a configuration descriptor to device init"); + } +} + +static VOID +vusb_cleanup(_In_ WDFOBJECT ude_usbdev) +{ + UNREFERENCED_PARAMETER(ude_usbdev); + TRD(VUSB, "Enter"); +} + +static pctx_vusb_t +vusb_plugin(pctx_vhci_t vhci, pvhci_pluginfo_t pluginfo) +{ + pctx_vusb_t vusb; + PUDECXUSBDEVICE_INIT pdinit; + UDECX_USB_DEVICE_PLUG_IN_OPTIONS opts; + UDECXUSBDEVICE ude_usbdev; + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status; + + pdinit = build_vusb_pdinit(vhci); + setup_descriptors(pdinit, pluginfo); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, ctx_vusb_t); + attrs.EvtCleanupCallback = vusb_cleanup; + + status = UdecxUsbDeviceCreate(&pdinit, &attrs, &ude_usbdev); + if (NT_ERROR(status)) { + TRE(VUSB, "failed to create usb device: %!STATUS!", status); + UdecxUsbDeviceInitFree(pdinit); + return NULL; + } + + UDECX_USB_DEVICE_PLUG_IN_OPTIONS_INIT(&opts); + opts.Usb20PortNumber = pluginfo->port; + status = UdecxUsbDevicePlugIn(ude_usbdev, &opts); + if (NT_ERROR(status)) { + TRE(VUSB, "failed to plugin a new device %!STATUS!", status); + WdfObjectDelete(ude_usbdev); + return NULL; + } + + if (!setup_vusb(ude_usbdev)) { + WdfObjectDelete(ude_usbdev); + return NULL; + } + vusb = TO_VUSB(ude_usbdev); + vusb->vhci = vhci; + vusb->devid = pluginfo->devid; + + return vusb; +} + +NTSTATUS +plugin_vusb(pctx_vhci_t vhci, WDFREQUEST req, pvhci_pluginfo_t pluginfo) +{ + pctx_vusb_t vusb; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + WdfWaitLockAcquire(vhci->lock, NULL); + + if (vhci->vusbs[pluginfo->port - 1] != NULL) { + WdfWaitLockRelease(vhci->lock); + return STATUS_OBJECT_NAME_COLLISION; + } + + vusb = vusb_plugin(vhci, pluginfo); + if (vusb != NULL) { + WDFFILEOBJECT fo = WdfRequestGetFileObject(req); + if (fo != NULL) { + pctx_vusb_t *pvusb = TO_PVUSB(fo); + *pvusb = vusb; + } + else { + TRE(IOCTL, "empty fileobject. setup failed"); + } + vhci->vusbs[pluginfo->port - 1] = vusb; + status = STATUS_SUCCESS; + } + + WdfWaitLockRelease(vhci->lock); + + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_plugout.c b/driver/vhci_ude/vhci_plugout.c new file mode 100644 index 00000000..9e1713e4 --- /dev/null +++ b/driver/vhci_ude/vhci_plugout.c @@ -0,0 +1,126 @@ +#include "vhci_driver.h" +#include "vhci_plugout.tmh" + +#include "usbip_vhci_api.h" + +static VOID +abort_pending_req_read(pctx_vusb_t vusb) +{ + WDFREQUEST req_read_pending; + + WdfWaitLockAcquire(vusb->lock, NULL); + req_read_pending = vusb->pending_req_read; + vusb->pending_req_read = NULL; + WdfWaitLockRelease(vusb->lock); + + if (req_read_pending != NULL) { + TRD(PLUGIN, "abort read request"); + WdfRequestUnmarkCancelable(req_read_pending); + WdfRequestComplete(req_read_pending, STATUS_DEVICE_NOT_CONNECTED); + } +} + +static VOID +abort_pending_urbr(purb_req_t urbr) +{ + TRD(PLUGIN, "abort pending urbr: %!URBR!", urbr); + complete_urbr(urbr, STATUS_DEVICE_NOT_CONNECTED); +} + +static VOID +abort_all_pending_urbrs(pctx_vusb_t vusb) +{ + WdfWaitLockAcquire(vusb->lock, NULL); + + while (!IsListEmpty(&vusb->head_urbr)) { + purb_req_t urbr; + + urbr = CONTAINING_RECORD(vusb->head_urbr.Flink, urb_req_t, list_all); + RemoveEntryListInit(&urbr->list_all); + RemoveEntryListInit(&urbr->list_state); + WdfWaitLockRelease(vusb->lock); + + abort_pending_urbr(urbr); + + WdfWaitLockAcquire(vusb->lock, NULL); + } + + WdfWaitLockRelease(vusb->lock); +} + +static NTSTATUS +vusb_plugout(pctx_vusb_t vusb) +{ + NTSTATUS status; + + abort_pending_req_read(vusb); + abort_all_pending_urbrs(vusb); + + status = UdecxUsbDevicePlugOutAndDelete(vusb->ude_usbdev); + if (NT_ERROR(status)) { + TRD(PLUGIN, "failed to plug out: %!STATUS!", status); + return status; + } + vusb->invalid = TRUE; + return STATUS_SUCCESS; +} + +static NTSTATUS +plugout_all_vusbs(pctx_vhci_t vhci) +{ + ULONG i; + + TRD(PLUGIN, "plugging out all the devices!"); + + WdfWaitLockAcquire(vhci->lock, NULL); + for (i = 0; i < vhci->n_max_ports; i++) { + NTSTATUS status; + pctx_vusb_t vusb = vhci->vusbs[i]; + if (vusb == NULL) + continue; + status = vusb_plugout(vusb); + if (NT_ERROR(status)) { + WdfWaitLockRelease(vhci->lock); + return STATUS_UNSUCCESSFUL; + } + + } + + WdfWaitLockRelease(vhci->lock); + + return STATUS_SUCCESS; +} + +NTSTATUS +plugout_vusb(pctx_vhci_t vhci, ULONG port) +{ + pctx_vusb_t vusb; + NTSTATUS status; + + if (port == 0) + return plugout_all_vusbs(vhci); + + TRD(IOCTL, "plugging out device: port: %u", port); + + WdfWaitLockAcquire(vhci->lock, NULL); + + vusb = vhci->vusbs[port - 1]; + if (vusb == NULL) { + TRD(PLUGIN, "no matching vusb: port: %u", port); + WdfWaitLockRelease(vhci->lock); + return STATUS_NO_SUCH_DEVICE; + } + + status = vusb_plugout(vusb); + if (NT_ERROR(status)) { + WdfWaitLockRelease(vhci->lock); + return STATUS_UNSUCCESSFUL; + } + vhci->vusbs[port - 1] = NULL; + + WdfWaitLockRelease(vhci->lock); + + TRD(IOCTL, "completed to plug out: port: %u", port); + + return STATUS_SUCCESS; +} diff --git a/driver/vhci_ude/vhci_proto.c b/driver/vhci_ude/vhci_proto.c new file mode 100644 index 00000000..819b6d25 --- /dev/null +++ b/driver/vhci_ude/vhci_proto.c @@ -0,0 +1,48 @@ +#include "vhci_driver.h" + +#include "usbip_proto.h" +#include "vhci_urbr.h" + +#define USBDEVFS_URB_SHORT_NOT_OK 0x01 +#define USBDEVFS_URB_ISO_ASAP 0x02 +#define USBDEVFS_URB_NO_FSBR 0x20 +#define USBDEVFS_URB_ZERO_PACKET 0x40 +#define USBDEVFS_URB_NO_INTERRUPT 0x80 + +unsigned int +transflag(unsigned int flags) +{ + unsigned int linux_flags = 0; + if (!(flags&USBD_SHORT_TRANSFER_OK)) + linux_flags |= USBDEVFS_URB_SHORT_NOT_OK; + if (flags&USBD_START_ISO_TRANSFER_ASAP) + linux_flags |= USBDEVFS_URB_ISO_ASAP; + return linux_flags; +} + +void +set_cmd_submit_usbip_header(struct usbip_header *h, unsigned long seqnum, unsigned int devid, + unsigned int direct, pctx_ep_t ep, unsigned int flags, unsigned int len) +{ + h->base.command = USBIP_CMD_SUBMIT; + h->base.seqnum = seqnum; + h->base.devid = devid; + h->base.direction = direct ? USBIP_DIR_IN : USBIP_DIR_OUT; + h->base.ep = ep ? (ep->addr & 0x7f): 0; + h->u.cmd_submit.transfer_flags = transflag(flags); + h->u.cmd_submit.transfer_buffer_length = len; + h->u.cmd_submit.start_frame = 0; + h->u.cmd_submit.number_of_packets = 0; + h->u.cmd_submit.interval = ep ? ep->interval: 0; +} + +void +set_cmd_unlink_usbip_header(struct usbip_header *h, unsigned long seqnum, unsigned int devid, unsigned long seqnum_unlink) +{ + h->base.command = USBIP_CMD_UNLINK; + h->base.seqnum = seqnum; + h->base.devid = devid; + h->base.direction = USBIP_DIR_OUT; + h->base.ep = 0; + h->u.cmd_unlink.seqnum = seqnum_unlink; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_queue_ep.c b/driver/vhci_ude/vhci_queue_ep.c new file mode 100644 index 00000000..1c2377ca --- /dev/null +++ b/driver/vhci_ude/vhci_queue_ep.c @@ -0,0 +1,62 @@ +#include "vhci_driver.h" +#include "vhci_queue_ep.tmh" + +static VOID +internal_device_control(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, + _In_ size_t outlen, _In_ size_t inlen, _In_ ULONG ioctl_code) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + + UNREFERENCED_PARAMETER(inlen); + UNREFERENCED_PARAMETER(outlen); + + TRD(EP, "Enter"); + + if (ioctl_code != IOCTL_INTERNAL_USB_SUBMIT_URB) { + TRE(EP, "unexpected ioctl: %!IOCTL!", ioctl_code); + } + else { + status = submit_req_urb(*TO_PEP(queue), req); + } + + if (status != STATUS_PENDING) + UdecxUrbCompleteWithNtStatus(req, status); + + TRD(EP, "Leave: %!STATUS!", status); +} + +static VOID +io_default(_In_ WDFQUEUE queue, _In_ WDFREQUEST req) +{ + UNREFERENCED_PARAMETER(queue); + UNREFERENCED_PARAMETER(req); + + TRE(EP, "unexpected io default callback"); +} + +WDFQUEUE +create_queue_ep(pctx_ep_t ep) +{ + WDFQUEUE queue; + WDF_IO_QUEUE_CONFIG conf; + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status; + + WDF_IO_QUEUE_CONFIG_INIT(&conf, WdfIoQueueDispatchParallel); + conf.EvtIoInternalDeviceControl = internal_device_control; + conf.EvtIoDefault = io_default; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, pctx_ep_t); + attrs.ParentObject = ep->ude_ep; + attrs.SynchronizationScope = WdfSynchronizationScopeQueue; + + status = WdfIoQueueCreate(ep->vusb->vhci->hdev, &conf, &attrs, &queue); + if (NT_ERROR(status)) { + TRE(EP, "failed to create queue: %!STATUS!", status); + return NULL; + } + + *TO_PEP(queue) = ep; + + return queue; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_queue_hc.c b/driver/vhci_ude/vhci_queue_hc.c new file mode 100644 index 00000000..30e77333 --- /dev/null +++ b/driver/vhci_ude/vhci_queue_hc.c @@ -0,0 +1,35 @@ +#include "vhci_driver.h" +#include "vhci_queue_hc.tmh" + +extern VOID io_device_control(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, + _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode); +extern VOID io_read(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, _In_ size_t len); +extern VOID io_write(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, _In_ size_t len); + +PAGEABLE VOID +create_queue_hc(pctx_vhci_t vhci) +{ + WDFQUEUE queue; + WDF_IO_QUEUE_CONFIG conf; + WDF_OBJECT_ATTRIBUTES attrs; + NTSTATUS status; + + PAGED_CODE(); + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&conf, WdfIoQueueDispatchParallel); + conf.EvtIoRead = io_read; + conf.EvtIoWrite = io_write; + conf.EvtIoDeviceControl = io_device_control; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, pctx_vhci_t); + attrs.SynchronizationScope = WdfSynchronizationScopeQueue; + + status = WdfIoQueueCreate(vhci->hdev, &conf, &attrs, &queue); + if (NT_SUCCESS(status)) { + *TO_PVHCI(queue) = vhci; + vhci->queue = queue; + } + else { + TRE(QUEUE, "failed to create queue: %!STATUS!", status); + } +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_read.c b/driver/vhci_ude/vhci_read.c new file mode 100644 index 00000000..90e6cc43 --- /dev/null +++ b/driver/vhci_ude/vhci_read.c @@ -0,0 +1,121 @@ +#include "vhci_driver.h" +#include "vhci_read.tmh" + +#include "vhci_urbr.h" + +extern NTSTATUS +store_urbr_partial(WDFREQUEST req_read, purb_req_t urbr); + +static purb_req_t +find_pending_urbr(pctx_vusb_t vusb) +{ + purb_req_t urbr; + + if (IsListEmpty(&vusb->head_urbr_pending)) + return NULL; + + urbr = CONTAINING_RECORD(vusb->head_urbr_pending.Flink, urb_req_t, list_state); + urbr->seq_num = ++(vusb->seq_num); + RemoveEntryListInit(&urbr->list_state); + return urbr; +} + +static VOID +req_read_cancelled(WDFREQUEST req_read) +{ + pctx_vusb_t vusb; + + TRD(READ, "a pending read req cancelled"); + + vusb = *TO_PVUSB(WdfRequestGetFileObject(req_read)); + WdfWaitLockAcquire(vusb->lock, NULL); + if (vusb->pending_req_read == req_read) { + vusb->pending_req_read = NULL; + } + WdfWaitLockRelease(vusb->lock); + + WdfRequestComplete(req_read, STATUS_CANCELLED); +} + +static NTSTATUS +read_vusb(pctx_vusb_t vusb, WDFREQUEST req) +{ + purb_req_t urbr; + NTSTATUS status; + + TRD(READ, "Enter"); + + WdfWaitLockAcquire(vusb->lock, NULL); + + if (vusb->pending_req_read) { + WdfWaitLockRelease(vusb->lock); + return STATUS_INVALID_DEVICE_REQUEST; + } + if (vusb->urbr_sent_partial != NULL) { + urbr = vusb->urbr_sent_partial; + + WdfWaitLockRelease(vusb->lock); + + status = store_urbr_partial(req, urbr); + + WdfWaitLockAcquire(vusb->lock, NULL); + vusb->len_sent_partial = 0; + } + else { + urbr = find_pending_urbr(vusb); + if (urbr == NULL) { + vusb->pending_req_read = req; + + WdfRequestMarkCancelable(req, req_read_cancelled); + WdfWaitLockRelease(vusb->lock); + + return STATUS_PENDING; + } + vusb->urbr_sent_partial = urbr; + WdfWaitLockRelease(vusb->lock); + + status = store_urbr(req, urbr); + + WdfWaitLockAcquire(vusb->lock, NULL); + } + + if (status != STATUS_SUCCESS) { + RemoveEntryListInit(&urbr->list_all); + WdfWaitLockRelease(vusb->lock); + + complete_urbr(urbr, status); + } + else { + if (vusb->len_sent_partial == 0) { + InsertTailList(&vusb->head_urbr_sent, &urbr->list_state); + vusb->urbr_sent_partial = NULL; + } + WdfWaitLockRelease(vusb->lock); + } + return status; +} + +VOID +io_read(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, _In_ size_t len) +{ + pctx_vusb_t vusb; + NTSTATUS status; + + UNREFERENCED_PARAMETER(queue); + + TRD(READ, "Enter: len: %u", (ULONG)len); + + vusb = *TO_PVUSB(WdfRequestGetFileObject(req)); + if (vusb->invalid) { + TRD(READ, "vusb disconnected: port: %u", vusb->port); + status = STATUS_DEVICE_NOT_CONNECTED; + } + else + status = read_vusb(vusb, req); + + if (status != STATUS_PENDING) { + WdfRequestComplete(req, status); + } + + TRD(READ, "Leave: %!STATUS!", status); +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_trace.h b/driver/vhci_ude/vhci_trace.h new file mode 100644 index 00000000..8fdbbc62 --- /dev/null +++ b/driver/vhci_ude/vhci_trace.h @@ -0,0 +1,55 @@ + +// +// Define the tracing flags. +// +// Tracing GUID - 99b7a5cf-7cb0-4af5-838d-c45d78e49101 +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + vhciTraceGuid, (99b7a5cf,7cb0,4af5,838d,c45d78e49101), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(DRIVER) \ + WPP_DEFINE_BIT(VHCI) \ + WPP_DEFINE_BIT(VHUB) \ + WPP_DEFINE_BIT(VUSB) \ + WPP_DEFINE_BIT(QUEUE) \ + WPP_DEFINE_BIT(READ) \ + WPP_DEFINE_BIT(WRITE) \ + WPP_DEFINE_BIT(EP) \ + WPP_DEFINE_BIT(URBR) \ + WPP_DEFINE_BIT(IOCTL) \ + WPP_DEFINE_BIT(PLUGIN) \ + ) + +#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) + +#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) + +// +// WPP orders static parameters before dynamic parameters. To support the Trace function +// defined below which sets FLAGS=MYDRIVER_ALL_INFO, a custom macro must be defined to +// reorder the arguments to what the .tpl configuration file expects. +// +#define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags) +#define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAGS=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// end_wpp +// diff --git a/driver/vhci_ude/vhci_urbr.c b/driver/vhci_ude/vhci_urbr.c new file mode 100644 index 00000000..0a9d6eb6 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr.c @@ -0,0 +1,276 @@ +#include "vhci_driver.h" + +#include "usbip_proto.h" +#include "vhci_urbr.tmh" +#include "vhci_urbr.h" + +PVOID +get_buf(PVOID buf, PMDL bufMDL) +{ + if (buf == NULL) { + if (bufMDL != NULL) + buf = MmGetSystemAddressForMdlSafe(bufMDL, LowPagePriority); + if (buf == NULL) { + TRE(READ, "No transfer buffer\n"); + } + } + return buf; +} + +struct usbip_header * +get_hdr_from_req_read(WDFREQUEST req_read) +{ + struct usbip_header *hdr; + NTSTATUS status; + + status = WdfRequestRetrieveOutputBuffer(req_read, sizeof(struct usbip_header), &hdr, NULL); + if (NT_ERROR(status)) { + return NULL; + } + return hdr; +} + +PVOID +get_data_from_req_read(WDFREQUEST req_read, ULONG length) +{ + PVOID data; + NTSTATUS status; + + status = WdfRequestRetrieveOutputBuffer(req_read, length, &data, NULL); + if (NT_ERROR(status)) { + return NULL; + } + return data; +} + +ULONG +get_read_payload_length(WDFREQUEST req_read) +{ + WDF_REQUEST_PARAMETERS params; + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(req_read, ¶ms); + + return (ULONG)(params.Parameters.Read.Length - sizeof(struct usbip_header)); +} + +void +build_setup_packet(usb_cspkt_t *csp, unsigned char direct_in, unsigned char type, unsigned char recip, unsigned char request) +{ + csp->bmRequestType.B = 0; + csp->bmRequestType.Type = type; + if (direct_in) + csp->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + csp->bmRequestType.Recipient = recip; + csp->bRequest = request; +} + +purb_req_t +find_sent_urbr(pctx_vusb_t vusb, struct usbip_header *hdr) +{ + PLIST_ENTRY le; + + WdfWaitLockAcquire(vusb->lock, NULL); + for (le = vusb->head_urbr_sent.Flink; le != &vusb->head_urbr_sent; le = le->Flink) { + purb_req_t urbr; + urbr = CONTAINING_RECORD(le, urb_req_t, list_state); + if (urbr->seq_num == hdr->base.seqnum) { + RemoveEntryListInit(&urbr->list_all); + RemoveEntryListInit(&urbr->list_state); + WdfWaitLockRelease(vusb->lock); + return urbr; + } + } + WdfWaitLockRelease(vusb->lock); + + return NULL; +} + +static PURB +get_urb_from_req(WDFREQUEST req) +{ + WDF_REQUEST_PARAMETERS params; + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(req, ¶ms); + if (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB) + return (PURB)params.Parameters.Others.Arg1; + return NULL; +} + +purb_req_t +create_urbr(pctx_ep_t ep, WDFREQUEST req, ULONG seq_num_unlink) +{ + WDFMEMORY hmem; + purb_req_t urbr; + NTSTATUS status; + + status = WdfMemoryCreateFromLookaside(ep->vusb->lookaside_urbr, &hmem); + if (NT_ERROR(status)) { + TRE(URBR, "failed to allocate memory for urbr: %!STATUS!", status); + return NULL; + } + + urbr = TO_URBR(hmem); + RtlZeroMemory(urbr, sizeof(urb_req_t)); + urbr->hmem = hmem; + urbr->ep = ep; + urbr->req = req; + if (req != NULL) { + urbr->urb = get_urb_from_req(req); + WdfRequestSetInformation(req, (ULONG_PTR)urbr); + } + + urbr->seq_num_unlink = seq_num_unlink; + InitializeListHead(&urbr->list_all); + InitializeListHead(&urbr->list_state); + + return urbr; +} + +static void +free_urbr(purb_req_t urbr) +{ + ASSERT(IsListEmpty(&urbr->list_all)); + ASSERT(IsListEmpty(&urbr->list_state)); + WdfObjectDelete(urbr->hmem); +} + +static void +submit_urbr_unlink(pctx_ep_t ep, unsigned long seq_num_unlink) +{ + purb_req_t urbr_unlink; + + urbr_unlink = create_urbr(ep, NULL, seq_num_unlink); + if (urbr_unlink != NULL) { + NTSTATUS status = submit_urbr(urbr_unlink); + if (NT_ERROR(status)) { + TRD(URBR, "failed to submit unlink urb: %!URBR!", urbr_unlink); + free_urbr(urbr_unlink); + } + } +} + +static VOID +urbr_cancelled(_In_ WDFREQUEST req) +{ + purb_req_t urbr = (purb_req_t)WdfRequestGetInformation(req); + pctx_vusb_t vusb = urbr->ep->vusb; + + WdfWaitLockAcquire(vusb->lock, NULL); + RemoveEntryListInit(&urbr->list_state); + RemoveEntryListInit(&urbr->list_all); + if (vusb->urbr_sent_partial == urbr) { + vusb->urbr_sent_partial = NULL; + vusb->len_sent_partial = 0; + } + WdfWaitLockRelease(vusb->lock); + + submit_urbr_unlink(urbr->ep, urbr->seq_num); + TRD(URBR, "cancelled urbr destroyed: %!URBR!", urbr); + complete_urbr(urbr, STATUS_CANCELLED); +} + +NTSTATUS +submit_urbr(purb_req_t urbr) +{ + pctx_vusb_t vusb = urbr->ep->vusb; + WDFREQUEST req_read; + NTSTATUS status = STATUS_PENDING; + + WdfWaitLockAcquire(vusb->lock, NULL); + + if (vusb->urbr_sent_partial || vusb->pending_req_read == NULL) { + if (urbr->urb != NULL) { + WdfRequestMarkCancelable(urbr->req, urbr_cancelled); + } + InsertTailList(&vusb->head_urbr_pending, &urbr->list_state); + InsertTailList(&vusb->head_urbr, &urbr->list_all); + WdfWaitLockRelease(vusb->lock); + + TRD(URBR, "urb pending: %!URBR!", urbr); + return STATUS_PENDING; + } + + req_read = vusb->pending_req_read; + vusb->urbr_sent_partial = urbr; + + urbr->seq_num = ++(vusb->seq_num); + + WdfWaitLockRelease(vusb->lock); + + status = store_urbr(req_read, urbr); + + WdfWaitLockAcquire(vusb->lock, NULL); + + if (status == STATUS_SUCCESS) { + if (urbr->urb != NULL) { + WdfRequestMarkCancelable(urbr->req, urbr_cancelled); + } + if (vusb->len_sent_partial == 0) { + vusb->urbr_sent_partial = NULL; + InsertTailList(&vusb->head_urbr_sent, &urbr->list_state); + } + + InsertTailList(&vusb->head_urbr, &urbr->list_all); + + vusb->pending_req_read = NULL; + WdfWaitLockRelease(vusb->lock); + + WdfRequestUnmarkCancelable(req_read); + WdfRequestComplete(req_read, STATUS_SUCCESS); + status = STATUS_PENDING; + } + else { + vusb->urbr_sent_partial = NULL; + WdfWaitLockRelease(vusb->lock); + + status = STATUS_INVALID_PARAMETER; + } + + TRD(URBR, "urb requested: status:%s", dbg_ntstatus(status)); + return status; +} + +NTSTATUS +submit_req_urb(pctx_ep_t ep, WDFREQUEST req) +{ + purb_req_t urbr; + + urbr = create_urbr(ep, req, 0); + if (urbr == NULL) + return STATUS_UNSUCCESSFUL; + return submit_urbr(urbr); +} + +NTSTATUS +submit_req_select(pctx_ep_t ep, WDFREQUEST req, UCHAR is_select_conf, UCHAR conf_value, UCHAR intf_num, UCHAR alt_setting) +{ + purb_req_t urbr; + + urbr = create_urbr(ep, req, 0); + if (urbr == NULL) + return STATUS_UNSUCCESSFUL; + urbr->is_select_conf = is_select_conf; + urbr->conf_value = conf_value; + urbr->intf_num = intf_num; + urbr->alt_setting = alt_setting; + return submit_urbr(urbr); +} + +void +complete_urbr(purb_req_t urbr, NTSTATUS status) +{ + WDFREQUEST req; + + req = urbr->req; + if (req != NULL) { + if (urbr->urb == NULL) + WdfRequestComplete(req, status); + else { + WdfRequestUnmarkCancelable(req); + UdecxUrbCompleteWithNtStatus(req, status); + } + } + free_urbr(urbr); +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr.h b/driver/vhci_ude/vhci_urbr.h new file mode 100644 index 00000000..4129f3e5 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#include "usb_cspkt.h" + +#include "vhci_dev.h" + +typedef struct _urb_req { + pctx_ep_t ep; + WDFREQUEST req; + PURB urb; + unsigned long seq_num, seq_num_unlink; + UCHAR is_select_conf, conf_value, intf_num, alt_setting; + LIST_ENTRY list_all; + LIST_ENTRY list_state; + /* back reference to WDFMEMORY for deletion */ + WDFMEMORY hmem; +} urb_req_t, *purb_req_t; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(urb_req_t, TO_URBR) + +#define IS_TRANSFER_FLAGS_IN(flags) ((flags) & USBD_TRANSFER_DIRECTION_IN) + +#define RemoveEntryListInit(le) do { RemoveEntryList(le); InitializeListHead(le); } while (0) + +extern struct usbip_header *get_hdr_from_req_read(WDFREQUEST req_read); +extern PVOID get_data_from_req_read(WDFREQUEST req_read, ULONG length); + +extern ULONG get_read_payload_length(WDFREQUEST req_read); + +extern PVOID get_buf(PVOID buf, PMDL bufMDL); + +extern NTSTATUS +copy_to_transfer_buffer(PVOID buf_dst, PMDL bufMDL, int dst_len, PVOID src, int src_len); + +extern void set_cmd_submit_usbip_header(struct usbip_header *hdr, unsigned long seqnum, unsigned int devid, + unsigned int direct, pctx_ep_t ep, unsigned int flags, unsigned int len); +extern void set_cmd_unlink_usbip_header(struct usbip_header *h, unsigned long seqnum, unsigned int devid, + unsigned long seqnum_unlink); + +extern void +build_setup_packet(usb_cspkt_t *csp, unsigned char direct_in, unsigned char type, unsigned char recip, unsigned char request); + +extern NTSTATUS +submit_req_urb(pctx_ep_t ep, WDFREQUEST req); +extern NTSTATUS +submit_req_select(pctx_ep_t ep, WDFREQUEST req, UCHAR is_select_conf, UCHAR conf_value, UCHAR intf_num, UCHAR alt_setting); +extern NTSTATUS +submit_urbr(purb_req_t urbr); +extern NTSTATUS +store_urbr(WDFREQUEST req_read, purb_req_t urbr); + +extern void +complete_urbr(purb_req_t urbr, NTSTATUS status); diff --git a/driver/vhci_ude/vhci_urbr_fetch.c b/driver/vhci_ude/vhci_urbr_fetch.c new file mode 100644 index 00000000..afbac02e --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch.c @@ -0,0 +1,119 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch.tmh" + +#include "vhci_urbr.h" +#include "usbd_helper.h" + +extern NTSTATUS +fetch_urbr_status(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_dscr(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_control_transfer(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_control_transfer_ex(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_vendor_or_class(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_bulk_or_interrupt(PURB urb, struct usbip_header *hdr); +extern NTSTATUS +fetch_urbr_iso(PURB urb, struct usbip_header *hdr); + +NTSTATUS +copy_to_transfer_buffer(PVOID buf_dst, PMDL bufMDL, int dst_len, PVOID src, int src_len) +{ + PVOID buf; + + if (dst_len < src_len) { + TRE(WRITE, "too small buffer: dest: %d, src: %d\n", dst_len, src_len); + return STATUS_INVALID_PARAMETER; + } + buf = get_buf(buf_dst, bufMDL); + if (buf == NULL) + return STATUS_INVALID_PARAMETER; + + RtlCopyMemory(buf, src, src_len); + return STATUS_SUCCESS; +} + +static NTSTATUS +fetch_urbr_urb(PURB urb, struct usbip_header *hdr) +{ + NTSTATUS status; + + switch (urb->UrbHeader.Function) { + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + status = fetch_urbr_status(urb, hdr); + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + status = fetch_urbr_dscr(urb, hdr); + break; + case URB_FUNCTION_CONTROL_TRANSFER: + status = fetch_urbr_control_transfer(urb, hdr); + break; + case URB_FUNCTION_CONTROL_TRANSFER_EX: + status = fetch_urbr_control_transfer_ex(urb, hdr); + break; + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_VENDOR_OTHER: + status = fetch_urbr_vendor_or_class(urb, hdr); + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + status = fetch_urbr_bulk_or_interrupt(urb, hdr); + break; + case URB_FUNCTION_ISOCH_TRANSFER: + status = fetch_urbr_iso(urb, hdr); + break; +#if 0 + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + status = STATUS_SUCCESS; + break; +#endif + default: + TRW(WRITE, "not supported func: %!URBFUNC!", urb->UrbHeader.Function); + status = STATUS_INVALID_PARAMETER; + break; + } + + if (status == STATUS_SUCCESS) + urb->UrbHeader.Status = to_usbd_status(hdr->u.ret_submit.status); + + return status; +} + +static NTSTATUS +fetch_urbr_error(purb_req_t urbr, struct usbip_header *hdr) +{ + if (urbr->req != NULL && urbr->urb != NULL) { + PURB urb = urbr->urb; + + urb->UrbHeader.Status = to_usbd_status(hdr->u.ret_submit.status); + if (urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { + urb->UrbBulkOrInterruptTransfer.TransferBufferLength = hdr->u.ret_submit.actual_length; + } + TRW(WRITE, "%!URBFUNC!: wrong status: %s", urb->UrbHeader.Function, dbg_usbd_status(urb->UrbHeader.Status)); + } + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +fetch_urbr(purb_req_t urbr, struct usbip_header *hdr) +{ + if (hdr->u.ret_submit.status != 0) + return fetch_urbr_error(urbr, hdr); + + if (urbr->urb == NULL) + return STATUS_SUCCESS; + + return fetch_urbr_urb(urbr->urb, hdr); +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_bulk.c b/driver/vhci_ude/vhci_urbr_fetch_bulk.c new file mode 100644 index 00000000..ab232384 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_bulk.c @@ -0,0 +1,20 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_bulk.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +fetch_urbr_bulk_or_interrupt(PURB urb, struct usbip_header *hdr) +{ + struct _URB_BULK_OR_INTERRUPT_TRANSFER *urb_bi = &urb->UrbBulkOrInterruptTransfer; + + if (IS_TRANSFER_FLAGS_IN(urb_bi->TransferFlags)) { + NTSTATUS status; + status = copy_to_transfer_buffer(urb_bi->TransferBuffer, urb_bi->TransferBufferMDL, + urb_bi->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_bi->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_control.c b/driver/vhci_ude/vhci_urbr_fetch_control.c new file mode 100644 index 00000000..fe05acf3 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_control.c @@ -0,0 +1,32 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_control.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +fetch_urbr_control_transfer(PURB urb, struct usbip_header *hdr) +{ + struct _URB_CONTROL_TRANSFER *urb_ctltrans = &urb->UrbControlTransfer; + NTSTATUS status; + + if (urb_ctltrans->TransferBufferLength == 0) + return STATUS_SUCCESS; + status = copy_to_transfer_buffer(urb_ctltrans->TransferBuffer, urb_ctltrans->TransferBufferMDL, + urb_ctltrans->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_ctltrans->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; +} + +NTSTATUS +fetch_urbr_control_transfer_ex(PURB urb, struct usbip_header *hdr) +{ + struct _URB_CONTROL_TRANSFER_EX *urb_ctltrans_ex = &urb->UrbControlTransferEx; + NTSTATUS status; + + status = copy_to_transfer_buffer(urb_ctltrans_ex->TransferBuffer, urb_ctltrans_ex->TransferBufferMDL, + urb_ctltrans_ex->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_ctltrans_ex->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_dscr.c b/driver/vhci_ude/vhci_urbr_fetch_dscr.c new file mode 100644 index 00000000..a9ae2c2d --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_dscr.c @@ -0,0 +1,17 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_status.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +fetch_urbr_dscr(PURB urb, struct usbip_header *hdr) +{ + struct _URB_CONTROL_DESCRIPTOR_REQUEST *urb_desc = &urb->UrbControlDescriptorRequest; + NTSTATUS status; + + status = copy_to_transfer_buffer(urb_desc->TransferBuffer, urb_desc->TransferBufferMDL, + urb_desc->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_desc->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_iso.c b/driver/vhci_ude/vhci_urbr_fetch_iso.c new file mode 100644 index 00000000..a4df6b45 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_iso.c @@ -0,0 +1,71 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_iso.tmh" + +#include "vhci_urbr.h" +#include "usbd_helper.h" + +static BOOLEAN +save_iso_desc(struct _URB_ISOCH_TRANSFER *urb, struct usbip_iso_packet_descriptor *iso_desc) +{ + ULONG i; + + for (i = 0; i < urb->NumberOfPackets; i++) { + if (iso_desc->offset > urb->IsoPacket[i].Offset) { + TRW(WRITE, "why offset changed?%d %d %d %d", i, iso_desc->offset, iso_desc->actual_length, urb->IsoPacket[i].Offset); + return FALSE; + } + urb->IsoPacket[i].Length = iso_desc->actual_length; + urb->IsoPacket[i].Status = to_usbd_status(iso_desc->status); + iso_desc++; + } + return TRUE; +} + +static void +fetch_iso_data(char *dest, ULONG dest_len, char *src, ULONG src_len, struct _URB_ISOCH_TRANSFER *urb) +{ + ULONG i; + ULONG offset = 0; + + for (i = 0; i < urb->NumberOfPackets; i++) { + if (urb->IsoPacket[i].Length == 0) + continue; + + if (urb->IsoPacket[i].Offset + urb->IsoPacket[i].Length > dest_len) { + TRW(WRITE, "Warning, why this?"); + break; + } + if (offset + urb->IsoPacket[i].Length > src_len) { + TRE(WRITE, "Warning, why that?"); + break; + } + RtlCopyMemory(dest + urb->IsoPacket[i].Offset, src + offset, urb->IsoPacket[i].Length); + offset += urb->IsoPacket[i].Length; + } + if (offset != src_len) { + TRW(WRITE, "why not equal offset:%d src_len:%d", offset, src_len); + } +} + +NTSTATUS +fetch_urbr_iso(PURB urb, struct usbip_header *hdr) +{ + struct _URB_ISOCH_TRANSFER *urb_iso = &urb->UrbIsochronousTransfer; + struct usbip_iso_packet_descriptor *iso_desc; + PVOID buf; + int in_len = 0; + + if (IS_TRANSFER_FLAGS_IN(urb_iso->TransferFlags)) + in_len = hdr->u.ret_submit.actual_length; + iso_desc = (struct usbip_iso_packet_descriptor *)((char *)(hdr + 1) + in_len); + if (!save_iso_desc(urb_iso, iso_desc)) + return STATUS_INVALID_PARAMETER; + + urb_iso->ErrorCount = hdr->u.ret_submit.error_count; + buf = get_buf(urb_iso->TransferBuffer, urb_iso->TransferBufferMDL); + if (buf == NULL) + return STATUS_INVALID_PARAMETER; + fetch_iso_data(buf, urb_iso->TransferBufferLength, (char *)(hdr + 1), hdr->u.ret_submit.actual_length, urb_iso); + urb_iso->TransferBufferLength = hdr->u.ret_submit.actual_length; + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_status.c b/driver/vhci_ude/vhci_urbr_fetch_status.c new file mode 100644 index 00000000..4a26a80e --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_status.c @@ -0,0 +1,17 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_status.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +fetch_urbr_status(PURB urb, struct usbip_header *hdr) +{ + struct _URB_CONTROL_GET_STATUS_REQUEST *urb_status = &urb->UrbControlGetStatusRequest; + NTSTATUS status; + + status = copy_to_transfer_buffer(urb_status->TransferBuffer, urb_status->TransferBufferMDL, + urb_status->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_status->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_fetch_vendor.c b/driver/vhci_ude/vhci_urbr_fetch_vendor.c new file mode 100644 index 00000000..ea1a0d4e --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_fetch_vendor.c @@ -0,0 +1,23 @@ +#include "vhci_driver.h" +#include "vhci_urbr_fetch_vendor.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +fetch_urbr_vendor_or_class(PURB urb, struct usbip_header *hdr) +{ + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *urb_vendor_class = &urb->UrbControlVendorClassRequest; + + if (IS_TRANSFER_FLAGS_IN(urb_vendor_class->TransferFlags)) { + NTSTATUS status; + status = copy_to_transfer_buffer(urb_vendor_class->TransferBuffer, urb_vendor_class->TransferBufferMDL, + urb_vendor_class->TransferBufferLength, hdr + 1, hdr->u.ret_submit.actual_length); + if (status == STATUS_SUCCESS) + urb_vendor_class->TransferBufferLength = hdr->u.ret_submit.actual_length; + return status; + } + else { + urb_vendor_class->TransferBufferLength = hdr->u.ret_submit.actual_length; + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store.c b/driver/vhci_ude/vhci_urbr_store.c new file mode 100644 index 00000000..94cf1004 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store.c @@ -0,0 +1,184 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store.tmh" + +#include "vhci_urbr.h" + +extern NTSTATUS +store_urbr_control_transfer_partial(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_control_transfer_ex_partial(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_vendor_class_partial(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_bulk_partial(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_iso_partial(WDFREQUEST req_read, purb_req_t urbr); + +extern NTSTATUS +store_urbr_get_status(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_dscr_dev(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_dscr_intf(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_control_transfer(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_control_transfer_ex(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_vendor_class(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_bulk(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_iso(WDFREQUEST req_read, purb_req_t urbr); + +extern NTSTATUS +store_urbr_select_config(WDFREQUEST req_read, purb_req_t urbr); +extern NTSTATUS +store_urbr_select_interface(WDFREQUEST req_read, purb_req_t urbr); + +NTSTATUS +store_urbr_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + PURB urb; + USHORT urbfunc; + WDF_REQUEST_PARAMETERS params; + NTSTATUS status; + + TRD(READ, "Enter: urbr: %!URBR!", urbr); + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + WdfRequestGetParameters(urbr->req, ¶ms); + + urb = (PURB)params.Parameters.Others.Arg1; + urbfunc = urb->UrbHeader.Function; + + switch (urbfunc) { + case URB_FUNCTION_CONTROL_TRANSFER: + status = store_urbr_control_transfer_partial(req_read, urbr); + break; + case URB_FUNCTION_CONTROL_TRANSFER_EX: + status = store_urbr_control_transfer_ex_partial(req_read, urbr); + break; + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + status = store_urbr_vendor_class_partial(req_read, urbr); + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + status = store_urbr_bulk_partial(req_read, urbr); + break; + case URB_FUNCTION_ISOCH_TRANSFER: + status = store_urbr_iso_partial(req_read, urbr); + break; + default: + TRW(READ, "unexpected partial urbr: %!URBFUNC!", urbfunc); + status = STATUS_INVALID_PARAMETER; + break; + } + + TRD(READ, "Leave: %!STATUS!", status); + + return status; +} + +static NTSTATUS +store_urbr_urb(WDFREQUEST req_read, purb_req_t urbr) +{ + USHORT urb_func; + NTSTATUS status; + + urb_func = urbr->urb->UrbHeader.Function; + TRD(READ, "urbr: %s, func:%!URBFUNC!", dbg_urbr(urbr), urb_func); + + switch (urb_func) { + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + status = store_urbr_get_status(req_read, urbr); + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + status = store_urbr_dscr_dev(req_read, urbr); + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + status = store_urbr_dscr_intf(req_read, urbr); + break; + case URB_FUNCTION_CONTROL_TRANSFER: + status = store_urbr_control_transfer(req_read, urbr); + break; + case URB_FUNCTION_CONTROL_TRANSFER_EX: + status = store_urbr_control_transfer_ex(req_read, urbr); + break; + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + status = store_urbr_vendor_class(req_read, urbr); + break; + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + status = store_urbr_bulk(req_read, urbr); + break; + case URB_FUNCTION_ISOCH_TRANSFER: + status = store_urbr_iso(req_read, urbr); + break; +#if 0 + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + status = store_urb_reset_pipe(irp, urb, urbr); + break; +#endif + default: + WdfRequestSetInformation(req_read, 0); + TRE(READ, "unhandled urb function: %!URBFUNC!", urb_func); + status = STATUS_INVALID_PARAMETER; + break; + } + + return status; +} + +static NTSTATUS +store_urbr_select(WDFREQUEST req_read, purb_req_t urbr) +{ + if (urbr->is_select_conf) + return store_urbr_select_config(req_read, urbr); + else + return store_urbr_select_interface(req_read, urbr); +} + +static NTSTATUS +store_cancelled_urbr(WDFREQUEST req_read, purb_req_t urbr) +{ + struct usbip_header *hdr; + + TRD(READ, "Enter"); + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_INVALID_PARAMETER; + + set_cmd_unlink_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, urbr->seq_num_unlink); + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr(WDFREQUEST req_read, purb_req_t urbr) +{ + TRD(READ, "urbr: %s", dbg_urbr(urbr)); + + if (urbr->req == NULL) { + return store_cancelled_urbr(req_read, urbr); + } + if (urbr->urb == NULL) { + return store_urbr_select(req_read, urbr); + } + return store_urbr_urb(req_read, urbr); +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_bulk.c b/driver/vhci_ude/vhci_urbr_store_bulk.c new file mode 100644 index 00000000..575972a3 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_bulk.c @@ -0,0 +1,66 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_bulk.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_bulk_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_BULK_OR_INTERRUPT_TRANSFER *urb_bi = &urbr->urb->UrbBulkOrInterruptTransfer; + PVOID dst, src; + NTSTATUS status; + + status = WdfRequestRetrieveOutputBuffer(req_read, urb_bi->TransferBufferLength, &dst, NULL); + if (NT_ERROR(status)) + return STATUS_BUFFER_TOO_SMALL; + + src = get_buf(urb_bi->TransferBuffer, urb_bi->TransferBufferMDL); + if (src == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(dst, src, urb_bi->TransferBufferLength); + WdfRequestSetInformation(req_read, urb_bi->TransferBufferLength); + urbr->ep->vusb->len_sent_partial = 0; + + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_bulk(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_BULK_OR_INTERRUPT_TRANSFER *urb_bi = &urbr->urb->UrbBulkOrInterruptTransfer; + struct usbip_header *hdr; + int in, type; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + /* Sometimes, direction in TransferFlags of _URB_BULK_OR_INTERRUPT_TRANSFER is not consistent with PipeHandle. + * Use a direction flag in pipe handle. + */ + in = IS_TRANSFER_FLAGS_IN(urb_bi->TransferFlags); + type = urbr->ep->type; + if (type != USB_ENDPOINT_TYPE_BULK && type != USB_ENDPOINT_TYPE_INTERRUPT) { + TRE(READ, "Error, not a bulk or a interrupt pipe\n"); + return STATUS_INVALID_PARAMETER; + } + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, in, urbr->ep, + urb_bi->TransferFlags, urb_bi->TransferBufferLength); + RtlZeroMemory(hdr->u.cmd_submit.setup, 8); + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + + if (!in) { + if (get_read_payload_length(req_read) >= urb_bi->TransferBufferLength) { + PVOID buf = get_buf(urb_bi->TransferBuffer, urb_bi->TransferBufferMDL); + if (buf == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(hdr + 1, buf, urb_bi->TransferBufferLength); + } + else { + urbr->ep->vusb->len_sent_partial = sizeof(struct usbip_header); + } + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_control.c b/driver/vhci_ude/vhci_urbr_store_control.c new file mode 100644 index 00000000..27c5f581 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_control.c @@ -0,0 +1,156 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_control.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_control_transfer_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_TRANSFER *urb_ctltrans = &urbr->urb->UrbControlTransfer; + PVOID dst; + char *buf; + + dst = get_data_from_req_read(req_read, urb_ctltrans->TransferBufferLength); + if (dst == NULL) + return STATUS_BUFFER_TOO_SMALL; + + /* + * reading from TransferBuffer or TransferBufferMDL, + * whichever of them is not null + */ + buf = get_buf(urb_ctltrans->TransferBuffer, urb_ctltrans->TransferBufferMDL); + if (buf == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(dst, buf, urb_ctltrans->TransferBufferLength); + WdfRequestSetInformation(req_read, urb_ctltrans->TransferBufferLength); + urbr->ep->vusb->len_sent_partial = 0; + + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_control_transfer_ex_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_TRANSFER_EX *urb_ctltrans_ex = &urbr->urb->UrbControlTransferEx; + PVOID dst; + char *buf; + + dst = get_data_from_req_read(req_read, urb_ctltrans_ex->TransferBufferLength); + if (dst == NULL) + return STATUS_BUFFER_TOO_SMALL; + + /* + * reading from TransferBuffer or TransferBufferMDL, + * whichever of them is not null + */ + buf = get_buf(urb_ctltrans_ex->TransferBuffer, urb_ctltrans_ex->TransferBufferMDL); + if (buf == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(dst, buf, urb_ctltrans_ex->TransferBufferLength); + WdfRequestSetInformation(req_read, urb_ctltrans_ex->TransferBufferLength); + urbr->ep->vusb->len_sent_partial = 0; + + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_control_transfer(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_TRANSFER *urb_ctltrans = &urbr->urb->UrbControlTransfer; + struct usbip_header *hdr; + int in = IS_TRANSFER_FLAGS_IN(urb_ctltrans->TransferFlags); + ULONG nread = 0; + NTSTATUS status = STATUS_SUCCESS; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, in, urbr->ep, + urb_ctltrans->TransferFlags | USBD_SHORT_TRANSFER_OK, urb_ctltrans->TransferBufferLength); + RtlCopyMemory(hdr->u.cmd_submit.setup, urb_ctltrans->SetupPacket, 8); + + nread = sizeof(struct usbip_header); + if (!in && urb_ctltrans->TransferBufferLength > 0) { + if (get_read_payload_length(req_read) >= urb_ctltrans->TransferBufferLength) { + PVOID buf = get_buf(urb_ctltrans->TransferBuffer, urb_ctltrans->TransferBufferMDL); + if (buf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + nread += urb_ctltrans->TransferBufferLength; + RtlCopyMemory(hdr + 1, buf, urb_ctltrans->TransferBufferLength); + } + else { + urbr->ep->vusb->len_sent_partial = sizeof(struct usbip_header); + } + } +out: + WdfRequestSetInformation(req_read, nread); + return status; +} + +NTSTATUS +store_urbr_control_transfer_ex(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_TRANSFER_EX *urb_ctltrans_ex = &urbr->urb->UrbControlTransferEx; + struct usbip_header *hdr; + int in = IS_TRANSFER_FLAGS_IN(urb_ctltrans_ex->TransferFlags); + ULONG nread = 0; + NTSTATUS status = STATUS_SUCCESS; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, in, urbr->ep, + urb_ctltrans_ex->TransferFlags, urb_ctltrans_ex->TransferBufferLength); + RtlCopyMemory(hdr->u.cmd_submit.setup, urb_ctltrans_ex->SetupPacket, 8); + + nread = sizeof(struct usbip_header); + if (!in) { + if (get_read_payload_length(req_read) >= urb_ctltrans_ex->TransferBufferLength) { + PVOID buf = get_buf(urb_ctltrans_ex->TransferBuffer, urb_ctltrans_ex->TransferBufferMDL); + if (buf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + nread += urb_ctltrans_ex->TransferBufferLength; + RtlCopyMemory(hdr + 1, buf, urb_ctltrans_ex->TransferBufferLength); + } + else { + urbr->ep->vusb->len_sent_partial = sizeof(struct usbip_header); + } + } +out: + WdfRequestSetInformation(req_read, nread); + return status; +} + +#if 0 ///DEL +NTSTATUS +store_urb_select_config(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_SELECT_CONFIGURATION *urb_sc = &urbr->urb->UrbSelectConfiguration; + struct usbip_header *hdr; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->vusb->devid, 0, 0, 0, 0); + build_setup_packet(csp, 0, BMREQUEST_STANDARD, BMREQUEST_TO_DEVICE, USB_REQUEST_SET_CONFIGURATION); + csp->wLength = 0; + if (urb_sc->ConfigurationDescriptor == NULL) + csp->wValue.W = 0; + else + csp->wValue.W = urb_sc->ConfigurationDescriptor->bConfigurationValue; + csp->wIndex.W = 0; + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} +#endif \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_dscr.c b/driver/vhci_ude/vhci_urbr_store_dscr.c new file mode 100644 index 00000000..fe8995ce --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_dscr.c @@ -0,0 +1,70 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_dscr.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_dscr_dev(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_DESCRIPTOR_REQUEST *urb_dscr = &urbr->urb->UrbControlDescriptorRequest; + struct usbip_header *hdr; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, USBIP_DIR_IN, NULL, + USBD_SHORT_TRANSFER_OK, urb_dscr->TransferBufferLength); + build_setup_packet(csp, USBIP_DIR_IN, BMREQUEST_STANDARD, BMREQUEST_TO_DEVICE, USB_REQUEST_GET_DESCRIPTOR); + + csp->wLength = (unsigned short)urb_dscr->TransferBufferLength; + csp->wValue.HiByte = urb_dscr->DescriptorType; + csp->wValue.LowByte = urb_dscr->Index; + + switch (urb_dscr->DescriptorType) { + case USB_DEVICE_DESCRIPTOR_TYPE: + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + csp->wIndex.W = 0; + break; + case USB_INTERFACE_DESCRIPTOR_TYPE: + csp->wIndex.W = urb_dscr->Index; + break; + case USB_STRING_DESCRIPTOR_TYPE: + csp->wIndex.W = urb_dscr->LanguageId; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_dscr_intf(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_DESCRIPTOR_REQUEST *urb_dscr = &urbr->urb->UrbControlDescriptorRequest; + struct usbip_header *hdr; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, USBIP_DIR_IN, NULL, + USBD_SHORT_TRANSFER_OK, urb_dscr->TransferBufferLength); + build_setup_packet(csp, USBIP_DIR_IN, BMREQUEST_STANDARD, BMREQUEST_TO_INTERFACE, USB_REQUEST_GET_DESCRIPTOR); + + csp->wLength = (unsigned short)urb_dscr->TransferBufferLength; + csp->wValue.HiByte = urb_dscr->DescriptorType; + csp->wValue.LowByte = urb_dscr->Index; + csp->wIndex.W = urb_dscr->LanguageId; + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_iso.c b/driver/vhci_ude/vhci_urbr_store_iso.c new file mode 100644 index 00000000..310584e9 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_iso.c @@ -0,0 +1,110 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_iso.tmh" + +#include "vhci_urbr.h" + +static NTSTATUS +store_iso_data(PVOID dst, struct _URB_ISOCH_TRANSFER *urb_iso) +{ + struct usbip_iso_packet_descriptor *iso_desc; + char *buf; + ULONG i, offset; + + buf = get_buf(urb_iso->TransferBuffer, urb_iso->TransferBufferMDL); + if (buf == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + if (IS_TRANSFER_FLAGS_IN(urb_iso->TransferFlags)) { + iso_desc = (struct usbip_iso_packet_descriptor *)dst; + } + else { + RtlCopyMemory(dst, buf, urb_iso->TransferBufferLength); + iso_desc = (struct usbip_iso_packet_descriptor *)((char *)dst + urb_iso->TransferBufferLength); + } + + offset = 0; + for (i = 0; i < urb_iso->NumberOfPackets; i++) { + if (urb_iso->IsoPacket[i].Offset < offset) { + TRW(READ, "strange iso packet offset:%d %d", offset, urb_iso->IsoPacket[i].Offset); + return STATUS_INVALID_PARAMETER; + } + iso_desc->offset = urb_iso->IsoPacket[i].Offset; + if (i > 0) + (iso_desc - 1)->length = urb_iso->IsoPacket[i].Offset - offset; + offset = urb_iso->IsoPacket[i].Offset; + iso_desc->actual_length = 0; + iso_desc->status = 0; + iso_desc++; + } + (iso_desc - 1)->length = urb_iso->TransferBufferLength - offset; + + return STATUS_SUCCESS; +} + +static ULONG +get_iso_payload_len(struct _URB_ISOCH_TRANSFER *urb_iso) +{ + ULONG len_iso; + + len_iso = urb_iso->NumberOfPackets * sizeof(struct usbip_iso_packet_descriptor); + if (!IS_TRANSFER_FLAGS_IN(urb_iso->TransferFlags)) { + len_iso += urb_iso->TransferBufferLength; + } + return len_iso; +} + +NTSTATUS +store_urbr_iso_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_ISOCH_TRANSFER *urb_iso = &urbr->urb->UrbIsochronousTransfer; + ULONG len_iso; + PVOID dst; + + len_iso = get_iso_payload_len(urb_iso); + + dst = get_data_from_req_read(req_read, len_iso); + if (dst == NULL) + return STATUS_BUFFER_TOO_SMALL; + + store_iso_data(dst, urb_iso); + urbr->ep->vusb->len_sent_partial = 0; + WdfRequestSetInformation(req_read, len_iso); + + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_iso(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_ISOCH_TRANSFER *urb_iso = &urbr->urb->UrbIsochronousTransfer; + struct usbip_header *hdr; + int in, type; + + in = IS_TRANSFER_FLAGS_IN(urb_iso->TransferFlags); + type = urbr->ep->type; + if (type != USB_ENDPOINT_TYPE_ISOCHRONOUS) { + TRE(READ, "Error, not a iso pipe"); + return STATUS_INVALID_PARAMETER; + } + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, in, urbr->ep, + urb_iso->TransferFlags | USBD_SHORT_TRANSFER_OK, urb_iso->TransferBufferLength); + hdr->u.cmd_submit.start_frame = urb_iso->StartFrame; + hdr->u.cmd_submit.number_of_packets = urb_iso->NumberOfPackets; + + + if (get_read_payload_length(req_read) >= get_iso_payload_len(urb_iso)) { + store_iso_data(hdr + 1, urb_iso); + WdfRequestSetInformation(req_read, sizeof(struct usbip_header) + get_iso_payload_len(urb_iso)); + } + else { + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + urbr->ep->vusb->len_sent_partial = sizeof(struct usbip_header); + } + + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_select.c b/driver/vhci_ude/vhci_urbr_store_select.c new file mode 100644 index 00000000..68d5eef5 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_select.c @@ -0,0 +1,48 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_select_config(WDFREQUEST req_read, purb_req_t urbr) +{ + struct usbip_header *hdr; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, 0, 0, 0, 0); + build_setup_packet(csp, 0, BMREQUEST_STANDARD, BMREQUEST_TO_DEVICE, USB_REQUEST_SET_CONFIGURATION); + csp->wLength = 0; + csp->wValue.W = urbr->conf_value; + csp->wIndex.W = 0; + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_select_interface(WDFREQUEST req_read, purb_req_t urbr) +{ + struct usbip_header *hdr; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, 0, 0, 0, 0); + build_setup_packet(csp, 0, BMREQUEST_STANDARD, BMREQUEST_TO_INTERFACE, USB_REQUEST_SET_INTERFACE); + csp->wLength = 0; + csp->wValue.W = urbr->intf_num; + csp->wIndex.W = urbr->alt_setting; + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} diff --git a/driver/vhci_ude/vhci_urbr_store_status.c b/driver/vhci_ude/vhci_urbr_store_status.c new file mode 100644 index 00000000..d117068a --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_status.c @@ -0,0 +1,53 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_status.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_get_status(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_GET_STATUS_REQUEST *urb_status = &urbr->urb->UrbControlGetStatusRequest; + struct usbip_header *hdr; + USHORT urbfunc; + char recip; + usb_cspkt_t *csp; + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, USBIP_DIR_IN, NULL, + USBD_SHORT_TRANSFER_OK, urb_status->TransferBufferLength); + + urbfunc = urb_status->Hdr.Function; + TRD(READ, "urbr: %!URBR!, func:%!URBFUNC!", urbr, urbfunc); + + switch (urbfunc) { + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + recip = BMREQUEST_TO_DEVICE; + break; + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + recip = BMREQUEST_TO_INTERFACE; + break; + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + recip = BMREQUEST_TO_ENDPOINT; + break; + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + recip = BMREQUEST_TO_OTHER; + break; + default: + TRW(READ, "unhandled urb function: %!URBFUNC!: len: %d", urbfunc, urb_status->Hdr.Length); + return STATUS_INVALID_PARAMETER; + } + + build_setup_packet(csp, USBIP_DIR_IN, BMREQUEST_STANDARD, recip, USB_REQUEST_GET_STATUS); + + csp->wLength = (unsigned short)urb_status->TransferBufferLength; + csp->wIndex.W = urb_status->Index; + csp->wValue.W = 0; + + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_urbr_store_vendor.c b/driver/vhci_ude/vhci_urbr_store_vendor.c new file mode 100644 index 00000000..529ef141 --- /dev/null +++ b/driver/vhci_ude/vhci_urbr_store_vendor.c @@ -0,0 +1,103 @@ +#include "vhci_driver.h" +#include "vhci_urbr_store_vendor.tmh" + +#include "vhci_urbr.h" + +NTSTATUS +store_urbr_vendor_class_partial(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *urb_vendor_class = &urbr->urb->UrbControlVendorClassRequest; + PVOID dst; + char *buf; + + dst = get_data_from_req_read(req_read, urb_vendor_class->TransferBufferLength); + if (dst == NULL) + return STATUS_BUFFER_TOO_SMALL; + + /* + * reading from TransferBuffer or TransferBufferMDL, + * whichever of them is not null + */ + buf = get_buf(urb_vendor_class->TransferBuffer, urb_vendor_class->TransferBufferMDL); + if (buf == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlCopyMemory(dst, buf, urb_vendor_class->TransferBufferLength); + WdfRequestSetInformation(req_read, urb_vendor_class->TransferBufferLength); + urbr->ep->vusb->len_sent_partial = 0; + + return STATUS_SUCCESS; +} + +NTSTATUS +store_urbr_vendor_class(WDFREQUEST req_read, purb_req_t urbr) +{ + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *urb_vendor_class = &urbr->urb->UrbControlVendorClassRequest; + struct usbip_header *hdr; + usb_cspkt_t *csp; + char type, recip; + int in = IS_TRANSFER_FLAGS_IN(urb_vendor_class->TransferFlags); + + hdr = get_hdr_from_req_read(req_read); + if (hdr == NULL) + return STATUS_BUFFER_TOO_SMALL; + + switch (urb_vendor_class->Hdr.Function) { + case URB_FUNCTION_CLASS_DEVICE: + type = BMREQUEST_CLASS; + recip = BMREQUEST_TO_DEVICE; + break; + case URB_FUNCTION_CLASS_INTERFACE: + type = BMREQUEST_CLASS; + recip = BMREQUEST_TO_INTERFACE; + break; + case URB_FUNCTION_CLASS_ENDPOINT: + type = BMREQUEST_CLASS; + recip = BMREQUEST_TO_ENDPOINT; + break; + case URB_FUNCTION_CLASS_OTHER: + type = BMREQUEST_CLASS; + recip = BMREQUEST_TO_OTHER; + break; + case URB_FUNCTION_VENDOR_DEVICE: + type = BMREQUEST_VENDOR; + recip = BMREQUEST_TO_DEVICE; + break; + case URB_FUNCTION_VENDOR_INTERFACE: + type = BMREQUEST_VENDOR; + recip = BMREQUEST_TO_INTERFACE; + break; + case URB_FUNCTION_VENDOR_ENDPOINT: + type = BMREQUEST_VENDOR; + recip = BMREQUEST_TO_ENDPOINT; + break; + case URB_FUNCTION_VENDOR_OTHER: + type = BMREQUEST_VENDOR; + recip = BMREQUEST_TO_OTHER; + break; + default: + return STATUS_INVALID_PARAMETER; + } + + csp = (usb_cspkt_t *)hdr->u.cmd_submit.setup; + + set_cmd_submit_usbip_header(hdr, urbr->seq_num, urbr->ep->vusb->devid, in, NULL, + urb_vendor_class->TransferFlags | USBD_SHORT_TRANSFER_OK, urb_vendor_class->TransferBufferLength); + build_setup_packet(csp, (unsigned char)in, type, recip, urb_vendor_class->Request); + //FIXME what is the usage of RequestTypeReservedBits? + csp->wLength = (unsigned short)urb_vendor_class->TransferBufferLength; + csp->wValue.W = urb_vendor_class->Value; + csp->wIndex.W = urb_vendor_class->Index; + + if (!in) { + if (get_read_payload_length(req_read) >= urb_vendor_class->TransferBufferLength) { + RtlCopyMemory(hdr + 1, urb_vendor_class->TransferBuffer, urb_vendor_class->TransferBufferLength); + WdfRequestSetInformation(req_read, sizeof(struct usbip_header) + urb_vendor_class->TransferBufferLength); + } + else { + WdfRequestSetInformation(req_read, sizeof(struct usbip_header)); + urbr->ep->vusb->len_sent_partial = sizeof(struct usbip_header); + } + } + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/driver/vhci_ude/vhci_write.c b/driver/vhci_ude/vhci_write.c new file mode 100644 index 00000000..a0846d15 --- /dev/null +++ b/driver/vhci_ude/vhci_write.c @@ -0,0 +1,75 @@ +#include "vhci_driver.h" +#include "vhci_write.tmh" + +#include "vhci_urbr.h" + +extern purb_req_t +find_sent_urbr(pctx_vusb_t vusb, struct usbip_header *hdr); + +extern NTSTATUS +fetch_urbr(purb_req_t urbr, struct usbip_header *hdr); + +static struct usbip_header * +get_hdr_from_req_write(WDFREQUEST req_write) +{ + struct usbip_header *hdr; + size_t len; + NTSTATUS status; + + status = WdfRequestRetrieveInputBuffer(req_write, sizeof(struct usbip_header), &hdr, &len); + if (NT_ERROR(status)) { + WdfRequestSetInformation(req_write, 0); + return NULL; + } + + WdfRequestSetInformation(req_write, len); + return hdr; +} + +static VOID +write_vusb(pctx_vusb_t vusb, WDFREQUEST req_write) +{ + struct usbip_header *hdr; + purb_req_t urbr; + NTSTATUS status; + + TRD(WRITE, "Enter"); + + hdr = get_hdr_from_req_write(req_write); + if (hdr == NULL) { + TRE(WRITE, "small write irp\n"); + status = STATUS_INVALID_PARAMETER; + goto out; + } + + urbr = find_sent_urbr(vusb, hdr); + if (urbr == NULL) { + // Might have been cancelled before, so return STATUS_SUCCESS + TRW(WRITE, "no urbr: seqnum: %d", hdr->base.seqnum); + status = STATUS_SUCCESS; + goto out; + } + + status = fetch_urbr(urbr, hdr); + complete_urbr(urbr, status); +out: + TRD(WRITE, "Leave: %!STATUS!", status); +} + +VOID +io_write(_In_ WDFQUEUE queue, _In_ WDFREQUEST req, _In_ size_t len) +{ + pctx_vusb_t vusb; + + UNREFERENCED_PARAMETER(queue); + + TRD(WRITE, "Enter: len: %u", (ULONG)len); + + vusb = *TO_PVUSB(WdfRequestGetFileObject(req)); + + write_vusb(vusb, req); + + WdfRequestCompleteWithInformation(req, STATUS_SUCCESS, len); + + TRD(WRITE, "Leave"); +} \ No newline at end of file diff --git a/include/usbip_vhci_api.h b/include/usbip_vhci_api.h index 0c9c2166..5b85dfac 100644 --- a/include/usbip_vhci_api.h +++ b/include/usbip_vhci_api.h @@ -77,6 +77,18 @@ typedef struct _ioctl_usbip_vhci_plugin wchar_t winstid[MAX_VHCI_INSTANCE_ID + 1]; } ioctl_usbip_vhci_plugin; +typedef struct _vhci_pluginfo +{ + /* vhci_pluginfo_t structure size */ + unsigned long size; + unsigned int devid; + signed char port; + wchar_t winstid[MAX_VHCI_INSTANCE_ID + 1]; + unsigned char dscr_dev[18]; + /* variable length. It's a full-length configuration descriptor */ + unsigned char dscr_conf[9]; +} vhci_pluginfo_t, *pvhci_pluginfo_t; + typedef struct _ioctl_usbip_vhci_get_ports_status { union { @@ -90,8 +102,7 @@ typedef struct _ioctl_usbip_vhci_unplug { signed char addr; char unused[3]; - -} ioctl_usbip_vhci_unplug; +} ioctl_usbip_vhci_unplug, *pvhci_unpluginfo_t; typedef struct _USBIP_VHCI_EJECT_HARDWARE { diff --git a/usbip_win.sln b/usbip_win.sln index 28bec9cc..0f4b7a8c 100644 --- a/usbip_win.sln +++ b/usbip_win.sln @@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbip_stub", "driver\stub\u EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdrv", "driver\lib\libdrv.vcxproj", "{27AB4325-4980-4634-9818-AE6BD61DE532}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "usbip_vhci_ude", "driver\vhci_ude\usbip_vhci_ude.vcxproj", "{27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -83,6 +85,18 @@ Global {27AB4325-4980-4634-9818-AE6BD61DE532}.Release|x86.ActiveCfg = Release|Win32 {27AB4325-4980-4634-9818-AE6BD61DE532}.Release|x86.Build.0 = Release|Win32 {27AB4325-4980-4634-9818-AE6BD61DE532}.Release|x86.Deploy.0 = Release|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x64.ActiveCfg = Debug|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x64.Build.0 = Debug|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x64.Deploy.0 = Debug|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x86.ActiveCfg = Debug|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x86.Build.0 = Debug|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Debug|x86.Deploy.0 = Debug|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x64.ActiveCfg = Release|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x64.Build.0 = Release|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x64.Deploy.0 = Release|x64 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x86.ActiveCfg = Release|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x86.Build.0 = Release|Win32 + {27D5F152-C29D-4C5C-A65C-78ABEE57BAEA}.Release|x86.Deploy.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/userspace/lib/usbip_forward.c b/userspace/lib/usbip_forward.c index 496fe22b..9424ad3f 100644 --- a/userspace/lib/usbip_forward.c +++ b/userspace/lib/usbip_forward.c @@ -398,6 +398,9 @@ read_completion(DWORD errcode, DWORD nread, LPOVERLAPPED lpOverlapped) if (nread == 0) rbuff->invalid = TRUE; } + else if (errcode == ERROR_DEVICE_NOT_CONNECTED) { + rbuff->invalid = TRUE; + } rbuff->in_reading = FALSE; SetEvent(rbuff->hEvent); } diff --git a/userspace/src/usbip/usbip.c b/userspace/src/usbip/usbip.c index 5d76c338..1a046654 100644 --- a/userspace/src/usbip/usbip.c +++ b/userspace/src/usbip/usbip.c @@ -67,6 +67,12 @@ static const struct command cmds[] = { .help = "Attach a remote USB device", .usage = usbip_attach_usage }, + { + .name = "attach_ude", + .fn = usbip_attach_ude, + .help = "Attach a remote USB device(via UDE-versino vhci)", + .usage = usbip_attach_usage + }, { .name = "detach", .fn = usbip_detach, @@ -103,6 +109,18 @@ static const struct command cmds[] = { .help = "Uninstall drivers for usbip", .usage = usbip_uninstall_usage }, + { + .name = "install_ude", + .fn = usbip_install_ude, + .help = "Install or reinstall drivers for usbip", + .usage = usbip_install_usage + }, + { + .name = "uninstall_ude", + .fn = usbip_uninstall_ude, + .help = "Uninstall drivers for usbip", + .usage = usbip_uninstall_usage + }, #if 0 /* Not implemented yet */ { .name = "port", diff --git a/userspace/src/usbip/usbip.h b/userspace/src/usbip/usbip.h index bc3e608c..f4b5fbb7 100644 --- a/userspace/src/usbip/usbip.h +++ b/userspace/src/usbip/usbip.h @@ -25,12 +25,15 @@ /* usbip commands */ int usbip_attach(int argc, char *argv[]); +int usbip_attach_ude(int argc, char *argv[]); int usbip_detach(int argc, char *argv[]); int usbip_list(int argc, char *argv[]); int usbip_bind(int argc, char *argv[]); int usbip_unbind(int argc, char *argv[]); int usbip_install(int argc, char* argv[]); int usbip_uninstall(int argc, char *argv[]); +int usbip_install_ude(int argc, char *argv[]); +int usbip_uninstall_ude(int argc, char *argv[]); void usbip_attach_usage(void); void usbip_detach_usage(void); diff --git a/userspace/src/usbip/usbip.vcxproj b/userspace/src/usbip/usbip.vcxproj index 4c8d0a61..fa7af0c0 100644 --- a/userspace/src/usbip/usbip.vcxproj +++ b/userspace/src/usbip/usbip.vcxproj @@ -157,9 +157,12 @@ + + + @@ -170,6 +173,7 @@ + diff --git a/userspace/src/usbip/usbip_attach_ude.c b/userspace/src/usbip/usbip_attach_ude.c new file mode 100644 index 00000000..1814c826 --- /dev/null +++ b/userspace/src/usbip/usbip_attach_ude.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2011 matt mooney + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "usbip_windows.h" + +#include + +#include "usbip_vhci_api.h" + +#include "usbip_common.h" +#include "usbip_network.h" +#include "usbip_vhci.h" +#include "usbip_forward.h" +#include "usbip_dscr.h" + +extern void usbip_attach_usage(void); + +static int +import_device(SOCKET sockfd, pvhci_pluginfo_t pluginfo, HANDLE *phdev) +{ + HANDLE hdev; + int rc; + int port; + + hdev = usbip_vhci_driver_open(); + if (hdev == INVALID_HANDLE_VALUE) { + err("open vhci driver"); + return 1; + } + + port = usbip_vhci_get_free_port(hdev); + if (port <= 0) { + err("no free port"); + usbip_vhci_driver_close(hdev); + return 1; + } + + dbg("got free port %d", port); + + pluginfo->port = port; + + rc = usbip_vhci_attach_device_ude(hdev, pluginfo); + + if (rc < 0) { + err("import device"); + usbip_vhci_driver_close(hdev); + return 1; + } + + *phdev = hdev; + + return port; +} + +static pvhci_pluginfo_t +build_pluginfo(SOCKET sockfd, unsigned devid) +{ + pvhci_pluginfo_t pluginfo; + unsigned long pluginfo_size; + unsigned short conf_dscr_len; + + if (fetch_conf_descriptor(sockfd, devid, NULL, &conf_dscr_len) < 0) { + err("failed to get configuration descriptor size"); + return NULL; + } + + pluginfo_size = sizeof(vhci_pluginfo_t) + conf_dscr_len - 9; + pluginfo = (pvhci_pluginfo_t)malloc(pluginfo_size); + if (pluginfo == NULL) { + err("out of memory or invalid vhci pluginfo size"); + return NULL; + } + if (fetch_device_descriptor(sockfd, devid, pluginfo->dscr_dev) < 0) { + err("failed to fetch device descriptor"); + free(pluginfo); + return NULL; + } + if (fetch_conf_descriptor(sockfd, devid, pluginfo->dscr_conf, &conf_dscr_len) < 0) { + err("failed to fetch configuration descriptor"); + free(pluginfo); + return NULL; + } + + pluginfo->size = pluginfo_size; + pluginfo->devid = devid; + + return pluginfo; +} + +static int query_import_device(SOCKET sockfd, const char *busid, HANDLE *phdev, const char *instid) +{ + int rc; + struct op_import_request request; + struct op_import_reply reply; + pvhci_pluginfo_t pluginfo; + uint16_t code = OP_REP_IMPORT; + unsigned devid; + + memset(&request, 0, sizeof(request)); + memset(&reply, 0, sizeof(reply)); + + /* send a request */ + rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); + if (rc < 0) { + err("send op_common"); + return 1; + } + + strncpy_s(request.busid, USBIP_BUS_ID_SIZE, busid, sizeof(request.busid)); + + PACK_OP_IMPORT_REQUEST(0, &request); + + rc = usbip_net_send(sockfd, (void *)&request, sizeof(request)); + if (rc < 0) { + err("send op_import_request"); + return 1; + } + + /* recieve a reply */ + rc = usbip_net_recv_op_common(sockfd, &code); + if (rc < 0) { + err("recv op_common"); + return 1; + } + + rc = usbip_net_recv(sockfd, (void *)&reply, sizeof(reply)); + if (rc < 0) { + err("recv op_import_reply"); + return 1; + } + + PACK_OP_IMPORT_REPLY(0, &reply); + + /* check the reply */ + if (strncmp(reply.udev.busid, busid, sizeof(reply.udev.busid))) { + err("recv different busid %s", reply.udev.busid); + return 1; + } + + devid = reply.udev.busnum << 16 | reply.udev.devnum; + pluginfo = build_pluginfo(sockfd, devid); + if (pluginfo == NULL) + return 2; + + if (instid != NULL) + mbstowcs_s(NULL, pluginfo->winstid, MAX_VHCI_INSTANCE_ID, instid, _TRUNCATE); + else + pluginfo->winstid[0] = L'\0'; + + /* import a device */ + return import_device(sockfd, pluginfo, phdev); +} + +static int +attach_device(const char *host, const char *busid, const char *instid) +{ + SOCKET sockfd; + int rhport; + HANDLE hdev = INVALID_HANDLE_VALUE; + + sockfd = usbip_net_tcp_connect(host, usbip_port_string); + if (sockfd == INVALID_SOCKET) { + err("tcp connect"); + return 1; + } + + rhport = query_import_device(sockfd, busid, &hdev, instid); + if (rhport < 0) { + err("query"); + return 1; + } + + usbip_forward(hdev, (HANDLE)sockfd, FALSE); + + usbip_vhci_detach_device(hdev, rhport); + + usbip_vhci_driver_close(hdev); + + closesocket(sockfd); + + return 0; +} + +int usbip_attach_ude(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "remote", required_argument, NULL, 'r' }, + { "busid", required_argument, NULL, 'b' }, + { "instid", optional_argument, NULL, 'i' }, + { NULL, 0, NULL, 0 } + }; + char *host = NULL; + char *busid = NULL; + char *instid = NULL; + int opt; + int ret = -1; + + for (;;) { + opt = getopt_long(argc, argv, "r:b:i:", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'r': + host = optarg; + break; + case 'b': + busid = optarg; + break; + case 'i': + instid = optarg; + break; + default: + goto err_out; + } + } + + if (!host || !busid) + goto err_out; + + ret = attach_device(host, busid, instid); + goto out; + +err_out: + usbip_attach_usage(); +out: + return ret; +} diff --git a/userspace/src/usbip/usbip_dscr.c b/userspace/src/usbip/usbip_dscr.c new file mode 100644 index 00000000..c64107f7 --- /dev/null +++ b/userspace/src/usbip/usbip_dscr.c @@ -0,0 +1,86 @@ +#include "usbip_windows.h" + +#include "usbip_wudev.h" +#include "usbip_proto.h" + +/* sufficient large enough seq used to avoid conflict with normal vhci operation */ +static unsigned seqnum = 0x7ffffff; + +static BOOL +is_zero_class(usbip_wudev_t *wudev) +{ + if (wudev->bDeviceClass == 0 && wudev->bDeviceSubClass == 0 && wudev->bDeviceProtocol == 0) + return TRUE; + return FALSE; +} + +static int +fetch_descriptor(SOCKET sockfd, UINT8 dscr_type, unsigned devid, char *dscr, unsigned short dscr_size) +{ + struct usbip_header uhdr; + unsigned alen; + + memset(&uhdr, 0, sizeof(uhdr)); + + uhdr.base.command = htonl(USBIP_CMD_SUBMIT); + uhdr.base.seqnum = seqnum++; + uhdr.base.direction = htonl(USBIP_DIR_IN); + uhdr.base.devid = htonl(devid); + + uhdr.u.cmd_submit.transfer_buffer_length = htonl(dscr_size); + uhdr.u.cmd_submit.setup[0] = 0x80; /* IN/control port */ + uhdr.u.cmd_submit.setup[1] = 6; /* GetDescriptor */ + *(unsigned short *)(uhdr.u.cmd_submit.setup + 6) = (unsigned short)dscr_size; /* Length */ + uhdr.u.cmd_submit.setup[3] = dscr_type; + + if (usbip_net_send(sockfd, &uhdr, sizeof(uhdr)) < 0) { + dbg("fetch_descriptor: failed to send usbip header\n"); + return -1; + } + if (usbip_net_recv(sockfd, &uhdr, sizeof(uhdr)) < 0) { + dbg("fetch_descriptor: failed to recv usbip header\n"); + return -1; + } + if (uhdr.u.ret_submit.status != 0) { + dbg("fetch_descriptor: command submit error: %d\n", uhdr.u.ret_submit.status); + return -1; + } + alen = ntohl(uhdr.u.ret_submit.actual_length); + if (alen < dscr_size) { + err("fetch_descriptor: too short response: actual length: %d\n", alen); + return -1; + } + if (usbip_net_recv(sockfd, dscr, alen) < 0) { + err("fetch_descriptor: failed to recv usbip payload\n"); + return -1; + } + return 0; +} + +/* assume the length of a device descriptor is 18 */ +int +fetch_device_descriptor(SOCKET sockfd, unsigned devid, char *dscr) +{ + return fetch_descriptor(sockfd, 1, devid, dscr, 18); +} + +int +fetch_conf_descriptor(SOCKET sockfd, unsigned devid, char *dscr, unsigned short *plen) +{ + char buf[9]; + unsigned short alen; + + if (fetch_descriptor(sockfd, 2, devid, buf, 9) < 0) + return -1; + alen = *((unsigned short *)buf + 1); + if (dscr == NULL) { + *plen = alen; + return 0; + } + if (*plen < alen) { + err("fetch_conf_descriptor: too small descriptor buffer\n"); + return -1; + } + *plen = alen; + return fetch_descriptor(sockfd, 2, devid, dscr, alen); +} \ No newline at end of file diff --git a/userspace/src/usbip/usbip_dscr.h b/userspace/src/usbip/usbip_dscr.h new file mode 100644 index 00000000..24e72250 --- /dev/null +++ b/userspace/src/usbip/usbip_dscr.h @@ -0,0 +1,11 @@ +#ifndef _USBIP_DSCR_H_ +#define _USBIP_DSCR_H_ + +#include + +extern int +fetch_device_descriptor(SOCKET sockfd, unsigned devid, char *dscr); +extern int +fetch_conf_descriptor(SOCKET sockfd, unsigned devid, char *dscr, unsigned short *plen); + +#endif /* _USBIP_DSCR_H_ */ diff --git a/userspace/src/usbip/usbip_install_ude.c b/userspace/src/usbip/usbip_install_ude.c new file mode 100644 index 00000000..71619174 --- /dev/null +++ b/userspace/src/usbip/usbip_install_ude.c @@ -0,0 +1,308 @@ + +#include "usbip.h" +#include "usbip_common.h" + +#include +#include +#include + +#define DEVICE_ID "ROOT\\USB\\0000" +#define INF_FILENAME "usbip_vhci_ude.inf" +#define HWID_INF_SECTION "Standard.NTamd64" +#define HWID_INF_KEY "usbip-win VHCI(ude)" +#define HWID "root\\vhci_ude" + +#if 0 ////DEL +typedef enum { + DRIVER_ROOT, + DRIVER_VHCI, +} drv_type_t; + +typedef struct { + const char *name; + const char *inf_filename; + const char *hwid_inf_section; + const char *hwid_inf_key; + const char *hwid; +} drv_info_t; + +static drv_info_t drv_infos[] = { + { "root", "usbip_root.inf", "Standard.NTamd64", "usbip-win VHCI Root", "USBIPWIN\\root\0" }, + { "vhci", "usbip_vhci.inf", "Standard.NTamd64", "usbip-win VHCI", "USBIPWIN\\vhci" } +}; +#endif + +static char * +get_source_inf_path(void) +{ + char inf_path[MAX_PATH]; + char exe_path[MAX_PATH]; + char *sep; + + if (GetModuleFileName(NULL, exe_path, MAX_PATH) == 0) { + err("failed to get a executable path"); + return NULL; + } + if ((sep = strrchr(exe_path, '\\')) == NULL) { + err("invalid executanle path: %s", exe_path); + return NULL; + } + *sep = '\0'; + snprintf(inf_path, MAX_PATH, "%s\\%s", exe_path, INF_FILENAME); + return _strdup(inf_path); +} + +static BOOL +is_driver_oem_inf(const char *inf_path) +{ + HINF hinf; + INFCONTEXT ctx; + BOOL found = FALSE; + + hinf = SetupOpenInfFile(inf_path, NULL, INF_STYLE_WIN4, NULL); + if (hinf == INVALID_HANDLE_VALUE) { + err("cannot open inf file: %s", inf_path); + return FALSE; + } + + if (SetupFindFirstLine(hinf, HWID_INF_SECTION, HWID_INF_KEY, &ctx)) { + char hwid[32]; + DWORD reqsize; + + if (SetupGetStringField(&ctx, 2, hwid, 32, &reqsize)) { + if (strcmp(hwid, HWID) == 0) + found = TRUE; + } + } + + SetupCloseInfFile(hinf); + return found; +} + +static char * +get_oem_inf_pattern(void) +{ + char oem_inf_pattern[MAX_PATH]; + char windir[MAX_PATH]; + + if (GetWindowsDirectory(windir, MAX_PATH) == 0) + return NULL; + snprintf(oem_inf_pattern, MAX_PATH, "%s\\inf\\oem*.inf", windir); + return _strdup(oem_inf_pattern); +} + +static char * +get_oem_inf(void) +{ + char *oem_inf_pattern; + HANDLE hFind; + WIN32_FIND_DATA wfd; + char *oem_inf_name = NULL; + + oem_inf_pattern = get_oem_inf_pattern(); + if (oem_inf_pattern == NULL) { + err("failed to get oem inf pattern"); + return NULL; + } + + hFind = FindFirstFile(oem_inf_pattern, &wfd); + free(oem_inf_pattern); + + if (hFind == INVALID_HANDLE_VALUE) { + err("failed to get oem inf: 0x%lx", GetLastError()); + return NULL; + } + + do { + if (is_driver_oem_inf(wfd.cFileName)) { + oem_inf_name = _strdup(wfd.cFileName); + break; + } + } while (FindNextFile(hFind, &wfd)); + + FindClose(hFind); + + return oem_inf_name; +} + +static BOOL +uninstall_driver_package(void) +{ + char *oem_inf_name; + + oem_inf_name = get_oem_inf(); + if (oem_inf_name == NULL) + return TRUE; + + if (!SetupUninstallOEMInf(oem_inf_name, 0, NULL)) { + err("failed to uninstall a old vhci driver package: 0x%lx", GetLastError()); + free(oem_inf_name); + return FALSE; + } + free(oem_inf_name); + + return TRUE; +} + +static BOOL +install_driver_package(void) +{ + char *inf_path; + BOOL res = TRUE; + + inf_path = get_source_inf_path(); + if (inf_path == NULL) + return FALSE; + + if (!SetupCopyOEMInf(inf_path, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL)) { + DWORD err = GetLastError(); + switch (err) { + case ERROR_FILE_NOT_FOUND: + err("%s or usbip_vhci_ude.sys file not found", INF_FILENAME); + break; + default: + err("failed to install vhci driver package: err:%lx", err); + break; + } + res = FALSE; + } + free(inf_path); + return res; +} + +static BOOL +uninstall_device(void) +{ + HDEVINFO hdevinfoset; + SP_DEVINFO_DATA devinfo; + + hdevinfoset = SetupDiCreateDeviceInfoList(NULL, NULL); + if (hdevinfoset == INVALID_HANDLE_VALUE) { + err("failed to create devinfoset"); + return FALSE; + } + + memset(&devinfo, 0, sizeof(SP_DEVINFO_DATA)); + devinfo.cbSize = sizeof(SP_DEVINFO_DATA); + if (!SetupDiOpenDeviceInfo(hdevinfoset, DEVICE_ID, NULL, 0, &devinfo)) { + /* If there's no root device, it fails with 0xe000020b error code. */ + SetupDiDestroyDeviceInfoList(hdevinfoset); + return TRUE; + } + + if (!DiUninstallDevice(NULL, hdevinfoset, &devinfo, 0, NULL)) { + err("cannot uninstall root device: error: 0x%lx", GetLastError()); + SetupDiDestroyDeviceInfoList(hdevinfoset); + return FALSE; + } + SetupDiDestroyDeviceInfoList(hdevinfoset); + return TRUE; +} + +static BOOL +create_devinfo(LPGUID pguid_usb, HDEVINFO hdevinfoset, PSP_DEVINFO_DATA pdevinfo) +{ + DWORD err; + + memset(pdevinfo, 0, sizeof(SP_DEVINFO_DATA)); + pdevinfo->cbSize = sizeof(SP_DEVINFO_DATA); + if (SetupDiCreateDeviceInfo(hdevinfoset, DEVICE_ID, pguid_usb, NULL, NULL, 0, pdevinfo)) + return TRUE; + + err = GetLastError(); + switch (err) { + case ERROR_ACCESS_DENIED: + err("access denied - make sure you are running as administrator"); + return FALSE; + default: + err("failed to create a root device info: 0x%lx", err); + break; + } + + return FALSE; +} + +static BOOL +setup_guid(LPCTSTR classname, LPGUID pguid) +{ + DWORD reqsize; + + if (!SetupDiClassGuidsFromName(classname, pguid, 1, &reqsize)) { + err("failed to get System setup class"); + return FALSE; + } + return TRUE; +} + +static BOOL +install_device(void) +{ + HDEVINFO hdevinfoset; + SP_DEVINFO_DATA devinfo; + GUID guid_usb; + + setup_guid("USB", &guid_usb); + + hdevinfoset = SetupDiGetClassDevs(&guid_usb, NULL, NULL, 0); + if (hdevinfoset == INVALID_HANDLE_VALUE) { + err("failed to create devinfoset"); + return FALSE; + } + + if (!create_devinfo(&guid_usb, hdevinfoset, &devinfo)) { + SetupDiDestroyDeviceInfoList(hdevinfoset); + return FALSE; + } + + if (!SetupDiSetDeviceRegistryProperty(hdevinfoset, &devinfo, SPDRP_HARDWAREID, HWID, (DWORD)(sizeof(HWID) - 1 + 2))) { + err("failed to set hw id: 0x%lx", GetLastError()); + SetupDiDestroyDeviceInfoList(hdevinfoset); + return FALSE; + } + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, hdevinfoset, &devinfo)) { + err("failed to register: 0x%lx", GetLastError()); + SetupDiDestroyDeviceInfoList(hdevinfoset); + return FALSE; + } + if (!DiInstallDevice(NULL, hdevinfoset, &devinfo, NULL, 0, NULL)) { + err("failed to install: 0x%lx", GetLastError()); + SetupDiDestroyDeviceInfoList(hdevinfoset); + return FALSE; + } + SetupDiDestroyDeviceInfoList(hdevinfoset); + return TRUE; +} + +int +usbip_install_ude(int argc, char *argv[]) +{ + /* remove first if vhci driver package already exists */ + uninstall_device(); + uninstall_driver_package(); + + if (!install_driver_package()) { + err("cannot install vhci driver package"); + return 2; + } + if (!install_device()) { + err("cannot install vhci device"); + return 3; + } + + info("vhci(ude) driver installed successfully"); + return 0; +} + +int +usbip_uninstall_ude(int argc, char *argv[]) +{ + uninstall_device(); + + if (!uninstall_driver_package()) { + err("cannot uninstall vhci driver package"); + return 2; + } + + info("vhci(ude) drivers uninstalled"); + return 0; +} \ No newline at end of file diff --git a/userspace/src/usbip/usbip_vhci.c b/userspace/src/usbip/usbip_vhci.c index 07d17f6f..e58c02c7 100644 --- a/userspace/src/usbip/usbip_vhci.c +++ b/userspace/src/usbip/usbip_vhci.c @@ -17,7 +17,7 @@ walker_devpath(HDEVINFO dev_info, PSP_DEVINFO_DATA pdev_info_data, devno_t devno PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_interface_detail; id_hw = get_id_hw(dev_info, pdev_info_data); - if (id_hw == NULL || _stricmp(id_hw, "usbipwin\\vhci") != 0) { + if (id_hw == NULL || (_stricmp(id_hw, "usbipwin\\vhci") != 0 && _stricmp(id_hw, "root\\vhci_ude") != 0)) { err("%s: invalid hw id: %s\n", __FUNCTION__, id_hw ? id_hw : ""); if (id_hw != NULL) free(id_hw); @@ -135,6 +135,20 @@ usbip_vhci_attach_device(HANDLE hdev, int port, const char *instid, usbip_wudev_ return 0; } +int +usbip_vhci_attach_device_ude(HANDLE hdev, pvhci_pluginfo_t pluginfo) +{ + unsigned long unused; + + if (!DeviceIoControl(hdev, IOCTL_USBIP_VHCI_PLUGIN_HARDWARE, + pluginfo, pluginfo->size, NULL, 0, &unused, NULL)) { + err("usbip_vhci_attach_device: DeviceIoControl failed: err: 0x%lx", GetLastError()); + return -1; + } + + return 0; +} + int usbip_vhci_detach_device(HANDLE hdev, int port) { diff --git a/userspace/src/usbip/usbip_vhci.h b/userspace/src/usbip/usbip_vhci.h index 54a90e04..8ea6b92b 100644 --- a/userspace/src/usbip/usbip_vhci.h +++ b/userspace/src/usbip/usbip_vhci.h @@ -3,12 +3,14 @@ #pragma +#include "usbip_vhci_api.h" #include "usbip_wudev.h" HANDLE usbip_vhci_driver_open(void); void usbip_vhci_driver_close(HANDLE hdev); int usbip_vhci_get_free_port(HANDLE hdev); int usbip_vhci_attach_device(HANDLE hdev, int port, const char *instid, usbip_wudev_t *wudev); +int usbip_vhci_attach_device_ude(HANDLE hdev, pvhci_pluginfo_t pluginfo); int usbip_vhci_detach_device(HANDLE hdev, int port); #endif /* __VHCI_DRIVER_H */