/****************************************************************************/ // tdasync.c // // Serial Transport Driver // // Copyright (C) 1998-2000 Microsoft Corporation /****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "tdasync.h" #include "zwprotos.h" #ifdef _HYDRA_ // This becomes the device name PWCHAR ModuleName = L"tdasync"; #endif /*============================================================================= == External Functions Defined =============================================================================*/ NTSTATUS DeviceOpen( PTD, PSD_OPEN ); NTSTATUS DeviceClose( PTD, PSD_CLOSE ); NTSTATUS DeviceCreateEndpoint( PTD, PICA_STACK_ADDRESS, PICA_STACK_ADDRESS ); NTSTATUS DeviceOpenEndpoint( PTD, PVOID, ULONG ); NTSTATUS DeviceCloseEndpoint( PTD ); NTSTATUS DeviceInitializeWrite( PTD, POUTBUF ); NTSTATUS DeviceIoctl( PTD, PSD_IOCTL ); NTSTATUS DeviceConnectionWait( PTD, PVOID, ULONG, PULONG ); NTSTATUS DeviceConnectionSend( PTD ); NTSTATUS DeviceConnectionRequest( PTD, PVOID, PVOID, ULONG, PULONG ); NTSTATUS DeviceSetParams( PTD ); NTSTATUS DeviceWaitForStatus( PTD ); NTSTATUS DeviceInitializeRead( PTD, PINBUF ); NTSTATUS DeviceSubmitRead( PTD, PINBUF ); NTSTATUS DeviceWaitForRead( PTD ); NTSTATUS DeviceReadComplete( PTD, PUCHAR, PULONG ); NTSTATUS DeviceCancelIo( PTD ); NTSTATUS DeviceSetLastError( PTD, ULONG ); NTSTATUS DeviceGetLastError( PTD, PICA_STACK_LAST_ERROR ); /*============================================================================= == Local Functions Defined =============================================================================*/ BOOLEAN _CheckForConnect( PTD, ULONG, ULONG ); BOOLEAN _CheckForDisconnect( PTD, ULONG, ULONG ); VOID _UpdateAsyncStatus( PTD, PTDASYNC, ULONG, ULONG ); NTSTATUS _SetupComm( PTD, HANDLE, ULONG, ULONG ); NTSTATUS _SetCommTimeouts( PTD, HANDLE, PSERIAL_TIMEOUTS ); NTSTATUS _GetCommModemStatus( PTD, HANDLE, PULONG ); NTSTATUS _GetCommProperties( PTD, HANDLE, PSERIAL_COMMPROP); NTSTATUS _GetCommState( PTD, HANDLE, PSERIAL_BAUD_RATE, PSERIAL_LINE_CONTROL, PSERIAL_CHARS, PSERIAL_HANDFLOW ); NTSTATUS _SetCommState( PTD, HANDLE, PSERIAL_BAUD_RATE, PSERIAL_LINE_CONTROL, PSERIAL_CHARS, PSERIAL_HANDFLOW ); NTSTATUS _ClearCommError( PTD, HANDLE, PSERIAL_STATUS ); NTSTATUS _PurgeComm( PTD, HANDLE, ULONG ); NTSTATUS _WaitCommEvent( PTD, HANDLE, PULONG, PTDIOSTATUS ); NTSTATUS _SetCommMask( PTD, HANDLE, ULONG ); NTSTATUS _IoControl( PTD, HANDLE, ULONG, PVOID, ULONG, PVOID, ULONG, PULONG ); NTSTATUS _OpenDevice( PTD ); NTSTATUS _PrepareDevice( PTD ); NTSTATUS _FillInEndpoint( PTD, PVOID, ULONG, PULONG ); /*============================================================================= == Functions used =============================================================================*/ VOID OutBufFree( PTD, POUTBUF ); NTSTATUS MemoryAllocate( ULONG, PVOID * ); VOID MemoryFree( PVOID ); /******************************************************************************* * * DeviceOpen * * Allocate and initialize private data structures * * ENTRY: * pTd (input) * Pointer to td data structure * pSdOpen (output) * pointer to td open parameter block * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceOpen( PTD pTd, PSD_OPEN pSdOpen ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; NTSTATUS Status; /* * Set protocol driver class */ pTd->SdClass = SdAsync; pAsync = &pTd->Params.Async; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceOpen entry\n" )); /* * Return size of header and parameters */ pSdOpen->SdOutBufHeader = 0; pSdOpen->SdOutBufTrailer = 0; /* * Allocate ASYNC TD data structure */ Status = MemoryAllocate( sizeof(*pTdAsync), &pTdAsync ); if ( !NT_SUCCESS(Status) ) goto badalloc; pTd->pPrivate = pTdAsync; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceOpen, pTd 0x%x, pPrivate 0x%x, &pTd->pPrivate 0x%x\n", pTd, pTd->pPrivate, &pTd->pPrivate )); /* * Initialize TDASYNC data structure */ RtlZeroMemory( pTdAsync, sizeof(*pTdAsync) ); /* * Create event for status wait */ Status = ZwCreateEvent( &pTdAsync->hStatusEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceOpen, Create StatusEvent failed (0x%x)\n", Status )); goto badstatusevent; } Status = ObReferenceObjectByHandle( pTdAsync->hStatusEvent, EVENT_MODIFY_STATE, NULL, KernelMode, (PVOID *) &pTdAsync->pStatusEventObject, NULL ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceOpen, Create StatusEventObject failed (0x%x)\n", Status )); goto badstatuseventobj; } return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ /* * create of status event object pointer failed */ badstatuseventobj: (VOID) ZwClose( pTdAsync->hStatusEvent ); pTdAsync->hStatusEvent = 0; /* * create of status event failed */ badstatusevent: MemoryFree( pTd->pPrivate ); pTd->pPrivate = NULL; /* * allocate failed */ badalloc: return( Status ); } /******************************************************************************* * * DeviceClose * * Close transport driver * * NOTE: this must not close the serial device * * * ENTRY: * pTd (input) * Pointer to td data structure * pSdClose (input) * pointer to td close parameter block * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceClose( PTD pTd, PSD_CLOSE pSdClose ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceClose entry\n" )); /* * If necessary, close the endpoint now. */ if ( pTdAsync->fCloseEndpoint ) { DeviceCloseEndpoint( pTd ); } ObDereferenceObject( pTdAsync->pStatusEventObject ); (VOID) ZwClose( pTdAsync->hStatusEvent ); pTdAsync->pStatusEventObject = NULL; pTdAsync->hStatusEvent = 0; return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceCreateEndpoint * * Open and initialize serial device * * * ENTRY: * pTd (input) * Pointer to td data structure * pLocalAddress (input) * Pointer to local address (not used) * pReturnedAddress (input) * Pointer to location to save returned (created) address (not used) * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceCreateEndpoint( PTD pTd, PICA_STACK_ADDRESS pLocalAddress, PICA_STACK_ADDRESS pReturnedAddress ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; SERIAL_TIMEOUTS SerialTo; NTSTATUS Status; /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; Status = _OpenDevice( pTd ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceCreateEndpoint, _OpenDevice failed 0x%x\n", Status )); goto badopen; } Status = _PrepareDevice( pTd ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceCreateEndpoint, _PrepareDevice failed 0x%x\n", Status )); goto badprepare; } /* * Copy pointers for use by the common TD routines. */ pTd->pFileObject = pTdAsync->Endpoint.pFileObject; pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject; /* * If DeviceClose is called before a successful ConnectionWait, * then we must close the endpoint during the DeviceClose. */ pTdAsync->fCloseEndpoint = TRUE; return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ /* * PrepareDevice failed */ badprepare: ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent ); pTdAsync->Endpoint.SignalIoStatus.hEvent = NULL; /* * open failed */ badopen: pTdAsync->Endpoint.hDevice = 0; return( Status ); } /******************************************************************************* * * DeviceOpenEndpoint * * Open an existing endpoint * * ENTRY: * pTd (input) * Pointer to td data structure * pEndpoint (input) * Pointer to endpoint structure * EndpointLength (input) * length of endpoint data * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceOpenEndpoint( PTD pTd, PVOID pEndpoint, ULONG EndpointLength ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; ULONG Mask; PTDASYNC_ENDPOINT pEp; NTSTATUS Status; pEp = (PTDASYNC_ENDPOINT) pEndpoint; /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceOpenEndpoint, old endpoint h 0x%x, f 0x%x, d 0x%x\n", pEp->hDevice, pEp->pFileObject, pEp->pDeviceObject )); /* * copy disconnected Endpoint structure */ pTdAsync->Endpoint.hDevice = pEp->hDevice; pTdAsync->Endpoint.pFileObject = pEp->pFileObject; pTdAsync->Endpoint.pDeviceObject = pEp->pDeviceObject; pTdAsync->Endpoint.SignalIoStatus.pEventObject = pEp->SignalIoStatus.pEventObject; pTdAsync->Endpoint.SignalIoStatus.hEvent = pEp->SignalIoStatus.hEvent; /* * Copy pointers for use by the common TD routines. */ pTd->pFileObject = pTdAsync->Endpoint.pFileObject; pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject; if ( !pAsync->fConnectionDriver ) { /* * Set the comm event mask for status changes */ Mask = EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD; if ( pAsync->Connect.fEnableBreakDisconnect ) Mask |= EV_BREAK; Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask ); if ( !NT_SUCCESS( Status ) ) { goto badsetcomm; } } pTd->pFileObject = pTdAsync->Endpoint.pFileObject; pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject; return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ badsetcomm: return( Status ); } /******************************************************************************* * * DeviceCloseEndpoint * * Close Serial device * * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceCloseEndpoint( PTD pTd ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceCloseEndpoint \"%S\"\n", pTd->Params.Async.DeviceName )); /* * Dereference our pointer to the file object, * and "forget" about the device object pointer as well. */ if ( pTdAsync->Endpoint.pFileObject ) { ObDereferenceObject( pTdAsync->Endpoint.pFileObject ); } pTd->pFileObject = pTdAsync->Endpoint.pFileObject = NULL; pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject = NULL; /* * Close the device handle */ if ( pTdAsync->Endpoint.hDevice ) { TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceCloseEndpoint Closing Device handle 0x%x\n", pTdAsync->Endpoint.hDevice )); ZwClose( pTdAsync->Endpoint.hDevice ); } pTdAsync->Endpoint.hDevice = NULL; /* * Dereference the SignalIoStatus event */ if ( pTdAsync->Endpoint.SignalIoStatus.pEventObject ) { ObDereferenceObject( pTdAsync->Endpoint.SignalIoStatus.pEventObject ); } pTdAsync->Endpoint.SignalIoStatus.pEventObject = NULL; /* * Close the SignalIoStatus event handle */ if ( pTdAsync->Endpoint.SignalIoStatus.hEvent ) { (VOID) ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent ); } pTdAsync->Endpoint.SignalIoStatus.hEvent = 0; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceCloseEndpoint success\n" )); return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceInitializeWrite * * Initialize a write operation for this device. * * * ENTRY: * pTd (input) * Pointer to td data structure * pOutBuf * Pointer to the OutBuf for this operation. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceInitializeWrite( PTD pTd, POUTBUF pOutBuf ) { PIRP Irp; PIO_STACK_LOCATION _IRPSP; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceInitializeWrite Entry\n" )); Irp = pOutBuf->pIrp; _IRPSP = IoGetNextIrpStackLocation( Irp ); /* * Setup a WRITE IRP */ _IRPSP->MajorFunction = IRP_MJ_WRITE; _IRPSP->Parameters.Write.Length = pOutBuf->ByteCount; ASSERT( Irp->MdlAddress == NULL ); /* * Determine whether the target device performs direct or buffered I/O. */ if ( pTd->pDeviceObject->Flags & DO_BUFFERED_IO ) { /* * The target device supports buffered I/O operations. Since our * output buffer is allocated from NonPagedPool memory, we can just * point the SystemBuffer to the output buffer. No buffer copying * will be required. */ Irp->AssociatedIrp.SystemBuffer = pOutBuf->pBuffer; Irp->UserBuffer = pOutBuf->pBuffer; Irp->Flags |= IRP_BUFFERED_IO; } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) { /* * The target device supports direct I/O operations. * Initialize the MDL and point to it from the IRP. * * This MDL is allocated for every OUTBUF, and free'd with it. */ MmInitializeMdl( pOutBuf->pMdl, pOutBuf->pBuffer, pOutBuf->ByteCount ); MmBuildMdlForNonPagedPool( pOutBuf->pMdl ); Irp->MdlAddress = pOutBuf->pMdl; } else { /* * The operation is neither buffered nor direct. Simply pass the * address of the buffer in the packet to the driver. */ Irp->UserBuffer = pOutBuf->pBuffer; } return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceIoctl * * Query/Set configuration information for the td. * * ENTRY: * pTd (input) * Pointer to td data structure * pSdIoctl (input/output) * Points to the parameter structure SD_IOCTL * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceIoctl( PTD pTd, PSD_IOCTL pSdIoctl ) { NTSTATUS Status; PTDASYNC pTdAsync; SERIAL_TIMEOUTS SerialTo; PICA_STACK_TAPI_ENDPOINT pTe; pTdAsync = (PTDASYNC) pTd->pPrivate; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceIoctl, entry (0x%x)\n", pSdIoctl->IoControlCode )); switch ( pSdIoctl->IoControlCode ) { /* * Special IOCTL called when there is a connection driver * handling this device (i.e. a TAPI device). */ case IOCTL_ICA_STACK_CD_CREATE_ENDPOINT : ASSERT( pSdIoctl->InputBuffer ); ASSERT( pSdIoctl->InputBufferLength == sizeof(ICA_STACK_TAPI_ENDPOINT) ); ASSERT(pTd->Params.Async.fConnectionDriver); pTe = (PICA_STACK_TAPI_ENDPOINT) pSdIoctl->InputBuffer; /* * Dup the connection driver's handles * We do this instead of using the same handle since it * has been found possible for TAPI to close the device * handle out from under us BEFORE we process a disconnect. * Therefore, we dup our own handle here. */ Status = ZwDuplicateObject( NtCurrentProcess(), pTe->hDevice, NtCurrentProcess(), &pTdAsync->Endpoint.hDevice, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceIoctl, Dup device handle failed 0x%x\n", Status )); goto baddup1; } Status = ZwDuplicateObject( NtCurrentProcess(), pTe->hDiscEvent, NtCurrentProcess(), &pTdAsync->Endpoint.SignalIoStatus.hEvent, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceIoctl, Dup event handle failed 0x%x\n", Status )); goto baddup2; } /* * The application opened the device. One instance of this is a * modem that has been configured by TAPI. Note, that only the * handle is provided, all other driver-based initialization is * still required. */ TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceIoctl, duping TAPI handle (0x%x -> 0x%x)\n", pTe->hDevice, pTdAsync->Endpoint.hDevice )); /* * Using the supplied handle, prepare this driver and the device. */ Status = _PrepareDevice( pTd ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceIoctl, _PrepareDevice failed 0x%x\n", Status )); goto badprepare; } /* * Copy pointers for use by the common TD routines. */ pTd->pFileObject = pTdAsync->Endpoint.pFileObject; pTd->pDeviceObject = pTdAsync->Endpoint.pDeviceObject; _FillInEndpoint( pTd, pSdIoctl->OutputBuffer, pSdIoctl->OutputBufferLength, &pSdIoctl->BytesReturned ); break; default : return( STATUS_NOT_SUPPORTED ); } return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ badprepare: ZwClose( pTdAsync->Endpoint.SignalIoStatus.hEvent ); pTdAsync->Endpoint.SignalIoStatus.hEvent = NULL; baddup2: ZwClose( pTdAsync->Endpoint.hDevice ); pTdAsync->Endpoint.hDevice = NULL; baddup1: return( Status ); } /******************************************************************************* * * DeviceConnectionWait * * Wait for serial device to be powered on * -- (i.e. wait for DSR signal) * * NOTE: The endpoint structure is an opaque, variable length data * structure whose length and contents are determined by the * transport driver. * * * ENTRY: * pTd (input) * Pointer to td data structure * pEndpoint (output) * pointer to buffer to return copy of endpoint structure * Length (input) * length of endpoint buffer * pEndpointLength (output) * pointer to address to return actual length of Endpoint * * EXIT: * STATUS_SUCCESS - no error * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small * ******************************************************************************/ NTSTATUS DeviceConnectionWait( PTD pTd, PVOID pEndpoint, ULONG Length, PULONG pEndpointLength ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; ULONG ModemStatus; ULONG Error; ULONG Mask; NTSTATUS Status; ULONG ActualEndpointLength = sizeof(TDASYNC_ENDPOINT); PTDASYNC_ENDPOINT pEp = (PTDASYNC_ENDPOINT) pEndpoint; ASSERT( pEndpoint ); TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceConnectionWait, pTd 0x%x, pPrivate 0x%x\n", pTd, pTd->pPrivate )); _FillInEndpoint( pTd, pEndpoint, Length, pEndpointLength ); /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; if ( pAsync->fConnectionDriver ) { /* * If a connection Driver is handling this connection, * assume the connection has been established. */ goto complete; } /* * Set the comm event mask for connect wait */ Mask = EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD; if ( pAsync->Connect.Type == Connect_FirstChar ) Mask |= EV_RXCHAR; if ( pAsync->Connect.fEnableBreakDisconnect ) Mask |= EV_BREAK; Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask ); if ( !NT_SUCCESS( Status ) ) { goto badsetcomm; } for(;;) { /* * Post read for modem signal event */ if ( !pTdAsync->fCommEventIoctl ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceConnectionWait, hD 0x%x, hE 0x%x\n", pEp->hDevice, pTdAsync->Endpoint.SignalIoStatus.hEvent )); pTdAsync->EventMask = 0; Status = _WaitCommEvent( pTd, pTdAsync->Endpoint.hDevice, &pTdAsync->EventMask, &pTdAsync->Endpoint.SignalIoStatus ); if ( !NT_SUCCESS( Status ) ) { if ( Status != STATUS_PENDING ) { goto badwaitcomm; } } pTdAsync->fCommEventIoctl = TRUE; } /* * Get the current modem status */ Status = _GetCommModemStatus( pTd, pTdAsync->Endpoint.hDevice, &ModemStatus ); if ( !NT_SUCCESS( Status ) ) { goto badstatus; } /* * Update protocol status */ _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask ); /* * Check for connect */ if ( _CheckForConnect( pTd, ModemStatus, pTdAsync->EventMask ) ) { break; } /* * Wait for modem status to change */ Status = IcaWaitForSingleObject( pTd->pContext, pTdAsync->Endpoint.SignalIoStatus.pEventObject, INFINITE ); pTdAsync->fCommEventIoctl = FALSE; /* * Check error code */ if ( Status != STATUS_WAIT_0 ) { goto waiterror; } } /* forever */ if ( !pAsync->fConnectionDriver ) { /* * Update comm event mask */ if ( pAsync->Connect.Type == Connect_FirstChar ) { Mask &= ~EV_RXCHAR; Status = _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, Mask ); if ( !NT_SUCCESS( Status ) ) { goto badsetcomm; } } } complete: /* * After a successful return from ConnectionWait, we no longer * have to close the endpoint on a DeviceClose call. */ pTdAsync->fCloseEndpoint = FALSE; return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ /* * wait for object failed * get comm modem status failed * wait comm event failed * set comm mask failed */ waiterror: badstatus: badwaitcomm: badsetcomm: return( Status ); } /******************************************************************************* * * DeviceConnectionRequest * * Initiate a connection to the specified address * - this is not supported by the serial transport driver * * * ENTRY: * pTd (input) * Pointer to td data structure * pRemoteAddress (input) * pointer to remote address to connect to * pEndpoint (output) * pointer to buffer to return copy of endpoint structure * Length (input) * length of endpoint buffer * pEndpointLength (output) * pointer to address to return actual length of Endpoint * * EXIT: * STATUS_SUCCESS - no error * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small * ******************************************************************************/ NTSTATUS DeviceConnectionRequest( PTD pTd, PVOID pRemoteAddress, PVOID pEndpoint, ULONG Length, PULONG pEndpointLength ) { return( STATUS_INVALID_DEVICE_REQUEST ); } /******************************************************************************* * * DeviceConnectionSend * * Initialize host module data structure * -- this structure gets sent to the client * * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceConnectionSend( PTD pTd ) { PCLIENTMODULES pClient; /* * Get pointer to client structure */ pClient = pTd->pClient; /* * Initialize Td host module structure */ pClient->TdVersionL = VERSION_HOSTL_TDASYNC; pClient->TdVersionH = VERSION_HOSTH_TDASYNC; pClient->TdVersion = VERSION_HOSTH_TDASYNC; return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceSetParams * * set serial device pararameters * * ENTRY: * pTd (input) * Pointer to Td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceSetParams( PTD pTd ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; PFLOWCONTROLCONFIG pFlow; NTSTATUS Status; SERIAL_COMMPROP CommProp; SERIAL_BAUD_RATE Baud; SERIAL_LINE_CONTROL LineControl; SERIAL_CHARS Chars; SERIAL_HANDFLOW HandFlow; /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; /* * Get current State */ Status = _GetCommState( pTd, pTdAsync->Endpoint.hDevice, &Baud, &LineControl, &Chars, &HandFlow ); if ( !NT_SUCCESS( Status ) ) { goto badgetstate; } /* * Set defaults */ if (pAsync->fEnableDsrSensitivity) HandFlow.ControlHandShake = SERIAL_DSR_SENSITIVITY; else HandFlow.ControlHandShake = 0; HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE; if ( !pAsync->fConnectionDriver ) { /* * Set Communication parameters */ Baud.BaudRate = pAsync->BaudRate; LineControl.Parity = (BYTE) pAsync->Parity; LineControl.StopBits = (BYTE) pAsync->StopBits; LineControl.WordLength = (BYTE) pAsync->ByteSize; } /* * The following was taken from terminal code */ /* * sep92 on low mem rx buffer can be < 1024 * set rx buffer to nice 4096 bytes size * driver will do its best and set the Rx buffer to this size * if it fails then dwCurrentRxQueue will be the one we have * so do getcommprop again to fetch this value, which can * be used to set xoff and xon lims */ TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams Old State: XonLim %u, XoffLim %u\n", HandFlow.XonLimit, HandFlow.XoffLimit )); _GetCommProperties( pTd, pTdAsync->Endpoint.hDevice, &CommProp ); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams Old Queues: RxQueue %u, TxQueue %u\n", CommProp.CurrentRxQueue, CommProp.CurrentTxQueue )); _SetupComm( pTd, pTdAsync->Endpoint.hDevice, 4096, 4096 ); CommProp.CurrentRxQueue = 0; // dirty it so that we // can use this only if !=0 _GetCommProperties( pTd, pTdAsync->Endpoint.hDevice, &CommProp ); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams New Queues: RxQueue %u, TxQueue %u\n", CommProp.CurrentRxQueue, CommProp.CurrentTxQueue )); /* * if for some wierd reason CurrentRxQueue is not * filled in by the driver, then let xon xoff lims * be the default which the driver has. * (CurrentRxQueue was set to 0 before calling Get again) */ if (CommProp.CurrentRxQueue != 0) { HandFlow.XonLimit = (LONG)(CommProp.CurrentRxQueue / 4); HandFlow.XoffLimit = (LONG)(CommProp.CurrentRxQueue / 4); } pFlow = &pAsync->FlowControl; /* * Initialize default DTR state */ HandFlow.ControlHandShake &= ~SERIAL_DTR_MASK; if ( pFlow->fEnableDTR ) HandFlow.ControlHandShake |= SERIAL_DTR_CONTROL; /* * Initialize default RTS state */ HandFlow.FlowReplace &= ~SERIAL_RTS_MASK; if ( pFlow->fEnableRTS ) HandFlow.FlowReplace |= SERIAL_RTS_CONTROL; /* * Initialize flow control */ switch ( pFlow->Type ) { /* * Initialize hardware flow control */ case FlowControl_Hardware : switch ( pFlow->HardwareReceive ) { case ReceiveFlowControl_RTS : HandFlow.FlowReplace = (HandFlow.FlowReplace & ~SERIAL_RTS_MASK) | SERIAL_RTS_HANDSHAKE; break; case ReceiveFlowControl_DTR : HandFlow.ControlHandShake = (HandFlow.ControlHandShake & ~SERIAL_DTR_MASK) | SERIAL_DTR_HANDSHAKE; break; } switch ( pFlow->HardwareTransmit ) { case TransmitFlowControl_CTS : HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE; break; case TransmitFlowControl_DSR : HandFlow.ControlHandShake |= SERIAL_DSR_HANDSHAKE; break; } break; /* * Initialize software flow control */ case FlowControl_Software : if (pFlow->fEnableSoftwareTx) HandFlow.FlowReplace |= SERIAL_AUTO_TRANSMIT; if (pFlow->fEnableSoftwareRx) HandFlow.FlowReplace |= SERIAL_AUTO_RECEIVE; Chars.XonChar = (char) pFlow->XonChar; Chars.XoffChar = (char) pFlow->XoffChar; break; case FlowControl_None : break; default : ASSERT( FALSE ); break; } TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams: baud %u, par %u, stop %u, data %u, dtr %u, rts %u\n", Baud.BaudRate, LineControl.Parity, LineControl.StopBits, LineControl.WordLength, HandFlow.ControlHandShake & SERIAL_DTR_MASK, HandFlow.FlowReplace & SERIAL_RTS_MASK )); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams: fOutX %u, fInX %u, xon %x, xoff %x, cts %u, dsr %u\n", (HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0, (HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0, Chars.XonChar, Chars.XoffChar, (HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0, (HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0 )); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceSetParams: XonLimit %u, XoffLimit %u\n", HandFlow.XonLimit, HandFlow.XoffLimit )); /* * Set new State */ Status = _SetCommState( pTd, pTdAsync->Endpoint.hDevice, &Baud, &LineControl, &Chars, &HandFlow ); if ( !NT_SUCCESS( Status ) ) { goto badsetstate; } return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ /* * State set failed * State query failed */ badsetstate: badgetstate: return( Status ); } /******************************************************************************* * * DeviceInitializeRead * * This routine is called for each read, it also starts the "read" for * serial device status changes. * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceInitializeRead( PTD pTd, PINBUF pInBuf ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; NTSTATUS Status; ULONG ModemStatus; PIRP Irp; PIO_STACK_LOCATION _IRPSP; pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceInitializeRead entry\n" )); /* * Initialize the IRP for a READ */ Irp = pInBuf->pIrp; _IRPSP = IoGetNextIrpStackLocation( Irp ); _IRPSP->Parameters.Read.Length = pTd->InBufHeader + pTd->OutBufLength; _IRPSP->MajorFunction = IRP_MJ_READ; ASSERT( Irp->MdlAddress == NULL ); /* * Determine whether the target device performs direct or buffered I/O. */ if ( pTd->pDeviceObject->Flags & DO_BUFFERED_IO ) { /* * The target device supports buffered I/O operations. Since our * input buffer is allocated from NonPagedPool memory, we can just * point the SystemBuffer to our input buffer. No buffer copying * will be required. */ Irp->AssociatedIrp.SystemBuffer = pInBuf->pBuffer; Irp->UserBuffer = pInBuf->pBuffer; Irp->Flags |= IRP_BUFFERED_IO; } else if ( pTd->pDeviceObject->Flags & DO_DIRECT_IO ) { /* * The target device supports direct I/O operations. * If we haven't already done so, allocate an MDL large enough * to map the input buffer and indicate it is contained in * NonPagedPool memory. * * The MDL is preallocated in the PTD and never freed by the Device leve * TD. */ MmInitializeMdl( pInBuf->pMdl, pInBuf->pBuffer, pTd->InBufHeader+pTd->OutBufLength ); MmBuildMdlForNonPagedPool( pInBuf->pMdl ); Irp->MdlAddress = pInBuf->pMdl; } else { /* * The operation is neither buffered nor direct. Simply pass the * address of the buffer in the packet to the driver. */ Irp->UserBuffer = pInBuf->pBuffer; } /* * If there is not already an Ioctl pending for serial * device status, then initiate one now. DeviceWaitForRead * uses the event within the SignalIoStatus structure. * If a Connection Driver is handling this connection, the connection * driver created an event, and passed it down in the Endpoint. * The connection driver will take care of the signaling mechanism, * so no operations other than waiting on the event are required. * NOTE: The connection driver event will only be signaled on * Disconnects. */ if ( !pTdAsync->fCommEventIoctl && !pAsync->fConnectionDriver ) { /* * Get the current modem status */ Status = _GetCommModemStatus( pTd, pTdAsync->Endpoint.hDevice, &ModemStatus ); if ( !NT_SUCCESS( Status ) ) { goto badgetcomm; } /* * Update protocol status */ _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask ); /* * Check for a disconnect */ if ( _CheckForDisconnect( pTd, ModemStatus, pTdAsync->EventMask )) { Status = STATUS_CTX_CLOSE_PENDING; goto disconnect; } pTdAsync->EventMask = 0; Status = _WaitCommEvent( pTd, pTdAsync->Endpoint.hDevice, &pTdAsync->EventMask, &pTdAsync->Endpoint.SignalIoStatus ); if ( !NT_SUCCESS( Status ) ) { if ( Status != STATUS_PENDING ) { goto badwaitcomm; } } pTdAsync->fCommEventIoctl = TRUE; } TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceInitializeRead success\n" )); return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ badgetcomm: disconnect: badwaitcomm: TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceInitializeRead status (0x%x)\n", Status )); return( Status ); } /******************************************************************************* * * DeviceSubmitRead * * Submit the read IRP to the driver. * * ENTRY: * pTd (input) * Pointer to TD data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceSubmitRead( PTD pTd, PINBUF pInBuf ) { PIRP Irp; NTSTATUS Status; Irp = pInBuf->pIrp; Status = IoCallDriver( pTd->pDeviceObject, Irp ); return( Status ); } /******************************************************************************* * * DeviceWaitForRead * * This routine waits for input data and detects broken connections. * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * -1 - disconnected * ******************************************************************************/ NTSTATUS DeviceWaitForRead( PTD pTd ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; PKEVENT pWait[2]; ULONG ModemStatus; NTSTATUS Status; ULONG WaitCount; pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; /* * Setup wait for input data, and a communication event * if a Connection Driver isn't handling this connection. */ WaitCount = 0; pWait[WaitCount++] = &pTd->InputEvent; pWait[WaitCount++] = pTdAsync->Endpoint.SignalIoStatus.pEventObject; /* * Loop until input data or broken connection */ for(;;) { TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceWaitForRead Loop\n" )); Status = IcaWaitForMultipleObjects( pTd->pContext, WaitCount, pWait, WaitAny, INFINITE ); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: DeviceWaitForRead: WaitForMultiple status 0x%x\n", Status )); /* * Check if input data is available */ if ( Status == STATUS_WAIT_0 ) { if ( pAsync->fConnectionDriver ) { /* * Since the connection driver has control over this port, * the event-mask method of waiting for modem signal status * changes can't be used, since setting our mask will destroy * the one TAPI has established. This makes TAPI very unhappy. * * Now, you might be thinking - why not just wait for status * changes that TAPI has established, and update status then. * Well, that's possible, but there's something else which must * be considered. When we want to shut down the IOCTL that is * waiting for status changes, a change of the event mask is * required. Hence, this would alter what TAPI has set. */ /* * Get the current modem status */ Status = _GetCommModemStatus( pTd, pTdAsync->Endpoint.hDevice, &ModemStatus ); if ( Status != STATUS_SUCCESS ) { return( Status ); } /* * Update protocol status */ _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask ); } break; } else if ( pAsync->fConnectionDriver && Status == STATUS_WAIT_1 ) { /* * If a Connection Driver is handling this connection, this * event was signaled because a disconnect was detected by * the connection driver. */ if ( pTd->fCallbackInProgress ) { /* * During callback the client will disconnect, but * in this case we don't want the error going back up * the stack. */ continue; } else { return( STATUS_CTX_CLOSE_PENDING ); } } /* * If modem status event was not signaled, return error */ if ( Status != STATUS_WAIT_1 ) { return( Status ); } pTdAsync->fCommEventIoctl = FALSE; /* * Get the current modem status */ Status = _GetCommModemStatus( pTd, pTdAsync->Endpoint.hDevice, &ModemStatus ); if ( !NT_SUCCESS( Status ) ) { return( Status ); } /* * Update protocol status */ _UpdateAsyncStatus( pTd, pTdAsync, ModemStatus, pTdAsync->EventMask ); /* * Check for a disconnect */ if ( _CheckForDisconnect( pTd, ModemStatus, pTdAsync->EventMask ) ) { return( STATUS_CTX_CLOSE_PENDING ); } /* * Signal event wait semaphore */ ZwSetEvent( pTdAsync->hStatusEvent, NULL ); /* * Post another read for a modem signal event */ pTdAsync->EventMask = 0; Status = _WaitCommEvent( pTd, pTdAsync->Endpoint.hDevice, &pTdAsync->EventMask, &pTdAsync->Endpoint.SignalIoStatus ); if ( !NT_SUCCESS( Status ) ) { return( Status ); } pTdAsync->fCommEventIoctl = TRUE; } return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceReadComplete * * Do any read complete processing * * * ENTRY: * pTd (input) * Pointer to td data structure * pBuffer (input) * Pointer to input buffer * pByteCount (input/output) * Pointer to location containing byte count read * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceReadComplete( PTD pTd, PUCHAR pBuffer, PULONG pByteCount ) { return( STATUS_SUCCESS ); } /******************************************************************************* * * DeviceWaitForStatus * * This routine waits for RS232 signal status to change * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceWaitForStatus( PTD pTd ) { PTDASYNC pTdAsync; NTSTATUS Status; pTdAsync = (PTDASYNC) pTd->pPrivate; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceWaitForStatus: Entry\n" )); ASSERT(!pTd->Params.Async.fConnectionDriver); /* * Wait for status to change */ Status = IcaWaitForSingleObject( pTd->pContext, pTdAsync->pStatusEventObject, INFINITE ); return( Status ); } /******************************************************************************* * DeviceCancelIo * * cancel all current and future i/o ******************************************************************************/ NTSTATUS DeviceCancelIo(PTD pTd) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDASYNC: DeviceCancelIo Entry\n" )); pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; /* * Signal event wait semaphore */ ZwSetEvent(pTdAsync->hStatusEvent, NULL); if (!pAsync->fConnectionDriver) { /* * Clear comm mask. This will cause the _WaitCommEvent event * to be set which will then cause the input thread to wakeup. */ (VOID) _SetCommMask( pTd, pTdAsync->Endpoint.hDevice, 0 ); } /* * Cancel all outstanding writes */ (VOID) _PurgeComm( pTd, pTdAsync->Endpoint.hDevice, SERIAL_PURGE_TXABORT | SERIAL_PURGE_TXCLEAR ); /* * Purge the recieve buffer and any pending read. */ (VOID) _PurgeComm( pTd, pTdAsync->Endpoint.hDevice, SERIAL_PURGE_RXABORT | SERIAL_PURGE_RXCLEAR ); return STATUS_SUCCESS; } /******************************************************************************* * DeviceQueryRemoteAddress * * not supported for Async transport ******************************************************************************/ NTSTATUS DeviceQueryRemoteAddress( PTD pTd, PVOID pIcaEndpoint, ULONG EndpointSize, PVOID pOutputAddress, ULONG OutputAddressSize, PULONG BytesReturned) { // // unsupported for Async // return STATUS_NOT_SUPPORTED; } /******************************************************************************* * * DeviceSetLastError * * save serial error code * * * ENTRY: * pTd (input) * Pointer to td data structure * Error (input) * serial error code * * EXIT: * NT error code * ******************************************************************************/ NTSTATUS DeviceSetLastError( PTD pTd, ULONG Error ) { if ( Error == 0 ) return( STATUS_SUCCESS ); pTd->LastError = Error; (void) IcaLogError( pTd->pContext, Error, NULL, 0, &pTd->Params.Async, sizeof(pTd->Params.Async) ); return( STATUS_CTX_TD_ERROR ); } /******************************************************************************* * * DeviceGetLastError * * This routine returns the last serial error code and message * * ENTRY: * pTd (input) * Pointer to td data structure * pLastError (output) * address to return information on last protocol error * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS DeviceGetLastError( PTD pTd, PICA_STACK_LAST_ERROR pLastError ) { pLastError->Error = pTd->LastError; RtlZeroMemory( pLastError->Message, sizeof(pLastError->Message) ); return( STATUS_SUCCESS ); } /******************************************************************************* * * _CheckForConnect * * check for a connect signal * * ENTRY: * pTd (input) * Pointer to td data structure * ModemStatus (input) * modem status flags (MS_?) * EventMask (input) * event mask (EV_?) * * EXIT: * TRUE if connected, FALSE otherwise * ******************************************************************************/ BOOLEAN _CheckForConnect( PTD pTd, ULONG ModemStatus, ULONG EventMask ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _CheckForConnect: modem 0x%x, event 0x%x, connect 0x%x\n", ModemStatus, EventMask, pTd->Params.Async.Connect.Type )); switch( pTd->Params.Async.Connect.Type ) { case Connect_CTS : if ( ModemStatus & MS_CTS_ON ) return( TRUE ); break; case Connect_DSR : if ( ModemStatus & MS_DSR_ON ) return( TRUE ); break; case Connect_RI : if ( ModemStatus & MS_RING_ON ) return( TRUE ); break; case Connect_DCD : if ( ModemStatus & MS_RLSD_ON ) return( TRUE ); break; case Connect_FirstChar : if ( EventMask & EV_RXCHAR ) return( TRUE ); break; case Connect_Perm : return( TRUE ); } return( FALSE ); } /******************************************************************************* * * _CheckForDisconnect * * check for a disconnect signal * * ENTRY: * pTd (input) * Pointer to td data structure * ModemStatus (input) * modem status flags (MS_?) * EventMask (input) * event mask (EV_?) * * EXIT: * TRUE if disconnected, FALSE otherwise * ******************************************************************************/ BOOLEAN _CheckForDisconnect( PTD pTd, ULONG ModemStatus, ULONG EventMask ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _CheckForDisconnect: modem 0x%x, event 0x%x, connect 0x%x\n", ModemStatus, EventMask, pTd->Params.Async.Connect.Type )); switch( pTd->Params.Async.Connect.Type ) { case Connect_CTS : if ( !(ModemStatus & MS_CTS_ON) ) return( TRUE ); break; case Connect_DSR : if ( !(ModemStatus & MS_DSR_ON) ) return( TRUE ); break; case Connect_RI : if ( !(ModemStatus & MS_RING_ON) ) return( TRUE ); break; case Connect_DCD : if ( !(ModemStatus & MS_RLSD_ON) ) return( TRUE ); break; case Connect_FirstChar : if ( EventMask & EV_BREAK ) return( TRUE ); break; case Connect_Perm : return( FALSE ); } return( FALSE ); } /******************************************************************************* * * _UpdateAsyncStatus * * update async signal status * * ENTRY: * pTd (input) * Pointer to td data structure * pTdAsync (input) * Pointer to td async data structure * ModemStatus (input) * modem status flags (MS_?) * EventMask (input) * event mask (EV_?) * * EXIT: * nothing * ******************************************************************************/ VOID _UpdateAsyncStatus( PTD pTd, PTDASYNC pTdAsync, ULONG ModemStatus, ULONG EventMask ) { PPROTOCOLSTATUS pStatus; PFLOWCONTROLCONFIG pFlow; SERIAL_STATUS SerialStat; pStatus = pTd->pStatus; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _UpdateAsyncStatus: modem %x, event %x\n", ModemStatus, EventMask )); /* * Update modem status */ pStatus->AsyncSignal = ModemStatus; /* * Or in status of DTR and RTS */ pFlow = &pTd->Params.Async.FlowControl; if ( pFlow->fEnableDTR ) pStatus->AsyncSignal |= MS_DTR_ON; if ( pFlow->fEnableRTS ) pStatus->AsyncSignal |= MS_RTS_ON; /* * OR in new event mask * -- EventMask get cleared when user program reads info */ pStatus->AsyncSignalMask |= EventMask; /* * Update async error counters */ if ( EventMask & EV_ERR ) { (VOID) _ClearCommError( pTd, pTdAsync->Endpoint.hDevice, &SerialStat ); if ( SerialStat.Errors & SERIAL_ERROR_OVERRUN ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_OVERRUN\n" )); pStatus->Output.AsyncOverrunError++; } if ( SerialStat.Errors & SERIAL_ERROR_FRAMING ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_FRAMING\n" )); pStatus->Input.AsyncFramingError++; } if ( SerialStat.Errors & SERIAL_ERROR_QUEUEOVERRUN ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_QUEUEOVERRUN\n" )); pStatus->Input.AsyncOverflowError++; } if ( SerialStat.Errors & SERIAL_ERROR_PARITY ) { TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _UpdateAsyncStatus: SERIAL_ERROR_PARITY\n" )); pStatus->Input.AsyncParityError++; } } } /******************************************************************************* * * _SetCommTimeouts * * This function establishes the timeout characteristics for all * read and write operations on the handle specified by hFile. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to receive the settings. * The CreateFile function returns this value. * pTo (input) * Points to a structure containing timeout parameters. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _SetCommTimeouts( PTD pTd, HANDLE hFile, PSERIAL_TIMEOUTS pTo ) { NTSTATUS Status; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetCommTimeouts: ReadIntervalTimeout %d\n", pTo->ReadIntervalTimeout )); Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_TIMEOUTS, pTo, sizeof(*pTo), NULL, 0, NULL ); return Status; } /******************************************************************************* * * _GetCommModemStatus * This routine returns the most current value of the modem * status register's non-delta values. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be examined. * pModemStat (output) * Points to a ULONG which is to receive the mask of * non-delta values in the modem status register. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _GetCommModemStatus( PTD pTd, HANDLE hFile, PULONG pModemStat ) { NTSTATUS Status; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_MODEMSTATUS, NULL, 0, pModemStat, sizeof(*pModemStat), NULL ); return Status; } /******************************************************************************* * * _WaitCommEvent * This function will wait until any of the events occur that were * provided in the EvtMask parameter to _SetCommMask. If while waiting * the event mask is changed (via another call to SetCommMask), the * function will return immediately. The function will fill the EvtMask * pointed to by the pEvtMask parameter with the reasons that the * wait was satisfied. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be waited on. * The CreateFile function returns this value. * pEvtMask (output) * Points to a mask that will receive the reason that * the wait was satisfied. * pOverLapped (input) * An optional overlapped handle. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _WaitCommEvent( PTD pTd, HANDLE hFile, PULONG pEvtMask, PTDIOSTATUS pIoStatus ) { NTSTATUS Status; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _WaitCommEvent: entry\n" )); ASSERT(!pTd->Params.Async.fConnectionDriver); if (ARGUMENT_PRESENT(pIoStatus)) { pIoStatus->Internal = (ULONG)STATUS_PENDING; Status = ZwDeviceIoControlFile( hFile, pIoStatus->hEvent, NULL, NULL, (PIO_STATUS_BLOCK)&pIoStatus->Internal, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0, pEvtMask, sizeof(*pEvtMask) ); } else { Status = _IoControl( pTd, hFile, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0, pEvtMask, sizeof(*pEvtMask), NULL ); } return( Status ); } /******************************************************************************* * * _SetupComm * The communication device is not initialized until SetupComm is * called. This function allocates space for receive and transmit * queues. These queues are used by the interrupt-driven transmit/ * receive software and are internal to the provider. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to receive the settings. * InQueue (input) * Specifies the recommended size of the provider's * internal receive queue in bytes. This value must be * even. A value of -1 indicates that the default should * be used. * OutQueue (input) * Specifies the recommended size of the provider's * internal transmit queue in bytes. This value must be * even. A value of -1 indicates that the default should be used. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _SetupComm( PTD pTd, HANDLE hFile, ULONG InQueue, ULONG OutQueue ) { NTSTATUS Status; SERIAL_QUEUE_SIZE NewSizes = {0}; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetupComm: InQueue %d, OutQueue %d\n", InQueue, OutQueue )); /* * Make sure that the sizes are even. */ if (OutQueue != ((ULONG)-1)) { if (((OutQueue/2)*2) != OutQueue) { return( STATUS_INVALID_PARAMETER ); } } if (InQueue != ((ULONG)-1)) { if (((InQueue/2)*2) != InQueue) { return( STATUS_INVALID_PARAMETER ); } } NewSizes.InSize = InQueue; NewSizes.OutSize = OutQueue; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_QUEUE_SIZE, &NewSizes, sizeof(NewSizes), NULL, 0, NULL ); return Status; } /******************************************************************************* * * _SetCommMask * * The function enables the event mask of the communication device * specified by the hFile parameter. The bits of the EvtMask parameter * define which events are to be enabled. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to receive the settings. * EvtMask (input) * Specifies which events are to enabled. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _SetCommMask( PTD pTd, HANDLE hFile, ULONG EvtMask ) { ULONG LocalMask = EvtMask; NTSTATUS Status; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetCommMask: EventMask 0x%x\n", EvtMask )); /* * Make sure that the users mask doesn't contain any values * we don't support. */ if (EvtMask & (~(EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY | EV_CTS | EV_DSR | EV_RLSD | EV_BREAK | EV_ERR | EV_RING | EV_PERR | EV_RX80FULL | EV_EVENT1 | EV_EVENT2))) { return( STATUS_INVALID_PARAMETER ); } Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_WAIT_MASK, &LocalMask, sizeof(LocalMask), NULL, 0, NULL ); return Status; } /******************************************************************************* * * _GetCommProperties * * This function fills the ubffer pointed to by pCommProp with the * communications properties associated with the communications device * specified by the hFile. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be examined. * pCommProp (output) * Points to the PSERIAL_COMMPROP data structure that is to * receive the communications properties structure. This * structure defines certain properties of the communications * device. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _GetCommProperties( PTD pTd, HANDLE hFile, PSERIAL_COMMPROP pCommProp ) { NTSTATUS Status; ULONG bufferLength; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _GetCommProperties: Entry\n" )); /* * Get the total length of what to pass down. If the * application indicates that there is provider specific data * (by setting dwProvSpec1 to COMMPROP_INITIAILIZED) then * use what's at the start of the commprop. */ bufferLength = sizeof(pCommProp); /* * Zero out the commprop. This might create an access violation * if it isn't big enough. Which is ok, since we would rather * get it before we create the sync event. */ RtlZeroMemory(pCommProp, bufferLength); Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_PROPERTIES, NULL, 0, pCommProp, bufferLength, NULL ); return( Status ); } /******************************************************************************* * * _GetCommState * * This function returns the stae of the communication device specified by * hFile parameter. * * ENTRY:: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be examined. * pBuad (output) * Pointer to a SERIAL_BAUD_RATE structure * pLineControl (output) * Pointer to a SERIAL_LINE_CONTROL structure * pChars (ouptut) * Pointer to a SERIAL_CHARS structure * pHandFlow (ouptut) * Pointer to a SERIAL_HANDFLOW structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _GetCommState( PTD pTd, HANDLE hFile, PSERIAL_BAUD_RATE pBaud, PSERIAL_LINE_CONTROL pLineControl, PSERIAL_CHARS pChars, PSERIAL_HANDFLOW pHandFlow ) { NTSTATUS Status; if ( ARGUMENT_PRESENT( pBaud ) ) { Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_BAUD_RATE, NULL, 0, pBaud, sizeof(*pBaud), NULL ); if ( !NT_SUCCESS(Status)) { return( Status ); } } if ( ARGUMENT_PRESENT( pLineControl ) ) { Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, pLineControl, sizeof(*pLineControl), NULL ); if ( !NT_SUCCESS(Status)) { return( Status ); } } TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _GetCommState: Baud 0x%x, Sbits 0x%x, Par 0x%x, WLen 0x%x\n", pBaud->BaudRate, pLineControl->StopBits, pLineControl->Parity, pLineControl->WordLength )); if ( ARGUMENT_PRESENT( pChars ) ) { Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_CHARS, NULL, 0, pChars, sizeof(*pChars), NULL ); if ( !NT_SUCCESS(Status)) { return( Status ); } } if ( ARGUMENT_PRESENT( pHandFlow ) ) { Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, pHandFlow, sizeof(*pHandFlow), NULL ); if ( !NT_SUCCESS(Status)) { return( Status ); } } TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _GetCommState: EOF 0x%x,ERR 0x%x,BRK 0x%x,EVT 0x%x,XON 0x%x,XOF 0x%x\n", pChars->EofChar, pChars->ErrorChar, pChars->BreakChar, pChars->EventChar, pChars->XonChar, pChars->XoffChar )); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _GetCommState: CtrlHandS 0x%x,FlwRep 0x%x,XonL 0x%x,XoffL 0x%x\n", pHandFlow->ControlHandShake, pHandFlow->FlowReplace, pHandFlow->XonLimit, pHandFlow->XoffLimit )); return( STATUS_SUCCESS ); } /******************************************************************************* * * TdSetComState * * The _SetCommState function sets the communication device specified by * hfile parameter. This function reinitializes all hardwae and controls * as specified, but does not empty the transmit or receive queues. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be examined. * pBuad (input) * Pointer to a SERIAL_BAUD_RATE structure * pLineControl (input) * Pointer to a SERIAL_LINE_CONTROL structure * pChars (input) * Pointer to a SERIAL_CHARS structure * pHandFlow (input) * Pointer to a SERIAL_HANDFLOW structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _SetCommState( PTD pTd, HANDLE hFile, PSERIAL_BAUD_RATE pBaud, PSERIAL_LINE_CONTROL pLineControl, PSERIAL_CHARS pChars, PSERIAL_HANDFLOW pHandFlow ) { NTSTATUS Status; SERIAL_BAUD_RATE LocalBaud; SERIAL_LINE_CONTROL LocalLineControl; SERIAL_CHARS LocalChars; SERIAL_HANDFLOW LocalHandFlow; /* * Get the current state before any changes are made, so that * in the case of an error, the original state be restored. */ Status = _GetCommState( pTd, hFile, &LocalBaud, &LocalLineControl, &LocalChars, &LocalHandFlow ); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetCommState: Baud 0x%x, Sbits 0x%x, Par 0x%x, WLen 0x%x\n", pBaud->BaudRate, pLineControl->StopBits, pLineControl->Parity, pLineControl->WordLength )); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetCommState: EOF 0x%x,ERR 0x%x,BRK 0x%x,EVT 0x%x,XON 0x%x,XOF 0x%x\n", pChars->EofChar, pChars->ErrorChar, pChars->BreakChar, pChars->EventChar, pChars->XonChar, pChars->XoffChar )); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _SetCommState: CtrlHandS 0x%x,FlwRep 0x%x,XonL 0x%x,XoffL 0x%x\n", pHandFlow->ControlHandShake, pHandFlow->FlowReplace, pHandFlow->XonLimit, pHandFlow->XoffLimit )); if ( NT_SUCCESS( Status ) ) { /* * Try to set the baud rate. If we fail here, we just return * because we never actually got to set anything. */ Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_BAUD_RATE, pBaud, sizeof(*pBaud), NULL, 0, NULL ); if ( !NT_SUCCESS( Status ) ) goto badsetnorestore; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_LINE_CONTROL, pLineControl, sizeof(*pLineControl), NULL, 0, NULL ); if ( !NT_SUCCESS( Status ) ) goto badset; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_CHARS, pChars, sizeof(*pChars), NULL, 0, NULL ); if ( !NT_SUCCESS( Status ) ) goto badset; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_SET_HANDFLOW, pHandFlow, sizeof(*pHandFlow), NULL, 0, NULL ); if ( !NT_SUCCESS( Status ) ) goto badset; return( STATUS_SUCCESS ); } /* * Error Encountered, Restore previous state. */ badset: _SetCommState( pTd, hFile, &LocalBaud, &LocalLineControl, &LocalChars, &LocalHandFlow ); badsetnorestore: return( Status ); } /******************************************************************************* * * _PurgeComm * * This function is used to purge all characters from the transmit * or receive queues of the communication device specified by the * hFile parameter. The Flags parameter specifies what function * is to be performed. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be purged. * Flags (input) * Bit mask defining actions to be taken. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _PurgeComm( PTD pTd, HANDLE hFile, ULONG Flags ) { NTSTATUS Status; Status = _IoControl( pTd, hFile, IOCTL_SERIAL_PURGE, &Flags, sizeof(Flags), NULL, 0, NULL ); return( Status ); } /******************************************************************************* * * * _ClearCommError * * In case of a communications error, such as a buffer overrun or * framing error, the communications software will abort all * read and write operations on the communication port. No further * read or write operations will be accepted until this function * is called. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Specifies the communication device to be adjusted. * pStat (output) * Points to the SERIAL_STATUS structure that is to receive * the device status. The structure contains information * about the communications device. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _ClearCommError( PTD pTd, HANDLE hFile, PSERIAL_STATUS pStat ) { NTSTATUS Status; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _ClearCommError: Entry\n" )); RtlZeroMemory( pStat, sizeof(*pStat) ); Status = _IoControl( pTd, hFile, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0, pStat, sizeof(*pStat), NULL ); return( Status ); } /******************************************************************************* * * * _IoControl * * The _IoControl function performs a specified I/O control function. * * ENTRY: * pTd (input) * Pointer to td data structure * hFile (input) * Supplies the open handle to the file that the overlapped structure. * IoControlCode (input) * Value of the I/O control command * pIn (input) * Pointer to the I/O control command's input buffer. * InSize (input) * Size (in bytes) of input buffer. * pOut (output) * Pointer to the I/O control command's output buffer. * OutSize (input) * Size (in bytes) of output buffer. * pBytesWritten (output) * Size (in bytes) of data actually written to the output buffer. * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _IoControl( PTD pTd, HANDLE hFile, ULONG IoControlCode, PVOID pIn, ULONG InSize, PVOID pOut, ULONG OutSize, PULONG pBytesWritten ) { IO_STATUS_BLOCK Iosb; HANDLE hEvent; NTSTATUS Status; TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _IoControl: Entry\n" )); Status = ZwCreateEvent( &hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ); if ( !NT_SUCCESS( Status ) ) { return Status; } Status = ZwDeviceIoControlFile( hFile, hEvent, NULL, NULL, &Iosb, IoControlCode, pIn, InSize, pOut, OutSize ); if ( Status == STATUS_PENDING ) { PKEVENT pEventObject; // Operation must complete before return & IoStatusBlock destroyed Status = ObReferenceObjectByHandle( hEvent, EVENT_MODIFY_STATE, NULL, KernelMode, (PVOID *) &pEventObject, NULL ); if ( NT_SUCCESS( Status ) ) { Status = IcaWaitForSingleObject( pTd->pContext, pEventObject, INFINITE ); ObDereferenceObject( pEventObject ); if ( NT_SUCCESS( Status ) ) { Status = Iosb.Status; } } } if ( ARGUMENT_PRESENT( pBytesWritten ) ) { *pBytesWritten = (ULONG)Iosb.Information; } ZwClose( hEvent ); return Status; } /******************************************************************************* * * _OpenDevice * * Open the communications device. * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _OpenDevice( PTD pTd ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES Obja; UNICODE_STRING DeviceName; DEVICENAMEW TempDeviceName; NTSTATUS Status; /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; /* * Open device */ wcscpy( TempDeviceName, L"\\DosDevices\\" ); wcscat( TempDeviceName, pAsync->DeviceName ); TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _OpenDevice, Opening \"%S\"\n", TempDeviceName )); RtlInitUnicodeString( &DeviceName, TempDeviceName); InitializeObjectAttributes( &Obja, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = ZwOpenFile( &pTdAsync->Endpoint.hDevice, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &Obja, &ioStatusBlock, 0, // ShareAccess FILE_NON_DIRECTORY_FILE ); if ( !NT_SUCCESS( Status ) ) { if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) { Status = STATUS_NO_SUCH_DEVICE; } goto badopen; } /* * Create event for I/O status */ Status = ZwCreateEvent( &pTdAsync->Endpoint.SignalIoStatus.hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: _OpenDevice, Create SignalEvent failed (0x%x)\n", Status )); goto badcreateevent; } TRACE(( pTd->pContext, TC_TD, TT_API2, "TDASYNC: _OpenDevice, SignalIoStatus event handle 0x%x\n", pTdAsync->Endpoint.SignalIoStatus.hEvent )); return( Status ); /*============================================================================= == Error returns =============================================================================*/ /* * Create of SignalIoStatus event failed. */ badcreateevent: ZwClose( pTdAsync->Endpoint.hDevice ); pTdAsync->Endpoint.hDevice = NULL; /* * OpenFile failed */ badopen: return( Status ); } /******************************************************************************* * * _PrepareDevice * * Prepare the communications device for ICA use. * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error * ******************************************************************************/ NTSTATUS _PrepareDevice( PTD pTd ) { PTDASYNC pTdAsync; PASYNCCONFIG pAsync; SERIAL_TIMEOUTS SerialTo; NTSTATUS Status; /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; pAsync = &pTd->Params.Async; /* * Obtain a referenced pointer to the file object. */ Status = ObReferenceObjectByHandle ( pTdAsync->Endpoint.hDevice, 0, *IoFileObjectType, KernelMode, (PVOID *)&pTdAsync->Endpoint.pFileObject, NULL ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: _PrepareDevice, ObReferenceObjectByHandle Device failed (0x%x)\n", Status )); goto badhandleobj; } pTdAsync->Endpoint.pDeviceObject = IoGetRelatedDeviceObject( pTdAsync->Endpoint.pFileObject); /* * Obtain a reference pointer to the SignalIoStatus Event */ Status = ObReferenceObjectByHandle( pTdAsync->Endpoint.SignalIoStatus.hEvent, EVENT_MODIFY_STATE, NULL, KernelMode, (PVOID *) &pTdAsync->Endpoint.SignalIoStatus.pEventObject, NULL ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: _PrepareDevice, ObReferenceObjectByHandle SignalEventObject failed (0x%x)\n", Status )); goto badsigeventobj; } /* * Set timeout parameters */ RtlZeroMemory( &SerialTo, sizeof(SerialTo) ); SerialTo.ReadIntervalTimeout = 1; // msec Status = _SetCommTimeouts( pTd, pTdAsync->Endpoint.hDevice, &SerialTo); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: _SetCommTimeouts failed 0x%x\n", Status )); goto badsetmode; } /* * Set communication parameters */ Status = DeviceSetParams( pTd ); if ( !NT_SUCCESS( Status ) ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceSetParams failed 0x%x\n", Status )); goto badparams; } return( STATUS_SUCCESS ); /*============================================================================= == Error returns =============================================================================*/ /* * set of communication parameters failed * set of timeout mode failed */ badparams: badsetmode: ObDereferenceObject( pTdAsync->Endpoint.SignalIoStatus.pEventObject ); pTdAsync->Endpoint.SignalIoStatus.pEventObject = NULL; badsigeventobj: ObDereferenceObject( pTdAsync->Endpoint.pFileObject ); pTdAsync->Endpoint.pFileObject = NULL; badhandleobj: return( Status ); } /******************************************************************************* * * _FillInEndpoint * * Fill in the endpoint to be returned via the ioctl's output buffer * * ENTRY: * pTd (input) * Pointer to td data structure * pEndpoint (output) * pointer to buffer to return copy of endpoint structure * Length (input) * length of endpoint buffer * pEndpointLength (output) * pointer to address to return actual length of Endpoint * * EXIT: * STATUS_SUCCESS - no error * STATUS_BUFFER_TOO_SMALL - endpoint buffer is too small * ******************************************************************************/ NTSTATUS _FillInEndpoint( PTD pTd, PVOID pEndpoint, ULONG Length, PULONG pEndpointLength ) { PTDASYNC pTdAsync; ULONG ActualEndpointLength = sizeof(TDASYNC_ENDPOINT); PTDASYNC_ENDPOINT pEp = (PTDASYNC_ENDPOINT) pEndpoint; /* * Always return actual size of Endpoint. */ if ( ARGUMENT_PRESENT( pEndpointLength ) ) { *pEndpointLength = ActualEndpointLength; } /* * Make sure endpoint buffer is large enough */ if ( ARGUMENT_PRESENT( pEndpoint ) && Length < ActualEndpointLength ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDASYNC: DeviceConnectionWait, Buffer too small %d, %d req'd\n", Length, ActualEndpointLength )); return( STATUS_BUFFER_TOO_SMALL ); } /* * Get pointer to async parameters */ pTdAsync = (PTDASYNC) pTd->pPrivate; /* * copy Endpoint structure */ if ( ARGUMENT_PRESENT( pEndpoint ) ) { pEp->hDevice = pTdAsync->Endpoint.hDevice; pEp->pFileObject = pTdAsync->Endpoint.pFileObject; pEp->pDeviceObject = pTdAsync->Endpoint.pDeviceObject; pEp->SignalIoStatus.pEventObject = pTdAsync->Endpoint.SignalIoStatus.pEventObject; pEp->SignalIoStatus.hEvent = pTdAsync->Endpoint.SignalIoStatus.hEvent; } return( STATUS_SUCCESS ); }