// Control.cpp -- IOCTL handlers for AIO16 driver #include "stddcls.h" #include "driver.h" #include "ioctls.h" #include "IOTechs.inc" NTSTATUS CacheControlRequest(PDEVICE_EXTENSION pdx, KSPIN_LOCK *Lock, PIRP Irp, PIRP* pIrp); VOID OnCancelPendingIoctl(PDEVICE_OBJECT fdo, PIRP Irp); NTSTATUS OnCompletePendingIoctl(PDEVICE_OBJECT junk, PIRP Irp, PDEVICE_EXTENSION pdx); NTSTATUS AIO16NT_EEPROM_Read(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_EEPROM_Write(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_EEPROM_Enable(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_EEPROM_Disable(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_ADC_Acquire(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer, PRATIONAL pDataBuffer); NTSTATUS AIO16NT_ADC_Stop(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_ADC_Read(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_DAC_Write(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_ADC_Cal(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_DAC_Cal(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_Init(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); NTSTATUS AIO16NT_GetSettings(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer); /////////////////////////////////////////////////////////////////////////////// #define AIO16NT_PACKETCHECK \ if ( InBufferSize < sizeof(AIO16NT_BUFFER) || OutBufferSize < sizeof(AIO16NT_BUFFER) ) {\ Info = 0; Status = STATUS_INVALID_PARAMETER; break; } //Don't return anything if check fails #pragma PAGEDCODE NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp) { // DispatchControl PDEVICE_EXTENSION pDX = (PDEVICE_EXTENSION) fdo->DeviceExtension; NTSTATUS Status = IoAcquireRemoveLock(&pDX->RemoveLock, Irp); if (!NT_SUCCESS(Status)) return CompleteRequest(Irp, Status, 0); ULONG Info = 0; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG InBufferSize = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG OutBufferSize = stack->Parameters.DeviceIoControl.OutputBufferLength; ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; PAIO16NT_BUFFER pIOBuffer = (PAIO16NT_BUFFER)Irp->AssociatedIrp.SystemBuffer; PVOID pDataBuffer; Irp->IoStatus.Information = Info = sizeof(AIO16NT_BUFFER); //Return a similar buffer packet unless overridden switch (code) { // process request case IOCTL_EEPROM_READ: AIO16NT_PACKETCHECK; Status = AIO16NT_EEPROM_Read(pDX, pIOBuffer); break; case IOCTL_EEPROM_WRITE: AIO16NT_PACKETCHECK; Status = AIO16NT_EEPROM_Write(pDX, pIOBuffer); break; case IOCTL_EEPROM_ENABLE: AIO16NT_PACKETCHECK; Status = AIO16NT_EEPROM_Enable(pDX, pIOBuffer); break; case IOCTL_EEPROM_DISABLE: AIO16NT_PACKETCHECK; Status = AIO16NT_EEPROM_Disable(pDX, pIOBuffer); break; case IOCTL_ADC_ACQUIRE: if ( pDX->AcquiredData ) { Info = 0; Status = STATUS_DEVICE_BUSY; } else if ( pIOBuffer->ExData > 0x1F80000 ) { Info = 0; Status = STATUS_INVALID_BUFFER_SIZE; } else { Irp->IoStatus.Information = OutBufferSize; //if ( win98 ) pDataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress); //else // pDataBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) ; if (pDataBuffer) { Status = AIO16NT_ADC_Acquire(pDX, pIOBuffer, PRATIONAL(pDataBuffer)); if ( Status == STATUS_PENDING ) { Status = CacheControlRequest(pDX, &pDX->AcqBufferLock, Irp, &(pDX->PendingAcqIRP)); } } else Status = STATUS_UNSUCCESSFUL ; } break; case IOCTL_ADC_STOP: AIO16NT_PACKETCHECK; Status = AIO16NT_ADC_Stop(pDX, pIOBuffer); break; case IOCTL_ADC_READ: AIO16NT_PACKETCHECK; if ( pDX->AcquiredData == NULL ) Status = STATUS_END_OF_MEDIA; else if ( pDX->PendingReadIRP ) Status = STATUS_DEVICE_BUSY; else { Status = AIO16NT_ADC_Read(pDX, pIOBuffer); if ( Status == STATUS_PENDING ) Status = CacheControlRequest(pDX, &pDX->ReadLock, Irp, &pDX->PendingReadIRP) ; } break; case IOCTL_DAC_WRITE: AIO16NT_PACKETCHECK; Status = AIO16NT_DAC_Write(pDX, pIOBuffer); break; case IOCTL_ADC_CAL: AIO16NT_PACKETCHECK; Status = AIO16NT_ADC_Cal(pDX, pIOBuffer); break; case IOCTL_DAC_CAL: AIO16NT_PACKETCHECK; Status = AIO16NT_DAC_Cal(pDX, pIOBuffer); break; case IOCTL_INIT: AIO16NT_PACKETCHECK; Status = AIO16NT_Init(pDX, pIOBuffer); break; case IOCTL_GETSETTINGS: AIO16NT_PACKETCHECK; Status = AIO16NT_GetSettings(pDX, pIOBuffer); break; default: Info = 0; Status = STATUS_INVALID_DEVICE_REQUEST; break; } // process request IoReleaseRemoveLock(&pDX->RemoveLock, Irp); if ( Status != STATUS_PENDING ) Status = CompleteRequest(Irp, Status, Info) ; return Status; } // DispatchControl PAIO16NT_BUFFER PseudoIOCTL(PIOCTLInternalHandler Func, PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer, ULONG Addr, ULONG Data, ULONG ExData) { pIOBuffer->Addr = Addr; pIOBuffer->Data = Data; pIOBuffer->ExData = ExData; Func(pDX, pIOBuffer); return pIOBuffer; } NTSTATUS AIO16NT_EEPROM_Read(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Result = 0, Base; UCHAR Addr; Addr = (UCHAR)pIOBuffer->Addr; Base = pDX->Base; OutPortB(Base + 0x0A, 0x81); //Start Bit OutPortB(Base + 0x0A, 0x81); //Opcode Bit 0 (10=Read) OutPortB(Base + 0x0A, 0x01); //Opcode Bit 1 "" OutPortB(Base + 0x0A, sbitd(Addr, 5)); //a5 (Address to write to) OutPortB(Base + 0x0A, sbitd(Addr, 4)); //a4 OutPortB(Base + 0x0A, sbitd(Addr, 3)); //a3 OutPortB(Base + 0x0A, sbitd(Addr, 2)); //a2 OutPortB(Base + 0x0A, sbitd(Addr, 1)); //a1 OutPortB(Base + 0x0A, sbitd(Addr, 0)); //a0 #define GetBit Result = (Result << 1) | (InPortB(Base + 0x0A) & 0x80 ? 1 : 0) GetBit; //d15 GetBit; //d14 GetBit; //d13 GetBit; //d12 GetBit; //d11 GetBit; //d10 GetBit; //d9 GetBit; //d8 GetBit; //d7 GetBit; //d6 GetBit; //d5 GetBit; //d4 GetBit; //d3 GetBit; //d2 GetBit; //d1 GetBit; //d0 #undef GetBit OutPortB(Base + 0x0A, 0x00); //end com pIOBuffer->Data = Result; return STATUS_SUCCESS; } NTSTATUS AIO16NT_EEPROM_Write(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Base; UCHAR Addr; USHORT Data; Base = pDX->Base; Addr = (UCHAR)pIOBuffer->Addr; Data = (USHORT)pIOBuffer->Data; PseudoIOCTL(AIO16NT_EEPROM_Enable, pDX, pIOBuffer, 0, 0, 0); OutPortB(Base + 0x0A, 0x81);//Start Bit OutPortB(Base + 0x0A, 0x01);//Opcode Bit 0 (01=write) OutPortB(Base + 0x0A, 0x81);//Opcode Bit 1 "" OutPortB(Base + 0x0A, sbitd(Addr,5));//a5 (Address to write to) OutPortB(Base + 0x0A, sbitd(Addr,4));//a4 OutPortB(Base + 0x0A, sbitd(Addr,3));//a3 OutPortB(Base + 0x0A, sbitd(Addr,2));//a2 OutPortB(Base + 0x0A, sbitd(Addr,1));//a1 OutPortB(Base + 0x0A, sbitd(Addr,0));//a0 OutPortB(Base + 0x0A, sbitd(Data,15));//d15 OutPortB(Base + 0x0A, sbitd(Data,14));//d14 OutPortB(Base + 0x0A, sbitd(Data,13));//d13 OutPortB(Base + 0x0A, sbitd(Data,12));//d12 OutPortB(Base + 0x0A, sbitd(Data,11));//d11 OutPortB(Base + 0x0A, sbitd(Data,10));//d10 OutPortB(Base + 0x0A, sbitd(Data,9));//d9 OutPortB(Base + 0x0A, sbitd(Data,8));//d8 OutPortB(Base + 0x0A, sbitd(Data,7));//d7 OutPortB(Base + 0x0A, sbitd(Data,6));//d6 OutPortB(Base + 0x0A, sbitd(Data,5));//d5 OutPortB(Base + 0x0A, sbitd(Data,4));//d4 OutPortB(Base + 0x0A, sbitd(Data,3));//d3 OutPortB(Base + 0x0A, sbitd(Data,2));//d2 OutPortB(Base + 0x0A, sbitd(Data,1));//d1 OutPortB(Base + 0x0A, sbitd(Data,0));//d0 OutPortB(Base + 0x0A, 0x00);//end trans PseudoIOCTL(AIO16NT_EEPROM_Disable, pDX, pIOBuffer, 0, 0, 0); return STATUS_SUCCESS; } NTSTATUS AIO16NT_EEPROM_Enable(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Base = pDX->Base; OutPortB(Base + 0x0a, 0x81);//start bit OutPortB(Base + 0x0a, 0x01);//Opcode bit 0 (00 = enable/disable) OutPortB(Base + 0x0a, 0x01);//Opcode bit 1 "" OutPortB(Base + 0x0a, 0x81);//a5 (must be 1 to enable) OutPortB(Base + 0x0a, 0x81);//a4 (must be 1 to enable) OutPortB(Base + 0x0a, 0x01);//a3 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a2 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a1 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a0 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x00);//end trans return STATUS_SUCCESS; } NTSTATUS AIO16NT_EEPROM_Disable(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Base = pDX->Base; OutPortB(Base + 0x0a, 0x81);//start bit OutPortB(Base + 0x0a, 0x01);//Opcode bit 0 (00 = enable/disable) OutPortB(Base + 0x0a, 0x01);//Opcode bit 1 "" OutPortB(Base + 0x0a, 0x01);//a5 (must be 0 to disable) OutPortB(Base + 0x0a, 0x01);//a4 (must be 0 to disable) OutPortB(Base + 0x0a, 0x01);//a3 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a2 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a1 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x01);//a0 (don't care because enable/disable) OutPortB(Base + 0x0a, 0x00);//end trans return STATUS_SUCCESS; } NTSTATUS AIO16NT_ADC_Acquire(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer, PRATIONAL pDataBuffer) { UCHAR Gain, Chans, MultiMode; USHORT GainBuf; USHORT CTRA, CTRB; ULONG Count; KIRQL OldIRQL; UCHAR GoByte; DisableCTRAcq(pDX->Base); //Stop card while setting up KeAcquireSpinLock(&pDX->AcqBufferLock, &OldIRQL); pDX->DataLength = 0; pDX->ReadLast = 0; pDX->AcquiredData = NULL; Gain = (UCHAR)pIOBuffer->Addr; Chans = (UCHAR)(pIOBuffer->Addr >> 8); MultiMode = (UCHAR)(pIOBuffer->Addr >> 16); CTRA = (USHORT)(pIOBuffer->Data >> 16); CTRB = (USHORT)pIOBuffer->Data; Count = (ULONG)pIOBuffer->ExData; if ( (pDX->Jumpers & jpADC16SE) == 0 && (Chans & 0x88) != 0 ) return STATUS_INVALID_PARAMETER; switch(MultiMode) { case 0: case 1: GoByte = 0x11; pDX->MultiMode = 0; break; case 2: GoByte = 0x91; pDX->MultiMode = 1; break; case 8: GoByte = 0x10; pDX->MultiMode = 3; break; case 16: GoByte = 0x90; pDX->MultiMode = 4; break; default: return STATUS_INVALID_PARAMETER; } pDX->SuckAmt = FIFOQUAR >> pDX->MultiMode; pDX->MultiCt = 1 << pDX->MultiMode; switch(Gain) { case 0: pDX->GainFactor.Base = 1; break; case 1: pDX->GainFactor.Base = 2; break; case 2: pDX->GainFactor.Base = 5; break; case 3: pDX->GainFactor.Base = 10; break; default: return STATUS_INVALID_PARAMETER; } if ( jpADC5V & pDX->Jumpers ) pDX->GainFactor.Base *= 2; pDX->GainFactor.Word4Mult = jpADCBip & pDX->Jumpers; pDX->DataNext = 0; pDX->DataLength = Count; pDX->AcquiredData = pDataBuffer; GainBuf = Gain * 0x5555; OutPort(pDX->Base + 0x04, GainBuf); OutPort(pDX->Base + 0x06, GainBuf); OutPortB(pDX->Base + 0x02, Chans); EnableCTRAcq(pDX->Base); CtrLoad(pDX->Base, 1, CTRA); CtrLoad(pDX->Base, 2, CTRB); OutPortB(pDX->Base + 0x1A, GoByte); KeReleaseSpinLock(&pDX->AcqBufferLock, OldIRQL); return STATUS_PENDING; } NTSTATUS AIO16NT_ADC_Stop(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { //pIOBuffer will be nil if called from Read KIRQL OldIRQL; ULONG OldAcq; PIRP OldAcqIRP, OldReadIRP; DisableCTRAcq(pDX->Base); KeAcquireSpinLock(&pDX->AcqBufferLock, &OldIRQL); KeAcquireSpinLockAtDpcLevel(&pDX->ReadLock); OldReadIRP = PIRP(InterlockedExchange(PLONG(&(pDX->PendingReadIRP)), NULL)); pDX->DataLength = 0; OldAcq = InterlockedExchange(PLONG(&(pDX->AcquiredData)), NULL); OldAcqIRP = PIRP(InterlockedExchange(PLONG(&(pDX->PendingAcqIRP)), NULL)); KeReleaseSpinLockFromDpcLevel(&pDX->ReadLock); KeReleaseSpinLock(&pDX->AcqBufferLock, OldIRQL); if ( OldAcq ) { 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); } return STATUS_SUCCESS; } NTSTATUS AIO16NT_ADC_Read(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { KIRQL OldIRQL; ULONG Result; ULONG MinResults = pIOBuffer->Addr; KeAcquireSpinLock(&pDX->ReadLock, &OldIRQL); ULONG DataNext = pDX->DataNext; ULONG ReadLast = pDX->ReadLast; ULONG DataLength = pDX->DataLength; if ( !MinResults || (DataNext - ReadLast) >= MinResults ) { Result = STATUS_SUCCESS; pDX->ReadLast = DataNext; pIOBuffer->Addr = ReadLast; pIOBuffer->Data = pDX->GainFactor.Calculated; pIOBuffer->ExData = DataNext; KeReleaseSpinLock(&pDX->ReadLock, OldIRQL); if ( DataNext >= DataLength ) { AIO16NT_ADC_Stop(pDX, NULL); } } else { Result = STATUS_PENDING; pDX->ReadReq = MinResults; KeReleaseSpinLock(&pDX->ReadLock, OldIRQL); } return Result; } NTSTATUS AIO16NT_DAC_Write(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { USHORT Count, RangeShift; ULONG Base, DACNum; Base = pDX->Base; DACNum = pIOBuffer->Addr; if ( DACNum > 1 ) return STATUS_INVALID_PARAMETER; RangeShift = pDX->Jumpers & (jpDAC5V >> DACNum) ? 0 : 1; Count = ((USHORT)pIOBuffer->Data >> RangeShift) & 0xFFF; OutPortB(Base + 8 + DACNum * 6, UCHAR(Count)); pIOBuffer->Data = Count << RangeShift; return STATUS_SUCCESS; } NTSTATUS AIO16NT_ADC_Cal(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Base; UCHAR B, M; Base = pDX->Base; M = (UCHAR)pIOBuffer->Data; B = (UCHAR)pIOBuffer->ExData; //write cal to A/D, offset first, then slope OutPortB(Base + 0x0B, 0x01); //a1 pot 00 is offset OutPortB(Base + 0x0B, 0x01); //a0 "" OutPortB(Base + 0x0B, sbitd(B, 7)); //data bit 7 of offset OutPortB(Base + 0x0B, sbitd(B, 6)); //data bit 6 of offset OutPortB(Base + 0x0B, sbitd(B, 5)); //data bit 5 of offset OutPortB(Base + 0x0B, sbitd(B, 4)); //data bit 4 of offset OutPortB(Base + 0x0B, sbitd(B, 3)); //data bit 3 of offset OutPortB(Base + 0x0B, sbitd(B, 2)); //data bit 2 of offset OutPortB(Base + 0x0B, sbitd(B, 1)); //data bit 1 of offset OutPortB(Base + 0x0B, sbitd(B, 0)); //data bit 0 of offset OutPortB(Base + 0x0B, 0x00); //end trans //write slope now OutPortB(Base + 0x0B, 0x01); //a1 pot 01 is slope of A/D OutPortB(Base + 0x0B, 0x81); //a0 pot 01 is slope of A/D OutPortB(Base + 0x0B, sbitd(M, 7)); //data bit 7 of slope OutPortB(Base + 0x0B, sbitd(M, 6)); //data bit 6 of slope OutPortB(Base + 0x0B, sbitd(M, 5)); //data bit 5 of slope OutPortB(Base + 0x0B, sbitd(M, 4)); //data bit 4 of slope OutPortB(Base + 0x0B, sbitd(M, 3)); //data bit 3 of slope OutPortB(Base + 0x0B, sbitd(M, 2)); //data bit 2 of slope OutPortB(Base + 0x0B, sbitd(M, 1)); //data bit 1 of slope OutPortB(Base + 0x0B, sbitd(M, 0)); //data bit 0 of slope OutPortB(Base + 0x0B, 0x00); //end trans return STATUS_SUCCESS; } NTSTATUS AIO16NT_DAC_Cal(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { ULONG Base; UCHAR DACNum, M; Base = pDX->Base; DACNum = (UCHAR)pIOBuffer->Addr; M = (UCHAR)pIOBuffer->Data; OutPortB(Base + 0x0B, 0x81); //a1 pot 10 is slope of DAC0 OutPortB(Base + 0x0B, sbitd(DACNum, 0)); //a0 pot 11 is slope of DAC1 OutPortB(Base + 0x0B, sbitd(M, 7)); //data bit 7 of slope OutPortB(Base + 0x0B, sbitd(M, 6)); //data bit 6 of slope OutPortB(Base + 0x0B, sbitd(M, 5)); //data bit 5 of slope OutPortB(Base + 0x0B, sbitd(M, 4)); //data bit 4 of slope OutPortB(Base + 0x0B, sbitd(M, 3)); //data bit 3 of slope OutPortB(Base + 0x0B, sbitd(M, 2)); //data bit 2 of slope OutPortB(Base + 0x0B, sbitd(M, 1)); //data bit 1 of slope OutPortB(Base + 0x0B, sbitd(M, 0)); //data bit 0 of slope OutPortB(Base + 0x0B, 0x00); //end trans return STATUS_SUCCESS; } NTSTATUS AIO16NT_GetSettings(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { pIOBuffer->Data = pDX->Jumpers; return STATUS_SUCCESS; } NTSTATUS AIO16NT_Init(PDEVICE_EXTENSION pDX, PAIO16NT_BUFFER pIOBuffer) { UCHAR ADRange; UCHAR AM, AB, DAM, DBM; pDX->Jumpers = InPortB(pDX->Base + 0x08); ADRange = pDX->Jumpers & 0x7; AB = (UCHAR)PseudoIOCTL(AIO16NT_EEPROM_Read, pDX, pIOBuffer, ADRange+0, 0, 0)->Data; //byte 0-7 in EEPROM holds "B" for ADC AM = (UCHAR)PseudoIOCTL(AIO16NT_EEPROM_Read, pDX, pIOBuffer, ADRange+8, 0, 0)->Data; //byte 8-f in EEPROM holds "M" for ADC DAM = (UCHAR)PseudoIOCTL(AIO16NT_EEPROM_Read, pDX, pIOBuffer, pDX->Jumpers & (jpDAC5V >> 0) ? 0x10 : 0x11, 0, 0)->Data; //byte 10h,11h in EEPROM holds "M" for DAC0 DBM = (UCHAR)PseudoIOCTL(AIO16NT_EEPROM_Read, pDX, pIOBuffer, pDX->Jumpers & (jpDAC5V >> 1) ? 0x12 : 0x13, 0, 0)->Data; //byte 12h,13h in EEPROM holds "M" for DAC1 PseudoIOCTL(AIO16NT_DAC_Cal, pDX, pIOBuffer, 0, DAM, 0); // Write the calibration value from EEPROM to CAL Pots PseudoIOCTL(AIO16NT_DAC_Cal, pDX, pIOBuffer, 1, DBM, 0); // " PseudoIOCTL(AIO16NT_ADC_Cal, pDX, pIOBuffer, 0, AM, AB); // " pIOBuffer->Addr = pDX->Base; pIOBuffer->Data = 0; return STATUS_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE VOID AbortPendingIoctls(PDEVICE_EXTENSION pdx, NTSTATUS status) { // AbortPendingIoctls PAGED_CODE(); InterlockedExchange(&pdx->IoctlAbortStatus, status); CleanupControlRequests(pdx, status, NULL); } // AbortPendingIoctls /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE NTSTATUS CacheControlRequest(PDEVICE_EXTENSION pdx, KSPIN_LOCK *Lock, PIRP Irp, PIRP *pIrp) { // CacheControlRequest ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KIRQL oldirql; KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql); NTSTATUS status; if (*pIrp) status = STATUS_UNSUCCESSFUL; // something already cached here else if (pdx->IoctlAbortStatus) status = pdx->IoctlAbortStatus; // rejecting new IRPs for some reason else { // try to cache IRP // Install a cancel routine and check for this IRP having already been // cancelled IoSetCancelRoutine(Irp, OnCancelPendingIoctl); if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) status = STATUS_CANCELLED; // already cancelled // Put this IRP on our list of pending IOCTLs. Install a completion // routine to nullify the cache pointer. Note that AddDevice would have // failed if there were no PDO below us, so we know there's at least // one free stack location here. else { // cache it IoMarkIrpPending(Irp); status = STATUS_PENDING; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); stack->Parameters.Others.Argument1 = (PVOID) pIrp; IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnCompletePendingIoctl, (PVOID) pdx, TRUE, TRUE, TRUE); IoSetNextIrpStackLocation(Irp); // so our completion routine will get called PFILE_OBJECT fop = stack->FileObject; stack = IoGetCurrentIrpStackLocation(Irp); stack->DeviceObject = pdx->DeviceObject; // so IoCancelIrp can give us right ptr stack->FileObject = fop; // for cleanup InsertTailList(&pdx->PendingIoctlList, &Irp->Tail.Overlay.ListEntry); *pIrp = Irp; } // cache it } // try to cache IRP KeReleaseSpinLock(&pdx->IoctlListLock, oldirql); return status; } // CacheControlRequest /////////////////////////////////////////////////////////////////////////////// #pragma PAGEDCODE VOID CleanupControlRequests(PDEVICE_EXTENSION pdx, NTSTATUS status, PFILE_OBJECT fop) { // CleanupControlRequests LIST_ENTRY cancellist; InitializeListHead(&cancellist); // Create a list of IRPs that belong to the same file object KIRQL oldirql; KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql); PLIST_ENTRY first = &pdx->PendingIoctlList; PLIST_ENTRY next; for (next = first->Flink; next != first; ) { // for each queued IRP PIRP Irp = CONTAINING_RECORD(next, IRP, Tail.Overlay.ListEntry); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // Follow the chain to the next IRP now (so that the next iteration of // the loop is properly setup whether we dequeue this IRP or not) PLIST_ENTRY current = next; next = next->Flink; // Skip this IRP if it's not for the same file object as the // current IRP_MJ_CLEANUP. if (fop && stack->FileObject != fop) continue; // not for same file object // Set the CancelRoutine pointer to NULL and remove the IRP from the // queue. if (!IoSetCancelRoutine(Irp, NULL)) continue; // being cancelled right this instant RemoveEntryList(current); InsertTailList(&cancellist, current); } // for each queued IRP // Release the spin lock. We're about to undertake a potentially time-consuming // operation that might conceivably result in a deadlock if we keep the lock. KeReleaseSpinLock(&pdx->IoctlListLock, oldirql); // Complete the selected requests. while (!IsListEmpty(&cancellist)) { // cancel selected requests next = RemoveHeadList(&cancellist); PIRP Irp = CONTAINING_RECORD(next, IRP, Tail.Overlay.ListEntry); Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } // cancel selected requests } // CleanupControlRequests /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE VOID OnCancelPendingIoctl(PDEVICE_OBJECT fdo, PIRP Irp) { // OnCancelPendingIoctl KIRQL oldirql = Irp->CancelIrql; IoReleaseCancelSpinLock(DISPATCH_LEVEL); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; // Remove the IRP from whatever queue it's on KeAcquireSpinLockAtDpcLevel(&pdx->IoctlListLock); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLockFromDpcLevel(&pdx->IoctlListLock); // Complete the IRP Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } // OnCancelPendingIoctl /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE NTSTATUS OnCompletePendingIoctl(PDEVICE_OBJECT junk, PIRP Irp, PDEVICE_EXTENSION pdx) { // OnCompletePendingIoctl KIRQL oldirql; KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql); PIRP* pIrp = (PIRP*) IoGetCurrentIrpStackLocation(Irp)->Parameters.Others.Argument1; if (*pIrp == Irp) *pIrp = NULL; KeReleaseSpinLock(&pdx->IoctlListLock, oldirql); return STATUS_SUCCESS; } // OnCompletePendingIoctl /////////////////////////////////////////////////////////////////////////////// #pragma LOCKEDCODE PIRP UncacheControlRequest(PDEVICE_EXTENSION pdx, PIRP* pIrp) { // UncacheControlRequest ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KIRQL oldirql; KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql); PIRP Irp = (PIRP) InterlockedExchangePointer(pIrp, NULL); if (Irp) { // an IRP was cached // Clear the cancel pointer for this IRP. Since both we and the // completion routine use a spin lock, it cannot happen that this // IRP pointer is suddenly invalid but the cache pointer cell // wasn't already NULL. if (IoSetCancelRoutine(Irp, NULL)) { RemoveEntryList(&Irp->Tail.Overlay.ListEntry); // N.B.: a macro!! } else Irp = NULL; // currently being cancelled } // an IRP was cached KeReleaseSpinLock(&pdx->IoctlListLock, oldirql); return Irp; } // UncacheControlRequest