Forcing a mixed-PnP driver to unload

I am having a problem with a filter driver I wrote that handles both some plug and play devices created by the PnP manager and a non-PnP control device created by the driver itself. When the PnP manager removes one of the PnP devices it checks to see if the driver has any devices left and unloads it if not, so if I close my non-PnP device before the last PnP device everything works out right and the driver is removed.

The problem is that if the non-PnP device has open handles when the last PnP device is removed, it can’t be removed at that time. It holds an internal count of its handle references and when they reach 0 it will remove itself, but when that happens the driver is not automatically unloading. Windows only seems to make the check for unloading when a PnP device is removed, but there are no PnP devices left. What’s the proper way for this driver to unload itself or signal the PnP manager to unload once all the devices have been removed if the last device was a non-PnP device?

You need to provide a little more information because the approach will
differ depending upon the answers.

  1. Does your driver ever need to run if the hardware is not present?
  2. Did you implement your legacy device object to handle PnP & Power
    requests?

If the answer to 1 is no, then just hold off processing your PnP remove
request until you have deleted the legacy device. If yes, implement PnP &
Power (root enumerated device) for the legacy device so when the device
object is deleted the driver unload will be called. Calling unload directly
from the legacy device object deletion can be another possibility. Since
you have an app involved on the legacy side, you can have it cause the
driver to be unloaded via the SCM if it has admin rights. Several
possibilities of which one may fit your needs.


David J. Craig
Engineer, Sr. Staff Software Systems
Broadcom Corporation

wrote in message news:xxxxx@ntdev…
>I am having a problem with a filter driver I wrote that handles both some
>plug and play devices created by the PnP manager and a non-PnP control
>device created by the driver itself. When the PnP manager removes one of
>the PnP devices it checks to see if the driver has any devices left and
>unloads it if not, so if I close my non-PnP device before the last PnP
>device everything works out right and the driver is removed.
>
> The problem is that if the non-PnP device has open handles when the last
> PnP device is removed, it can’t be removed at that time. It holds an
> internal count of its handle references and when they reach 0 it will
> remove itself, but when that happens the driver is not automatically
> unloading. Windows only seems to make the check for unloading when a PnP
> device is removed, but there are no PnP devices left. What’s the proper
> way for this driver to unload itself or signal the PnP manager to unload
> once all the devices have been removed if the last device was a non-PnP
> device?
>
>

> You need to provide a little more information because the approach will

differ depending upon the answers.

  1. Does your driver ever need to run if the hardware is not present?

I’m not sure if the answer to this is no or yes. I don’t ever run the
legacy device unless the PnP hardware devices are loaded, but once the
legacy device is in memory it can’t unload until all its handles are closed
so it may need to run for a long time after the actual PnP hardware is
removed if the user doesn’t close whatever application has a handle to it.

  1. Did you implement your legacy device object to handle PnP & Power
    requests?

The legacy device object does not handle PnP and Power requests. It returns
success for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER to keep from blocking
system power changes (if it even receives them - not sure it does), but
returns ERROR_NOT_SUPPORTED for all other PnP and Power requests. It is a
software-only device, so has no need or desire to control power states, just
a desire not to interfere with them and it has no hardware to allocate
resources to.

If the answer to 1 is no, then just hold off processing your PnP remove
request until you have deleted the legacy device.

The legacy device may not be released for a long time after the PnP manager
requests removal of the PnP hardware device. If I fail the request for a
PnP removal, won’t the device manager request the user to reboot the
machine? I want the removal of the legacy device to be transparent to the
user so that they don’t have to care about whether or not it is still
loaded.

If yes, implement PnP & Power (root enumerated device) for the legacy
device so when the device object is deleted the driver unload will be
called.

For code simplicity I’m trying to avoid adding what would probably amount to
50+ lines of code to handle PnP and Power control for the legacy device if
possible. Nearly all of that code would be superfluous since the
software-only device doesn’t have any power states or hardware resources to
be configured. If I did that I could use IoInvalidateDeviceState to tell
the PnP manager when I’m ready to unload the legacy device and I assume it
would work, but I don’t want to do that if I don’t have to.

Calling unload directly from the legacy device object deletion can be
another possibility.

This either does not work or does not apply to me I think. The PnP manager
detects the PnP hardware and starts the driver. In the DriverEntry I create
a legacy device to be able to send control requests. Later on my driver
removes the legacy device when it detects that A) all handles to the legacy
device have been closed and B) all the PnP devices have been removed. That
occurs either in the CreateClose dispatch routine for the legacy device or
the PnP dispatch for the PnP device depending upon whether the system still
had handles to the legacy device open when the last PnP remove occurred. My
DriverUnload routine has no code in it. By the time it is called by the PnP
manager all the devices are already closed. If I call it myself directly it
will do nothing and return. The problem is not that some devices have not
been removed so the driver is staying open, its that all of them have been
removed but the PnP manager didn’t request the removal of the last one so it
doesn’t realize it yet and doesn’t unload.

you have an app involved on the legacy side, you can have it cause the
driver to be unloaded via the SCM if it has admin rights.

My user applications will have administrator rights but I’m not sure if the
device can be unloaded that way since it was initially loaded by the PnP
manager. Its possible this would work since all the PnP devices have been
closed but it forces every user application to link with advapi32.dll,
something that I don’t want to do due to the bloat.

I’m not entirely satisfied with any of these solutions. Is there no way for
a PnP driver (not device) to request removal of itself or ask the PnP
manager to recheck its status to see that all the devices that were open and
keeping it from unloading are now closed? It recognizes that if the last
device is a PnP device, but not if it was a legacy device that was removed.
Is there is some kind of internal ioctl that I could send to the PnP manager
or something?

No, there is no message back to the io manager to recheck unload logic.
One other issue you might have is that creation of the legacy device in
DriverEntry may also lead to a situation where you will not unload if
AddDevice is never called. Instead of creating the device in DE(),
create it in the first pnp AddDevice, this will close the logic window
for this particular issue.

Who has handles with respect to the legacy device? Does the legacy
device open handles to other devices or is there open handles against
the legacy device? If it is the latter, you can still safely delete the
device when there are open handles against it. DriverUnload() may be
called, but the image will not be unloaded until the last handle is
closed.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 4:33 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

You need to provide a little more information because the approach
will
differ depending upon the answers.

  1. Does your driver ever need to run if the hardware is not present?

I’m not sure if the answer to this is no or yes. I don’t ever run the
legacy device unless the PnP hardware devices are loaded, but once the
legacy device is in memory it can’t unload until all its handles are
closed
so it may need to run for a long time after the actual PnP hardware is
removed if the user doesn’t close whatever application has a handle to
it.

  1. Did you implement your legacy device object to handle PnP & Power
    requests?

The legacy device object does not handle PnP and Power requests. It
returns
success for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER to keep from
blocking
system power changes (if it even receives them - not sure it does), but
returns ERROR_NOT_SUPPORTED for all other PnP and Power requests. It is
a
software-only device, so has no need or desire to control power states,
just
a desire not to interfere with them and it has no hardware to allocate
resources to.

If the answer to 1 is no, then just hold off processing your PnP
remove
request until you have deleted the legacy device.

The legacy device may not be released for a long time after the PnP
manager
requests removal of the PnP hardware device. If I fail the request for
a
PnP removal, won’t the device manager request the user to reboot the
machine? I want the removal of the legacy device to be transparent to
the
user so that they don’t have to care about whether or not it is still
loaded.

If yes, implement PnP & Power (root enumerated device) for the legacy
device so when the device object is deleted the driver unload will be
called.

For code simplicity I’m trying to avoid adding what would probably
amount to
50+ lines of code to handle PnP and Power control for the legacy device
if
possible. Nearly all of that code would be superfluous since the
software-only device doesn’t have any power states or hardware resources
to
be configured. If I did that I could use IoInvalidateDeviceState to
tell
the PnP manager when I’m ready to unload the legacy device and I assume
it
would work, but I don’t want to do that if I don’t have to.

Calling unload directly from the legacy device object deletion can be
another possibility.

This either does not work or does not apply to me I think. The PnP
manager
detects the PnP hardware and starts the driver. In the DriverEntry I
create
a legacy device to be able to send control requests. Later on my driver

removes the legacy device when it detects that A) all handles to the
legacy
device have been closed and B) all the PnP devices have been removed.
That
occurs either in the CreateClose dispatch routine for the legacy device
or
the PnP dispatch for the PnP device depending upon whether the system
still
had handles to the legacy device open when the last PnP remove occurred.
My
DriverUnload routine has no code in it. By the time it is called by the
PnP
manager all the devices are already closed. If I call it myself
directly it
will do nothing and return. The problem is not that some devices have
not
been removed so the driver is staying open, its that all of them have
been
removed but the PnP manager didn’t request the removal of the last one
so it
doesn’t realize it yet and doesn’t unload.

you have an app involved on the legacy side, you can have it cause the

driver to be unloaded via the SCM if it has admin rights.

