Thanks for the suggestions & comments people.
Tim Roberts first:
What kind of pipe do you use for step 1? (It’s the first pipe in your descriptors, apparently.)
Its a bulk OUT pipe, maximum packet size is 64 for historical reasons, it handles low-bandwidth text comms to the device.
Do you ever see any errors in the URB completion routine?
No.
Are you guaranteed that all requests will be synchronous? By storing the incoming text in the
device extension, you are assuming you never get simultaneous requests.
I’m not sure I understand what you mean by all requests synchronous. All text output to the device is provided by DIOC calls which operate synchronously at user level. These put data into a (spinlock protected) buffer in the device extension and call the SendChars function. This tests the (spinlock protected) sendcharspending flag and, if a transfer is not in progress, kicks off the IRP. If a transfer is already in progress we rely on the completion routine kicking off the next transfer - this works fine but is not happening in this case. So we are protected against a request while a transfer is in progress and the spinlock prevents two bits of code meddling with the buffer at the same time.
But one of the things that has worried me is the sending of any more text by kicking off SendChars in the completion routine - does this annoy the lower driver so that later on it jams up? But it looks like it is a legitimate thing to do - my current code queues a Dpc to call SendChars because I was uncertain if this would help - appears to make no difference.
Is there a reason you have to defer the transmission? Why not just queue up the URB when you
get the request?
I don’t defer the transmission unless there is already one running, as above. The lower level driver defers and returns STATUS_PENDING, but that is normal.
I’m afraid I don’t understand what you mean by queuing the URB. I, in effect, queue the data and build the URB on demand. But I think I have missed your point.
What does trigger the sending of the request?
You mean what does actually cause the text to be sent and completion routine for stage #1 to actually happen? So far I have found two things that kick it off:
a) Executing the synchronous control transaction that gets back 8 bytes of status I mentioned abobe.
b) More work since my last post has revealed that, when everything is jammed up, if I use the debugger to send a 1-byte text packet back on a separate interrupt IN pipe (as I think I mentioned an Irp to read from this pipe is amost always running), the debugger shows first the char packet arriving, then another Irp for the text IN pipe being queued, and then the character send completion routine happening & the text data arriving in the device. So it looks as if submitting an Irp will shake things loose in the same way as a control transaction.
Fascinating. I’ve never seen this. I could imagine that the pipe was being stalled,
but you should get back an error in the previous URB.
Me neither. The endpoint is not being stalled, at least as far as the hardware in the device is concerned.
And Randy Aull:
Have you use a bus analyzer to see what is going on over the wire? How are you confirming
that there are no outs?
I am embarrassed to admit that my boss has not forked-out for an analyser so I am doing all this the hard way. However running a JTAG debugger on the device I am able to break into the code when things have jammed, and I can then inspect the registers in the 2272 chip. This shows that no OUT tokens have been received on the relevant endpoint since the last transaction was completed (the finish off code clears a status bit for OUT token RX). So I am pretty certain that there is no attempt being made to transmit the text data to the devi8ce.
Is it possible that the endpoint is halted (did the previous transfer succeed)?
The previous transfer succeeded, the chip in the device does not show a stall condition and none of the various things that cause the transmit to wake up do anything to clear a stall/halt on the text OUT pipe. So I am assuming that no halt has happened. Is there an IOCTL that I could submit to the lower level driver to interrogate the status of a pipe and its associated queue? I have looked for such a thing without success but I could easily arrange for this to be done as part of my debug code that I can execute once things jam up.
Is there a DATA toggle mismatch?
You’ve got me here - I don’t know. Doesn’t that only apply to ISO pipes? There is an endpoint toggle bit in the 2272 registers that I can see in this situation, but I have no idea how to find out what value it should be matched-to. But if you point me at the right IOCTL I can find out.
I await further suggestions with interest. I am fairly sure that, with a bit of devious coding, I could cause the remote device (or maybe the driver) to issue something that would cause a wakeup if everything has gone quiet for a while, but I would much rather sort out the basic problem and not do that.