You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3356 lines
95 KiB
3356 lines
95 KiB
/*-------------------------------------------------------------------
|
|
| 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<len; i++)
|
|
{
|
|
trace_buf[j] = (CHAR) newdata[i];
|
|
if ((trace_buf[j] < 0x20) || (trace_buf[j] > 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 = "<float format not supported>";
|
|
len = strlen(str);
|
|
goto EmitString;
|
|
|
|
default:
|
|
str = "<bad format character>";
|
|
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; i<tenth_secs; i++)
|
|
{
|
|
// set wait-time to .1 second.(-1000 000 = relative(-), 100-ns units)
|
|
//WaitTime = RtlConvertLongToLargeInteger(-1000000L);
|
|
// set wait-time to .1 second.(-1000 000 = relative(-), 100-ns units)
|
|
WaitTime.QuadPart = -1000000L;
|
|
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
ms_time_stall -
|
|
|----------------------------------------------------------------------*/
|
|
void ms_time_stall(int millisecs)
|
|
{
|
|
int i;
|
|
LARGE_INTEGER WaitTime; // Actual time req'd for buffer to drain
|
|
|
|
// set wait-time to .001 second.(-10000 = relative(-), 100-ns units)
|
|
WaitTime.QuadPart = -10000L * millisecs;
|
|
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
str_to_wstr_dup - allocate wchar string and convert from char to wchar.
|
|
|----------------------------------------------------------------------*/
|
|
WCHAR *str_to_wstr_dup(char *str, int alloc_space)
|
|
{
|
|
WCHAR *wstr;
|
|
WCHAR *wtmpstr;
|
|
int siz;
|
|
siz = (strlen(str) * 2) + 4;
|
|
|
|
wstr = ExAllocatePool (alloc_space, siz);
|
|
if ( wstr ) {
|
|
RtlZeroMemory(wstr, siz);
|
|
wtmpstr = wstr;
|
|
while (*str != 0)
|
|
{
|
|
*wtmpstr = (WCHAR) *str;
|
|
++wtmpstr;
|
|
++str;
|
|
}
|
|
}
|
|
return wstr;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
NumDevices - return number of devices in device linked list.
|
|
|----------------------------------------------------------------------*/
|
|
int NumDevices(void)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION board_ext = NULL;
|
|
int num_devices;
|
|
|
|
num_devices = 0;
|
|
while (board_ext != NULL)
|
|
{
|
|
board_ext = board_ext->board_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; i<HDLC_TX_PKT_QUEUE_SIZE; i++ ) {
|
|
if ( (hd->TxPackets[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; i<HDLC_TX_PKT_QUEUE_SIZE; i++ ) {
|
|
if ( (hd->TxPackets[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
|