📄 usbios.c
字号:
}
}
}
#endif
if (Extension->CharsInInterruptBuffer <
Extension->BufferSize) {
*Extension->CurrentCharSlot = CharToPut;
Extension->CharsInInterruptBuffer++;
//
// If we've become 80% full on this character
// and this is an interesting event, note it.
//
if (Extension->CharsInInterruptBuffer ==
Extension->BufferSizePt8) {
// To remember not to submit the next read URB when back in
// read interrupt routine.
DbgPrint("80% full reached\n");
Extension->ToSubmitReadUrb = FALSE;
Extension->NoReadUrb = TRUE;
if (Extension->IsrWaitMask &
SERIAL_EV_RX80FULL) {
Extension->HistoryMask |= SERIAL_EV_RX80FULL;
if (Extension->IrpMaskLocation) {
*Extension->IrpMaskLocation =
Extension->HistoryMask;
Extension->IrpMaskLocation = NULL;
Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->
IoStatus.Information = sizeof(ULONG);
SerialInsertQueueDpc(
&Extension->CommWaitDpc,
NULL,
NULL,
Extension
);
}
}
}
//
// Point to the next available space
// for a received character. Make sure
// that we wrap around to the beginning
// of the buffer if this last character
// received was placed at the last slot
// in the buffer.
//
if (Extension->CurrentCharSlot ==
Extension->LastCharSlot) {
Extension->CurrentCharSlot =
Extension->InterruptReadBuffer;
} else {
Extension->CurrentCharSlot++;
}
} else {
//
// We have a new character but no room for it.
//
DbgPrint("Buffer Overflow\n");
Extension->PerfStats.BufferOverrunErrorCount++;
Extension->WmiPerfData.BufferOverrunErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
//
// Place the error character into the last
// valid place for a character. Be careful!,
// that place might not be the previous location!
//
if (Extension->CurrentCharSlot ==
Extension->InterruptReadBuffer) {
*(Extension->InterruptReadBuffer+
(Extension->BufferSize-1)) =
Extension->SpecialChars.ErrorChar;
} else {
*(Extension->CurrentCharSlot-1) =
Extension->SpecialChars.ErrorChar;
}
}
//
// If the application has requested it, abort all reads
// and writes on an error.
//
if (Extension->HandFlow.ControlHandShake &
SERIAL_ERROR_ABORT) {
SerialInsertQueueDpc(
&Extension->CommErrorDpc,
NULL,
NULL,
Extension
);
}
}
}
}
NTSTATUS
StartInterruptUrb(
PDEVICE_EXTENSION Extension
)
{ // StartInterruptUrb
// If the interrupt polling IRP is currently running, don't try to start
// it again.
USBD_PIPE_HANDLE PipeHandle;
BOOLEAN startirp;
KIRQL oldirql;
PIRP Irp;
PURB urb;
PIO_STACK_LOCATION stack;
// KeAcquireSpinLock(&Extension->polllock, &oldirql);
if (Extension->pollpending)
startirp = FALSE;
else
startirp = TRUE, Extension->pollpending = TRUE;
// KeReleaseSpinLock(&Extension->polllock, oldirql);
if (!startirp)
return STATUS_DEVICE_BUSY; // already pending
Irp = Extension->PollingIrp;
urb = Extension->PollingUrb;
PipeHandle = Extension->UsbInterface->Pipes[Extension->InterruptPipe].PipeHandle;
ASSERT(Irp && urb);
// Acquire the remove lock so we can't remove the device while the IRP
// is still active.
/*henry
NTSTATUS status = IoAcquireRemoveLock(&Extension->RemoveLock, Irp);
if (!NT_SUCCESS(status))
{
Extension->pollpending = 0;
return status;
}
*/
// Initialize the URB we use for reading the interrupt pipe
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER),
PipeHandle,
&Extension->intdata,
NULL,
4,
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
NULL);
// Install "OnInterrupt" as the completion routine for the polling IRP.
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE) OnInterrupt,
Extension,
TRUE,
TRUE,
TRUE);
// Initialize the IRP for an internal control request
stack = IoGetNextIrpStackLocation(Irp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
stack->Parameters.Others.Argument1 = urb;
// This IRP might have been cancelled the last time it was used, in which case
// the cancel flag will still be on. Clear it to prevent USBD from thinking that it's
// been cancelled again! A better way to do this would be to call IoReuseIrp,
// but that function is not declared in WDM.H.
Irp->Cancel = FALSE;
// UsbCom_IncrementIoCount(Extension->DeviceObject); //henry
return IoCallDriver(Extension->TopOfStackDeviceObject, Irp);
} // StartInterruptUrb
NTSTATUS
OnInterrupt(
PDEVICE_OBJECT junk,
PIRP Irp,
PDEVICE_EXTENSION Extension
)
{ // OnInterrupt
KIRQL oldirql;
// KeAcquireSpinLock(&Extension->polllock, &oldirql);
Extension->pollpending = FALSE; // allow another poll to be started
// PVOID powercontext = Extension->powercontext;
// Extension->powercontext = NULL;
// KeReleaseSpinLock(&Extension->polllock, oldirql);
// If the poll completed successfully, do whatever it is we do when we
// get an interrupt (in this sample, that's answering an IOCTL) and
// reissue the read. We're trying to have a read outstanding on the
// interrupt pipe all the time except when power is off.
if (NT_SUCCESS(Irp->IoStatus.Status)) { // device signalled an interrupt
DbgPrint(" - Interrupt!\n");
DbgPrint("Byte 1 = 0x%x\n", Extension->intdata[0]);
DbgPrint("Byte 2 = 0x%x\n", Extension->intdata[1]);
DbgPrint("Byte 3 = 0x%x\n", Extension->intdata[2]);
DbgPrint("Byte 4 = 0x%x\n", Extension->intdata[3]);
if (Extension->DeviceIsOpened == TRUE && // Ensure that device is opened.
(Extension->intdata[2] == 0x60)) {
SerialHandleModemUpdate(
Extension,
FALSE
);
}
DbgPrint("Submitting the next interrupt URB\n");
// Unless we're in the middle of a power-off sequence, reissue the
// polling IRP. Normally, SaveContext would have tried to cancel the
// IRP, and we won't get to this statement because STATUS_CANCELLED
// will fail the NT_SUCCESS test. We don't have any guarantee that the
// IRP will actually complete with STATUS_CANCELLED, though. Hence this test.
// if (!powercontext)
StartInterruptUrb(Extension); // issue next polling request
} // device signalled an interrupt
#if DBG
else {
DbgPrint(" - Interrupt polling IRP %X failed - %X (USBD status %X)\n",
Irp, Irp->IoStatus.Status, URB_STATUS(Extension->PollingUrb));
}
#endif
// UsbCom_DecrementIoCount(Extension->DeviceObject); //henry
// If we cancelled the poll during a power-down sequence, notify our
// power management code that it can continue.
/*
if (powercontext)
GenericSaveRestoreComplete(powercontext);
IoReleaseRemoveLock(&Extension->RemoveLock, Irp); // balances acquisition in StartInterruptUrb
*/
return STATUS_MORE_PROCESSING_REQUIRED;
} // OnInterrupt
NTSTATUS
StartReadUrb(
PDEVICE_EXTENSION Extension
)
{ // StartInterruptUrb
// If the interrupt polling IRP is currently running, don't try to start
// it again.
USBD_PIPE_HANDLE PipeHandle;
BOOLEAN startirp;
KIRQL oldirql;
PIRP Irp;
PURB urb;
PIO_STACK_LOCATION stack;
// KeAcquireSpinLock(&Extension->polllock, &oldirql);
if (Extension->readpending)
startirp = FALSE;
else
startirp = TRUE, Extension->readpending = TRUE;
// KeReleaseSpinLock(&Extension->polllock, oldirql);
if (!startirp)
return STATUS_DEVICE_BUSY; // already pending
Irp = Extension->ReadingIrp;
urb = Extension->ReadingUrb;
PipeHandle = Extension->UsbInterface->Pipes[Extension->DataInPipe].PipeHandle;
ASSERT(Irp && urb);
// Acquire the remove lock so we can't remove the device while the IRP
// is still active.
/*henry
NTSTATUS status = IoAcquireRemoveLock(&Extension->RemoveLock, Irp);
if (!NT_SUCCESS(status))
{
Extension->pollpending = 0;
return status;
}
*/
// Initialize the URB we use for reading the interrupt pipe
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER),
PipeHandle,
&Extension->ReadData,
NULL,
64,
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
NULL);
// Install "OnInterrupt" as the completion routine for the polling IRP.
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE) OnReadInterrupt,
Extension,
TRUE,
TRUE,
TRUE);
// Initialize the IRP for an internal control request
stack = IoGetNextIrpStackLocation(Irp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
stack->Parameters.Others.Argument1 = urb;
// This IRP might have been cancelled the last time it was used, in which case
// the cancel flag will still be on. Clear it to prevent USBD from thinking that it's
// been cancelled again! A better way to do this would be to call IoReuseIrp,
// but that function is not declared in WDM.H.
Irp->Cancel = FALSE;
// UsbCom_IncrementIoCount(Extension->DeviceObject); //henry
return IoCallDriver(Extension->TopOfStackDeviceObject, Irp);
} // StartInterruptUrb
NTSTATUS
OnReadInterrupt(
PDEVICE_OBJECT junk,
PIRP Irp,
PDEVICE_EXTENSION Extension
)
{ // OnInterrupt
PURB Urb;
KIRQL oldirql;
// KeAcquireSpinLock(&Extension->polllock, &oldirql);
Extension->readpending = FALSE; // allow another read to be started
// PVOID powercontext = Extension->powercontext;
// Extension->powercontext = NULL;
// KeReleaseSpinLock(&Extension->polllock, oldirql);
// If the poll completed successfully, do whatever it is we do when we
// get an interrupt (in this sample, that's answering an IOCTL) and
// reissue the read. We're trying to have a read outstanding on the
// interrupt pipe all the time except when power is off.
Urb = Extension->ReadingUrb;
DbgPrint("ReadInterrupt_Routine: DO=%08x Irp=%08x TransferLength=%d, Urb Status=%x, Irp Status = %x\n",
Extension->DeviceObject,
Irp,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
Urb->UrbHeader.Status,
Irp->IoStatus.Status);
if (NT_SUCCESS(Irp->IoStatus.Status)) { // device signalled an interrupt
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength &&
(Extension->DeviceIsOpened == TRUE)) { // Ensure that device is opened.
KeAcquireSpinLock(
&Extension->IntBufferLock,
&oldirql
);
TransferData(Extension, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
KeReleaseSpinLock(
&Extension->IntBufferLock,
oldirql
);
}
// Unless we're in the middle of a power-off sequence, reissue the
// polling IRP. Normally, SaveContext would have tried to cancel the
// IRP, and we won't get to this statement because STATUS_CANCELLED
// will fail the NT_SUCCESS test. We don't have any guarantee that the
// IRP will actually complete with STATUS_CANCELLED, though. Hence this test.
// if (!powercontext)
if (Extension->ToSubmitReadUrb) {
//DbgPrint("Submitting the next read URB\n");
StartReadUrb(Extension); // issue next polling request
}
} // device signalled an interrupt
#if DBG
else {
DbgPrint(" - Read polling IRP %X failed - %X (USBD status %X)\n",
Irp, Irp->IoStatus.Status, URB_STATUS(Extension->ReadingUrb));
}
#endif
// UsbCom_DecrementIoCount(Extension->DeviceObject); //henry
// If we cancelled the poll during a power-down sequence, notify our
// power management code that it can continue.
/*
if (powercontext)
GenericSaveRestoreComplete(powercontext);
IoReleaseRemoveLock(&Extension->RemoveLock, Irp); // balances acquisition in StartInterruptUrb
*/
return STATUS_MORE_PROCESSING_REQUIRED;
} // OnInterrupt
NTSTATUS
StartWriteUrb(
PDEVICE_EXTENSION Extension
)
{ // StartInterruptUrb
// If the interrupt polling IRP is currently running, don't try to start
// it again.
USBD_PIPE_HANDLE PipeHandle;
BOOLEAN startirp;
KIRQL oldirql;
PIRP Irp;
PURB urb;
PIO_STACK_LOCATION stack;
// DbgPrint("Enter StartWriteUrb()\n");
// KeAcquireSpinLock(&Extension->polllock, &oldirql);
if (Extension->writepending)
startirp = FALSE;
else
startirp = TRUE, Extension->writepending = TRUE;
// KeReleaseSpinLock(&Extension->polllock, oldirql);
if (!startirp)
return STATUS_DEVICE_BUSY; // already pending
Irp = Extension->WritingIrp;
urb = Extension->WritingUrb;
PipeHandle = Extension->UsbInterface->Pipes[Extension->DataOutPipe].PipeHandle;
ASSERT(Irp && urb);
// Acquire the remove lock so we can't remove the device while the IRP
// is still active.
/*henry
NTSTATUS status = IoAcquireRemoveLock(&Extension->RemoveLock, Irp);
if (!NT_SUCCESS(status))
{
Extension->pollpending = 0;
return status;
}
*/
// Initialize the URB we use for reading the interrupt pipe
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER),
PipeHandle,
Extension->WriteCurrentChar,
NULL,
Extension->WriteSize,
USBD_TRANSFER_DIRECTION_OUT,
NULL);
// Install "OnInterrupt" as the completion routine for the polling IRP.
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE) OnWriteInterrupt,
Extension,
TRUE,
TRUE,
TRUE);
// Initialize the IRP for an internal control request
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -