Jungo WinDriver
Official Documentation
|
The easiest way to write a Kernel PlugIn driver is to use DriverWizard to generate the Kernel PlugIn code for your hardware (see 12.5.3. Sample/Generated Kernel PlugIn Driver Code Overview and
12.5.4.3. The Generated DriverWizard Kernel PlugIn Directory).
Alternatively, you can use one of the WinDriver Kernel PlugIn samples as the basis for your Kernel PlugIn development. You can also develop your code "from scratch", if you wish.
As indicated in 12.5.3. Sample/Generated Kernel PlugIn Driver Code Overview, the Kernel PlugIn documentation in this manual focuses on the generated DriverWizard code, and the generic PCI Kernel PlugIn sample — KP_PCI
, located in the WinDriver/samples/c/pci_diag/kp_pci
directory. If you are using the a PCI Express card with the Xilinx Bus Master DMA (BMD) design, you can also use the KP_BMD
Kernel PlugIn sample as the basis for your development; the WinDriver/samples/c/xilinx/bmd_design
directory contains all the relevant sample files — see the Xilinx BMD Kernel PlugIn directory structure note at the end of (12.5.4.1. pci_diag and kp_pci Sample Directories).
The following is a step-by-step guide to creating your Kernel PlugIn driver.
The Kernel PlugIn should be used only after your driver code has been written and debugged in the user mode. This way, all of the logical problems of creating a device driver are solved in the user mode, where development and debugging are much easier.
Determine whether a Kernel PlugIn should be written by consulting Chapter 11: Improving PCI Performance, which explains how to improve the performance of your driver. In addition, the Kernel PlugIn affords greater flexibility, which is not always available when writing the driver in the user mode (specifically in regard to the interrupt handling).
The Kernel PlugIn is a kernel module, and therefore must be written in the C language. The user application that calls the Kernel PlugIn can be of any langauge supported by WinDriver: C, C#.NET, Visual Basic.NET, Python, Java.
When generating code in the DriverWizard in languages other than C with Kernel PlugIn, the Kernel PlugIn code will still be generated in C.
Please follow this step:
Keep in mind that the kernel stack is relatively limited in size. Therefore, code that will be moved into the Kernel PlugIn should not contain static memory allocations. Use the malloc()
function to allocate memory dynamically instead. This is especially important for large data structures.
If the user-mode code that you are porting to the kernel accesses memory addresses directly using the user-mode mapping of the physical address returned from the low-level WD_CardRegister() function — note that in the kernel you will need to use the kernel mapping of the physical address instead (the kernel mapping is also returned by WD_CardRegister() ).
When using the API of the WDC library to access memory, you do not need to worry about this, since this API ensures that the correct mapping of the memory is used depending on whether the relevant APIs are used from the user mode or from the kernel mode.
As indicated above, you can use DriverWizard to generate a new Kernel PlugIn project (and a corresponding user-mode project) for your device (recommended), or use one of the WinDriver Kernel PlugIn samples as the basis for your development.
⚠ Attention
To successfully build a Kernel PlugIn project using MS Visual Studio, the path to the project directory must not contain any spaces.
If you select to start your development with the KP_PCI sample, follow these steps:
WinDriver/samples/c/pci_diag/kp_pci
directory. For example, to create a new Kernel PlugIn project called KP_MyDrv, copy WinDriver/samples/c/pci_diag/kp_pci
to WinDriver/samples/c/mydrv
.The names of the KP_PCI_xxx() functions in the kp_pci.c files do not have to be changed, but the code will be clearer if you use your selected driver name in the function names.
pci_lib
library API from your Kernel PlugIn driver and user-mode application, copy the pci_lib.h
and pci_lib.c
files from the WinDriver/samples/c/pci_diag
directory to your new mydrv directory.You can change the names of the library functions to use your driver's name (MyDrv) instead of "PCI", but note that in this case you will also need to modify the names in all calls to these functions from your Kernel PlugIn project and usermode application. If you do not copy the shared library to your new project, you will need to modify the sample Kernel PlugIn code and replace all references to the PCI_xxx
library APIs with alternative code.
#include
paths in the source files, as needed (depending on the location in which you selected to save your new project directory).pci_diag
user-mode application, copy WinDriver/samples/c/pci_diag/pci_diag.c
and the relevant pci_diag
project, solution, or make files to your mydrv directory, rename the files (if you wish), and replace all pci_diag
references in the files with your preferred usermode application name.To use the solution files, also replace the references to "KP_PCI" in the files with your new Kernel PlugIn driver, e.g., "KP_MyDrv". Then modify the sample code to implement your desired driver functionality.
For a general description of the sample and generated Kernel PlugIn code and its structure,
see 12.5.3. Sample/Generated Kernel PlugIn Driver Code Overview and
12.5.4. Kernel PlugIn Sample/Generated Code Directory Structure (respectively).
To open a handle to a Kernel PlugIn driver, WD_KernelPlugIn() needs to be called from the user mode. This low-level function is called from WDC_KernelPlugInOpen() — when it is called with the name of a Kernel PlugIn driver.
When using the high-level WDC API you should use the following method to open a Kernel PlugIn handle:
⚠ Attention
This method cannot be used to open a handle to a 64-bit Kernel PlugIn driver from a 32-bit application, or to open a Kernel PlugIn handle from a .NET application.
To ensure that your code works correctly in all the supported configurations, use the first method described above.
The generated DriverWizard and the sample pci_diag
shared library (xxx_lib.c
/ pci_lib.c
) demonstrate how to open a handle to the Kernel PlugIn — see the generated/sample XXX_DeviceOpen()
/ PCI_DeviceOpen()
library function (which is called from the generated/sample xxx_diag
/pci_diag
user-mode application).
The handle to the Kernel PlugIn driver is closed when the WD_KernelPlugInClose() function is called from the user mode.
When using the low-level WinDriver API, this function is called directly from the user-mode application.
When using the high-level WDC API , the function is called automatically when calling WDC_PciDeviceClose() / WDC_IsaDeviceClose() ) with a device handle that contains an open Kernel PlugIn handle. The function is also called by WinDriver as part of the application cleanup, for any identified open Kernel PlugIn handles.
Kindly follow these instructions:
The generated DriverWizard and the sample pci_diag
shared library (xxx_lib.c
/ pci_lib.c
) demonstrate how this should be done — see the generated/sample XXX_IntEnable()/PCI_IntEnable() library function (which is called from the generated/sample xxx_diag
/pci_diag
user-mode application).
If you are not using the WDC_xxx API , in order to enable interrupts in the Kernel PlugIn call WD_IntEnable() or InterruptEnable() (which calls WD_IntEnable()), and pass the handle to the Kernel PlugIn driver that you received from WD_KernelPlugInOpen() (within the hKernelPlugIn field of the WD_KERNEL_PLUGIN structure that was passed to the function).
You can implement this function to set the interrupt context that will be passed to the high-IRQL and DPC Kernel PlugIn interrupt handler routines, as well as write to the device to actually enable the interrupts in the hardware, for example, or implement any other code required in order to correctly enable your device's interrupts.
Deferred processing of the interrupt can be moved to the relevant DPC handler — KP_IntAtDpc — which will be executed once the high-IRQL handler completes it processing and returns TRUE. You can also modify the code to make it more efficient, due to the advantages of handling the interrupts directly in the kernel, which provides you with greater flexibility (e.g., you can read from a specific register and write back the value that was read, or toggle specific register bits). For a detailed explanation on how to handle interrupts in the kernel using a Kernel PlugIn, refer to 12.5.5. Handling Interrupts in the Kernel PlugIn of the manual.
Perform the next steps:
In the sample/generated DriverWizard Kernel PlugIn projects, the message IDs and other information that should be shared by the user-mode application and Kernel PlugIn driver are defined in the pci_lib.h
/xxx_lib.h
shared library header file.
The Kernel PlugIn is not backward compatible. Therefore, when switching to a different version of WinDriver, you need to rebuild your Kernel PlugIn driver using the new version.
The sample WinDriver\samples\c\pci_diag\kp_pci
Kernel PlugIn directory and the generated DriverWizard Kernel PlugIn <project_dir>\kermode
directory (where <project_dir>
is the directory in which you selected to save the generated driver project) contain the following Kernel PlugIn project files (where xxx
is the driver name — pci for the sample / the name you selected when generating the code with the wizard):
x86
— 32-bit project files:msdev_<version>\kp_xxx.vcxproj
— 32-bit MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 32-bit Windows GCC (MinGW/Cygwin) makefileamd64
— 64-bit project files:msdev_<version>\kp_xxx.vcxproj
— 64-bit MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 64-bit Windows GCC (MinGW/Cygwin) makefilearm64
— 64-bit ARM64 project files:msdev_<version>\kp_xxx.vcxproj
— 64-bit ARM64 MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 64-bit ARM64 Windows GCC (MinGW/Cygwin) makefileThe sample WinDriver\samples\c\pci_diag
directory and the generated <project_dir>
directory contain the following project files for the user-mode application that drives the respective Kernel PlugIn driver (where xxx
is the driver name — pci
for the sample / the name you selected when generating the code with the wizard):
x86
— 32-bit project files:msdev_<version>\xxx_diag.vcxproj
— 32-bit MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 32-bit Windows GCC (MinGW/Cygwin) makefileamd64
— 64-bit project files:msdev_<version>\xxx_diag.vcxproj
— 64-bit MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 64-bit Windows GCC (MinGW/Cygwin) makefilearm64
— 64-bit ARM64 project files:msdev_<version>\xxx_diag.vcxproj
— 64-bit ARM MS Visual Studio project file (where <version>
signifies the IDE version — e.g., "2019")win_gcc/makefile
— 64-bit ARM64 Windows GCC (MinGW/Cygwin) makefileThe msdev_<version>
MS Visual Studio directories listed above also contain xxx_diag.sln
solution files that include both the Kernel PlugIn and user-mode projects.
If you used DriverWizard to generate your code and you selected to generate a dynamic link library (DLL), the generated <project_dir>
directory will also have a libproj DLL project directory. This directory has x86 (32-bit) and/or amd64 (64-bit) and/or arm64 (64-bit ARM64) directories that contain msdev_<version> directories for your selected IDEs, and each IDE directory has an xxx_libapi.vcproj project file for building the DLL. The DLL is used from the wizard-generated user-mode diagnostics project (xxx_diag.vcxproj
).
To build your Kernel PlugIn driver and respective user-mode application on Windows, follow these steps:
kp_pci.sys
— sample / kp_xxx.sys
— wizard generated code):From your driver project directory, open the Visual Studio Kernel PlugIn solution file — <project_dir>\msdev_<version>\xxx_diag.sln
, where <project_dir>
is your driver project directory (pci_diag
for the sample code / the directory in which you selected to save the generated DriverWizard code), msdev_<version>
is your target Visual Studio directory (e.g., msdev_2019
), and xxx
is the driver name (pci
for the sample / the name you selected when generating the code with the wizard).
When using DriverWizard to generate code for MS Visual Studio, you can use the IDE to Invoke option to have the wizard automatically open the generated solution file in your selected IDE, after generating the code files.
kp_pci.vcxproj
/ kp_xxx.vcxproj
) as the active project.Project Properties -> Driver Settings -> Target OS Version
, select Windows 10 as it is the lowest version currently supported by WinDriver.pci_diag.exe
— sample / xxx_diag.exe
— wizard-generated code):pci_diag.vcxproj
— sample / xxx_diag.vcxproj
— wizard generated code) as the active project. Then build the application: Build the project from the Build menu or using the relevant shortcut key (e.g., CTRL+SHIFT+B in Visual Studio 2017).Do the following from your selected Windows GCC development environment (MinGW/Cygwin):
Change directory to your target Windows GCC application directory — <project_dir>/<CPU>/win_gcc
, where <project_dir>
is your driver project directory (pci_diag
for the sample code / the directory in which you selected to save the generated DriverWizard code), and <CPU>
is the target CPU architecture (x86 for x86 platforms, amd64 for x64 platforms and arm64 for ARM64 platforms).
For example:
pci_diag
application, which drives the sample KP_PCI driver —— where <project_dir>
signifies the path to your generated DriverWizard project directory (for example, ~/WinDriver/wizard/my_projects/my_kp
).
To build your Kernel PlugIn driver and respective user-mode application on Linux, follow these steps:
For example:
— where <project_dir>
signifies the path to your generated DriverWizard project directory (for example, ~/WinDriver/wizard/my_projects/my_kp
).
If you have renamed the WinDriver kernel module, be sure to uncomment the following line in your Kernel PlugIn configuration script (by removing the pound sign — "#"), before executing the script, in order to build the driver with the -DWD_DRIVER_NAME_CHANGE
flag (see 17.2.2. Linux Driver Renaming):
The configuration script creates a makefile based on the running kernel. You may select to use another installed kernel source, by executing the script with the --with-kernel-source=<path>
option, where <path>
is the full path to the kernel source directory — e.g., /usr/src/linux
. If the Linux kernel version is 2.6.26 or higher, the configuration script generates makefiles that use kbuild to compile the kernel modules.
make
command.This command creates a new LINUX.<kernel version>.<CPU>
directory, which contains the created kp_xxx_module.o/.ko
driver.
For the KP_PCI sample driver —
For the generated DriverWizard Kernel PlugIn driver —
make
command.Beginning with version 10.3.0 of WinDriver, you can communicate with a 64-bit Kernel PlugIn driver from a 32-bit user-mode application. To support such a configuration, you need to keep in mind the following points:
The handle cannot be opened using one of the WDC device-open functions, e.g. WDC_PciDeviceOpen(), by calling it with the name of a Kernel PlugIn driver. In all Kernel PlugIn configurations, except for a 64-bit driver that interacts with a 32-bit application, either of these methods can be used to open a handle to the Kernel PlugIn from the application.
The Kernel PlugIn driver’s KP_Init() function must set this callback in the funcOpen_32_64 field of the KP_INIT structure that it initializes. This field was added in version 10.3.0 of WinDriver.
The callback set in the KP_INIT funcOpen_32_64 field, is called by WinDriver when a 32-bit application opens a handle to a Kernel PlugIn driver. This callback will hereby be referred to as the funcOpen_32_64 callback. The callback set in the KP_INIT funcOpen field is the standard KP_Open callback, which is called by WinDriver whenever an application opens a Kernel PlugIn handle, except for the specific configuration in which the funcOpen_32_64 callback is used. This callback will hereby be referred to as the funcOpen callback. When writing your Kernel PlugIn driver, you can select whether to provide both of these callback types or just one of them — depending on how you plan to build the driver and how you expect it to be used. For example, if you are not planning to use the driver on a 64-bit operating system, you do not need to implement and set funcOpen_32_64.
In version 10.3.0 and above of WinDriver, the generated DriverWizard Kernel PlugIn projects, and the sample PCI Kernel PlugIn project (kp_pci), are written so as to support all types of user-mode and Kernel PlugIn configurations, including using a 32-bit application with a 64-bit Kernel PlugIn.
To modify code developed with earlier versions of WinDriver to afford the same support, follow these steps:
In the user-mode code, do the following:
pcKPDriverName
and pKPOpenData
.For the function’s hDev parameter, pass the same handle whose address was passed as the phDev
parameter of the device-open function.
⚠ Attention
You are passing hDev — WDC_DEVICE_HANDLE — and not &hDev — WDC_DEVICE_HANDLE* — like in the first parameter of WDC_PciDeviceOpen() / WDC_IsaDeviceOpen().
For the pcKPDriverName parameter, pass the name of your Kernel PlugIn driver (as previously done for the equivalent device-open function parameter, if you used it to also open the Kernel PlugIn handle).
For the pKPOpenData parameter, pass the data you wish to pass down from the application to the Kernel PlugIn (similar to the device-open function parameter of the same name).
In the older WinDriver sample and generated code, the device handle was passed as the open-data. However, to reduce the work that would need to be done in the Kernel PlugIn to convert the 32-bit data to64-bit, the newer code now passes only the necessary information to the Kernel PlugIn, we recommend that you do the same:
In the Kernel PlugIn driver code, do the following:
If you have changed the type of the open-data that is passed from the user mode to the driver, you need to adjust the implementation of your open-callback accordingly. If your existing code was based on the sample or generated Kernel PlugIn code in earlier versions of WinDriver, and you have selected to pass the address of a PCI_DEV_ADDR_DESC struct as your Kernel PlugIn open-data modify your funcOpen callback as follows:
hDev;
definition with PCI_DEV_ADDR_DESC *pDevAddrDesc;
and replace instances of WDC_DEVICE and pDev in the function with PCI_DEV_ADDR_DESC and pDevAddrDesc respectively.Copy your funcOpen callback function, and rename it. The renamed function will be modified to implement your funcOpen_32_64 callback — for opening a handle to a64-bit Kernel PlugIn driver from a 32-bit application. In the WinDriver/samples/c/pci_diag/kp_pci/kp_pci.c
sample, the funcOpen function is named KP_PCI_Open(), and the funcOpen_32_64 function is named KP_PCI_Open_32_64(). The generated DriverWizard Kernel PlugIn open functions are named in a similar manner, except that “PCI” is replaced with your selected driver project name.
⚠ Attention
If you only plan to support a 32-bit application and 64-bit Kernel PlugIn configuration, you can skip this step, and in the next step modify your KP_Open callback to use it as your funcOpen_32_64 callback, and then assign this callback to the KP_INIT funcOpen_32_64 field, instead of to the funcOpenfield.
However, to keep your code portable, it’s best to implement both types of callbacks.
For example, if your original code was based on the sample or generated Kernel PlugIn code in earlier versions of WinDriver, and you have selected to pass the address of a PCI_DEV_ADDR_DESC struct as your Kernel PlugIn open-data modify the code as follows:
Then add the following lines after the kpOpenCall field assignments, in order to copy to the kernel mode the 32-bit data that was received from the user mode:
Then replace the following line — COPY_FROM_USER(pDevAddrDesc, pOpenData, dwSize)
— with these lines, in order to copy the 32-bit data into a 64-bit structure:
Replace the second COPY_FROM_USER() call — COPY_FROM_USER(pAddrDesc, pDevAddrDesc->pAddrDesc, dwSize)
— with the following:
Notify WinDriver of your funcOpen_32_64 callback, by assigning your funcOpen_32_64 callback to the funcOpen_32_64 field of the KP_INIT struct that is initialized in KP_Init():
For example, this is the assignment line from the updated kp_pci.c
sample:
⚠ Attention
If you select to only implement a funcOpen_32_64 callback, and not to implement a standard funcOpencallback, remove the assignment to the KP_INIT funcOpen field in KP_Init().
If you have changed the type of the open-data that is passed from the user mode to the driver, you need to edit the related type handling in your Kernel PlugIn code. For example, if you previously passed PWDC_DEVICE as the open-data type, and you now pass PCI_DEV_ADDR_DESC, and your code was previously developed using the a WinDriver sample or wizard-generated Kernel PlugIn driver, you would need to make the following additional changes:
PWDC_DEVICE pDev = (PWDC_DEVICE)pIntContext;
— with the following:and edit any remaining pDev instances in the function. For example, replace this line — pAddrDesc = &pDev->pAddrDesc[INTCSR_ADDR_SPACE];
— with the following:
Verify that the WinDriver kernel module is installed: Before installing your Kernel PlugIn driver, verify that the WinDriver driver — windrvr<version>.sys/.o/.ko
in the newer WinDriver versions (e.g., windrvr1630.sys/.o/.ko
) — is installed, since the Kernel PlugIn module depends on the WinDriver module for its successful operation. You can run the Debug Monitor to verify that WinDriver is loaded.
Install your Kernel PlugIn driver:
my_kp.sys
driver, run this command: ⚠ Attention
The Kernel PlugIn is not backward compatible. Therefore, when switching to a different version of WinDriver, you need to rebuild your Kernel PlugIn driver using the new version.
Driver installation on Windows requires administrator privileges.
The following steps can also be performed with the wdreg_frontend.exe
GUI application. For additional information, refer to 16.3. The wdreg_frontend utility.
xxx.sys
) to the target platform's drivers directory: windir%\system32\drivers
(e.g., C:\WINDOWS\system32\drivers
).wdreg.exe
or wdreg_gui.exe
utility:In the following instructions, KP_NAME stands for your Kernel PlugIn driver's name, without the .sys
extension. To install your driver, run this command:
Kernel PlugIn drivers are dynamically loadable — i.e., they can be loaded and unloaded without reboot. For additional information, refer to 16.2.3. Dynamically Loading/Unloading Your Kernel PlugIn Driver.
On Linux, you do not need to copy the driver file, since the driver installation (make install
) will handle this for you:
For example, when installing the sample KP_PCI driver, run
When installing a driver created using the Kernel PlugIn files generated by DriverWizard, run the following command, where <path>
signifies the path to your generated DriverWizard project directory (e.g., ~/WinDriver/wizard/my_projects/my_kp
):
The following command must be executed with root privileges.
Kernel PlugIn drivers are dynamically loadable — i.e., they can be loaded and unloaded without reboot. For additional information, refer to 16.4.1. Dynamically Loading/Unloading Your Kernel PlugIn Driver.
The Kernel PlugIn is a kernel module, and therefore must be written in the C language. However, the user application that calls the Kernel PlugIn can be of any langauge supported by WinDriver: C, C#.NET, Visual Basic.NET, Java, Python. When generating code in the DriverWizard in languages other than C with Kernel PlugIn, the Kernel PlugIn code will still be generated in C. This user application would communicate with the C-language Kernel PlugIn.
If you select to implement such a design, in order to ensure the correct interaction between the user mode and Kernel PlugIn applications, you will need to implement a file in your programming language that contains common definitions for the Kernel PlugIn and the user mode applications — as done in the library header files of the sample and DriverWizard generated Kernel PlugIn C projects (e.g. WinDriver\samples\pci_diag\pci_lib.h
, used by the sample KP_PCI driver). WinDriver implements these files for you when you generate code with DriverWizard, and they should be generated in your project directory, for you to start as fast and easy as possible.
For further examples check: WinDriver/include/windrvr.h
C header file and the corresponding WinDriver/samples/python/wdlib/windrvr.py
(Python), WinDriver/src/wdapi_dotnet/windrvr.h
(.NET), WinDriver/lib/wdapi_javaXXX.jar
(Java) as examples of implementing the same code both in C and other supported/ languages.
WinDriver implements malloc()
and free()
in its Kernel PlugIn library (kp_nt1630.lib
/kp_linux1630.o_shipped
), to which your Kernel PlugIn code is linked.
These functions are implemented to allocate locked memory when called from the kernel mode, so you can use that memory in your interrupt handler as well.
PCI interrupts are normally handled at the kernel level. Therefore, the best way to handle PCI interrupts with WinDriver is using the Kernel PlugIn feature, which lets you implement code directly at the kernel level. This is specifically true when handling interrupts that are shared between different hardware devices — a very common phenomenon in the case of PCI interrupts, which are by definition sharable.
The Kernel PlugIn consists of two interrupt handler functions:
⚠ Attention
Replace “KP_” in the function names below with the name of your Kernel PlugIn driver. For example, the Kernel PlugIn interrupt handler functions for the sample KP_PCI driver are
KP_PCI_IntAtIrql
andKP_PCI_IntAtDpc
.
If additional deferred kernel- or user-mode interrupt processing is required, KP_IntAtIrql should return TRUE, in which case the deferred KP_IntAtDpc routine (see below) will be executed once the high-level processing is completed. Otherwise, the function should return FALSE and KP_IntAtDpc (as well as any existing user-mode interrupt-handler routine) will not be executed. The generated and sample WinDriver Kernel PlugIn projects, for example, schedule deferred interrupt processing once every five interrupts by implementing code that returns TRUE only for every fifth KP_IntAtIrql call.
WDC_InterruptEnable()
from the user-mode) will be executed once the control returns to the user mode.To handle shared PCI interrupts with WinDriver, perform the following steps:
WinDriver\samples\c\pci_diag\kp_pci\kp_pci.c
) — as the basis for your Kernel PlugIn project. If you are developing a driver for a Xilinx PCI Express card with Bus Master DMA (BMD) design, you can use the sample Kernel PlugIn driver for this design — KP_BMD (WinDriver\samples\c\xilinx\bmd_design\kp\kp_bmd.c
) — or select to generate customized DriverWizard code for this design, including Kernel Plugin code.The advantage of using the DriverWizard is that the generated code will utilize the specific device configuration information detected for your device, as well as any hardware-specific information that you define with the DriverWizard. When generating Kernel PlugIn code for handling PCI interrupts, in the DriverWizard’s Registers tab define the registers that you wish to access upon the detection of an interrupt, and then in the Interrupts tab assign the registers read/write commands that you wish to perform at high IRQ level (KP_IntAtIrql) to the interrupt. The exact commands for acknowledging the interrupt are hardware-specific and you should therefore consult your hardware specification to determine the correct commands to set.
fIsMyInterrupt
parameter to TRUE in order to accept control of the interrupt, and then proceed to write/read the relevant hardware register(s) in order to acknowledge the interrupt, and either return TRUE to perform additional deferred processing or return FALSEif no such processing is required (see above). If, however, you determine that the interrupt was not generated by your hardware, fIsMyInterrupt
should be set to FALSE, in order to ensure that the interrupt will be passed on to other drivers in the system, and KP_IntAtIrql should return FALSE. Important to mention that there is no real harm in setting fIsMyInterrupt
to FALSE even if the interrupt belongs to you, as done by default in the generated and sample WinDriver code, since other drivers in the system, assuming they were implemented correctly, should not attempt to handle the interrupt if it was not generated by their hardware.The portion of the code that performs the check whether your hardware generated the interrupt is based on hardware-specific logic that cannot be defined in the DriverWizard. You will therefore need to modify the generated/sample KP_IntAtIrql implementation and add a relevant “if” clause to ensure that you do not accept control of an interrupt that was not generated by your hardware and do not attempt to clear the source of such an interrupt in the hardware.
Following is a sample KP_IntAtIrql implementation. The code reads the INTCSR memory register (defined elsewhere in the code) and only proceeds to accept control of the interrupt and acknowledge it if the value read from the INTCSR is 0xFF (which serves as an indication in this sample that our hardware generated the interrupt). The interrupt in this sample is acknowledged by writing back to the INTCSR the value that was read from it.
pIntContext
is private context data that is passed from KP_IntEnable to the Kernel PlugIn interrupt handler functions — KP_IntAtIrql() and KP_IntAtDpc().
Jungo strongly recommends using the high-level WDC (PCI) API instead of using the low-level API.
To obtain the handle to WinDriver’s kernel module (hWD) from the Kernel PlugIn, you can call WD_Open() directly from the Kernel PlugIn.
For PCI/ISA, you can also use the hWD
handle, which is passed from the user mode via WD_KernelPlugInOpen(), and received as the second argument of the Kernel PlugIn callback function KP_Open(). Alternatively, you can also pass the handle from the user mode to the Kernel PlugIn using the pData field of the WD_KERNEL_PLUGIN_CALL struct, which is used in the call to WD_KernelPlugInCall() in the user mode and results in a callback to KP_Call() in the Kernel PlugIn.
After obtaining the handle to WinDriver, the call to WD_Transfer() (or any other WinDriver API that receives a handle to WinDriver as a parameter) is the same as in the user mode.
Variables defined in the Kernel PlugIn project (such as global and local variables) are non paged. WinDriver also implements malloc()
to allocate non-paged memory when used from within the kernel.
If you are using a pointer to the memory in the user mode from within the Kernel PlugIn, you need to make a copy of its contents (allocate memory and copy the data to the non-paged memory) in order to access it from your KP_IntAtIrql
function, in order to ensure safe access to the data at all times.
You can call WD_Transfer() from within the KP_IntAtIrql or KP_IntAtDpc functions (replace “KP” in the function names with your Kernel PlugIn driver name — e.g., “KP_PCI”) in order to access the hardware.
⚠ Attention
You can also access the memory or I/O directly from within the Kernel PlugIn interrupt functions. For direct memory access, use the kernel mapping of the memory, returned from WD_CardRegister() in
cardReg.Card.Item[i].I.Mem.pTransAddr
.
When calling WD_Transfer() you will need to pass as the first argument a handle to WinDriver (hWD
). You can refer to the FAQ questions in this chapter to find out how to obtain a handle to WinDriver from within the Kernel PlugIn.
As specified in the aforementioned FAQ questions, you can store the handle to WinDriver in a global Kernel PlugIn variable (recommended), or pass it from one function to another. Below is an example of passing a handle to WinDriver from KP_Open() to KP_IntAtIrql:
Add the following line to KP_Open()
Add the following line to KP_IntEnable()
You can now use WD_Transfer() to access memory/IO from within KP_IntAtIrql. For example (IO access):
This will write 0x65 to port 0x378 upon interrupt. The hWD
handle is passed from KP_Open() to KP_IntEnable() to KP_IntAtIrql via the context.
You can also view the generated DriverWizard Kernel PlugIn code for an example of calling WD_MultiTransfer() from KP_IntAtIrql, provided you have used the DriverWizard to define and assign the register/s for the interrupt acknowledgment before generating the code.
From your user application, use the WDS_SharedBufferAlloc()
function to allocate a shared memory buffer, which can be used both from a user-mode application and a Kernel PlugIn driver.
Pass the returned ppKerBuf->pKernelAddr
value from the above function to the Kernel PlugIn using the pData paramter of the function WDC_CallKerPlug(). Note that WDS_SharedBufferAlloc()
is part of the Server APIs of WinDriver, these APIs require a special license.
ℹ️ Note
If you would like to get more information about Server APIs licensing, please send an e-mail to WinDr.nosp@m.iver.nosp@m.@jung.nosp@m.o.co.nosp@m.m, and our team will assist you.
No. Only the callbacks used by WinDriver need to be declared as __cdecl.