NOTE
For a detailed description of the Kernel PlugIn feature, and the related development process and APIs, refer to the WinDriver PCI User’s Manual.

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 application must open a handle to the Kernel PlugIn driver using WDC_KernelPlugInOpen() (or the low-levelWD_KernelPlugInOpen() function, if you are not using the WDC library).
    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 must implement a KP_Open callback that correctly translates the 32-bit data received from the user mode, into 64-bit kernel data.
    The Kernel PlugIn driver’s KP_Init() function must set this callback in the funcOpen_32_64 field of the KP_INITstructure that it initializes. (This field was added in version 10.3.0 of WinDriver.)

    NOTE
    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 thefuncOpen_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:

    1. In the user-mode code, do the following:

1. Separate the steps of opening a handle to the device and opening a handle to the Kernel PlugIn. In version 10.2.1 and below of WinDriver, the sample and generated code used the WDC_xxxDeviceOpen() functions (e.g., WDC_PciDeviceOpen()) to open both of these handles. As explained above, this method cannot be used if you also wish to work with a 32-bit application and a 64-bit Kernel PlugIn driver. If your code uses this method, modify the call to WDC_xxxDeviceOpen() so that you pass NULL for the last two parameters —pcKPDriverName and pKPOpenData.

2.  Use WDC_KernelPlugInOpen() to open the handle to the Kernel PlugIn driver.

For the function’s hDev parameter, pass the same handle whose address was passed as the phDevparameter of the device-open function. (Note that here you are passing hDevWDC_DEVICE_HANDLE — and not &hDevWDC_DEVICE_HANDLE* — like in the first parameter of WDC_xxxDeviceOpen().)

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:

  1. Define the following types, to be used both by the user-mode and Kernel PlugIn code; (in the sample and generated code, these types are defined in the xxx_lib.h file):
    /* Device address description struct */
    typedef struct {
        DWORD dwNumAddrSpaces;    /* Total number of device address spaces */
        WDC_ADDR_DESC *pAddrDesc; /* Array of device address spaces information */
    } PCI_DEV_ADDR_DESC;
    
  2. Allocate a variable of type PCI_DEV_ADDR_DESC and set its fields according to the information returned by the previous call to the WDC_xxxDeviceOpen() function.
    In the sample and generated code, this is done in the xxx_lib.c file as shown below:

    PCI_DEV_ADDR_DESC devAddrDesc;
    PWDC_DEVICE pDev; 
    
    ...
    
    dwStatus = WDC_PciDeviceOpen(&hDev, pDeviceInfo, pDevCtx, NULL, NULL, NULL);
    ...
    pDev = hDev;
    devAddrDesc.dwNumAddrSpaces = pDev->dwNumAddrSpaces;
    devAddrDesc.pAddrDesc = pDev->pAddrDesc;
    
    WDC_KernelPlugInOpen(hDev, KP_PCI_DRIVER_NAME, &devAddrDesc);
    

 

  1. In the Kernel PlugIn driver code, do the following:

1. Modify your funcOpen callback: 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 — as recommended in Step I.2 — modify your funcOpen callback as follows:

  • Replace the PWDC_DEVICE 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.
  • Remove the temp variable definition, and replace the two COPY_FROM_USER calls (which use the tempvariable) with the following call: COPY_FROM_USER(pDevAddrDesc, pOpenData, dwSize);
  • As an additional unrelated fix to previous sample and generated WinDriver funcOpenimplementations, move the call to the library initialization function (PCI_LibInit() in the PCI sample / XXX_LibInit in the generated DriverWizard code — where XXX is the name of your driver project) to the beginning of the function — right after the variable declarations and before the first call to the Kernel PlugIn trace messages function (KP_PCI_Trace() in the PCI sample /KP_XXX_Trace() in the wizard-generated code).

2. Create your funcOpen_32_64 callback: 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/pci_diag/kp_pci/kp_pci.c sample, the funcOpen function is namedKP_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.

NOTE
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_64callback; 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.

3. Edit your Kernel PlugIn code to handle the translation of the 32-bit data passed from the user mode, into 64-bit kernel data:

  1. Add a 32-bit definition of the Kernel PlugIn open-data type.
  2. In your funcOpen_32_64 callback, translate the 32-bit open-date received from the user mode, into the equivalent 64-bit type.

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 — as recommended in Step I.2 — modify the code as follows:

  1. Add the following definitions at the beginning of the file:
    #define PTR32 DWORD
      	 
    typedef struct WDC_DEV_ADDR_DESC_32B {
        DWORD dwNumAddrSpaces; /* Total number of device address spaces */
        PTR32 pAddrDesc;       /* Array of device address spaces information */
    } WDC_DEV_ADDR_DESC_32B, *PWDC_DEV_ADDR_DESC_32B;
    
  2. Modify your funcOpen_32_64 callback as follows:
    • Add the following definition:
      WDC_DEV_ADDR_DESC_32B devAddrDesc_32;
      
    • 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:
      /* Copy device information sent from a 32-bit user application */
      COPY_FROM_USER(&devAddrDesc_32, pOpenData, sizeof(PCI_DEV_ADDR_DESC_32B));
      
    • 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:
      /* Copy the 32-bit data to a 64-bit struct */
      pDevAddrDesc->dwNumAddrSpaces = devAddrDesc_32.dwNumAddrSpaces;
      
    • Replace the second COPY_FROM_USER call — COPY_FROM_USER(pAddrDesc, pDevAddrDesc->pAddrDesc, dwSize); — with the following:
      COPY_FROM_USER(pAddrDesc, (PVOID)(KPTR)devAddrDesc_32.pAddrDesc, dwSize);
      
      1. <res_desc=”‘br’ not=”” used=”” here=”” on=”” purpose.”=””>

4. Update your KP_Init() function: Notify WinDriver of your funcOpen_32_64 callback, by assigning yourfuncOpen_32_64 callback to the funcOpen_32_64 field of the KP_INIT struct that is initialized in KP_Init():

kpInit->funcOpen_32_64 = <Your funcOpen_32_64 callback >;

For example, this is the assignment line from the updated kp_pci.c sample:

kpInit->funcOpen_32_64 = KP_PCI_Open_32_64;
NOTE
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().

5. Edit all remaining device-open type handling: 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 passPCI_DEV_ADDR_DESC* (as recommended in Step I.2), 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:

  • In KP_Close, replace this line — free(((PWDC_DEVICE)pDrvContext)->pAddrDesc); — with the following, to free the correct type:
    if (((PCI_DEV_ADDR_DESC *)pDrvContext)->pAddrDesc)
        free(((PCI_DEV_ADDR_DESC *)pDrvContext)->pAddrDesc);
    
  • In KP_IntAtIrql, replace this line — PWDC_DEVICE pDev = (PWDC_DEVICE)pIntContext; — with the following:
    PCI_DEV_ADDR_DESC *pDevAddrDesc = (PCI_DEV_ADDR_DESC *)pIntContext;
    

    and edit any remaining pDev instances in the function; for example, replace this line —pAddrDesc = &pDev->pAddrDesc[INTCSR_ADDR_SPACE]; — with the following:

    pAddrDesc = &pDevAddrDesc->pAddrDesc[INTCSR_ADDR_SPACE];