/*------------------------------------------------------------------- | utils.c - This module contains code that perform queueing and completion manipulation on requests. 1-21-99 fix tick count [#] on peer traces. kpb. 11-24-98 Minor adjustment to purge to when WaitOnTx selected. kpb. 6-01-98 Add modem reset/row routines (generic for VS and Rkt) 3-18-98 Add time_stall function for modem settle time after reset clear - jl 3-04-98 Add synch. routine back in to synch up to isr service routine. kpb. 7-10-97 Adjust SerialPurgeTxBuffers to not purge tx-hardware buffer as per MS driver. Now we only purge it if it is flowed-off. Copyright 1993-98 Comtrol Corporation. All rights reserved. |--------------------------------------------------------------------*/ #include "precomp.h" //-- local funcs BOOLEAN SerialPurgeRxBuffers(IN PVOID Context); BOOLEAN SerialPurgeTxBuffers(IN PVOID Context, int always); NTSTATUS SerialStartFlush(IN PSERIAL_DEVICE_EXTENSION Extension); static char *szParameters = {"\\Parameters"}; /*---------------------------------------------------------------------------- SyncUp - sync up to either the IRQ or Timer-DPC. If an Interrupt is used, then we must use KeSynchronizeExecution(), if a timer-dpc is used then we |----------------------------------------------------------------------------*/ VOID SyncUp(IN PKINTERRUPT IntObj, IN PKSPIN_LOCK SpinLock, IN PKSYNCHRONIZE_ROUTINE SyncProc, IN PVOID Context) { KIRQL OldIrql; if (IntObj != NULL) { KeSynchronizeExecution(IntObj, SyncProc, Context); } else // assume spinlock, using timer { KeAcquireSpinLock(SpinLock, &OldIrql); SyncProc(Context); KeReleaseSpinLock(SpinLock, OldIrql ); } } /*-------------------------------------------------------------------------- SerialKillAllReadsOrWrites - This function is used to cancel all queued and the current irps for reads or for writes. Arguments: DeviceObject - A pointer to the serial device object. QueueToClean - A pointer to the queue which we're going to clean out. CurrentOpIrp - Pointer to a pointer to the current irp. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialKillAllReadsOrWrites( IN PDEVICE_OBJECT DeviceObject, IN PLIST_ENTRY QueueToClean, IN PIRP *CurrentOpIrp ) { KIRQL cancelIrql; PDRIVER_CANCEL cancelRoutine; // We acquire the cancel spin lock. This will prevent the // irps from moving around. IoAcquireCancelSpinLock(&cancelIrql); // Clean the list from back to front. while (!IsListEmpty(QueueToClean)) { PIRP currentLastIrp = CONTAINING_RECORD( QueueToClean->Blink, IRP, Tail.Overlay.ListEntry ); RemoveEntryList(QueueToClean->Blink); cancelRoutine = currentLastIrp->CancelRoutine; currentLastIrp->CancelIrql = cancelIrql; currentLastIrp->CancelRoutine = NULL; currentLastIrp->Cancel = TRUE; cancelRoutine( DeviceObject, currentLastIrp ); IoAcquireCancelSpinLock(&cancelIrql); } // The queue is clean. Now go after the current if it's there. if (*CurrentOpIrp) { cancelRoutine = (*CurrentOpIrp)->CancelRoutine; (*CurrentOpIrp)->Cancel = TRUE; // If the current irp is not in a cancelable state // then it *will* try to enter one and the above // assignment will kill it. If it already is in // a cancelable state then the following will kill it. if (cancelRoutine) { (*CurrentOpIrp)->CancelRoutine = NULL; (*CurrentOpIrp)->CancelIrql = cancelIrql; // This irp is already in a cancelable state. We simply // mark it as canceled and call the cancel routine for it. cancelRoutine( DeviceObject, *CurrentOpIrp ); } else { IoReleaseCancelSpinLock(cancelIrql); } } else { IoReleaseCancelSpinLock(cancelIrql); } } /*-------------------------------------------------------------------------- SerialGetNextIrp - This function is used to make the head of the particular queue the current irp. It also completes the what was the old current irp if desired. Arguments: CurrentOpIrp - Pointer to a pointer to the currently active irp for the particular work list. Note that this item is not actually part of the list. QueueToProcess - The list to pull the new item off of. NextIrp - The next Irp to process. Note that CurrentOpIrp will be set to this value under protection of the cancel spin lock. However, if *NextIrp is NULL when this routine returns, it is not necessaryly true the what is pointed to by CurrentOpIrp will also be NULL. The reason for this is that if the queue is empty when we hold the cancel spin lock, a new irp may come in immediately after we release the lock. CompleteCurrent - If TRUE then this routine will complete the irp pointed to by the pointer argument CurrentOpIrp. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialGetNextIrp( IN PIRP *CurrentOpIrp, IN PLIST_ENTRY QueueToProcess, OUT PIRP *NextIrp, IN BOOLEAN CompleteCurrent, IN PSERIAL_DEVICE_EXTENSION extension ) { PIRP oldIrp; KIRQL oldIrql; IoAcquireCancelSpinLock(&oldIrql); oldIrp = *CurrentOpIrp; if (oldIrp) { if (CompleteCurrent) { MyAssert(!oldIrp->CancelRoutine); } } // Check to see if there is a new irp to start up. if (!IsListEmpty(QueueToProcess)) { PLIST_ENTRY headOfList; headOfList = RemoveHeadList(QueueToProcess); *CurrentOpIrp = CONTAINING_RECORD( headOfList, IRP, Tail.Overlay.ListEntry ); IoSetCancelRoutine( *CurrentOpIrp, NULL ); } else { *CurrentOpIrp = NULL; } *NextIrp = *CurrentOpIrp; IoReleaseCancelSpinLock(oldIrql); if (CompleteCurrent) { if (oldIrp) { SerialCompleteRequest(extension, oldIrp, IO_SERIAL_INCREMENT); } } } /*-------------------------------------------------------------------------- SerialTryToCompleteCurrent - This routine attempts to kill all of the reasons there are references on the current read/write. If everything can be killed it will complete this read/write and try to start another. NOTE: This routine assumes that it is called with the cancel spinlock held. Arguments: Extension - Simply a pointer to the device extension. SynchRoutine - A routine that will synchronize with the isr and attempt to remove the knowledge of the current irp from the isr. NOTE: This pointer can be null. IrqlForRelease - This routine is called with the cancel spinlock held. This is the irql that was current when the cancel spinlock was acquired. StatusToUse - The irp's status field will be set to this value, if this routine can complete the irp. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialTryToCompleteCurrent( IN PSERIAL_DEVICE_EXTENSION Extension, IN PKSYNCHRONIZE_ROUTINE SynchRoutine OPTIONAL, IN KIRQL IrqlForRelease, IN NTSTATUS StatusToUse, IN PIRP *CurrentOpIrp, IN PLIST_ENTRY QueueToProcess OPTIONAL, IN PKTIMER IntervalTimer OPTIONAL, IN PKTIMER TotalTimer OPTIONAL, IN PSERIAL_START_ROUTINE Starter OPTIONAL, IN PSERIAL_GET_NEXT_ROUTINE GetNextIrp OPTIONAL, IN LONG RefType ) { KIRQL OldIrql; // We can decrement the reference to "remove" the fact // that the caller no longer will be accessing this irp. SERIAL_CLEAR_REFERENCE(*CurrentOpIrp, RefType); if (SynchRoutine) { #ifdef USE_SYNC_LOCKS if (Driver.InterruptObject != NULL) { KeSynchronizeExecution(Driver.InterruptObject, SynchRoutine, Extension); } else // assume spinlock, using timer dpc { KeAcquireSpinLock(&Driver.TimerLock, &OldIrql); SynchRoutine(Extension); KeReleaseSpinLock(&Driver.TimerLock, OldIrql ); } #else SynchRoutine(Extension); #endif } // Try to run down all other references to this irp. SerialRundownIrpRefs( CurrentOpIrp, IntervalTimer, TotalTimer ); // See if the ref count is zero after trying to kill everybody else. if (!SERIAL_REFERENCE_COUNT(*CurrentOpIrp)) { PIRP newIrp; // The ref count was zero so we should complete this request. // The following call will also cause the current irp to be completed. (*CurrentOpIrp)->IoStatus.Status = StatusToUse; if (StatusToUse == STATUS_CANCELLED) { (*CurrentOpIrp)->IoStatus.Information = 0; } if (GetNextIrp) { IoReleaseCancelSpinLock(IrqlForRelease); GetNextIrp( CurrentOpIrp, QueueToProcess, &newIrp, TRUE, Extension ); if (newIrp) { Starter(Extension); } } else { PIRP oldIrp = *CurrentOpIrp; // There was no get next routine. We will simply complete // the irp. We should make sure that we null out the // pointer to the pointer to this irp. *CurrentOpIrp = NULL; IoReleaseCancelSpinLock(IrqlForRelease); SerialCompleteRequest(Extension, oldIrp, IO_SERIAL_INCREMENT); } } else { IoReleaseCancelSpinLock(IrqlForRelease); } } /*-------------------------------------------------------------------------- SerialRundownIrpRefs - This routine runs through the various items that *could* have a reference to the current read/write. It try's to kill the reason. If it does succeed in killing the reason it will decrement the reference count on the irp. NOTE: This routine assumes that it is called with the cancel spin lock held. Arguments: CurrentOpIrp - Pointer to a pointer to current irp for the particular operation. IntervalTimer - Pointer to the interval timer for the operation. NOTE: This could be null. TotalTimer - Pointer to the total timer for the operation. NOTE: This could be null. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialRundownIrpRefs( IN PIRP *CurrentOpIrp, IN PKTIMER IntervalTimer OPTIONAL, IN PKTIMER TotalTimer OPTIONAL ) { // This routine is called with the cancel spin lock held // so we know only one thread of execution can be in here // at one time. // First we see if there is still a cancel routine. If // so then we can decrement the count by one. if ((*CurrentOpIrp)->CancelRoutine) { SERIAL_CLEAR_REFERENCE(*CurrentOpIrp, SERIAL_REF_CANCEL); IoSetCancelRoutine( *CurrentOpIrp, NULL ); } if (IntervalTimer) { // Try to cancel the operations interval timer. If the operation // returns true then the timer did have a reference to the // irp. Since we've canceled this timer that reference is // no longer valid and we can decrement the reference count. // If the cancel returns false then this means either of two things: // a) The timer has already fired. // b) There never was an interval timer. // In the case of "b" there is no need to decrement the reference // count since the "timer" never had a reference to it. // In the case of "a", then the timer itself will be coming // along and decrement it's reference. Note that the caller // of this routine might actually be the this timer, but it // has already decremented the reference. if (KeCancelTimer(IntervalTimer)) { SERIAL_CLEAR_REFERENCE(*CurrentOpIrp,SERIAL_REF_INT_TIMER); } } if (TotalTimer) { // Try to cancel the operations total timer. If the operation // returns true then the timer did have a reference to the // irp. Since we've canceled this timer that reference is // no longer valid and we can decrement the reference count. // If the cancel returns false then this means either of two things: // a) The timer has already fired. // b) There never was an total timer. // In the case of "b" there is no need to decrement the reference // count since the "timer" never had a reference to it. // In the case of "a", then the timer itself will be coming // along and decrement it's reference. Note that the caller // of this routine might actually be the this timer, but it // has already decremented the reference. if (KeCancelTimer(TotalTimer)) { SERIAL_CLEAR_REFERENCE(*CurrentOpIrp,SERIAL_REF_TOTAL_TIMER); } } } /*-------------------------------------------------------------------------- SerialStartOrQueue - This routine is used to either start or queue any requst that can be queued in the driver. Arguments: Extension - Points to the serial device extension. Irp - The irp to either queue or start. In either case the irp will be marked pending. QueueToExamine - The queue the irp will be place on if there is already an operation in progress. CurrentOpIrp - Pointer to a pointer to the irp the is current for the queue. The pointer pointed to will be set with to Irp if what CurrentOpIrp points to is NULL. Starter - The routine to call if the queue is empty. Return Value: This routine will return STATUS_PENDING if the queue is not empty. Otherwise, it will return the status returned from the starter routine (or cancel, if the cancel bit is on in the irp). |--------------------------------------------------------------------------*/ NTSTATUS SerialStartOrQueue( IN PSERIAL_DEVICE_EXTENSION Extension, IN PIRP Irp, IN PLIST_ENTRY QueueToExamine, IN PIRP *CurrentOpIrp, IN PSERIAL_START_ROUTINE Starter ) { KIRQL oldIrql; IoAcquireCancelSpinLock(&oldIrql); // If this is a write irp then take the amount of characters // to write and add it to the count of characters to write. if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_WRITE) { Extension->TotalCharsQueued += IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length; } else if ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_DEVICE_CONTROL) && ((IoGetCurrentIrpStackLocation(Irp) ->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) || (IoGetCurrentIrpStackLocation(Irp) ->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) { Extension->TotalCharsQueued++; // immediate char } if ((IsListEmpty(QueueToExamine)) && !(*CurrentOpIrp)) { // There was no current operation. Mark this one as // current and start it up. *CurrentOpIrp = Irp; IoReleaseCancelSpinLock(oldIrql); return Starter(Extension); } else { // We don't know how long the irp will be in the // queue. So we need to handle cancel. if (Irp->Cancel) { IoReleaseCancelSpinLock(oldIrql); Irp->IoStatus.Status = STATUS_CANCELLED; SerialCompleteRequest(Extension, Irp, 0); return STATUS_CANCELLED; } else { Irp->IoStatus.Status = STATUS_PENDING; IoMarkIrpPending(Irp); InsertTailList( QueueToExamine, &Irp->Tail.Overlay.ListEntry ); IoSetCancelRoutine( Irp, SerialCancelQueued ); IoReleaseCancelSpinLock(oldIrql); return STATUS_PENDING; } } } /*-------------------------------------------------------------------------- SerialCancelQueued - This routine is used to cancel Irps that currently reside on a queue. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP to be canceled. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialCancelQueued( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; RemoveEntryList(&Irp->Tail.Overlay.ListEntry); // If this is a write irp then take the amount of characters // to write and subtract it from the count of characters to write. if (irpSp->MajorFunction == IRP_MJ_WRITE) { extension->TotalCharsQueued -= irpSp->Parameters.Write.Length; } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) { // If it's an immediate then we need to decrement the // count of chars queued. If it's a resize then we // need to deallocate the pool that we're passing on // to the "resizing" routine. if ((irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) || (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER)) { extension->TotalCharsQueued--; } #ifdef COMMENT_OUT //#ifdef DYNAMICQUEUE // Dynamic transmit queue size else if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_QUEUE_SIZE) { // We shoved the pointer to the memory into the // the type 3 buffer pointer which we KNOW we // never use. MyAssert(irpSp->Parameters.DeviceIoControl.Type3InputBuffer); our_free(irpSp->Parameters.DeviceIoControl.Type3InputBuffer); irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL; } #endif //DYNAMICQUEUE } IoReleaseCancelSpinLock(Irp->CancelIrql); SerialCompleteRequest(extension, Irp, IO_SERIAL_INCREMENT); } /*-------------------------------------------------------------------------- Routine Description: If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and there is an error and the application requested abort on errors, then cancel the irp. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP to test. Return Value: STATUS_SUCCESS or STATUS_CANCELLED. |--------------------------------------------------------------------------*/ NTSTATUS SerialCompleteIfError( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; NTSTATUS status = STATUS_SUCCESS; if ((extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) && extension->ErrorWord) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); // There is a current error in the driver. No requests should // come through except for the GET_COMMSTATUS. if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) || (irpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_SERIAL_GET_COMMSTATUS)) { status = STATUS_CANCELLED; Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; SerialCompleteRequest(extension, Irp, 0); } } return status; } /*-------------------------------------------------------------------------- Routine Description: This routine is invoked at dpc level to in response to a comm error. All comm errors kill all read and writes Arguments: Dpc - Not Used. DeferredContext - Really points to the device object. SystemContext1 - Not Used. SystemContext2 - Not Used. Return Value: None. |--------------------------------------------------------------------------*/ VOID SerialCommError( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PSERIAL_DEVICE_EXTENSION Extension = DeferredContext; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemContext1); UNREFERENCED_PARAMETER(SystemContext2); SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->WriteQueue, &Extension->CurrentWriteIrp ); SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->ReadQueue, &Extension->CurrentReadIrp ); } /*-------------------------------------------------------------------------- Routine Description: This is the dispatch routine for flush. Flushing works by placing this request in the write queue. When this request reaches the front of the write queue we simply complete it since this implies that all previous writes have completed. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: Could return status success, cancelled, or pending. |--------------------------------------------------------------------------*/ NTSTATUS SerialFlush(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension; ExtTrace(Extension,D_Ioctl,("Flush")) Irp->IoStatus.Information = 0L; if (SerialIRPPrologue(Extension) == TRUE) { if (Extension->ErrorWord) { if (SerialCompleteIfError( DeviceObject, Irp ) != STATUS_SUCCESS) { return STATUS_CANCELLED; } } return SerialStartOrQueue( Extension, Irp, &Extension->WriteQueue, &Extension->CurrentWriteIrp, SerialStartFlush ); } else { Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; return STATUS_NO_SUCH_DEVICE; } } /*-------------------------------------------------------------------------- Routine Description: This routine is called if there were no writes in the queue. The flush became the current write because there was nothing in the queue. Note however that does not mean there is nothing in the queue now! So, we will start off the write that might follow us. Arguments: Extension - Points to the serial device extension Return Value: This will always return STATUS_SUCCESS. |--------------------------------------------------------------------------*/ NTSTATUS SerialStartFlush(IN PSERIAL_DEVICE_EXTENSION Extension) { PIRP NewIrp; Extension->CurrentWriteIrp->IoStatus.Status = STATUS_SUCCESS; // The following call will actually complete the flush. SerialGetNextWrite( &Extension->CurrentWriteIrp, &Extension->WriteQueue, &NewIrp, TRUE, Extension ); if (NewIrp) { MyAssert(NewIrp == Extension->CurrentWriteIrp); SerialStartWrite(Extension); } return STATUS_SUCCESS; } /*-------------------------------------------------------------------------- SerialStartPurge - Routine Description: Depending on the mask in the current irp, purge the interrupt buffer, the read queue, or the write queue, or all of the above. Arguments: Extension - Pointer to the device extension. Return Value: Will return STATUS_SUCCESS always. This is reasonable since the DPC completion code that calls this routine doesn't care and the purge request always goes through to completion once it's started. |--------------------------------------------------------------------------*/ NTSTATUS SerialStartPurge(IN PSERIAL_DEVICE_EXTENSION Extension) { PIRP NewIrp; do { ULONG Mask; Mask = *((ULONG *) (Extension->CurrentPurgeIrp->AssociatedIrp.SystemBuffer)); if (Mask & SERIAL_PURGE_RXABORT) { SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->ReadQueue, &Extension->CurrentReadIrp ); } if (Mask & SERIAL_PURGE_RXCLEAR) { KIRQL OldIrql; // Flush the Rocket Tx FIFO KeAcquireSpinLock( &Extension->ControlLock, &OldIrql ); // KeSynchronizeExecution( // Driver.Interrupt, // SerialPurgeRxBuffers, // Extension // ); SerialPurgeRxBuffers(Extension); KeReleaseSpinLock( &Extension->ControlLock, OldIrql ); } if (Mask & SERIAL_PURGE_TXABORT) { SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->WriteQueue, &Extension->CurrentWriteIrp ); SerialKillAllReadsOrWrites( Extension->DeviceObject, &Extension->WriteQueue, &Extension->CurrentXoffIrp ); if (Extension->port_config->WaitOnTx) { // if they have this option set, then // really do a purge of tx hardware buffer. SerialPurgeTxBuffers(Extension, 1); } } if (Mask & SERIAL_PURGE_TXCLEAR) { KIRQL OldIrql; // Flush the Rocket Rx FIFO and the system side buffer // Note that we do this under protection of the // the drivers control lock so that we don't hose // the pointers if there is currently a read that // is reading out of the buffer. KeAcquireSpinLock(&Extension->ControlLock, &OldIrql); // KeSynchronizeExecution( // Driver.Interrupt, // SerialPurgeTxBuffers, // Extension // ); if (Extension->port_config->WaitOnTx) SerialPurgeTxBuffers(Extension, 1); // force else SerialPurgeTxBuffers(Extension, 0); // only if flowed off KeReleaseSpinLock(&Extension->ControlLock, OldIrql); } Extension->CurrentPurgeIrp->IoStatus.Status = STATUS_SUCCESS; Extension->CurrentPurgeIrp->IoStatus.Information = 0; SerialGetNextIrp( &Extension->CurrentPurgeIrp, &Extension->PurgeQueue, &NewIrp, TRUE, Extension ); } while (NewIrp); return STATUS_SUCCESS; } /*-------------------------------------------------------------------------- Routine Description: Flushes out the Rx data pipe: Rocket Rx FIFO, Host side Rx buffer NOTE: This routine is being called from KeSynchronizeExecution. Arguments: Context - Really a pointer to the device extension. |--------------------------------------------------------------------------*/ BOOLEAN SerialPurgeRxBuffers(IN PVOID Context) { PSERIAL_DEVICE_EXTENSION Extension = Context; q_flush(&Extension->RxQ); // flush our rx buffer #ifdef S_VS PortFlushRx(Extension->Port); // flush rx hardware #else sFlushRxFIFO(Extension->ChP); //Extension->RxQ.QPut = Extension->RxQ.QGet = 0; #endif return FALSE; } /*-------------------------------------------------------------------------- Routine Description: Flushes the Rocket Tx FIFO NOTE: This routine is being called from KeSynchronizeExecution(not). Arguments: Context - Really a pointer to the device extension. |--------------------------------------------------------------------------*/ BOOLEAN SerialPurgeTxBuffers(IN PVOID Context, int always) { PSERIAL_DEVICE_EXTENSION Extension = Context; /* The stock com-port driver does not purge its hardware queue, but just ignores TXCLEAR. Since we do flow-control in hardware buffer and have a larger buffer, we will purge it only if it is "stuck" or flowed off. This hopefully provides a somewhat compatible and useful match. We shouldn't need to check for EV_TXEMPTY here, as the ISR will take care of this. */ #ifdef S_VS // check for tx-flowed off condition if ((Extension->Port->msr_value & MSR_TX_FLOWED_OFF) || always) PortFlushTx(Extension->Port); // flush tx hardware #else { int TxCount; ULONG wstat; if (always) { sFlushTxFIFO(Extension->ChP); } else { wstat = sGetChanStatusLo(Extension->ChP); // check for tx-flowed off condition if ((wstat & (TXFIFOMT | TXSHRMT)) == TXSHRMT) { wstat = sGetChanStatusLo(Extension->ChP); if ((wstat & (TXFIFOMT | TXSHRMT)) == TXSHRMT) { TxCount = sGetTxCnt(Extension->ChP); ExtTrace1(Extension,D_Ioctl,"Purge %d bytes from Hardware.", TxCount); sFlushTxFIFO(Extension->ChP); } } } } #endif return FALSE; } /*-------------------------------------------------------------------------- Routine Description: This routine is used to query the end of file information on the opened serial port. Any other file information request is retured with an invalid parameter. This routine always returns an end of file of 0. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call |--------------------------------------------------------------------------*/ NTSTATUS SerialQueryInformationFile( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { // The status that gets returned to the caller and // set in the Irp. NTSTATUS Status; BOOLEAN acceptingIRPs; // The current stack location. This contains all of the // information we need to process this particular request. PIO_STACK_LOCATION IrpSp; UNREFERENCED_PARAMETER(DeviceObject); acceptingIRPs = SerialIRPPrologue((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension); if (acceptingIRPs == FALSE) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; SerialCompleteRequest((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension, Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; } if (SerialCompleteIfError(DeviceObject, Irp) != STATUS_SUCCESS) { return STATUS_CANCELLED; } IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0L; Status = STATUS_SUCCESS; if (IrpSp->Parameters.QueryFile.FileInformationClass == FileStandardInformation) { PFILE_STANDARD_INFORMATION Buf = Irp->AssociatedIrp.SystemBuffer; Buf->AllocationSize = RtlConvertUlongToLargeInteger(0ul); Buf->EndOfFile = Buf->AllocationSize; Buf->NumberOfLinks = 0; Buf->DeletePending = FALSE; Buf->Directory = FALSE; Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); } else if (IrpSp->Parameters.QueryFile.FileInformationClass == FilePositionInformation) { ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)-> CurrentByteOffset = RtlConvertUlongToLargeInteger(0ul); Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION); } else { Status = STATUS_INVALID_PARAMETER; } Irp->IoStatus.Status = Status; SerialCompleteRequest((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension, Irp, 0); return Status; } /*-------------------------------------------------------------------------- Routine Description: This routine is used to set the end of file information on the opened serial port. Any other file information request is retured with an invalid parameter. This routine always ignores the actual end of file since the query information code always returns an end of file of 0. Arguments: DeviceObject - Pointer to the device object for this device Irp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call |--------------------------------------------------------------------------*/ NTSTATUS SerialSetInformationFile( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { // The status that gets returned to the caller and // set in the Irp. NTSTATUS Status; BOOLEAN acceptingIRPs; UNREFERENCED_PARAMETER(DeviceObject); acceptingIRPs = SerialIRPPrologue((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension); if (acceptingIRPs == FALSE) { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; SerialCompleteRequest((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension, Irp, IO_NO_INCREMENT); return STATUS_NO_SUCH_DEVICE; } if (SerialCompleteIfError( DeviceObject, Irp ) != STATUS_SUCCESS) { return STATUS_CANCELLED; } Irp->IoStatus.Information = 0L; if ((IoGetCurrentIrpStackLocation(Irp)-> Parameters.SetFile.FileInformationClass == FileEndOfFileInformation) || (IoGetCurrentIrpStackLocation(Irp)-> Parameters.SetFile.FileInformationClass == FileAllocationInformation)) { Status = STATUS_SUCCESS; } else { Status = STATUS_INVALID_PARAMETER; } Irp->IoStatus.Status = Status; SerialCompleteRequest((PSERIAL_DEVICE_EXTENSION)DeviceObject-> DeviceExtension, Irp, 0); return Status; } /*-------------------------------------------------------------------------- UToC1 - Simple convert from NT-Unicode string to c-string. !!!!!!!Uses a statically(static prefix) allocated buffer!!!!! This means that it is NOT re-entrant. Which means only one thread can use this call at a time. Also, a thread could get in trouble if it tried to use it twice recursively(calling a function that uses this, which calls a function which uses this.) Since these translator functions are used mainly during driver initialization and teardown, we do not have to worry about multiple callers at that time. Any calls which may be time sliced(port-calls) should not use this routine due to possible time-slice conflict with another thread. It should allocate a variable on the stack and use UToCStr(). |--------------------------------------------------------------------------*/ OUT PCHAR UToC1(IN PUNICODE_STRING ustr) { // we make it a ULONG to avoid alignment problems(gives ULONG alignment). static char cstr[140]; return UToCStr(cstr, ustr, sizeof(cstr)); } /*-------------------------------------------------------------------------- UToCStr - Purpose: Convert a Unicode string to c-string. Used to easily convert given a simple char buffer. Parameters: Buffer - Working buffer to set up the c-string AND ansi_string struct in. u_str - unicode string structure. BufferSize - number of bytes in Buffer which we can use. Return: pointer to our c-string on success, NULL on err. |--------------------------------------------------------------------------*/ OUT PCHAR UToCStr( IN OUT PCHAR Buffer, IN PUNICODE_STRING ustr, IN int BufferSize) { // assume unicode structure over Buffer. ANSI_STRING astr; astr.Buffer = Buffer; astr.Length = 0; astr.MaximumLength = BufferSize - 1; if (RtlUnicodeStringToAnsiString(&astr,ustr,FALSE) == STATUS_SUCCESS) return Buffer; // ok MyKdPrint(D_Init,("Bad UToCStr!\n")) Buffer[0] = 0; return Buffer; } /*-------------------------------------------------------------------------- CToU1 - Simple convert from c-string to NT-Unicode string. !!!!!!!Uses a statically(static prefix) allocated buffer!!!!! This means that it is NOT re-entrant. Which means only one thread can use this call at a time. Also, a thread could get in trouble if it tried to use it twice recursively(calling a function that uses this, which calls a function which uses this.) Since these translator functions are used mainly during driver initialization and teardown, we do not have to worry about multiple callers at that time. Any calls which may be time sliced(port-calls) should not use this routine due to possible time-slice conflict with another thread. It should allocate a variable on the stack and use CToUStr(). |--------------------------------------------------------------------------*/ OUT PUNICODE_STRING CToU1(IN const char *c_str) { // we make it a ULONG to avoid alignment problems(gives ULONG alignment). static USTR_160 ubuf; // equal to 160 normal chars length return CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put c_str, // our c-string we wish to convert sizeof(ubuf)); } /*-------------------------------------------------------------------------- CToU2 - Simple convert from c-string to NT-Unicode string. !!!!!!!Uses a statically(static prefix) allocated buffer!!!!! This means that it is NOT re-entrant. Which means only one thread can use this call at a time. Also, a thread could get in trouble if it tried to use it twice recursively(calling a function that uses this, which calls a function which uses this.) Since these translator functions are used mainly during driver initialization and teardown, we do not have to worry about multiple callers at that time. Any calls which may be time sliced(port-calls) should not use this routine due to possible time-slice conflict with another thread. It should allocate a variable on the stack and use CToUStr(). |--------------------------------------------------------------------------*/ OUT PUNICODE_STRING CToU2(IN const char *c_str) { // we make it a ULONG to avoid alignment problems(gives ULONG alignment). static USTR_160 ubuf; // equal to 160 normal chars length return CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put c_str, // our c-string we wish to convert sizeof(ubuf)); } /*-------------------------------------------------------------------------- Function: CToUStr Purpose: Convert a c-style null-terminated char[] string to a Unicode string Parameters: Buffer - Working buffer to set up the unicode structure AND unicode_string in. c_str - normal c-style string. BufferSize - number of bytes in Buffer which we can use. Return: pointer to our converted UNICODE_STRING on success, NULL on err. |-------------------------------------------------------------------------*/ OUT PUNICODE_STRING CToUStr( OUT PUNICODE_STRING Buffer, IN const char * c_str, IN int BufferSize) { // assume unicode structure followed by wchar Buffer. USTR_40 *us = (USTR_40 *)Buffer; ANSI_STRING astr; // ansi structure, temporary go between RtlInitAnsiString(&astr, c_str); // c-str to ansi-string struct // configure the unicode string to: point the buffer ptr to the wstr. us->ustr.Buffer = us->wstr; us->ustr.Length = 0; us->ustr.MaximumLength = BufferSize - sizeof(UNICODE_STRING); // now translate from ansi-c-struct-str to unicode-struct-str if (RtlAnsiStringToUnicodeString(&us->ustr,&astr,FALSE) == STATUS_SUCCESS) return (PUNICODE_STRING) us; // ok - return ptr MyKdPrint(D_Init,("Bad CToUStr!\n")) return NULL; // error } /*-------------------------------------------------------------------------- Function: WStrToCStr Purpose: Convert a wide-string to byte-c-style string. Assume wstr is null-terminated. |-------------------------------------------------------------------------*/ VOID WStrToCStr(OUT PCHAR c_str, IN PWCHAR w_str, int max_size) { int i = 0; // assume unicode structure followed by wchar Buffer. while ((*w_str != 0) && (i < (max_size-1))) { *c_str = (CHAR) *w_str; ++c_str; ++w_str; ++i; } *c_str = 0; } /*-------------------------------------------------------------------------- get_reg_value - |-------------------------------------------------------------------------*/ int get_reg_value( IN HANDLE keyHandle, OUT PVOID outptr, IN PCHAR val_name, int max_size) { NTSTATUS status = STATUS_SUCCESS; char tmparr[80]; PKEY_VALUE_PARTIAL_INFORMATION parInfo = (PKEY_VALUE_PARTIAL_INFORMATION) &tmparr[0]; int stat = 0; ULONG length = 0; USTR_40 ubuf; // equal to 40 normal chars length PUNICODE_STRING ustr; ustr = CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put val_name, // our c-string we wish to convert sizeof(ubuf)); if (ustr == NULL) return 3; // err status = ZwQueryValueKey (keyHandle, ustr, // input reg key name KeyValuePartialInformation, parInfo, sizeof(tmparr) -2, &length); if (NT_SUCCESS(status)) { if (parInfo->Type == REG_SZ) { tmparr[length] = 0; // null terminate it. tmparr[length+1] = 0; // null terminate it. WStrToCStr((PCHAR) outptr, (PWCHAR)&parInfo->Data[0], max_size); } else if (parInfo->Type == REG_DWORD) { *((ULONG *)outptr) = *((ULONG *) &parInfo->Data[0]); } else { stat = 1; MyKdPrint(D_Error,("regStrErr56!\n")) } } else { stat = 2; MyKdPrint(D_Error,("regStrErr57!\n")) } return stat; } #if DBG /*----------------------------------------------------------------------- MyAssertMessage - Our Assertion error message. We do our own assert because the normal DDK ASSERT() macro only works or reports under checked build of NT OS. |-----------------------------------------------------------------------*/ void MyAssertMessage(char *filename, int line) { MyKdPrint(D_Init,("ASSERT FAILED!!! File %s, line %d !!!!\n", filename, line)) #ifdef COMMENT_OUT char str[40]; strcpy(str, "FAIL:"); strcat(str, filename); strcat(str, " ln:%d "); mess1(str, line); #endif } #endif /*----------------------------------------------------------------------- EvLog - EvLog an event to NT's event log. |-----------------------------------------------------------------------*/ void EvLog(char *mess) { static USTR_160 ubuf; // our own private buffer(static) UNICODE_STRING *u; NTSTATUS event_type; if (mess == NULL) { MyKdPrint(D_Init,("EvLog Err1!\n")) return; } if ((mess[0] == 'E') && (mess[1] == 'r')) // "Error..." event_type = SERIAL_CUSTOM_ERROR_MESSAGE; else if ((mess[0] == 'W') && (mess[1] == 'a')) // "Warning..." event_type = SERIAL_CUSTOM_ERROR_MESSAGE; else event_type = SERIAL_CUSTOM_INFO_MESSAGE; u = CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put mess, // our c-string we wish to convert sizeof(ubuf)); if (u==NULL) { MyKdPrint(D_Init,("EvLog Err2!\n")) return; } // MyKdPrint(D_Init,("EvLog Size:%d, messsize:%d!\n",u->Length, strlen(mess) )) EventLog(Driver.GlobalDriverObject, STATUS_SUCCESS, event_type, // red"stop" or blue"i".. u->Length + sizeof(WCHAR), u->Buffer); } /*------------------------------------------------------------------- | our_ultoa - |--------------------------------------------------------------------*/ char * our_ultoa(unsigned long u, char* s, int radix) { long pow, prevpow; int digit; char* p; if ( (radix < 2) || (36 < radix) ) { *s = 0; return s; } if (u == 0) { s[0] = '0'; s[1] = 0; return s; } p = s; for (prevpow=0, pow=1; (u >= (unsigned long)pow) && (prevpow < pow); pow *= radix) prevpow=pow; pow = prevpow; while (pow != 0) { digit = u/pow; *p = (digit <= 9) ? ('0'+digit) : ( ('a'-10)+digit); p++; u -= digit*pow; pow /= radix; } *p = 0; return s; } /*------------------------------------------------------------------- | our_ltoa - |--------------------------------------------------------------------*/ char * our_ltoa(long value, char* s, int radix) { unsigned long u; long pow, prevpow; int digit; char* p; if ( (radix < 2) || (36 < radix) ) { *s = 0; return s; } if (value == 0) { s[0] = '0'; s[1] = 0; return s; } p = s; if ( (radix == 10) && (value < 0) ) { *p++ = '-'; value = -value; } *(long*)&u = value; for (prevpow=0, pow=1; (u >= (unsigned long)pow) && (prevpow < pow); pow *= radix) prevpow=pow; pow = prevpow; while (pow != 0) { digit = u/pow; *p = (digit <= 9) ? ('0'+digit) : ( ('a'-10)+digit); p++; u -= digit*pow; pow /= radix; } *p = 0; return s; } /*------------------------------------------------------------------- | our_assert - |--------------------------------------------------------------------*/ void our_assert(int id, int line) { Tprintf("Assert %d line:%d!", id, line); } /*------------------------------------------------------------------- | TTprintf - Trace printf with prefix. Dump trace messages to debug port. With TRACE_PORT turned on, this allows us to use a spare port for tracing another. |--------------------------------------------------------------------*/ void __cdecl TTprintf(char *leadstr, const char *format, ...) { #ifdef TRACE_PORT #endif char temp[120]; va_list Next; int sCount, ls; ls = strlen(leadstr); memcpy(temp, leadstr, ls); temp[ls++] = ' '; va_start(Next, format); our_vsnprintf(&temp[ls], 78, format, Next); sCount = strlen(temp); temp[sCount++] = '['; our_ultoa( (long) Driver.PollCnt, &temp[sCount], 10); sCount += strlen(&temp[sCount]); temp[sCount++] = ']'; temp[sCount++] = 0xd; temp[sCount++] = 0xa; temp[sCount] = 0; TracePut(temp, sCount); // dump out to normal nt debug console DbgPrint(temp); } /*------------------------------------------------------------------- | Tprintf - Trace printf. Dump trace messages to debug port. With TRACE_PORT turned on, this allows us to use a spare port for tracing another. |--------------------------------------------------------------------*/ void __cdecl Tprintf(const char *format, ...) { #ifdef TRACE_PORT #endif char temp[100]; va_list Next; int sCount; va_start(Next, format); our_vsnprintf(temp, 78, format, Next); sCount = strlen(temp); temp[sCount++] = '['; our_ultoa( (long) Driver.PollCnt, &temp[sCount], 10); sCount += strlen(&temp[sCount]); temp[sCount++] = ']'; temp[sCount++] = 0xd; temp[sCount++] = 0xa; temp[sCount] = 0; TracePut(temp, sCount); // dump out to normal nt debug console DbgPrint(temp); } /*------------------------------------------------------------------- | OurTrace - Trace, put data into debug ports buffer. |--------------------------------------------------------------------*/ void OurTrace(char *leadstr, char *newdata) { char temp[86]; int ls, ds; ls = strlen(leadstr); if (ls > 20) ls = 20; ds = strlen(newdata); if (ds > 60) ds = 60; memcpy(temp, leadstr, ls); temp[ls++] = ' '; memcpy(&temp[ls], newdata, ds); ds += ls; temp[ds++] = 0xd; temp[ds++] = 0xa; temp[ds] = 0; TracePut(temp, ds); // dump out to normal nt debug console DbgPrint(temp); } /*------------------------------------------------------------------- | TraceDump - Trace, put data into debug ports buffer. |--------------------------------------------------------------------*/ void TraceDump(PSERIAL_DEVICE_EXTENSION ext, char *newdata, int sCount, int style) { int len,i,j; char trace_buf[50]; len = sCount; j = 0; trace_buf[j++] = ' '; trace_buf[j++] = 'D'; trace_buf[j++] = 'A'; trace_buf[j++] = 'T'; trace_buf[j++] = 'A'; trace_buf[j++] = ':'; // dump data into the trace buffer in a hex or ascii dump format if (len > 32) len = 32; for (i=0; i 0x80)) trace_buf[j] = '.'; ++j; } trace_buf[j++] = 0xd; trace_buf[j++] = 0xa; trace_buf[j] = 0; TracePut(trace_buf, j); } /*------------------------------------------------------------------- | TracePut - Trace, put data into debug ports buffer. |--------------------------------------------------------------------*/ void TracePut(char *newdata, int sCount) { #ifdef TRACE_PORT // int RxFree,i; KIRQL controlIrql; // PSERIAL_DEVICE_EXTENSION extension; // drop this into our debug queue... //----- THIS COMES BACK AS DISPATCH_LEVEL OR PASSIVE LEVEL, is it //----- SAFE FOR SPINLOCK TO HAVE BOTH ?????? //-- YES, SpinLocks meant for calling when <= DISPATCH_LEVEL #if DBG if ((KeGetCurrentIrql() != DISPATCH_LEVEL) && (KeGetCurrentIrql() != PASSIVE_LEVEL)) { MyKdPrint(D_Error, ("BAD IRQL:%d ", KeGetCurrentIrql(), newdata)) return; } #endif if (sCount == 0) sCount = strlen(newdata); KeAcquireSpinLock(&Driver.DebugLock, &controlIrql); q_put(&Driver.DebugQ, (BYTE *) newdata, sCount); KeReleaseSpinLock(&Driver.DebugLock, controlIrql); #endif } /*------------------------------------------------------------------- | Dprintf - |--------------------------------------------------------------------*/ void __cdecl Dprintf(const char *format, ...) { char temp[100]; va_list Next; va_start(Next, format); our_vsnprintf(temp, 100, format, Next); // EvLog(temp); // dump out to normal nt debug console DbgPrint(temp); DbgPrint("\n"); } /*------------------------------------------------------------------- | Sprintf - |--------------------------------------------------------------------*/ void __cdecl Sprintf(char *dest, const char *format, ...) { va_list Next; va_start(Next, format); our_vsnprintf(dest, 80, format, Next); } /*------------------------------------------------------------------- | Eprintf - |--------------------------------------------------------------------*/ void __cdecl Eprintf(const char *format, ...) { char temp[80]; va_list Next; va_start(Next, format); our_vsnprintf(temp, 79, format, Next); if (KeGetCurrentIrql() == PASSIVE_LEVEL) { EvLog(temp); } strcat(temp, "\n"); DbgPrint(temp); } /*------------------------------------------------------------------- | our_vsnprintf - |--------------------------------------------------------------------*/ int __cdecl our_vsnprintf(char *buffer, size_t Limit, const char *format, va_list Next) { #ifndef BOOL #define BOOL int #endif int InitLimit = Limit; // Limit at entry point BOOL bMore; // Loop control int Width; // Optional width int Precision; // Optional precision char *str; // String char strbuf[36]; // Constructed string int len; // Length of string int nLeadingZeros; // Number of leading zeros required int nPad; // Number of pad characters required char cPad; // Current pad character ('0' or ' ') char *sPrefix; // Prefix string unsigned long val; // Value of current number BOOL bLeftJustify; // Justification BOOL bPlusSign; // Show plus sign? BOOL bBlankSign; // Blank for positives? BOOL bZeroPrefix; // Want 0x for hex, 0 for octal? BOOL bIsShort; // TRUE if short BOOL bIsLong; // TRUE if long #define PUTONE(c) if (Limit) { --Limit; *buffer++ = c; } else c; #define fLeftJustify (1 << 0) #define fPlusSign (1 << 1) #define fZeroPad (1 << 2) #define fBlankSign (1 << 3) #define fPrefixOX (1 << 4) #define fIsShort (1 << 5) #define fIsLong (1 << 6) if (Limit == 0) return -1; Limit--; // Leave room for terminating NULL while (*format != '\0') { // Everything but '%' is copied to buffer if (*format != '%') // '%' gets special handling here PUTONE(*format++) else { // Set default flags, etc Width = 0; Precision = -1; cPad = ' '; bLeftJustify = FALSE; bPlusSign = FALSE; bBlankSign = FALSE; bZeroPrefix = FALSE; bIsShort = FALSE; bIsLong = FALSE; sPrefix = ""; format++; bMore = TRUE; while (bMore) { // optional flags switch (*format) { case '-': bLeftJustify = TRUE; format++; break; case '+': bPlusSign = TRUE; format++; break; case '0': cPad = '0'; format++; break; case ' ': bBlankSign = TRUE; format++; break; case '#': bZeroPrefix = TRUE; format++; break; default: bMore = FALSE; } } // optional width if (*format == '*') { Width = (int) va_arg(Next, int); format++; } else if (our_isdigit(*format)) { while (our_isdigit(*format)) { Width *= 10; Width += (*format++) - '0'; } } // optional precision if (*format == '.') { format++; Precision = 0; if (*format == '*') { Precision = (int) va_arg(Next, int); format++; } else while (our_isdigit(*format)) { Precision *= 10; Precision += (*format++) - '0'; } } // optional size switch (*format) { case 'h': bIsShort = TRUE; format++; break; case 'l': bIsLong = TRUE; format++; break; } // All controls are completed, dispatch on the conversion character switch (*format++) { case 'd': case 'i': if (bIsLong) // Signed long int our_ltoa( (long) va_arg(Next, long), strbuf, 10); else // Signed int our_ltoa( (long) va_arg(Next, int), strbuf, 10); // _itoa( (int) va_arg(Next, int), strbuf, 10); if (strbuf[0] == '-') sPrefix = "-"; else { if (bPlusSign) sPrefix = "+"; else if (bBlankSign) sPrefix = " "; } goto EmitNumber; case 'u': if (bIsLong) // Unsigned long int our_ultoa( (long) va_arg(Next, long), strbuf, 10); else // Unsigned int our_ultoa( (long) (int) va_arg(Next, int), strbuf, 10); goto EmitNumber; // set sPrefix for these... case 'o': if (bZeroPrefix) sPrefix = "0"; if (bIsLong) val = (long) va_arg(Next, long); else val = (int) va_arg(Next, int); our_ultoa(val, strbuf, 8); if (val == 0) sPrefix = ""; goto EmitNumber; case 'x': case 'X': if (bZeroPrefix) sPrefix = "0x"; if (bIsLong) val = (unsigned long) va_arg(Next, long); else val = (unsigned int) va_arg(Next, int); our_ultoa(val, strbuf, 16); if (val == 0) sPrefix = ""; goto EmitNumber; case 'c': strbuf[0] = (char) va_arg(Next, char); str = strbuf; len = 1; goto EmitString; case 's': str = (char *) va_arg(Next, char*); len = strlen(str); if (Precision != -1 && Precision < len) len = Precision; goto EmitString; case 'n': case 'p': break; case '%': strbuf[0] = '%'; str = strbuf; len = 1; goto EmitString; break; case 'f': case 'e': case 'E': case 'g': case 'G': str = ""; len = strlen(str); goto EmitString; default: str = ""; len = strlen(str); goto EmitString; } EmitNumber: if (Precision == -1) Precision = 1; str = strbuf; if (*str == '-') str++; // if negative, already have prefix len = strlen(str); nLeadingZeros = Precision - len; if (nLeadingZeros < 0) nLeadingZeros = 0; nPad = Width - (len + nLeadingZeros + strlen(sPrefix)); if (nPad < 0) nPad = 0; if (nPad && !bLeftJustify) { // Left padding required while (nPad--) { PUTONE(cPad); } nPad = 0; // Indicate padding completed } while (*sPrefix != '\0') PUTONE(*sPrefix++); while (nLeadingZeros-- > 0) PUTONE('0'); while (len-- > 0) { PUTONE(*str++); } if (nPad) { // Right padding required while (nPad--) PUTONE(' '); } goto Done; EmitString: // Here we have the string ready to emit. Handle padding, etc. if (Width > len) nPad = Width - len; else nPad = 0; if (nPad && !bLeftJustify) { // Left padding required while (nPad--) PUTONE(cPad); } while (len-- > 0) PUTONE(*str++); if (nPad) { // Right padding required while (nPad--) PUTONE(' '); } Done: ; } } *buffer = '\0'; return InitLimit - Limit - 1; // Don't count terminating NULL } /*------------------------------------------------------------------- | our_isdigit - |--------------------------------------------------------------------*/ int our_isdigit(char c) { if ((c >= '0') && (c <= '9')) return 1; return 0; } /*----------------------------------------------------------------- listfind - find matching string in list. List is null terminated. |------------------------------------------------------------------*/ int listfind(char *str, char **list) { int i=0; for (i=0; list[i] != NULL; i++) { if (my_lstricmp(str, list[i]) == 0) // match return i; } return -1; } /*----------------------------------------------------------------- getnum - get a number. Hex or Dec. |------------------------------------------------------------------*/ int getnum(char *str, int *index) { int i,val; int ch_i; *index = 0; ch_i = 0; while (*str == ' ') { ++str; ++ch_i; } if ((*str == '0') && (my_toupper(str[1]) == 'X')) { str += 2; ch_i += 2; val = (int) gethint(str,&i); if (i==0) return 0; } else { val = getint(str,&i); if (i==0) return 0; } ch_i += i; *index = ch_i; // num bytes consumed return val; } /*----------------------------------------------------------------- getnumbers - get numbers from string, comma or space delimited. return number of integers read. |------------------------------------------------------------------*/ int getnumbers(char *str, long *nums, int max_nums, int hex_flag) { // int stat; int i,j, num_cnt; ULONG *wnums = (ULONG *)nums; i = 0; num_cnt = 0; while (num_cnt < max_nums) { while ((str[i] == ' ') || (str[i] == ',') || (str[i] == ':')) ++i; if (hex_flag) wnums[num_cnt] = gethint(&str[i], &j); else nums[num_cnt] = getint(&str[i], &j); i += j; if (j == 0) return num_cnt; else ++num_cnt; } return num_cnt; } /*----------------------------------------------------------------- my_lstricmp - |------------------------------------------------------------------*/ int my_lstricmp(char *str1, char *str2) { if ((str1 == NULL) || (str2 == NULL)) return 1; // not a match if ((*str1 == 0) || (*str2 == 0)) return 1; // not a match while ( (my_toupper(*str1) == my_toupper(*str2)) && (*str1 != 0) && (*str2 != 0)) { ++str1; ++str2; } if ((*str1 == 0) && (*str2 == 0)) return 0; // ok match return 1; // no match } /*----------------------------------------------------------------- my_sub_lstricmp - |------------------------------------------------------------------*/ int my_sub_lstricmp(const char *name, const char *codeline) { int c; if ((name == NULL) || (codeline == NULL)) return 1; // not a match if ((*name == 0) || (*codeline == 0)) return 1; // not a match while ( (my_toupper(*name) == my_toupper(*codeline)) && (*name != 0) && (*codeline != 0)) { ++name; ++codeline; } // return if either is at end of string if (*name == 0) { c = my_toupper(*codeline); if ((c <= 'Z') && (c >= 'A')) return 1; // not a match if (c == '_') return 1; // not a match return 0; // ok match } return 1; // no match } /*------------------------------------------------------------------------ | getstr - grab a text string parameter off a command line. |-----------------------------------------------------------------------*/ int getstr(char *deststr, char *textptr, int *countptr, int max_size) { // int number; int tempcount, i; *deststr = 0; tempcount = 0; while ((*textptr == ' ') || (*textptr == ',')) { ++textptr; ++tempcount; } i = 0; while ((*textptr != 0) && (*textptr != ' ') && (*textptr != ',') && (i < max_size) ) { *deststr++ = *textptr; ++textptr; ++tempcount; ++i; } *deststr = 0; *countptr = tempcount; return 0; } /*------------------------------------------------------------------------ | getint - |-----------------------------------------------------------------------*/ int getint(char *textptr, int *countptr) { int number; int tempcount; int negate = 0; int digit_cnt = 0; tempcount = 0; number = 0; while (*textptr == 0x20) { ++textptr; ++tempcount; } if (*textptr == '-') { ++textptr; ++tempcount; negate = 1; } while ( ((*textptr >= 0x30) && (*textptr <= 0x39)) ) { number = (number * 10) + ( *textptr & 0x0f); ++textptr; ++tempcount; ++digit_cnt; } if (digit_cnt == 0) { tempcount = 0; number = 0; } if (countptr) *countptr = tempcount; if (negate) return (-number); return number; } /* getint */ /*------------------------------------------------------------------------ | gethint - for finding hex words. |-----------------------------------------------------------------------*/ unsigned int gethint(char *bufptr, int *countptr) { unsigned int count; unsigned char temphex; unsigned int number; int digit_cnt = 0; number = 0; count = 0; while (*bufptr == 0x20) { ++bufptr; ++count; } while ( ((*bufptr >= 0x30) && (*bufptr <= 0x39)) || ((my_toupper(*bufptr) >= 0x41) && (my_toupper(*bufptr) <= 0x46)) ) { if (*bufptr > 0x39) temphex = (my_toupper(*bufptr) & 0x0f) + 9; else temphex = *bufptr & 0x0f; number = (number * 16) + temphex; ++bufptr; ++count; ++digit_cnt; } if (digit_cnt == 0) { count = 0; number = 0; } if (countptr) *countptr = count; return number; } /* gethint */ /*----------------------------------------------------------------- my_toupper - to upper case |------------------------------------------------------------------*/ int my_toupper(int c) { if ((c >= 'a') && (c <= 'z')) return ((c-'a') + 'A'); else return c; } /*---------------------------------------------------------------------------- | hextoa - |----------------------------------------------------------------------------*/ void hextoa(char *str, unsigned int v, int places) { while (places > 0) { --places; if ((v & 0xf) < 0xa) str[places] = '0' + (v & 0xf); else str[places] = 'A' + (v & 0xf) - 0xa; v >>= 4; } } //#define DUMP_MEM #if DBG #define TRACK_MEM #endif /*---------------------------------------------------------------------------- | our_free - |----------------------------------------------------------------------------*/ void our_free(PVOID ptr, char *str) { #ifdef TRACK_MEM ULONG size; BYTE *bptr; if (ptr == NULL) { MyKdPrint(D_Error, ("MemFree Null Error\n")) //Tprintf("ERR,MemNull Err!"); return; } bptr = ptr; bptr -= 16; if (*((DWORD *)bptr) != 0x1111) // frame it with something we can check { MyKdPrint(D_Error, ("MemFree Frame Error\n")) //Tprintf("ERR, MemFree Frame!"); } bptr += 4; size = *((DWORD *)bptr); // frame it with something we can check bptr -= 4; Driver.mem_alloced -= size; // track how much memory we are using #ifdef DUMP_MEM MyKdPrint(D_Init, ("Free:%x(%d),%s, [T:%d]\n",bptr, size, str, Driver.mem_alloced)) //Tprintf("Free:%x(%d),%s, [T:%d]",bptr, size, str, Driver.mem_alloced); #endif ExFreePool(bptr); #else ExFreePool(ptr); #endif } /*---------------------------------------------------------------------------- | our_locked_alloc - |----------------------------------------------------------------------------*/ PVOID our_locked_alloc(ULONG size, char *str) { BYTE *bptr; #ifdef TRACK_MEM int i; size += 16; #endif bptr = ExAllocatePool(NonPagedPool, size); if (bptr == NULL) { MyKdPrint(D_Error, ("MemCreate Fail\n")) //Tprintf("ERR, MemCreate Error!"); return NULL; } RtlZeroMemory(bptr, size); #ifdef TRACK_MEM #ifdef DUMP_MEM MyKdPrint(D_Init, ("Alloc:%x(%d),%s\n",bptr, size, str)) //Tprintf("Alloc:%x(%d),%s",bptr, size, str); #endif *((DWORD *)bptr) = 0x1111; // frame it with something we can check bptr += 4; *((DWORD *)bptr) = size; bptr += 4; for (i=0; i<4; i++) // copy the name { bptr[i] = str[i]; if (str[i] == 0) break; } bptr += 8; #endif Driver.mem_alloced += size; // track how much memory we are using return bptr; } #ifdef S_VS /*---------------------------------------------------------------------- mac_cmp - compare two 6-byte mac addresses, return -1 if mac1 < ma2, 0 if mac1==mac2, 1 if mac1 > mac2. |----------------------------------------------------------------------*/ int mac_cmp(UCHAR *mac1, UCHAR *mac2) { int i; for (i=0; i<6; i++) { if (mac1[i] != mac2[i]) { if (mac1[i] < mac2[i]) return -1; else return 1; } } return 0; // same } #endif /*---------------------------------------------------------------------- time_stall - |----------------------------------------------------------------------*/ void time_stall(int tenth_secs) { int i; LARGE_INTEGER WaitTime; // Actual time req'd for buffer to drain // set wait-time to .1 second.(-1000 000 = relative(-), 100-ns units) WaitTime.QuadPart = -1000000L * tenth_secs; KeDelayExecutionThread(KernelMode,FALSE,&WaitTime); #if 0 // this is wasteing resources, see new version above // wait .4 seconds for response for (i=0; iboard_ext; ++num_devices; } return num_devices; } /*---------------------------------------------------------------------- NumPorts - return number of ports for a device based on the actual number of Object extensions linked to our device. board_ext - board/device to return number of ports, or NULL for a count of all ports for all boards. |----------------------------------------------------------------------*/ int NumPorts(PSERIAL_DEVICE_EXTENSION board_ext) { int num_devices; PSERIAL_DEVICE_EXTENSION port_ext; int all_devices = 0; if (board_ext == NULL) { all_devices = 1; board_ext = Driver.board_ext; } num_devices = 0; while (board_ext != NULL) { port_ext = board_ext->port_ext; while (port_ext != NULL) { port_ext = port_ext->port_ext; ++num_devices; } if (all_devices) board_ext = board_ext->board_ext; // next else board_ext = NULL; // only the one } return num_devices; } /*---------------------------------------------------------------------- BoardExtToNumber - generate a board number based on the position in linked list with head Driver.board_ext. Used for NT4.0 driver install to report a board number. |----------------------------------------------------------------------*/ int BoardExtToNumber(PSERIAL_DEVICE_EXTENSION board_ext) { PSERIAL_DEVICE_EXTENSION ext; int board_num; if (board_ext == NULL) return 0; // walk list of boards to determine which "board number" we are board_num = 0; ext = Driver.board_ext; while (ext != NULL) { if (board_ext == ext) { return board_num; } ext = ext->board_ext; ++board_num; } return 0; // return first board index as default. } /*---------------------------------------------------------------------- PortExtToIndex - Given a port extension, return the index into the devices or drivers ports. driver_flag - if set, then return in relation to driver, otherwise return port index in relation to parent device. |----------------------------------------------------------------------*/ int PortExtToIndex(PSERIAL_DEVICE_EXTENSION port_ext, int driver_flag) { PSERIAL_DEVICE_EXTENSION b_ext; PSERIAL_DEVICE_EXTENSION p_ext; int port_num; if (port_ext == NULL) return 0; // walk list of boards & ports port_num = 0; b_ext = Driver.board_ext; while (b_ext != NULL) { if (!driver_flag) port_num = 0; p_ext = b_ext->port_ext; while (p_ext != NULL) { if (p_ext == port_ext) return port_num; p_ext = p_ext->port_ext; ++port_num; } b_ext = b_ext->board_ext; } // walk list of boards & pdo ports port_num = 0; b_ext = Driver.board_ext; while (b_ext != NULL) { if (!driver_flag) port_num = 0; p_ext = b_ext->port_pdo_ext; while (p_ext != NULL) { if (p_ext == port_ext) return port_num; p_ext = p_ext->port_ext; ++port_num; } b_ext = b_ext->board_ext; } MyKdPrint(D_Error,("PortExtErr5!\n")) return 0; // return 0(same as first port) if not found } /*---------------------------------------------------------------------------- | find_ext_by_name - Given name("COM5"), find the extension structure |----------------------------------------------------------------------------*/ PSERIAL_DEVICE_EXTENSION find_ext_by_name(char *name, int *dev_num) { int Dev; PSERIAL_DEVICE_EXTENSION ext; PSERIAL_DEVICE_EXTENSION board_ext; board_ext = Driver.board_ext; while (board_ext) { ext = board_ext->port_ext; Dev = 0; while (ext) { if (my_lstricmp(name, ext->SymbolicLinkName) == 0) { if (dev_num != NULL) *dev_num = Dev; return ext; } ++Dev; ext = ext->port_ext; // next in chain } // while port extension board_ext = board_ext->board_ext; // next in chain } // while board extension return NULL; } /*---------------------------------------------------------------------------- | is_board_in_use - Given Board extension, determine if anyone is using it. (If any ports associated with it are open.) |----------------------------------------------------------------------------*/ int is_board_in_use(PSERIAL_DEVICE_EXTENSION board_ext) { PSERIAL_DEVICE_EXTENSION port_ext; int in_use = 0; #ifdef S_VS int i; Hdlc *hd; #endif if (board_ext == NULL) return 0; #ifdef S_VS hd = board_ext->hd; if ( hd ) { for( i=0; i<2; i++ ) { if ( (hd->TxCtlPackets[i]) && (hd->TxCtlPackets[i]->ProtocolReserved[1]) ) { in_use = 1; } } for( i=0; iTxPackets[i]) && (hd->TxPackets[i]->ProtocolReserved[1]) ) { in_use = 1; } } } #endif port_ext = board_ext->port_ext; while((in_use == 0) && (port_ext != NULL)) { if (port_ext->DeviceIsOpen) { in_use = 1; } #ifdef S_VS hd = port_ext->hd; if ( hd ) { for( i=0; i<2; i++ ) { if ( (hd->TxCtlPackets[i]) && (hd->TxCtlPackets[i]->ProtocolReserved[1]) ) { in_use = 1; } } for( i=0; iTxPackets[i]) && (hd->TxPackets[i]->ProtocolReserved[1]) ) { in_use = 1; } } } #endif port_ext = port_ext->port_ext; } return in_use; // not in use. } /*---------------------------------------------------------------------------- | find_ext_by_index - Given device X and port Y, find the extension structure If port_num is -1, then a board ext is assumed to be looked for. |----------------------------------------------------------------------------*/ PSERIAL_DEVICE_EXTENSION find_ext_by_index(int dev_num, int port_num) { PSERIAL_DEVICE_EXTENSION ext; PSERIAL_DEVICE_EXTENSION board_ext; int bn; int pn; bn = -1; pn = -1; board_ext = Driver.board_ext; while ( (board_ext) && (bn < dev_num) ) { bn++; if (bn == dev_num) { ext = board_ext->port_ext; if (port_num == -1) return board_ext; // they wanted a board ext. while (ext) { pn++; if (pn == port_num) return ext; else ext = ext->port_ext; // next in port chain } } board_ext = board_ext->board_ext; // next in device chain } return NULL; } /*---------------------------------------------------------------------------- | ModemReset - wrappers around hardware routines to put SocketModems into or | clear SocketModems from reset state. |----------------------------------------------------------------------------*/ void ModemReset(PSERIAL_DEVICE_EXTENSION ext, int on) { #ifdef S_RK sModemReset(ext->ChP, on); #else if (on == 1) { // put the modem into reset state (firmware will pull it out of reset // automatically) ext->Port->action_reg |= ACT_MODEM_RESET; } else { // don't need to do anything to clear a modem from reset on the vs } #endif } /*----------------------------------------------------------------- our_enum_key - Enumerate a registry key, handle misc stuff. |------------------------------------------------------------------*/ int our_enum_key(IN HANDLE handle, IN int index, IN CHAR *buffer, IN ULONG max_buffer_size, OUT PCHAR *retdataptr) { NTSTATUS status; PKEY_BASIC_INFORMATION KeyInfo; ULONG actuallyReturned; KeyInfo = (PKEY_BASIC_INFORMATION) buffer; max_buffer_size -= 8; // subtract off some space for nulling end, slop, etc. // return a pointer to the start of data. *retdataptr = ((PCHAR)(&KeyInfo->Name[0])); // Pad the name returned with 2 wchar zeros. RtlZeroMemory( ((PUCHAR)(&KeyInfo->Name[0])), sizeof(WCHAR)*2); status = ZwEnumerateKey(handle, index, KeyBasicInformation, KeyInfo, max_buffer_size, &actuallyReturned); if (status == STATUS_NO_MORE_ENTRIES) { //MyKdPrint(D_Init, ("Done.\n")) return 1; // err, done } if (status != STATUS_SUCCESS) { MyKdPrint(D_Error, ("Err3G\n")) return 2; // err } if (KeyInfo->NameLength > max_buffer_size) // check limits KeyInfo->NameLength = max_buffer_size; // Pad the name returned with 2 wchar zeros. RtlZeroMemory( ((PUCHAR)(&KeyInfo->Name[0]))+KeyInfo->NameLength, sizeof(WCHAR)*2); return 0; // ok, done } /*----------------------------------------------------------------- our_enum_value - Enumerate a registry value, handle misc stuff. |------------------------------------------------------------------*/ int our_enum_value(IN HANDLE handle, IN int index, IN CHAR *buffer, IN ULONG max_buffer_size, OUT PULONG type, OUT PCHAR *retdataptr, OUT PCHAR sz_retname) { NTSTATUS status; PKEY_VALUE_FULL_INFORMATION KeyValueInfo; //PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONG actuallyReturned; ULONG i; KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; max_buffer_size -= 8; // subtract off some space for nulling end, slop, etc. // Pad the name returned with 2 wchar zeros. RtlZeroMemory( ((PUCHAR)(&KeyValueInfo->Name[0])), sizeof(WCHAR)*2); // return a pointer to the start of data. *retdataptr = ((PCHAR)(&KeyValueInfo->Name[0])); *sz_retname = 0; status = ZwEnumerateValueKey(handle, index, KeyValueFullInformation, KeyValueInfo, max_buffer_size, &actuallyReturned); if (status == STATUS_NO_MORE_ENTRIES) { //MyKdPrint(D_Init, ("Done.\n")) return 1; // err, done } if (status != STATUS_SUCCESS) { MyKdPrint(D_Init, ("Err3H\n")) return 2; // err } if (KeyValueInfo->NameLength < 80) // limit to 40 char entries { for (i=0; i<(KeyValueInfo->NameLength/2); i++) { sz_retname[i] = (CHAR)KeyValueInfo->Name[i]; } sz_retname[i] = 0; } *retdataptr = ((PCHAR) KeyValueInfo) + KeyValueInfo->DataOffset; // Pad the data returned with 2 wchar zeros. RtlZeroMemory( (PUCHAR)(*retdataptr + KeyValueInfo->DataLength), sizeof(WCHAR)*2); if (type != NULL) *type = KeyValueInfo->Type; return 0; // ok, done } /*----------------------------------------------------------------- our_query_value - get data from an entry in the registry. We give a generic buffer space(and size), and the routine passes back a ptr (into this generic buffer space where the data is read into. |------------------------------------------------------------------*/ int our_query_value(IN HANDLE Handle, IN char *key_name, IN CHAR *buffer, IN ULONG max_buffer_size, OUT PULONG type, OUT PCHAR *retdataptr) { NTSTATUS status; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONG length; OUT USTR_40 ubuf; // about 90 bytes on stack if (strlen(key_name) > 38) { MyKdPrint(D_Error, ("Err, KeyValue Len!\n")) return 2; } // convert our name to unicode; CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put key_name, // our c-string we wish to convert sizeof(ubuf)); KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer; max_buffer_size -= 8; // subtract off some space for nulling end, slop, etc. // return a pointer to the start of data. *retdataptr = ((PCHAR)(&KeyValueInfo->Data[0])); // Pad the name returned with 2 wchar zeros. RtlZeroMemory( ((PUCHAR)(&KeyValueInfo->Data[0])), sizeof(WCHAR)*2); status = ZwQueryValueKey (Handle, (PUNICODE_STRING) &ubuf, // input reg key name KeyValuePartialInformation, KeyValueInfo, max_buffer_size, &length); if (status != STATUS_SUCCESS) { //MyKdPrint(D_Init, ("No Value\n")) return 1; // err } if (KeyValueInfo->DataLength > max_buffer_size) KeyValueInfo->DataLength = max_buffer_size; // Pad the data returned with a null,null. RtlZeroMemory( ((PUCHAR)(&KeyValueInfo->Data[0]))+KeyValueInfo->DataLength, sizeof(WCHAR)*2); if (type != NULL) *type = KeyValueInfo->Type; return 0; // ok } /*----------------------------------------------------------------- our_set_value - get data from an entry in the registry. |------------------------------------------------------------------*/ int our_set_value(IN HANDLE Handle, IN char *key_name, IN PVOID pValue, IN ULONG value_size, IN ULONG value_type) { NTSTATUS status; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; ULONG length; OUT USTR_40 ubuf_name; // about 90 bytes on stack OUT USTR_40 ubuf_val; // about 90 bytes on stack if (strlen(key_name) > 38) { MyKdPrint(D_Error, ("Err, KeyValue Len!\n")) return 2; } // convert our name to unicode; CToUStr( (PUNICODE_STRING) &ubuf_name, // where unicode struct & string gets put key_name, // our c-string we wish to convert sizeof(ubuf_name)); if (value_type == REG_SZ) { // convert our value to unicode; CToUStr( (PUNICODE_STRING) &ubuf_val, // where unicode struct & string gets put (char *)pValue, // our c-string we wish to convert sizeof(ubuf_val)); MyKdPrint(D_Init, ("set_value reg_sz %s=%s\n", key_name, (char *)pValue)) pValue = (PVOID)ubuf_val.ustr.Buffer; value_size = ubuf_val.ustr.Length; } status = ZwSetValueKey (Handle, (PUNICODE_STRING) &ubuf_name, 0, // type optional value_type, pValue, value_size); if (status != STATUS_SUCCESS) { MyKdPrint(D_Error, ("Error setting reg %\n",key_name)) return 1; // err } return 0; // ok } /*----------------------------------------------------------------- our_open_key - Make sure *pHandle is initialized to NULL, because this routine auto-closes the handle with ZwClose(). |------------------------------------------------------------------*/ int our_open_key(OUT PHANDLE phandle, IN OPTIONAL HANDLE relative_key_handle, IN char *regkeyname, IN ULONG attribs) { OBJECT_ATTRIBUTES objAttribs; NTSTATUS status; OUT USTR_160 ubuf; // about 340 bytes on the stack if (strlen(regkeyname) > 158) { MyKdPrint(D_Error, ("Err, Key Len!\n")) return 2; } // convert our name to unicode; CToUStr( (PUNICODE_STRING) &ubuf, // where unicode struct & string gets put regkeyname, // our c-string we wish to convert sizeof(ubuf)); // if previously open, then close it up. if (*phandle != NULL) { ZwClose(*phandle); *phandle = NULL; } InitializeObjectAttributes(&objAttribs, (PUNICODE_STRING) &ubuf, OBJ_CASE_INSENSITIVE, relative_key_handle, // root dir relative handle NULL); // security desc status = ZwOpenKey(phandle, attribs, &objAttribs); if ((status != STATUS_SUCCESS) && (attribs == KEY_ALL_ACCESS)) { MyKdPrint(D_Error, ("OpenKey,Try to Create %s, status 0x%x\n", regkeyname,status)) status = ZwCreateKey(phandle, attribs, //KEY_ALL_ACCESS, etc &objAttribs, 0, // index, optional NULL, // ptr to unicode string, class REG_OPTION_NON_VOLATILE, NULL); // disposition, tells if created if (status == STATUS_SUCCESS) { // try to open the original key again. status = ZwOpenKey(phandle, attribs, &objAttribs); } else { MyKdPrint(D_Error, ("OpenKey,Error Creating %s\n", regkeyname)) } } if (status != STATUS_SUCCESS) { MyKdPrint(D_Error, ("OpenKey,Error Opening %s, status 0x%x\n", regkeyname,status)) //MyKdPrint(D_Init, ("Failed ZwOpenKey\n")) *phandle = NULL; // make sure null if not open return 1; } return 0; } /*----------------------------------------------------------------- our_open_device_reg - |------------------------------------------------------------------*/ int our_open_device_reg(OUT HANDLE *pHandle, IN PSERIAL_DEVICE_EXTENSION dev_ext, IN ULONG RegOpenRights) { NTSTATUS status; HANDLE DriverHandle = NULL; HANDLE DevHandle = NULL; #if TRY_NEW_NT50 // PLUGPLAY_REGKEY_DRIVER opens up the control\class\{guid}\node // PLUGPLAY_REGKEY_DEVICE opens up the enum\enum-type\node\Device Parameters status = IoOpenDeviceRegistryKey(dev_ext->Pdo, PLUGPLAY_REGKEY_DRIVER, RegOpenRights, pHandle); if (status != STATUS_SUCCESS) { //MyKdPrint(D_Init, ("Failed ZwOpenKey\n")) *phandle = NULL; // make sure null if not open return 1; } #else { int j, stat; char dev_str[60]; char tmpstr[200]; OBJECT_ATTRIBUTES objAttribs; MyKdPrint(D_Init, ("our_open_device_reg\n")) #if NT50 if (dev_ext->config->szNt50DevObjName[0] == 0) { MyKdPrint(D_Error, ("Error, device options Pnp key!\n")) *pHandle = NULL; return 1; // err } Sprintf(dev_str, "%s\\%s", szParameters, dev_ext->config->szNt50DevObjName); #else j = BoardExtToNumber(dev_ext); Sprintf(dev_str, "%s\\Device%d", szParameters, BoardExtToNumber(dev_ext)); #endif // force a creation of "Parameters" if not exist stat = our_open_driver_reg(&DriverHandle, KEY_ALL_ACCESS); if (stat) { MyKdPrint(D_Error, ("Err4b!\n")) *pHandle = NULL; return 1; } ZwClose(DriverHandle); DriverHandle = NULL; MyKdPrint(D_Init, ("Driver.OptionRegPath: %s\n", dev_str)) stat = MakeRegPath(dev_str); // this forms Driver.OptionRegPath if (stat) { *pHandle = NULL; return 1; } UToCStr(tmpstr, &Driver.OptionRegPath, sizeof(tmpstr)); stat = our_open_key(pHandle, NULL, tmpstr, RegOpenRights); if (stat != 0) { MyKdPrint(D_Error, ("Err3e\n")) *pHandle = NULL; // make sure null if not open return 1; } } #endif return 0; } /*----------------------------------------------------------------- our_open_driver_reg - |------------------------------------------------------------------*/ int our_open_driver_reg(OUT HANDLE *pHandle, IN ULONG RegOpenRights) { NTSTATUS status; int j, stat; OBJECT_ATTRIBUTES objAttribs; char tmpstr[200]; stat = MakeRegPath(szParameters); // this forms Driver.OptionRegPath if ( stat ) { *pHandle = NULL; // make sure null if not open return 1; } UToCStr(tmpstr, &Driver.OptionRegPath, sizeof(tmpstr)); stat = our_open_key(pHandle, NULL, tmpstr, RegOpenRights); if (stat != 0) { MyKdPrint(D_Error, ("Failed ZwOpenKey %s\n",tmpstr)) *pHandle = NULL; // make sure null if not open return 1; } return 0; } /*---------------------------------------------------------------------------- | ModemSpeakerEnable - wrappers around hardware routines to enable the | RocketModemII speaker... |----------------------------------------------------------------------------*/ void ModemSpeakerEnable(PSERIAL_DEVICE_EXTENSION ext) { MyKdPrint(D_Init,("ModemSpeakerEnable: %x\n",(unsigned long)ext)) #ifdef S_RK sModemSpeakerEnable(ext->ChP); #endif } /*---------------------------------------------------------------------------- | ModemWriteROW - wrappers around hardware routines to send ROW config | commands to SocketModems. |----------------------------------------------------------------------------*/ void ModemWriteROW(PSERIAL_DEVICE_EXTENSION ext,USHORT CountryCode) { int count; char *ModemConfigString; MyKdPrint(D_Init,("ModemWriteROW: %x, %x\n",(unsigned long)ext,CountryCode)) // DEBUG time_stall(10); // DEBUG #ifdef S_RK sModemWriteROW(ext->ChP,CountryCode); #else { // fix so compiles, 1-18-99 kpb static char *ModemConfigString = {"AT*NCxxZ\r"}; if (CountryCode == 0) { // bad country code, skip the write and let modem use power-on default MyKdPrint(D_Init,("Undefined ROW Write\n")) return; } if (CountryCode == ROW_NA) { MyKdPrint(D_Init,("ROW Write, North America\n")) return; } // create the country config string ModemConfigString[5] = '0' + (CountryCode / 10); ModemConfigString[6] = '0' + (CountryCode % 10); PortFlushTx(ext->Port); /* we just reset, so a flush shouldn't matter */ q_put(&ext->Port->QOut, ModemConfigString, strlen(ModemConfigString)); } #endif } #ifdef S_RK /******************************************************************** wrappers around hardware routines to send strings to modems... *********************************************************************/ void ModemWrite(PSERIAL_DEVICE_EXTENSION ext,char *string,int length) { sModemWrite(ext->ChP,string,length); } /******************************************************************** wrappers around hardware routines to send strings to modems... *********************************************************************/ int ModemRead(PSERIAL_DEVICE_EXTENSION ext, char *string,int length, int poll_retries) { return(sModemRead(ext->ChP,string,length,poll_retries)); } /******************************************************************** wrappers around hardware routines to send strings to modems... *********************************************************************/ int ModemReadChoice(PSERIAL_DEVICE_EXTENSION ext, char *s0,int len0, char *s1,int len1, int poll_retries) { return(sModemReadChoice(ext->ChP,s0,len0,s1,len1,poll_retries)); } /******************************************************************** wrappers around hardware routines to send strings to modems, one byte at a time... *********************************************************************/ void ModemWriteDelay(PSERIAL_DEVICE_EXTENSION ext, char *string,int length) { sModemWriteDelay(ext->ChP,string,length); } /******************************************************************** wrappers around hardware routines to check FIFO status... *********************************************************************/ int RxFIFOReady(PSERIAL_DEVICE_EXTENSION ext) { return(sRxFIFOReady(ext->ChP)); } int TxFIFOReady(PSERIAL_DEVICE_EXTENSION ext) { return(sTxFIFOReady(ext->ChP)); } int TxFIFOStatus(PSERIAL_DEVICE_EXTENSION ext) { return(sTxFIFOStatus(ext->ChP)); } /******************************************************************** wrappers around hardware routines to prepare modem ports for IO... *********************************************************************/ void ModemIOReady(PSERIAL_DEVICE_EXTENSION ext,int speed) { if (sSetBaudRate(ext->ChP,speed,FALSE)) { MyKdPrint(D_Init,("Unable to set baud rate to %d\n",speed)) return; } sFlushTxFIFO(ext->ChP); sFlushRxFIFO(ext->ChP); ext->BaudRate = speed; sSetBaudRate(ext->ChP,ext->BaudRate,TRUE); sSetData8(ext->ChP); sSetParity(ext->ChP,0); // No Parity sSetRxMask(ext->ChP,0xff); sClrTxXOFF(ext->ChP) /* destroy any pending stuff */ sEnRTSFlowCtl(ext->ChP); sEnCTSFlowCtl(ext->ChP); if (sGetChanStatus(ext->ChP) & STATMODE) { sDisRxStatusMode(ext->ChP); } sGetChanIntID(ext->ChP); sEnRxFIFO(ext->ChP); sEnTransmit(ext->ChP); /* enable transmitter if not already enabled */ sSetDTR(ext->ChP); sSetRTS(ext->ChP); } /******************************************************************** wrappers around hardware routines to shut down modem ports for now... *********************************************************************/ void ModemUnReady(PSERIAL_DEVICE_EXTENSION ext) { sFlushTxFIFO(ext->ChP); sFlushRxFIFO(ext->ChP); sSetData8(ext->ChP); sSetParity(ext->ChP,0); sSetRxMask(ext->ChP,0xff); ext->BaudRate = 9600; sSetBaudRate(ext->ChP,ext->BaudRate,TRUE); sClrTxXOFF(ext->ChP) // destroy any pending stuff if (sGetChanStatus(ext->ChP) & STATMODE) { sDisRxStatusMode(ext->ChP); } sGetChanIntID(ext->ChP); sDisRTSFlowCtl(ext->ChP); sDisCTSFlowCtl(ext->ChP); sClrRTS(ext->ChP); sClrDTR(ext->ChP); time_stall(1); // wait for port to quiet... } #endif // S_RK