doc

Driver and application interface

  • 2013-09-20
  • 48KB
  • Points it Requires : 2

There are two ways to communicate between a device and an application: 1. Through a symbolic link created for the device; 2. Through an interface WDM drivers recommend using an interface instead of creating a symbolic link. This interface ensures the security of PDO and also ensures that a unique, language-independent method of accessing the device is created safely. An application uses Win32 APIs to call the device. There is a mapping relationship between certain Win32 APIs and the dispatch function of the device object. The first step to gain access to the device object is to open a handle to the device object. Opening a handle to a device with a symbolic link To open a device, an application needs to use CreateFile. If the device has a symbolic link export, the application can open the handle in the form of the following example: hDevice = CreateFile(\"\\\\\\\\.\\\\OMNIPORT3\", GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL ,NULL); The prefix \"\\\\.\\\" in the file path name tells the system that this call hopes to open a device. The device must have a symbolic link so that the application can open it. See the section on Kdevice and CreateLink for details. The part after the prefix in the first parameter of the above call is the name of the symbolic link. Note: The first parameter in CreateFile is not the path to the driver (.sys file) in Windows 98/2000. It is the symbolic link to the device object. If you use DriverWizard to create the driver, it usually uses the class KunitizedName to form the symbolic link for the device. This means that the symbolic link name has a number appended to it, usually 0. For example: if the stem of the link name is L\"TestDevice\" then the string in CreateFile would be \"\\\\\\\\.\\\\TestDevice0\". If the application needs overlaid I/O, the sixth parameter (Flags) must be set to FILE_FLAG_OVERLAPPED. Opening a handle using an output interface Opening a handle this way is a little more cumbersome. The DriverWorks library provides two helper classes to make it easier to gain access to the interface, CDeviceInterface, and CdeviceInterfaceClass. The CdeviceInterfaceClass class encapsulates a device information set that contains all device interface information in a special class. An application can use an instance of the CdeviceInterfaceClass class to obtain one or more instances of the CdeviceInterface class. The CdeviceInterface class is an abstraction of a single device interface. Its member function DevicePath() returns a pointer to a path name that can be used in CreateFile to open the device. The following small example shows the most basic usage of these classes: extern GUID TestGuid; HANDLE OpenByInterface( GUID* pClassGuid, DWORD instance, PDWORD pError){ CDeviceInterfaceClass DevClass(pClassGuid, pError); if (*pError != ERROR_SUCCESS) return INVALID_HANDLE_VALUE; CDeviceInterface DevInterface(&DevClass, instance, pError); if (*pError != ERROR_SUCCESS) return INVALID_HANDLE_VALUE; cout << \"The device path is \" << DevInterface.DevicePath() << endl; HANDLE hDev; hDev = CreateFile( DevInterface.DevicePath(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDev == INVALID_HANDLE_VALUE) *pError = GetLastError(); return hDev;} Performing I/O on the Device Once an application has a valid device handle, it can use Win32 APIs to generate IRPs to the device object. The following table shows the correspondence. Win32 API DRIVER_FUNCTION_xxxIRP_MJ_xxx KDevice subclass member function CreateFile CREATE Create ReadFile READ Read WriteFile WRITE Write DeviceIoControl DEVICE_CONTROL DeviceControl CloseHandle CLOSECLEANUP CloseCleanUp The Close and CleanUp of the device class members require some explanation: CreateFile causes the kernel to create a new file object for the device. This allows multiple handles to map to the same file object. The I/O Manager calls CleanUp when the last user-level handle to the file object is revoked. The I/O Manager calls Close when there are no more user-level or kernel-level accesses to the file object. If the device being opened does not support the specified function, the corresponding Win32 call will cause an error (invalid function). Application code in VxDs written for Windows 95 may use the FILE_FLAG_DELETE_ON_CLOSE attribute when opening the device. In Windows NT/2000, it is recommended not to use this attribute because it will cause unprivileged users to attempt to open the device, which is unlikely to succeed. The way the I/O Manager converts the buff parameter of ReadFile and WriteFile into an IRP field depends on the attributes of the device object. When the device sets the DO_DIRECT_IO flag, the I/O Manager locks the buff in memory and creates an MDL field that is stored in the IRP. A device can access the MDL by calling Kirp::Mdl. When the device sets the DO_BUFFERED_IO flag, the device object obtains the buff address for read or write operations through KIrp::BufferedReadDest or KIrp::BufferedWriteSource, respectively. When the device does not set the DO_BUFFERED_IO flag nor the DO_DIRECT_IO flag, the kernel sets the UserBuffer field of the IRP to correspond to the buff parameter in ReadFile or WriteFile. However, the storage area is not locked and the address is valid only for the calling process. The driver can use KIrp::UserBuffer to access the IRP field. For DeviceIoControl calls, the conversion of the buffer parameter depends on a special I/O control code, which is not in the characteristics of the device object. The macro CTL_CODE (defined in winioctl.h) is used to construct the control code. One of the parameters of this macro indicates that the buffering method is METHOD_BUFFERED,METHOD_IN_DIRECT, METHOD_OUT_DIRECT, or METHOD_NEITHER. The following table shows these methods and the corresponding KIrp member functions that can obtain the input buffer and output buffer: Method Input Buffer Parameter Output Buffer Parameter METHOD_BUFFERED KIrp::IoctlBuffer KIrp::IoctlBuffer METHOD_IN_DIRECT KIrp::IoctlBuffer KIrp::Mdl METHOD_OUT_DIRECT KIrp::IoctlBuffer KIrp::Mdl METHOD_NEITHER KIrp::IoctlType3InputBuffer KIrp::UserBuffer If the control code indicates METHOD_BUFFERED, the system allocates a single buffer for input and output. The driver must copy the input data before placing it in the output buffer. The driver obtains the buffer address by calling KIrp::IoctlBuffer. Upon completion, the I/O Manager copies the data from the system buffer into a buffer available to the Ring 3 caller. The driver must store the amount of data copied into the Information member of the IRP before terminating. If the control code does not indicate METHOD_IN_DIRECT or METHOD_OUT_DIRECT, the parameters to DeviceIoControl take on different meanings. The InputBuffer parameter is copied to a system buffer that the driver can access by calling KIrp::IoctlBuffer. The OutputBuffer parameter is mapped to a KMemory object that the driver can access by calling KIrp::Mdl. For METHOD_OUT_DIRECT, the caller must have write access to the buffer. Note that for METHOD_NEITHER, the kernel only provides the virtual address; it does not do any mapping to configure the buffer. The virtual address is valid only for the calling process. Here is an example using METHOD_BUFFERED: First, define an IOCTL code using the CTL_CODE macro: #define IOCTL_MYDEV_GET_FIRMWARE_REV \\CTL_CODE (FILE_DEVICE_UNKNOWN, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) Now use a DeviceIoControl call: BOOLEAN b; CHAR FirmwareRev[60]; ULONG FirmwareRevSize; b = DeviceIoControl(hDevice, IOCTL_MYDEV_GET_VERSION_STRING, NULL, // no input Note that this is the string pointer containing the execution command 0, FirmwareRev, // This is the output string pointer, which stores the string returned from the driver. sizeof(FirmwareRev),& FirmwareRevSize, NULL // not overlapped I/O );If the output buffer is large enough, the device copies the string into it and sets the copied string to FirmwareRevSize. In the driver, the code looks like this:const char* FIRMWARE_REV = \"FW 16.33 v5\";NTSTATUS MyDevice::DeviceControl( KIrp I ){ ULONG fwLength=0; switch ( I.IoctlCode() ) { case IOCTL_MYDEV_GET_FIRMWARE_REV: fwLength = strlen(FIRMWARE_REV)+1; if (I.IoctlOutputBufferSize() >= fwLength) { strcpy((PCHAR)I.IoctlBuffer(),FIRMWARE_REV); I.Information() = fwLength; return I.Complete(STATUS_SUCCESS); } else { } case . . . } }//This is the output string pointer, which stores the string returned from the driver. sizeof(FirmwareRev),& FirmwareRevSize, NULL // not overlapped I/O );If the output buffer is large enough, the device copies the string into it and sets the end of the copy to FirmwareRevSize. In the driver, the code would look like this:const char* FIRMWARE_REV = \"FW 16.33 v5\";NTSTATUS MyDevice::DeviceControl(KIrp I){ ULONG fwLength=0; switch (I.IoctlCode()) { case IOCTL_MYDEV_GET_FIRMWARE_REV: fwLength = strlen(FIRMWARE_REV)+1; if (I.IoctlOutputBufferSize() >= fwLength) { strcpy((PCHAR)I.IoctlBuffer(),FIRMWARE_REV); I.Information() = fwLength; return I.Complete(STATUS_SUCCESS); } else { } case . . . } }//This is the output string pointer, which stores the string returned from the driver. sizeof(FirmwareRev),& FirmwareRevSize, NULL // not overlapped I/O );If the output buffer is large enough, the device copies the string into it and sets the copied data to FirmwareRevSize. In the driver, the code would look like this:const char* FIRMWARE_REV = \"FW 16.33 v5\";NTSTATUS MyDevice::DeviceControl(KIrp I){ ULONG fwLength=0; switch (I.IoctlCode()) { case IOCTL_MYDEV_GET_FIRMWARE_REV: fwLength = strlen(FIRMWARE_REV)+1; if (I.IoctlOutputBufferSize() >= fwLength) { strcpy((PCHAR)I.IoctlBuffer(),FIRMWARE_REV); I.Information() = fwLength; return I.Complete(STATUS_SUCCESS); } else { } case . . . } }

unfold

You Might Like

Uploader
jasionla
 

Recommended ContentMore

Popular Components

Just Take a LookMore

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
×