Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

610 lines
14 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
core.c
Abstract:
We maintain two lists for Transfer Irps
(1)
PendingTransferIrps - transfers on the endpoint pending List
protected by PendingIrpLock
(2)
ActiveTransferIrps - transfers on the enpoint ACTIVE, CANCEL list
or on the MapTransfer List
protected by ActiveIrpLock
each list has its own cancel and completion routine
Environment:
kernel mode only
Notes:
Revision History:
6-20-99 : created
--*/
#include "common.h"
#ifdef ALLOC_PRAGMA
#endif
// non paged functions
// USBPORT_QueuePendingTransferIrp
// USBPORT_CancelPendingTransferIrp
// USBPORT_InsertIrpInTable
// USBPORT_RemoveIrpFromTable
// USBPORT_FindIrpInTable
VOID
USBPORT_InsertIrpInTable(
PDEVICE_OBJECT FdoDeviceObject,
PUSBPORT_IRP_TABLE IrpTable,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
PUSBPORT_IRP_TABLE t = IrpTable;
USBPORT_ASSERT(IrpTable != NULL);
t = (PUSBPORT_IRP_TABLE) &IrpTable;
do {
t = t->NextTable;
for (i = 0; i<IRP_TABLE_LENGTH; i++) {
if (t->Irps[i] == NULL) {
t->Irps[i] = Irp;
return;
}
}
} while (t->NextTable);
// no room, grow the table and recurse
ALLOC_POOL_Z(t->NextTable, NonPagedPool,
sizeof(USBPORT_IRP_TABLE));
if (t->NextTable != NULL) {
USBPORT_InsertIrpInTable(FdoDeviceObject, t->NextTable, Irp);
} else {
// we should handle this more gracefully
// you can hit this in a low resource scenario
BUGCHECK(USBBUGCODE_INTERNAL_ERROR, 0, 0, 0);
}
return;
}
PIRP
USBPORT_RemoveIrpFromTable(
PDEVICE_OBJECT FdoDeviceObject,
PUSBPORT_IRP_TABLE IrpTable,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
PUSBPORT_IRP_TABLE t = IrpTable;
USBPORT_ASSERT(IrpTable != NULL);
t = (PUSBPORT_IRP_TABLE) &IrpTable;
do {
t = t->NextTable;
for (i = 0; i<IRP_TABLE_LENGTH; i++) {
if (t->Irps[i] == Irp) {
t->Irps[i] = NULL;
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmIP', i, Irp, IrpTable);
return Irp;
}
}
} while (t->NextTable);
return NULL;
}
PIRP
USBPORT_FindUrbInIrpTable(
PDEVICE_OBJECT FdoDeviceObject,
PUSBPORT_IRP_TABLE IrpTable,
PTRANSFER_URB Urb,
PIRP InputIrp
)
/*++
Routine Description:
Given and table urb we scan for it in the the irp table
if we find it it means the client has submitted the same
urb twice.
This function is used to validate client drivers, there is
a small perf hit taken here but probably worth it.
Arguments:
Return Value:
--*/
{
ULONG i;
PUSBPORT_IRP_TABLE t = IrpTable;
PIRP tIrp = NULL;
PTRANSFER_URB urb;
PIO_STACK_LOCATION irpStack;
USBPORT_ASSERT(IrpTable != NULL);
t = (PUSBPORT_IRP_TABLE) &IrpTable;
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fndU', t, Urb, 0);
do {
t = t->NextTable;
for (i=0; i<IRP_TABLE_LENGTH; i++) {
tIrp = t->Irps[i];
if (tIrp != NULL) {
irpStack = IoGetCurrentIrpStackLocation(tIrp);
urb = irpStack->Parameters.Others.Argument1;
if (urb == Urb) {
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fkkX', tIrp, urb, InputIrp);
if (tIrp == InputIrp) {
// this is a double submit by the client driver, that
// is the irp is still pending
BUGCHECK(USBBUGCODE_DOUBLE_SUBMIT, (ULONG_PTR) tIrp,
(ULONG_PTR) urb, 0);
} else {
// this is the case where the URB is attached to
// another irp
BUGCHECK(USBBUGCODE_BAD_URB, (ULONG_PTR) tIrp, (ULONG_PTR) InputIrp,
(ULONG_PTR) urb);
}
}
}
}
} while (t->NextTable);
return tIrp;
}
PIRP
USBPORT_FindIrpInTable(
PDEVICE_OBJECT FdoDeviceObject,
PUSBPORT_IRP_TABLE IrpTable,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
PUSBPORT_IRP_TABLE t = IrpTable;
USBPORT_ASSERT(IrpTable != NULL);
t = (PUSBPORT_IRP_TABLE) &IrpTable;
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fIPT', t, Irp, 0);
do {
t = t->NextTable;
for (i = 0; i<IRP_TABLE_LENGTH; i++) {
if (t->Irps[i] == Irp) {
return Irp;
}
}
} while (t->NextTable);
return NULL;
}
VOID
USBPORT_QueuePendingTransferIrp(
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
None.
--*/
{
PHCD_TRANSFER_CONTEXT transfer;
PHCD_ENDPOINT endpoint;
KIRQL cancelIrql, irql;
PDEVICE_OBJECT fdoDeviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION devExt;
PTRANSFER_URB urb;
// on entry the urb is not cancelable ie
// no cancel routine
// extract the urb;
irpStack = IoGetCurrentIrpStackLocation(Irp);
urb = irpStack->Parameters.Others.Argument1;
ASSERT_TRANSFER_URB(urb);
transfer = urb->pd.HcdTransferContext;
endpoint = transfer->Endpoint;
fdoDeviceObject = endpoint->FdoDeviceObject;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'tIRP', transfer, endpoint, 0);
USBPORT_ASSERT(Irp == transfer->Irp);
USBPORT_ASSERT(Irp != NULL);
Irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
ACQUIRE_PENDING_IRP_LOCK(devExt, irql);
IoSetCancelRoutine(Irp, USBPORT_CancelPendingTransferIrp);
if (Irp->Cancel &&
IoSetCancelRoutine(Irp, NULL)) {
// irp was canceled and our cancel routine
// did not run
RELEASE_PENDING_IRP_LOCK(devExt, irql);
USBPORT_CompleteTransfer(urb,
USBD_STATUS_CANCELED);
} else {
// cancel routine is set
USBPORT_InsertPendingTransferIrp(fdoDeviceObject, Irp);
USBPORT_QueuePendingUrbToEndpoint(endpoint, urb);
RELEASE_PENDING_IRP_LOCK(devExt, irql);
}
}
VOID
USBPORT_CancelPendingTransferIrp(
PDEVICE_OBJECT PdoDeviceObject,
PIRP CancelIrp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PIRP irp;
PDEVICE_EXTENSION devExt, rhDevExt;
PHCD_TRANSFER_CONTEXT transfer;
PHCD_ENDPOINT endpoint;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT fdoDeviceObject;
KIRQL irql;
// release cancel spinlock
IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
ASSERT_PDOEXT(rhDevExt);
fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'canP', fdoDeviceObject, CancelIrp, 0);
ACQUIRE_PENDING_IRP_LOCK(devExt, irql);
irp = USBPORT_RemovePendingTransferIrp(fdoDeviceObject, CancelIrp);
if (irp) {
PTRANSFER_URB urb;
// found it
irpStack = IoGetCurrentIrpStackLocation(CancelIrp);
urb = irpStack->Parameters.Others.Argument1;
ASSERT_TRANSFER_URB(urb);
transfer = urb->pd.HcdTransferContext;
endpoint = transfer->Endpoint;
USBPORT_ASSERT(fdoDeviceObject == endpoint->FdoDeviceObject);
ACQUIRE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'Le10');
// remove request from the endpoint,
// it will be on the pending list
#if DBG
USBPORT_ASSERT(
USBPORT_FindUrbInList(urb, &endpoint->PendingList));
#endif
RemoveEntryList(&transfer->TransferLink);
transfer->TransferLink.Flink = NULL;
transfer->TransferLink.Blink = NULL;
RELEASE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'Ue10');
}
RELEASE_PENDING_IRP_LOCK(devExt, irql);
// noone nows about this irp anymore
// complete it with status canceled
if (irp) {
USBPORT_CompleteTransfer(transfer->Urb,
USBD_STATUS_CANCELED);
}
}
VOID
USBPORT_CancelActiveTransferIrp(
PDEVICE_OBJECT PdoDeviceObject,
PIRP CancelIrp
)
/*++
Routine Description:
Cancels come in on the root hub Pdo
Arguments:
Return Value:
--*/
{
PIRP irp;
PDEVICE_EXTENSION devExt, rhDevExt;
PHCD_TRANSFER_CONTEXT transfer;
PHCD_ENDPOINT endpoint;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT fdoDeviceObject;
KIRQL irql;
GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
ASSERT_PDOEXT(rhDevExt);
fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'canA', fdoDeviceObject, CancelIrp, 0);
// when we have the fdo we can release the global cancel lock
IoReleaseCancelSpinLock(CancelIrp->CancelIrql);
ACQUIRE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
irp = USBPORT_FindActiveTransferIrp(fdoDeviceObject, CancelIrp);
// if irp is not on our list then we have already completed it.
if (irp) {
PTRANSFER_URB urb;
USBPORT_ASSERT(irp == CancelIrp);
LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'CANA', fdoDeviceObject, irp, 0);
// found it
// mark the transfer so it will be canceled the next
// time we process the endpoint.
irpStack = IoGetCurrentIrpStackLocation(irp);
urb = irpStack->Parameters.Others.Argument1;
ASSERT_TRANSFER_URB(urb);
transfer = urb->pd.HcdTransferContext;
endpoint = transfer->Endpoint;
USBPORT_ASSERT(fdoDeviceObject == endpoint->FdoDeviceObject);
ACQUIRE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'LeI0');
if (TEST_FLAG(transfer->Flags, USBPORT_TXFLAG_SPLIT)) {
KIRQL tIrql;
PLIST_ENTRY listEntry;
PHCD_TRANSFER_CONTEXT childTransfer;
SET_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED);
ACQUIRE_TRANSFER_LOCK(fdoDeviceObject, transfer, tIrql);
// mark all children as cancelled
GET_HEAD_LIST(transfer->SplitTransferList, listEntry);
while (listEntry &&
listEntry != &transfer->SplitTransferList) {
childTransfer = (PHCD_TRANSFER_CONTEXT) CONTAINING_RECORD(
listEntry,
struct _HCD_TRANSFER_CONTEXT,
SplitLink);
ASSERT_TRANSFER(childTransfer);
SET_FLAG(childTransfer->Flags, USBPORT_TXFLAG_CANCELED);
listEntry = childTransfer->SplitLink.Flink;
}
RELEASE_TRANSFER_LOCK(fdoDeviceObject, transfer, tIrql);
} else {
SET_FLAG(transfer->Flags, USBPORT_TXFLAG_CANCELED);
}
RELEASE_ENDPOINT_LOCK(endpoint, fdoDeviceObject, 'UeI0');
RELEASE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
// if we canceled a transfer then
// this endpoint needs attention
USBPORT_InvalidateEndpoint(fdoDeviceObject,
endpoint,
IEP_SIGNAL_WORKER);
} else {
RELEASE_ACTIVE_IRP_LOCK(fdoDeviceObject, devExt, irql);
}
}
PIRP
USBPORT_FindActiveTransferIrp(
PDEVICE_OBJECT FdoDeviceObject,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'fnAC', 0, Irp, 0);
return USBPORT_FindIrpInTable(FdoDeviceObject,
devExt->ActiveTransferIrpTable,
Irp);
}
PIRP
USBPORT_RemoveActiveTransferIrp(
PDEVICE_OBJECT FdoDeviceObject,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmAC', 0, Irp, 0);
return USBPORT_RemoveIrpFromTable(FdoDeviceObject,
devExt->ActiveTransferIrpTable,
Irp);
}
PIRP
USBPORT_RemovePendingTransferIrp(
PDEVICE_OBJECT FdoDeviceObject,
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'rmPN', 0, Irp, 0);
return USBPORT_RemoveIrpFromTable(FdoDeviceObject,
devExt->PendingTransferIrpTable,
Irp);
}
VOID
USBPORT_FreeIrpTable(
PDEVICE_OBJECT FdoDeviceObject,
PUSBPORT_IRP_TABLE BaseIrpTable
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PUSBPORT_IRP_TABLE tmp;
while (BaseIrpTable != NULL) {
tmp = BaseIrpTable->NextTable;
FREE_POOL(FdoDeviceObject, BaseIrpTable);
BaseIrpTable = tmp;
};
}