My user applications will have administrator rights but I’m not sure if
the
device can be unloaded that way since it was initially loaded by the PnP

manager. Its possible this would work since all the PnP devices have
been
closed but it forces every user application to link with advapi32.dll,
something that I don’t want to do due to the bloat.

I’m not entirely satisfied with any of these solutions. Is there no way
for
a PnP driver (not device) to request removal of itself or ask the PnP
manager to recheck its status to see that all the devices that were open
and
keeping it from unloading are now closed? It recognizes that if the
last
device is a PnP device, but not if it was a legacy device that was
removed.
Is there is some kind of internal ioctl that I could send to the PnP
manager
or something?


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

>“Doron Holan” wrote in message
>news:xxxxx@ntdev…
>No, there is no message back to the io manager to recheck unload logic.
>One other issue you might have is that creation of the legacy device in
>DriverEntry may also lead to a situation where you will not unload if
>AddDevice is never called. Instead of creating the device in DE(),
>create it in the first pnp AddDevice, this will close the logic window
>for this particular issue.

You are correct that it will not unload if AddDevice is never called,
although I am not sure why DriverEntry would ever be called unless the PnP
manager had found one of the PnP devices and decided to spawn the driver to
operate it. At one time I did create the legacy device in AddDevice and
moved it to DriverEntry to help me debug some faulty logic. I fixed it but I
haven’t moved it back yet. Thanks for pointing that out.

>Who has handles with respect to the legacy device? Does the legacy
>device open handles to other devices or is there open handles against
>the legacy device? If it is the latter, you can still safely delete the
>device when there are open handles against it. DriverUnload() may be
>called, but the image will not be unloaded until the last handle is
>closed.

The legacy device has no handles against other devices. User applications
may have handles against the legacy device at the time of the PnP removal
because they were controlling it and those applications were not closed
before the user tried to remove the PnP device(s) in the device manager.
Before I implemented the handle count on the legacy device to control when
it would try to unload, I tried unloading it at the time of the last PnP
device thinking that any open handles would automatically be invalidated,
but I ended up crashing the machine with a blue screen when I tried to
unload then reload the PnP devices whille holding a handle open to the
legacy device.

My problem is that when I remove the legacy device last, there are no
handles open and no devices open, but DriverUnload is not called by the PnP
manager because the PnP manager only makes that check after it makes a
device removal request apparently but it doesn’t make a removal request for
the legacy device because it didn’t ask for it to be created to start
with – my driver chose to create it on its own. If I am in that state and
I add then remove a PnP device with the device manager without opening or
closing any new handles to the legacy device, the PnP manager will then see
that there are no handles or devices left and unload properly. If somehow I
could just tell the PnP manager, “hey, I’m done” it would look and see that
there are no handles or devices in use and remove the driver. Since it
doesn’t seem like there is any way to do that, I guess I will either have to
make my legacy device PnP, which seems like pain in the rear, or just simply
live with the fact that the driver will only unload if someone closes all
the applications using it before the PnP devices are removed from the
control panel, or I suppose I can fail removal requests on the last PnP
device which will cause the device manager to ask the user to reboot I
think.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 4:33 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

> You need to provide a little more information because the approach
will
> differ depending upon the answers.
>
> 1. Does your driver ever need to run if the hardware is not present?

I’m not sure if the answer to this is no or yes. I don’t ever run the
legacy device unless the PnP hardware devices are loaded, but once the
legacy device is in memory it can’t unload until all its handles are
closed
so it may need to run for a long time after the actual PnP hardware is
removed if the user doesn’t close whatever application has a handle to
it.

> 2. Did you implement your legacy device object to handle PnP & Power
> requests?

The legacy device object does not handle PnP and Power requests. It
returns
success for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER to keep from
blocking
system power changes (if it even receives them - not sure it does), but
returns ERROR_NOT_SUPPORTED for all other PnP and Power requests. It is
a
software-only device, so has no need or desire to control power states,
just
a desire not to interfere with them and it has no hardware to allocate
resources to.

> If the answer to 1 is no, then just hold off processing your PnP
remove
> request until you have deleted the legacy device.

The legacy device may not be released for a long time after the PnP
manager
requests removal of the PnP hardware device. If I fail the request for
a
PnP removal, won’t the device manager request the user to reboot the
machine? I want the removal of the legacy device to be transparent to
the
user so that they don’t have to care about whether or not it is still
loaded.

> If yes, implement PnP & Power (root enumerated device) for the legacy
> device so when the device object is deleted the driver unload will be
> called.

