Bill M: Thanks for the pointer to III, it worked like a charm.
Alas, now I’m suffering from another problem.
To reiterate, I’m working on a virtual bus that creates pairs of serial ports
that are ‘linked’ such that app A can open one port, app B can open the other,
and anything app A sends will be received by app B, and vice versa. I’m doing
this in order to emulate (with a user-mode program) a device that would normally
connect to the PC over a serial port (the real device has a usermode program
that requires a serial port in order to run). The idea is this: emulator opens
port A, device’s app opens port B, and they talk to each other this way – the
device’s app doesn’t need to be changed. Plus, it’s a flexible driver that
could be used for dozens of purposes (with the amount of work it takes to write
these things, I want it to be as reusable as possible!)
Because of this, it makes sense that these pairs of ports behave somewhat like
siamese twins – if one is disabled, the other should also be disabled; if one
is removed, the other should also be removed.
It appears now that the proper thing for removal is to handle the
RemovalRelations IRP (and possibly EjectionRelations?). However, when I tried
pairing disables together, my pile of bugs^W^W^Wdriver indicates that
something’s going seriously wrong.
What I did was, when one device gets a REMOVE irp (so that it is disabled), I
call IoInvalidateDeviceState(). When it gets a START irp, I again call
IoInvalidateDeviceState(). Whenever a QUERY_PNP_DEVICE_STATE irp comes in, I
check to see if the peer is started; if not, I set the PNP_DEVICE_DISABLED bit.
(If the peer has been completely removed from the system, I set
PNP_DEVICE_REMOVED.)
However, a slight catch-22 presented itself when I tested this version of the
driver. Here’s how things seem to go (based on my debug output):
The first device is started (IRP_MN_START_DEVICE). This causes an
IoInvalidateDeviceState() on the peer (device 2).
The first device, as part of win2k’s initialization, gets a
QUERY_PNP_DEVICE_STATE irp automatically. Since the peer had not been started
yet, it sets the PNP_DEVICE_DISABLED bit.
Th 2nd device is started (IRP_MN_START_DEVICE). The code calls
IoInvalidateDeviceState() on device 1.
The 2nd device, as part of the init, gets a QUERY_PNP_DEVICE_STATE. Since
device 1 *HAS* been started at this point, we leave with the PNP_DEVICE_DISABLED
bit cleared. [Note: I’m thinking that this automatically clears the
IoInvalidateDeviceState that occurred when device 1 was started.]
Device 1 now gets a 2nd QUERY_PNP_DEVICE_STATE irp (presumably due to the
invalidation requested by dev2’s START_DEVICE handler). Now that device 2 has
been started, we complete the irp with the PNP_DEVICE_DISABLED flag cleared to 0.
Woo! I hope everybody (or at least one person) is still following… because
this is about where I get confused.
I get a RemovalRelations irp for dev1 which I fail with a STATUS_NOT_SUPPORTED.
I then get a SURPRISE_REMOVAL irp for dev1. I don’t know why, because I didn’t
seem to do anything that indicated that the device was removed… <- This is the
part that i’m getting confused about.
The REMOVE_DEVICE then arrives in for dev1. Since I don’t understand the
intricacies of when to actually call IoDeleteDevice, I delete dev1 here.
Just before I delete the device, I call IoInvalidateDeviceState() on dev2.
Dev2 now gets a QUERY_PNP_DEVICE_STATE irp. dev2 sees that dev1 has left the
building, and sets the PNP_DEVICE_REMOVED flag.
Beyond this is stuff that I hope I can figure out once Walter Oney’s book
finally arrives in the mail ![:wink: :wink:](/images/emoji/twitter/wink.png?v=12)
Now dev2 gets a RemovalRelations irp, followed by SURPRISE_REMOVAL and
REMOVE_DEVICE irps. This I can understand (the ddk doesn’t say HOW Windows
detects a surprise removal, but I suppose that doing it as a result of a
PNP_DEVICE_REMOVED state makes sense.). Again, my ignorance of proper device
removal procedure has me call IoDeleteDevice() on dev2’s PDO.
Now I get two consecutive EjectionRelations queries for dev1, two
RemovalRelations queries for dev1, one EjectionRelations query for dev2, one
RemovalRelations query for dev2.
The bus itself then receives a BusRelations query (which should report no
devices, as they’ve been deleted, though I haven’t directly verified this).
Now dev1 gets an EjectionRelations, dev2 gets an EjectionRelations, dev1 gets a
REMOVE_DEVICE, dev2 gets another EjectionRelations, and dev2 gets a
REMOVE_DEVICE where it incorrectly IoDeleteDevice()s itself a 2nd time and blows
up with an IRQL_NOT_LESS_OR_EQUAL.
So, in summary, my questions are these: Why does marking a device as disabled
(by setting state=PNP_DEVICE_DISABLED) send me a IRP_MN_SURPRISE_REMOVAL irp,
and what’s the proper way to indicate that a particular device is present yet
disabled?
–
- Stevie-O
Real Programmers use COPY CON PROGRAM.EXE