How to create an exclusive device or debug why your device is exclusive
Certain devices are exclusive access, or in simpler terms, only one handle can be opened for a particular device. A serial port is an example of an exclusive device; it would make no sense for 2 applications to have the port open because each would expect exclusive state with device plugged into the port and the settings (baud, parity, etc.) on the port itself.
You, as the driver writer, can also choose to make your device exclusive (if you are not writing a driver for a particular device class). Alternatively, you might choose to allow multiple handles to be created against your device. Finally, you might even want to have file system semantics for exclusive access or shared access (which is a whole topic in and of itself).
But what happens if you are trying to create a device which can have multiple handles created against it, but it ends up being exclusive for some unknown reason? How do yo debug this? The biggest aid in debugging this issue is understanding how you can create an exclusive device in the first place. Here is a list of ways of how to create an exclusive access device. (This list is by no means a exhaustive list, it just contains the methods I know of ;) ).
The DDK also has a great section on this topic, you can read it here. Hopefully the link does not move around.
When calling IoCreateDevice(), you specify TRUE for the Exclusive parameter (the sixth one). This method works for legacy (e.g. non PnP) devices and for raw PDOs, but it does not work well for non raw PDOs, FDOs, or filters and here is why:
- PDO: Typically you don't know what device stack is going to be loaded on the PDO. As such, creating an exclusive access device might be contrary to the needs of the stack that is loaded on the PDO.
- FDO or Filter DO: These devices typically are unnamed devices. When you create a device interface, it uses the PDO's name as the destination for the symbolic link. When the I/O manager resolves the symbolic link, it uses the settings of the named device object itself (and not the top of stack) to manage exclusivity (and actual rights for access based on the security descritor for the device). You could create a named FDO or Filter device object so that the I/O manager does the check on the correct device object, but that doesn't stop someone from opening the stack using the PDO's name, so this solution does not work all the time.
As a further point of complexity, the I/O manager only enforces exclusivity on the base name of the device object. If the caller appends a string to the end of the base name, the I/O manager will not count that create as exclusive.
When you implement your dispatch routine for IRP_MJ_CREATE (in WDM) or EvtDeviceFileCreate (in KMDF), you maintain a count of handles which have been opened against your device and fail requests when the count is > 1. Typically this count is maintained on a field in the device extension using the InterlockedIncrement()/Decrement() functions and is decremented in your IRP_MJ_CLOSE dispatch routine (in WDM) or EvtFileClose (in KMDF). Note: in KMDF you don't need to do this at all. During device initialization, if you call WdfDeviceInitSetExclusive(), KMDF will maintain this count for you automatically.
A (class) filter driver above your could be enforcing exclusivity. For example, in the keyboard or mouse device classes, the class driver (kbdclass.sys or mouclass.sys) will enforce exlusivity on the device (by maintaining a count of open handles). To debug this, you really need to consider which device class you are installed under. The device class is controlled by the INF which installs your device.
The INF can enforce exclusivity. By using the INF, you solve the problem where the FDO wants exclusivity while the PDO (which has the openable name) was marked as exclusive when it was created. With the INF directive in place, the PnP manager will apply the exclusivity setting to each device in the device stack after the stack has successfully completed the IRP_MN_START_DEVICE IRP. You can specify exclusivity for the class or only for specific device instances. Under the [ClassInstall32] or [DDInstall.HW] sections, add the following
HKR,,Exclusive,0x10001,exclusive-device
where exclusive-device is 1 and then the PnP manager will apply the exclusive attribute to all devices in the stack. The same caveat I mentioned earlier about the I/O manager skipping the exclusivity check if there is an additional path at the end of the file name applies here as well.
So, now that you know how to create an exclusive device object, how do you debug it? Well, you know if you are specifying Exclusive in IoCreateDevice(), so there is no need to debug that at runtime. What you can debug at runtime is a filter on top of you failing the create request. First, you run !devstack on your devobj to find the filter driver attached to your device. Then, run !drvobj [driver name] 3 and you will get the IRP_MJ_CREATE dispatch handler. Put a bp on that handler and then see if the request is being completed without being sent down the stack. Obviously you are now debugging code with out source, but at least you have a place to start.
Comments
- Anonymous
May 27, 2006
I wrote usb touch screen driver.It now works almost fine.When I
move finger on the touch screen, the cursor on window move OK.
Now I want write data do usb device through application.Because
the driver is exclusive to win32,I have to add second device object.
Now DDK Tool devicetree can see second device object. But applicaton cannot open it's handle.
Could you advice?Thanks a lot. - Anonymous
May 27, 2006
did you clear DO_DEVICE_INITIALIZING on the 2nd device object? did you create a symbolic link for the 2nd device?
d - Anonymous
May 28, 2006
I clear DO_DEVICE_INITIALIZING on the 2nd device object.I tried
two methods to create a symbolic link for the 2nd device.The 1st,
use IoRegisterDeviceInterface,return not STUTUS_SUCCESS,the
2nd,use IoCreateSymboliclink.Application cannot open the device
handle with Neither above methods.
By th way,I use CreateFile("\.\Child".....) to open handle in application.In driver,device name string is "\device\child".
Could you advice?Thanks a lot. - Anonymous
June 01, 2006
I try to write mouse driver and usb device driver.The mouse driver has no PID&VID.It receives IOCTLs from usb device driver and communicate with mouclass.
My Question is
1)How to install the mouse driver without PID & VID?
2)How to send IOCTLs from usb device driver to mouse driver?
Thanks a lot. - Anonymous
June 01, 2006
The comment has been removed - Anonymous
June 01, 2006
Yu Zhou, with respect to your second question, here is the same answer I gave on the NTDEV mailing list
1) I think you are asking how to install a root enumerated device, e.g. a device which is not detected by any hardware bus (or bus driver) on the machine. Devcon can do this for you. For instance, to install the KMDF sample driver statbus
devcon install statbus.inf rootstatbus
2) you have the same problem as before. For the usb driver to send info to the mouse driver, it needs to open the mouse driver. But you can't open the mouse driver because mouclass will prevent it. You should get the one driver solution working w/out complicating things by introducing 2 device stacks. - Anonymous
June 04, 2006
doronh,as your guide,I read the topic"Intoduction to MS-DOS Device Names".I try to create symbolic link string,
"\DosDevices\Child".I use CreateFile("\.\child"...) to open device.GetLastError is 2,which indicates cannot open device.
I implement IRP_MJ_CREATE/CLEANUP/CLOSE dispatch routines
in the driver.but not yet handle child device in those routines.
Could you advice?Thanks a lot. - Anonymous
June 04, 2006
you need to handle IRP_MJ_CREATE/CLEANUP/CLOSE for the child device in your dispatch handler. if you don't handle IRP_MJ_CREATE, you cannot create the handle.
d