For code simplicity I’m trying to avoid adding what would probably
amount to
50+ lines of code to handle PnP and Power control for the legacy device
if
possible. Nearly all of that code would be superfluous since the
software-only device doesn’t have any power states or hardware resources
to
be configured. If I did that I could use IoInvalidateDeviceState to
tell
the PnP manager when I’m ready to unload the legacy device and I assume
it
would work, but I don’t want to do that if I don’t have to.

> Calling unload directly from the legacy device object deletion can be
> another possibility.

This either does not work or does not apply to me I think. The PnP
manager
detects the PnP hardware and starts the driver. In the DriverEntry I
create
a legacy device to be able to send control requests. Later on my driver

removes the legacy device when it detects that A) all handles to the
legacy
device have been closed and B) all the PnP devices have been removed.
That
occurs either in the CreateClose dispatch routine for the legacy device
or
the PnP dispatch for the PnP device depending upon whether the system
still
had handles to the legacy device open when the last PnP remove occurred.
My
DriverUnload routine has no code in it. By the time it is called by the
PnP
manager all the devices are already closed. If I call it myself
directly it
will do nothing and return. The problem is not that some devices have
not
been removed so the driver is staying open, its that all of them have
been
removed but the PnP manager didn’t request the removal of the last one
so it
doesn’t realize it yet and doesn’t unload.

> you have an app involved on the legacy side, you can have it cause the

> driver to be unloaded via the SCM if it has admin rights.

My user applications will have administrator rights but I’m not sure if
the
device can be unloaded that way since it was initially loaded by the PnP

manager. Its possible this would work since all the PnP devices have
been
closed but it forces every user application to link with advapi32.dll,
something that I don’t want to do due to the bloat.

I’m not entirely satisfied with any of these solutions. Is there no way
for
a PnP driver (not device) to request removal of itself or ask the PnP
manager to recheck its status to see that all the devices that were open
and
keeping it from unloading are now closed? It recognizes that if the
last
device is a PnP device, but not if it was a legacy device that was
removed.
Is there is some kind of internal ioctl that I could send to the PnP
manager
or something?


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

What was the bugcheck when you deleted the legacy device object with
handles still open? This does work b/c this is exactly how NT4 behaved,
you could delete a device object with open handles, get unloaded and
then still receive i/o on the handles. I would guess that the bugcheck
you are seeing is due to a driver bug, not an OS issue.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 6:24 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

“Doron Holan” wrote in message
>news:xxxxx@ntdev…
>No, there is no message back to the io manager to recheck unload logic.
>One other issue you might have is that creation of the legacy device in
>DriverEntry may also lead to a situation where you will not unload if
>AddDevice is never called. Instead of creating the device in DE(),
>create it in the first pnp AddDevice, this will close the logic window
>for this particular issue.

You are correct that it will not unload if AddDevice is never called,
although I am not sure why DriverEntry would ever be called unless the
PnP
manager had found one of the PnP devices and decided to spawn the driver
to
operate it. At one time I did create the legacy device in AddDevice and

moved it to DriverEntry to help me debug some faulty logic. I fixed it
but I
haven’t moved it back yet. Thanks for pointing that out.

>Who has handles with respect to the legacy device? Does the legacy
>device open handles to other devices or is there open handles against
>the legacy device? If it is the latter, you can still safely delete
the
>device when there are open handles against it. DriverUnload() may be
>called, but the image will not be unloaded until the last handle is
>closed.

The legacy device has no handles against other devices. User
applications
may have handles against the legacy device at the time of the PnP
removal
because they were controlling it and those applications were not closed
before the user tried to remove the PnP device(s) in the device manager.

Before I implemented the handle count on the legacy device to control
when
it would try to unload, I tried unloading it at the time of the last PnP

device thinking that any open handles would automatically be
invalidated,
but I ended up crashing the machine with a blue screen when I tried to
unload then reload the PnP devices whille holding a handle open to the
legacy device.

My problem is that when I remove the legacy device last, there are no
handles open and no devices open, but DriverUnload is not called by the
PnP
manager because the PnP manager only makes that check after it makes a
device removal request apparently but it doesn’t make a removal request
for
the legacy device because it didn’t ask for it to be created to start
with – my driver chose to create it on its own. If I am in that state
and
I add then remove a PnP device with the device manager without opening
or
closing any new handles to the legacy device, the PnP manager will then
see
that there are no handles or devices left and unload properly. If
somehow I
could just tell the PnP manager, “hey, I’m done” it would look and see
that
there are no handles or devices in use and remove the driver. Since it
doesn’t seem like there is any way to do that, I guess I will either
have to
make my legacy device PnP, which seems like pain in the rear, or just
simply
live with the fact that the driver will only unload if someone closes
all
the applications using it before the PnP devices are removed from the
control panel, or I suppose I can fail removal requests on the last PnP
device which will cause the device manager to ask the user to reboot I
think.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 4:33 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

