// Read/Write request processors for AIO16 driver #include "stddcls.h" #include "driver.h" #include "IOTechs.inc" /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE NTSTATUS DispatchCreate(PDEVICE_OBJECT fdo, PIRP Irp) { // DispatchCreate PAGED_CODE(); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // Claim the remove lock in Win2K so that removal waits until the // handle closes. Don't do this in Win98, however, because this // device might be removed by surprise with handles open, whereupon // we'll deadlock in HandleRemoveDevice waiting for a close that // can never happen because we can't run the user-mode code that // would do the close. NTSTATUS status; if (win98) status = STATUS_SUCCESS; else status = IoAcquireRemoveLock(&pdx->RemoveLock, stack->FileObject); if (NT_SUCCESS(status)) { // okay to open if (InterlockedIncrement(&pdx->handles) == 1) { // first open handle } // okay to open } // first open handle return CompleteRequest(Irp, status, 0); } // DispatchCreate /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE NTSTATUS DispatchClose(PDEVICE_OBJECT fdo, PIRP Irp) { // DispatchClose PAGED_CODE(); PDEVICE_EXTENSION pDX = (PDEVICE_EXTENSION) fdo->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); if (InterlockedDecrement(&pDX->handles) == 0) { // no more open handles ULONG OldAcq; PIRP OldAcqIRP, OldReadIRP; InterlockedExchange(PLONG(&(pDX->DataLength)), NULL); OldAcq = InterlockedExchange(PLONG(&(pDX->AcquiredData)), NULL); OldAcqIRP = PIRP(InterlockedExchange(PLONG(&(pDX->PendingAcqIRP)), NULL)); OldReadIRP = PIRP(InterlockedExchange(PLONG(&(pDX->PendingReadIRP)), NULL)); if ( OldAcq || OldAcqIRP ) DisableCTRAcq(pDX->Base); if ( OldAcqIRP ) { PIRP OtherAcqIRP = OldAcqIRP; OldAcqIRP->IoStatus.Status = STATUS_CANCELLED; OldAcqIRP->IoStatus.Information = 0; UncacheControlRequest(pDX, &OtherAcqIRP); IoSetCancelRoutine(OldAcqIRP, NULL); IoCompleteRequest(OldAcqIRP, IO_NO_INCREMENT); } if ( OldReadIRP ) { PIRP OtherReadIRP = OldReadIRP; OldReadIRP->IoStatus.Status = STATUS_CANCELLED; OldReadIRP->IoStatus.Information = 0; UncacheControlRequest(pDX, &OtherReadIRP); IoSetCancelRoutine(OldReadIRP, NULL); IoCompleteRequest(OldReadIRP, IO_NO_INCREMENT); } } // no more open handles // Release the remove lock to match the acquisition done in DispatchCreate if (!win98) IoReleaseRemoveLock(&pDX->RemoveLock, stack->FileObject); return CompleteRequest(Irp, STATUS_SUCCESS, 0); } // DispatchClose /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE void GetSamples(PDEVICE_EXTENSION pDX, TRATIONAL *pRat, ULONG Ct) { ULONG Buf; for (ULONG I = 0; I < Ct; ++I) { Buf = 0; for (ULONG J = 0; J < pDX->MultiCt; ++J) Buf += InPort(pDX->Base + 0x00); pRat->Numerator = USHORT(Buf >> pDX->MultiMode); //Denominator is not set because it's global ++pRat; } } /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pDX) { // OnInterrupt if ( (InPortB(pDX->Base + 0x0C) & 0x10) == 0 ) return FALSE; USHORT MultiBuffer[16]; //TRATIONAL *AcquiredData = PRATIONAL(InterlockedExchange(PLONG(&pDX->AcquiredData), NULL)); TRATIONAL *AcquiredData = pDX->AcquiredData; if ( AcquiredData && pDX->DataNext < pDX->DataLength ) { //Handle FIFO full once we get a FIFO full bit if ( pDX->DataNext + pDX->SuckAmt >= pDX->DataLength ) { GetSamples(pDX, (AcquiredData + pDX->DataNext), pDX->DataLength - pDX->DataNext); pDX->DataNext = pDX->DataLength; CtrMode(pDX->Base, 2, 2); IoRequestDpc(pDX->DeviceObject, NULL, pDX); } else { GetSamples(pDX, (AcquiredData + pDX->DataNext), pDX->SuckAmt); pDX->DataNext += pDX->SuckAmt; if ( (pDX->PendingReadIRP && pDX->DataNext >= pDX->ReadLast + pDX->ReadReq) || (pDX->DataNext >= pDX->DataLength) ) IoRequestDpc(pDX->DeviceObject, NULL, pDX) ; } } else ClearFIFO(pDX->Base); OutPortB(pDX->Base + 0x0C, 0x10); return TRUE; } // OnInterrupt /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE void CompletePendingRequest(PIRP *PendingIRP) { (**PendingIRP).IoStatus.Status = STATUS_SUCCESS; IoSetCancelRoutine(*PendingIRP, NULL); IoCompleteRequest(*PendingIRP, IO_SOUND_INCREMENT); *PendingIRP = NULL; } /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pDX) { // DpcForIsr PIRP IRPCopy; KeAcquireSpinLockAtDpcLevel(&pDX->AcqBufferLock); BOOLEAN AcquireComplete = pDX->AcquiredData && pDX->DataNext >= pDX->DataLength; if ( AcquireComplete ) { DisableCTRAcq(pDX->Base); } KeReleaseSpinLockFromDpcLevel(&pDX->AcqBufferLock); KeAcquireSpinLockAtDpcLevel(&pDX->ReadLock); ULONG DataNext = pDX->DataNext; ULONG ReadLast = pDX->ReadLast; if ( pDX->PendingReadIRP && (AcquireComplete || (DataNext - ReadLast) >= pDX->ReadReq) ) { pDX->ReadLast = DataNext; PAIO16NT_BUFFER pIOBuffer = (PAIO16NT_BUFFER)pDX->PendingReadIRP->AssociatedIrp.SystemBuffer; pIOBuffer->Addr = ReadLast; pIOBuffer->Data = pDX->GainFactor.Calculated; pIOBuffer->ExData = DataNext; IRPCopy = pDX->PendingReadIRP; UncacheControlRequest(pDX, &IRPCopy); CompletePendingRequest(&pDX->PendingReadIRP); KeReleaseSpinLockFromDpcLevel(&pDX->ReadLock); if ( AcquireComplete ) { KeAcquireSpinLockAtDpcLevel(&pDX->AcqBufferLock); if ( pDX->PendingAcqIRP ) { IRPCopy = pDX->PendingAcqIRP; UncacheControlRequest(pDX, &IRPCopy); CompletePendingRequest(&pDX->PendingAcqIRP); } pDX->DataLength = 0; pDX->AcquiredData = 0; KeReleaseSpinLockFromDpcLevel(&pDX->AcqBufferLock); } } else KeReleaseSpinLockFromDpcLevel(&pDX->ReadLock); } // DpcForIsr /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated) { // StartDevice PDEVICE_EXTENSION pDX = (PDEVICE_EXTENSION) fdo->DeviceExtension; NTSTATUS status; // Identify the I/O resources we're supposed to use. ULONG vector; KIRQL irql; KINTERRUPT_MODE mode; KAFFINITY affinity; BOOLEAN irqshare; BOOLEAN gotinterrupt = FALSE; PHYSICAL_ADDRESS portbase; BOOLEAN gotport = FALSE; if (!translated) return STATUS_DEVICE_CONFIGURATION_ERROR; // no resources assigned?? PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = translated->PartialDescriptors; ULONG nres = translated->Count; for (ULONG i = 0; i < nres; ++i, ++resource) { // for each resource switch (resource->Type) { // switch on resource type case CmResourceTypePort: portbase = resource->u.Port.Start; pDX->nports = resource->u.Port.Length; pDX->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0; gotport = TRUE; break; case CmResourceTypeInterrupt: irql = (KIRQL) resource->u.Interrupt.Level; vector = resource->u.Interrupt.Vector; affinity = resource->u.Interrupt.Affinity; mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; irqshare = resource->ShareDisposition == CmResourceShareShared; gotinterrupt = TRUE; break; default: KdPrint((DRIVERNAME " - Unexpected I/O resource type %d\n", resource->Type)); break; } // switch on resource type } // for each resource // Verify that we got all the resources we were expecting if (!(TRUE && gotinterrupt && gotport )) { KdPrint((DRIVERNAME " - Didn't get expected I/O resources\n")); return STATUS_DEVICE_CONFIGURATION_ERROR; } if (pDX->mappedport) { // map port address for RISC platform pDX->portbase = (PUCHAR) MmMapIoSpace(portbase, pDX->nports, MmNonCached); if (!pDX->mappedport) { KdPrint((DRIVERNAME " - Unable to map port range %I64X, length %X\n", portbase, pDX->nports)); return STATUS_INSUFFICIENT_RESOURCES; } } // map port address for RISC platform else pDX->portbase = (PUCHAR) portbase.QuadPart; pDX->Base = (USHORT)pDX->portbase; // TODO Temporarily prevent device from interrupt if that's possible. // Enable device for interrupts when IoConnectInterrupt returns status = IoConnectInterrupt(&pDX->InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt, (PVOID) pDX, NULL, vector, irql, irql, mode, irqshare, affinity, FALSE); if (!NT_SUCCESS(status)) { KdPrint((DRIVERNAME " - IoConnectInterrupt failed - %X\n", status)); if (pDX->portbase && pDX->mappedport) MmUnmapIoSpace(pDX->portbase, pDX->nports); pDX->portbase = NULL; return status; } return STATUS_SUCCESS; } // StartDevice /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE VOID StopDevice(IN PDEVICE_OBJECT fdo, BOOLEAN oktouch /* = FALSE */) { // StopDevice PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; AbortPendingIoctls(pdx, STATUS_CANCELLED); if (pdx->InterruptObject) { // disconnect interrupt // TODO prevent device from generating more interrupts if possible IoDisconnectInterrupt(pdx->InterruptObject); pdx->InterruptObject = NULL; } // disconnect interrupt if (pdx->portbase && pdx->mappedport) MmUnmapIoSpace(pdx->portbase, pdx->nports); pdx->portbase = NULL; } // StopDevice