> You need to provide a little more information because the approach
will
> differ depending upon the answers.
>
> 1. Does your driver ever need to run if the hardware is not present?

I’m not sure if the answer to this is no or yes. I don’t ever run the
legacy device unless the PnP hardware devices are loaded, but once the
legacy device is in memory it can’t unload until all its handles are
closed
so it may need to run for a long time after the actual PnP hardware is
removed if the user doesn’t close whatever application has a handle to
it.

> 2. Did you implement your legacy device object to handle PnP & Power
> requests?

The legacy device object does not handle PnP and Power requests. It
returns
success for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER to keep from
blocking
system power changes (if it even receives them - not sure it does), but
returns ERROR_NOT_SUPPORTED for all other PnP and Power requests. It is
a
software-only device, so has no need or desire to control power states,
just
a desire not to interfere with them and it has no hardware to allocate
resources to.

> If the answer to 1 is no, then just hold off processing your PnP
remove
> request until you have deleted the legacy device.

The legacy device may not be released for a long time after the PnP
manager
requests removal of the PnP hardware device. If I fail the request for
a
PnP removal, won’t the device manager request the user to reboot the
machine? I want the removal of the legacy device to be transparent to
the
user so that they don’t have to care about whether or not it is still
loaded.

> If yes, implement PnP & Power (root enumerated device) for the legacy
> device so when the device object is deleted the driver unload will be
> called.

For code simplicity I’m trying to avoid adding what would probably
amount to
50+ lines of code to handle PnP and Power control for the legacy device
if
possible. Nearly all of that code would be superfluous since the
software-only device doesn’t have any power states or hardware resources
to
be configured. If I did that I could use IoInvalidateDeviceState to
tell
the PnP manager when I’m ready to unload the legacy device and I assume
it
would work, but I don’t want to do that if I don’t have to.

> Calling unload directly from the legacy device object deletion can be
> another possibility.

This either does not work or does not apply to me I think. The PnP
manager
detects the PnP hardware and starts the driver. In the DriverEntry I
create
a legacy device to be able to send control requests. Later on my driver

removes the legacy device when it detects that A) all handles to the
legacy
device have been closed and B) all the PnP devices have been removed.
That
occurs either in the CreateClose dispatch routine for the legacy device
or
the PnP dispatch for the PnP device depending upon whether the system
still
had handles to the legacy device open when the last PnP remove occurred.
My
DriverUnload routine has no code in it. By the time it is called by the
PnP
manager all the devices are already closed. If I call it myself
directly it
will do nothing and return. The problem is not that some devices have
not
been removed so the driver is staying open, its that all of them have
been
removed but the PnP manager didn’t request the removal of the last one
so it
doesn’t realize it yet and doesn’t unload.

> you have an app involved on the legacy side, you can have it cause the

> driver to be unloaded via the SCM if it has admin rights.

My user applications will have administrator rights but I’m not sure if
the
device can be unloaded that way since it was initially loaded by the PnP

manager. Its possible this would work since all the PnP devices have
been
closed but it forces every user application to link with advapi32.dll,
something that I don’t want to do due to the bloat.

I’m not entirely satisfied with any of these solutions. Is there no way
for
a PnP driver (not device) to request removal of itself or ask the PnP
manager to recheck its status to see that all the devices that were open
and
keeping it from unloading are now closed? It recognizes that if the
last
device is a PnP device, but not if it was a legacy device that was
removed.
Is there is some kind of internal ioctl that I could send to the PnP
manager
or something?


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Why not abandon the entire ‘legacy device’ approach here and instead
implement your control device as a full pnp virtual device? I think this
would resolve your issues, at the added cost of the additional code for
full pnp support, which you can fetch from the toaster sample. Up in
user mode you need a control app or service that starts/stops your
virtual device.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 9:24 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

“Doron Holan” wrote in message
>news:xxxxx@ntdev…
>No, there is no message back to the io manager to recheck unload logic.
>One other issue you might have is that creation of the legacy device in
>DriverEntry may also lead to a situation where you will not unload if
>AddDevice is never called. Instead of creating the device in DE(),
>create it in the first pnp AddDevice, this will close the logic window
>for this particular issue.

You are correct that it will not unload if AddDevice is never called,
although I am not sure why DriverEntry would ever be called unless the
PnP
manager had found one of the PnP devices and decided to spawn the driver
to
operate it. At one time I did create the legacy device in AddDevice and

moved it to DriverEntry to help me debug some faulty logic. I fixed it
but I
haven’t moved it back yet. Thanks for pointing that out.

>Who has handles with respect to the legacy device? Does the legacy
>device open handles to other devices or is there open handles against
>the legacy device? If it is the latter, you can still safely delete
the
>device when there are open handles against it. DriverUnload() may be
>called, but the image will not be unloaded until the last handle is
>closed.

The legacy device has no handles against other devices. User
applications
may have handles against the legacy device at the time of the PnP
removal
because they were controlling it and those applications were not closed
before the user tried to remove the PnP device(s) in the device manager.

Before I implemented the handle count on the legacy device to control
when
it would try to unload, I tried unloading it at the time of the last PnP

device thinking that any open handles would automatically be
invalidated,
but I ended up crashing the machine with a blue screen when I tried to
unload then reload the PnP devices whille holding a handle open to the
legacy device.

My problem is that when I remove the legacy device last, there are no
handles open and no devices open, but DriverUnload is not called by the
PnP
manager because the PnP manager only makes that check after it makes a
device removal request apparently but it doesn’t make a removal request
for
the legacy device because it didn’t ask for it to be created to start
with – my driver chose to create it on its own. If I am in that state
and
I add then remove a PnP device with the device manager without opening
or
closing any new handles to the legacy device, the PnP manager will then
see
that there are no handles or devices left and unload properly. If
somehow I
could just tell the PnP manager, “hey, I’m done” it would look and see
that
there are no handles or devices in use and remove the driver. Since it
doesn’t seem like there is any way to do that, I guess I will either
have to
make my legacy device PnP, which seems like pain in the rear, or just
simply
live with the fact that the driver will only unload if someone closes
all
the applications using it before the PnP devices are removed from the
control panel, or I suppose I can fail removal requests on the last PnP
device which will cause the device manager to ask the user to reboot I
think.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Sunday, June 24, 2007 4:33 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

> You need to provide a little more information because the approach
will
> differ depending upon the answers.
>
> 1. Does your driver ever need to run if the hardware is not present?

I’m not sure if the answer to this is no or yes. I don’t ever run the
legacy device unless the PnP hardware devices are loaded, but once the
legacy device is in memory it can’t unload until all its handles are
closed
so it may need to run for a long time after the actual PnP hardware is
removed if the user doesn’t close whatever application has a handle to
it.

> 2. Did you implement your legacy device object to handle PnP & Power
> requests?

The legacy device object does not handle PnP and Power requests. It
returns
success for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER to keep from
blocking
system power changes (if it even receives them - not sure it does), but
returns ERROR_NOT_SUPPORTED for all other PnP and Power requests. It is
a
software-only device, so has no need or desire to control power states,
just
a desire not to interfere with them and it has no hardware to allocate
resources to.

> If the answer to 1 is no, then just hold off processing your PnP
remove
> request until you have deleted the legacy device.

The legacy device may not be released for a long time after the PnP
manager
requests removal of the PnP hardware device. If I fail the request for
a
PnP removal, won’t the device manager request the user to reboot the
machine? I want the removal of the legacy device to be transparent to
the
user so that they don’t have to care about whether or not it is still
loaded.

> If yes, implement PnP & Power (root enumerated device) for the legacy
> device so when the device object is deleted the driver unload will be
> called.

For code simplicity I’m trying to avoid adding what would probably
amount to
50+ lines of code to handle PnP and Power control for the legacy device
if
possible. Nearly all of that code would be superfluous since the
software-only device doesn’t have any power states or hardware resources
to
be configured. If I did that I could use IoInvalidateDeviceState to
tell
the PnP manager when I’m ready to unload the legacy device and I assume
it
would work, but I don’t want to do that if I don’t have to.

> Calling unload directly from the legacy device object deletion can be
> another possibility.

This either does not work or does not apply to me I think. The PnP
manager
detects the PnP hardware and starts the driver. In the DriverEntry I
create
a legacy device to be able to send control requests. Later on my driver

removes the legacy device when it detects that A) all handles to the
legacy
device have been closed and B) all the PnP devices have been removed.
That
occurs either in the CreateClose dispatch routine for the legacy device
or
the PnP dispatch for the PnP device depending upon whether the system
still
had handles to the legacy device open when the last PnP remove occurred.
My
DriverUnload routine has no code in it. By the time it is called by the
PnP
manager all the devices are already closed. If I call it myself
directly it
will do nothing and return. The problem is not that some devices have
not
been removed so the driver is staying open, its that all of them have
been
removed but the PnP manager didn’t request the removal of the last one
so it
doesn’t realize it yet and doesn’t unload.

> you have an app involved on the legacy side, you can have it cause the

> driver to be unloaded via the SCM if it has admin rights.

My user applications will have administrator rights but I’m not sure if
the
device can be unloaded that way since it was initially loaded by the PnP

manager. Its possible this would work since all the PnP devices have
been
closed but it forces every user application to link with advapi32.dll,
something that I don’t want to do due to the bloat.

I’m not entirely satisfied with any of these solutions. Is there no way
for
a PnP driver (not device) to request removal of itself or ask the PnP
manager to recheck its status to see that all the devices that were open
and
keeping it from unloading are now closed? It recognizes that if the
last
device is a PnP device, but not if it was a legacy device that was
removed.
Is there is some kind of internal ioctl that I could send to the PnP
manager
or something?


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

>“Doron Holan” wrote in message
>news:xxxxx@ntdev…
>What was the bugcheck when you deleted the legacy device object with
>handles still open? This does work b/c this is exactly how NT4 behaved,
>you could delete a device object with open handles, get unloaded and
>then still receive i/o on the handles. I would guess that the bugcheck
>you are seeing is due to a driver bug, not an OS issue.

I disabled the reference counting to make it happen again and when it did I
wrote down

STOP 0x0000000a (0x41b2886, 0x00000002, 0x00000001, 0x8050037e)

I must have missed a letter or number since the first term in the
parenthesis does not have 8 numbers in it. I did some more analysis of this
problem and I believe that it is indeed a bug in my code and the reference
check does stop this particular bug from happening in that limited case, but
there still exist other faults and the improper code needs to be fixed
nonetheless.

What I had been doing is traversing the DriverObject->DeviceObject and
DeviceObject->NextDevice list to find devices of a certain type (legacy or
PnP) in my code. I now realize that this won’t work because that list is
not updated at the time of calling IoDeleteDevice, it is instead updated at
the time that the device is actually able to release, which is not
immediately in the case of one with handles left open like my legacy device.
Because of that I end up locating the same legacy device in the list and
starting to use it again even after I removed it. I may end up removing it
more than once or sending data to it after it truly does remove itself and
both of those will almost certainly lead to a BSOD. I’ll have to keep my
own list of devices to traverse because there’s no way I can rely on the
devices in that system list actually being in a usable state I realize now.

Once I fix that, removing the reference check should be viable, but it does
not solve the problem of the PnP manager not noticing that the driver is
ready for removal if the legacy device is the last one to have handles open.
Experimentally, I removed the check so my code deletes the legacy device at
the same time as the last PnP device, but I found that the PnP manager still
does not unload immediately because of the open handles, even though all the
devices have been removed. If the legacy device is the last one to have a
handle open to it the PnP manager still fails to recognize that everything
has shut down and been released and it is safe to unload.

Could I manually release those references with ObDereferenceObject before I
close the PnP device so that the legacy device can remove immediately at
that time? I know ObDereferenceObject works on files, but I’m not sure
about device objects. I’m unsure about what ramifications that may have on
open applications with handles or on the system. I was trying to shut down
in a more elegant manner, but this brute force method could be a possibility
if its legal and won’t bring down the machine in the process.

>“Roddy, Mark” wrote in message news:xxxxx@ntdev…
>Why not abandon the entire ‘legacy device’ approach here and instead
>implement your control device as a full pnp virtual device? I think this
>would resolve your issues, at the added cost of the additional code for
>full pnp support, which you can fetch from the toaster sample. Up in
>user mode you need a control app or service that starts/stops your
>virtual device.

Microsoft’s licensing constraints on the DDK and WDK sample code do not
allow redistribution of the sample code except in object form (not source
form) as far as I can understand from reading the license agreement. It is
my desire to be able to freely distribute my source code in any fashion I
choose, including possibly in open source software, which Microsoft’s
licensing agreement seems to explicitly exclude. As such, it is
unacceptable to include any sample code in my code. I have written every
line of my driver from the ground up and although I’m certain this takes
much longer and is fraught with pitfalls that have been resolved in sample
code but that I may have to discover myself along the way, I am also certain
that when it is complete I am the owner of the code and can do what I choose
with it.

I don’t have a full enough understanding of PnP and Power handling to
actually implement all that code myself without a good deal of further
research into the topic I believe at this time. My PnP devices are filter
devices which really don’t have to do any power handling other than passing
everything down the stack to the next device. Somewhere down the line the
power policy manager handles whatever needs to be handled. I have had to
implement the bare minimum PnP handling, far less than would be required of
a PDO, so I just don’t have that knowledge yet. Also, since my device
doesn’t actually have any power states and doesn’t reserve any device
resources, that code seems to unnecessarily introduce extra bloat and
complexity into my source code base so I am against that unless I find that
there is no way to accomplish my goals otherwise. It may indeed be the case
that there is no easy way to do what I want to do without superfluous code
bloat. It would not be the first time I have had that problem using
Microsoft technologies.

A virtual device doesn’t have to do much either in terms of power and
pnp. The power stuff is all on the order of: ‘pass it down’ and the pnp
stuff is entirely boilerplate code. If you really are worried about the
license restrictions use any of the existing WDM books for your model or
switch over to KMDF, which provides the pnp/pm code in its entirety
already done for you.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Matthew Carter
Sent: Monday, June 25, 2007 12:32 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Forcing a mixed-PnP driver to unload

“Roddy, Mark” wrote in message
news:xxxxx@ntdev…
>Why not abandon the entire ‘legacy device’ approach here and instead
>implement your control device as a full pnp virtual device? I think
this
>would resolve your issues, at the added cost of the additional code for
>full pnp support, which you can fetch from the toaster sample. Up in
>user mode you need a control app or service that starts/stops your
>virtual device.

Microsoft’s licensing constraints on the DDK and WDK sample code do not
allow redistribution of the sample code except in object form (not
source
form) as far as I can understand from reading the license agreement. It
is
my desire to be able to freely distribute my source code in any fashion
I
choose, including possibly in open source software, which Microsoft’s
licensing agreement seems to explicitly exclude. As such, it is
unacceptable to include any sample code in my code. I have written
every
line of my driver from the ground up and although I’m certain this takes

much longer and is fraught with pitfalls that have been resolved in
sample
code but that I may have to discover myself along the way, I am also
certain
that when it is complete I am the owner of the code and can do what I
choose
with it.

I don’t have a full enough understanding of PnP and Power handling to
actually implement all that code myself without a good deal of further
research into the topic I believe at this time. My PnP devices are
filter
devices which really don’t have to do any power handling other than
passing
everything down the stack to the next device. Somewhere down the line
the
power policy manager handles whatever needs to be handled. I have had
to
implement the bare minimum PnP handling, far less than would be required
of
a PDO, so I just don’t have that knowledge yet. Also, since my device
doesn’t actually have any power states and doesn’t reserve any device
resources, that code seems to unnecessarily introduce extra bloat and
complexity into my source code base so I am against that unless I find
that
there is no way to accomplish my goals otherwise. It may indeed be the
case
that there is no easy way to do what I want to do without superfluous
code
bloat. It would not be the first time I have had that problem using
Microsoft technologies.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

>A virtual device doesn’t have to do much either in terms of power and

pnp. The power stuff is all on the order of: ‘pass it down’ and the pnp
stuff is entirely boilerplate code. If you really are worried about the
license restrictions use any of the existing WDM books for your model or
switch over to KMDF, which provides the pnp/pm code in its entirety
already done for you.

My virtual device would have no one to pass anything down to since it has no
pdo. I was under the impression I’d need to make a bus driver to
enumerate a pdo and do ALL the power and PnP handling, even things that
don’t really apply. Am I incorrect in thinking that? Does the operating
system provide a pdo for devices with no hardware?

It is true that KMDF can handle this easily. I actually wrote the driver as
a KMDF driver to start with then I translated it backwards into WDM because
A) I’m an anal-retentive perfectionist and I found KMDF to just be a layer
of bloat over top of WDF, although its true that it does make development
quite a bit simpler, B) the WDF is an enormous download and I suspect that
some people that may want to use my source code may have no need for any of
its functionality except to compile this driver, C) the WDF is only
available through subscription to Microsoft Connect or MSDN where the
Windows 2003 SP1 DDK can be downloaded from Microsoft Downloads freely
without signing up for anything, D) Drivers created by WDF do not show their
imports when dumped with dumpbin, which I personally found an annoyance as I
like to understand what is going on, E) gmer (a rootkit detection utility)
reports that drivers created with WDF may be root kits (I understand why and
it is harmless, but for an end user this could alarm them and it may set off
older antivirus programs if they use similar detection).