/*++ Copyright (c) 1998 Gemplus developpement Name: GNTSER.C (Gemplus Win NT SERial port management) Description : This module holds the functions needed for a communication on a serial line. Environment: Kernel mode Revision History : dd/mm/yy 13/03/98: V1.00.001 (GPZ) - Start of development. 26/04/98: V1.00.002 (GPZ) 22/01/99: V1.00.003 (YN) - Remove the IRPCancel durnig call the serial driver --*/ #include #include "gntscr.h" #include "gntser.h" // // Type section: // TPORT_CONFIG: // - WaitRelease holds the timeout for the release of the semaphore. // - Counter holds the number of opened session. If its value is 0, the port is // closed. // - Error holds Rx over state. // - TimeOut holds the character level time out. // - TxSize memorises the transmit buffer size. // - RxSize memorises the reception buffer size. // - pSerialPortDevice is a pointer on the serial Device Object. // typedef struct { ULONG WaitRelease; USHORT Counter; short Error; ULONG TimeOut; USHORT TxSize; USHORT RxSize; PDEVICE_OBJECT pSerialPortDevice; PKMUTEX pExchangeMutex; } TPORT_CONFIG; #define GTSER_DEF_WAIT_RELEASE 2000 #define GTSER_IOCTL_WRITE SCARD_CTL_CODE(1001) #define GTSER_IOCTL_READ SCARD_CTL_CODE(1000) // // Macro section: // - WORD_LEN, PARITY and STOP retreive the configuration values to pass to // Windows to configure the port. // #define WORD_LEN(x) (BYTE)(((x) & 0x03) + 5) #define PARITY(x) (BYTE)(parity[((BYTE)(x) >> 3) & 3]) #define STOP(x) (BYTE)(stop[((x) >> 2) & 1]) // // Global variable section: // - port_config is an array of TPORT_CONFIG which memorises the port // configuration at each time. // TPORT_CONFIG port_config[HGTSER_MAX_PORT] = { {0,0,0,0,0,0,NULL,NULL}, {0,0,0,0,0,0,NULL,NULL}, {0,0,0,0,0,0,NULL,NULL}, {0,0,0,0,0,0,NULL,NULL} }; static USHORT parity[] = { NO_PARITY, ODD_PARITY, NO_PARITY, EVEN_PARITY }; static USHORT stop[] = { STOP_BIT_1, STOP_BITS_2 }; // // Local function definition section: // static NTSTATUS GDDKNT_GetCommStatus ( const SHORT Handle, SERIAL_STATUS *SerialStatus ); NTSTATUS GDDK_SerPortOpen( const TGTSER_PORT *Param, SHORT *Handle ) /*++ Routine Description: This routine opens a serial port and initializes it according to the parameters found in Param. Arguments: Param holds the following parameters: - Port indicates the selected port. - BaudRate is used to set port baud rate. - Mode gathers * word size WORD_5 (0), WORD_6 (1), WORD_7 (2) or WORD_8 (3), * stop bit number STOP_BIT_1 (0) or STOP_BIT_2 (4) and * parity NO_PARITY (0), ODD_PARITY (8) or EVEN_PARITY (24). - TxSize is the transmit buffer size, in bytes. - RxSize is the reception buffer size, in bytes. --*/ { NTSTATUS status; PSMARTCARD_EXTENSION SmartcardExtension; SERIAL_READER_CONFIG SerialConfig; PREADER_EXTENSION pReaderExtension; SERIAL_QUEUE_SIZE SerialQueueSize; USHORT LengthOut = 0; SHORT handle = Param->Port - 1; // Controls the given parameters: if ((handle < 0) || (handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[handle].Counter != 0) { return STATUS_DEVICE_ALREADY_ATTACHED; } // Retrieve the SmartcardExtension structure of the current device. SmartcardExtension = (PSMARTCARD_EXTENSION)(Param->pSmartcardExtension); pReaderExtension = SmartcardExtension->ReaderExtension; port_config[handle].pSerialPortDevice = pReaderExtension->AttachedDeviceObject; port_config[handle].pExchangeMutex = &pReaderExtension->ExchangeMutex; // The current port state is read and stored in current_dcb structure by // calling GetCommState function. // If the reading is possible (GetCommState return 0) // Then // The current_dcb structure is updated with the given parameter (baud // rate, ByteSize, Parity, StopBits). // The modified state is written by calling SetCommState. status = GDDKNT_GetCommState(handle,&SerialConfig); if (NT_SUCCESS(status)) { SerialQueueSize.InSize = 4096L; SerialQueueSize.OutSize = 4096L; status = GDDKNT_SerPortIoRequest( handle, IOCTL_SERIAL_SET_QUEUE_SIZE, 500UL, sizeof(SERIAL_QUEUE_SIZE), (PUCHAR)&SerialQueueSize, &LengthOut, NULL ); // Set the serial port communication parameters SerialConfig.BaudRate.BaudRate = Param->BaudRate; SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode); SerialConfig.LineControl.Parity = PARITY(Param->Mode); SerialConfig.LineControl.StopBits = STOP(Param->Mode); // Set timeouts SerialConfig.Timeouts.ReadIntervalTimeout = 1000; SerialConfig.Timeouts.ReadTotalTimeoutConstant = 50000; SerialConfig.Timeouts.ReadTotalTimeoutMultiplier = 0; // 50; // Set special characters SerialConfig.SerialChars.ErrorChar = 0; SerialConfig.SerialChars.EofChar = 0; SerialConfig.SerialChars.EventChar = 0; SerialConfig.SerialChars.XonChar = 0; SerialConfig.SerialChars.XoffChar = 0; SerialConfig.SerialChars.BreakChar = 0xFF; // Set handflow SerialConfig.HandFlow.XonLimit = 0; SerialConfig.HandFlow.XoffLimit = 0; SerialConfig.HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE ; SerialConfig.HandFlow.ControlHandShake = 0; status = GDDKNT_SetCommState(handle,&SerialConfig); } if (!NT_SUCCESS(status)) { return status; } // Memorises the given parameters in port_config structure. // Counter, Error, TimeOut, TxSize and RxSize fields are updated. port_config[handle].Counter = 1; port_config[handle].Error = 0; port_config[handle].TimeOut = Param->TimeOut; port_config[handle].TxSize = Param->TxSize; port_config[handle].RxSize = Param->RxSize; // We update the handle value. *Handle = handle; return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortAddUser( const SHORT Port, SHORT *Handle ) /*++ Routine Description: Add a new user on a port. This function return the handle of a previously opened port. When this function is successful, it is mandatory to call G_SerPortClose to decrement the user number. Arguments: Port - indicates the selected port: G_COMx Return Value: --*/ { // Controls the given parameters: if ((Port < G_COM1) || (Port > G_COM4)) { return STATUS_INVALID_PARAMETER; } if (port_config[Port - 1].Counter == 0) { return STATUS_PORT_DISCONNECTED; } if (port_config[Port - 1].Counter == 65535lu) { return STATUS_INSUFFICIENT_RESOURCES; } // Increments the port_config.Counter. port_config[Port - 1].Counter += 1; // We return the Port number. *Handle = Port - 1; return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortClose ( const SHORT Handle ) /*++ Routine Description: This routine closes a previously opened serial port. When port is shared, the close will be effective only when all clients will have closed the port. Arguments: Handle - holds the port handle. Return Value: --*/ { // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { return STATUS_PORT_DISCONNECTED; } // Decrements the port_config.Counter field. port_config[Handle].Counter -= 1; // Closes really the port for the last user: // The queues are flushed. if (port_config[Handle].Counter == 0) { GDDK_SerPortFlush(Handle,SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_TXABORT); } return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortWrite( const SHORT Handle, const USHORT Length, const BYTE Buffer[] ) /*++ Routine Description: This routine writes bytes on a previously opened serial port. Arguments: Handle - holds the port handle. Length - holds the number of bytes to write. Buffer - holds the bytes to write. Return Value: --*/ { NTSTATUS status; SERIAL_STATUS SerialStatus; USHORT LengthOut; ASSERT(Buffer != NULL); // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { return STATUS_PORT_DISCONNECTED; } // Control if the write can be made in one time: // The windows port status is read by calling GetCommError to know how many // bytes remain in Tx queue (port_config.Error field is updated if needed). status = GDDKNT_GetCommStatus(Handle,&SerialStatus); ASSERT(status == STATUS_SUCCESS); if (status != STATUS_SUCCESS) { return status; } port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors); if (Length > ( port_config[Handle].TxSize - SerialStatus.AmountInOutQueue)) { return STATUS_INVALID_PARAMETER; } // Writes the given byte in Tx queue . // If an error occurs during this operation // Then // The ClearCommError function is called to unblock the port // (port_config.Error field is updated if needed). LengthOut = 0; status = GDDKNT_SerPortIoRequest( Handle, GTSER_IOCTL_WRITE, 500UL, Length, Buffer, &LengthOut, NULL ); if (!NT_SUCCESS(status)) { GDDKNT_GetCommStatus(Handle,&SerialStatus); port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors); LengthOut = 0; status = GDDKNT_SerPortIoRequest( Handle, IOCTL_SERIAL_RESET_DEVICE, 500UL, 0, NULL, &LengthOut, NULL ); return STATUS_PORT_DISCONNECTED; } return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortRead( const SHORT Handle, USHORT *Length, BYTE Buffer[] ) /*++ Routine Description: This routine reads bytes on a previously opened serial port. It ends when required length = read length or when a character level timeout is detected. Arguments: Handle - holds the port handle. Length - holds the number of bytes to read. Buffer - is a free area of, at least, Length bytes. Return Value: --*/ { NTSTATUS status; ASSERT(Buffer != NULL); // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { *Length = 0; return STATUS_PORT_DISCONNECTED; } // Try to read the bytes. status = GDDKNT_SerPortIoRequest( Handle, GTSER_IOCTL_READ, port_config[Handle].TimeOut, 0, NULL, Length, Buffer ); if (!NT_SUCCESS(status)) { return status; } else { if (*Length == 0) { return STATUS_INVALID_DEVICE_STATE; } } return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortFlush( const SHORT Handle, const USHORT Select ) /*++ Routine Description: This function clears Tx and Rx buffers. When RX_QUEUE is selected, the RX_OVER flag is reseted. Arguments: Handle - holds the port handle. Select - holds the buffers to clear: Return Value: --*/ { NTSTATUS status; USHORT LengthOut = 0; ULONG PurgeMask; // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { return STATUS_PORT_DISCONNECTED; } // Clears the selected queues if (Select & HGTSER_TX_QUEUE) { PurgeMask = SERIAL_PURGE_TXCLEAR; } if (Select & HGTSER_RX_QUEUE) { PurgeMask = SERIAL_PURGE_RXCLEAR; port_config[Handle].Error = 0; } status = GDDKNT_SerPortIoRequest( Handle, IOCTL_SERIAL_PURGE, 500UL, sizeof(PurgeMask), (PUCHAR)&PurgeMask, &LengthOut, NULL ); return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortGetState( const SHORT Handle, TGTSER_PORT *Param, USHORT *UserNb ) /*++ Routine Description: This routine read the currently in use parameters for an opened serial port. Arguments: Handle - holds the port handle. Param - is a pointer on the Param structure. UserNb - is a pointer on the number of user for this port. Return Value: --*/ { NTSTATUS status; SERIAL_READER_CONFIG SerialConfig; ASSERT(Param != NULL); ASSERT(UserNb != NULL); // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { return STATUS_PORT_DISCONNECTED; } // The current port state is read and stored in current_dcb structure by calling // GetCommState function. status = GDDKNT_GetCommState(Handle,&SerialConfig); if (!NT_SUCCESS(status)) { return status; } // The parameters are updated with the read values. Param->BaudRate = SerialConfig.BaudRate.BaudRate; switch (SerialConfig.LineControl.WordLength) { case 5: Param->Mode = HGTSER_WORD_5; break; case 6: Param->Mode = HGTSER_WORD_6; break; case 7: Param->Mode = HGTSER_WORD_7; break; case 8: Param->Mode = HGTSER_WORD_8; break; default: return STATUS_INVALID_DEVICE_STATE; } switch (SerialConfig.LineControl.Parity) { case NO_PARITY: Param->Mode |= HGTSER_NO_PARITY; break; case ODD_PARITY: Param->Mode |= HGTSER_ODD_PARITY; break; case EVEN_PARITY: Param->Mode |= HGTSER_EVEN_PARITY; break; case SERIAL_PARITY_MARK: case SERIAL_PARITY_SPACE: default: return STATUS_INVALID_DEVICE_STATE; } switch (SerialConfig.LineControl.StopBits) { case STOP_BIT_1: Param->Mode |= HGTSER_STOP_BIT_1; break; case STOP_BITS_2: Param->Mode |= HGTSER_STOP_BIT_2; break; case STOP_BITS_1_5: default: return STATUS_INVALID_DEVICE_STATE; } // Updates the library fields TimeOut, TxSize and RxSize. Param->TimeOut = port_config[Handle].TimeOut; Param->TxSize = port_config[Handle].TxSize; Param->RxSize = port_config[Handle].RxSize; // The UserNb parameter is filled with the port_config.Counter. *UserNb = port_config[Handle].Counter; return STATUS_SUCCESS; } NTSTATUS GDDK_SerPortSetState( const SHORT Handle, TGTSER_PORT *Param ) /*++ Routine Description: This routine alters the currently in use parameters for an opened serial port. Arguments: Handle - holds the port handle. Param - is a pointer on the Param structure. Return Value: --*/ { NTSTATUS status; SERIAL_READER_CONFIG SerialConfig; ULONG error = 0; ASSERT(Param != NULL); // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return STATUS_INVALID_PARAMETER; } if (port_config[Handle].Counter == 0) { return STATUS_PORT_DISCONNECTED; } status = GDDKNT_GetCommState(Handle,&SerialConfig); if (NT_SUCCESS(status)) { SerialConfig.BaudRate.BaudRate = Param->BaudRate; SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode); SerialConfig.LineControl.Parity = PARITY(Param->Mode); SerialConfig.LineControl.StopBits = STOP(Param->Mode); status = GDDKNT_SetCommState(Handle,&SerialConfig); } if (!NT_SUCCESS(status)) { return status; } // Updates the library fields TimeOut, TxSize and RxSize. port_config[Handle].TimeOut = Param->TimeOut; port_config[Handle].TxSize = Param->TxSize; port_config[Handle].RxSize = Param->RxSize; return status; } BOOLEAN GDDK_SerPortLockComm( const SHORT Handle, const ULONG WaitRelease ) /*++ Routine Description: Take the mutex for a serial port communication if is free or wait the release Arguments: Handle - holds the port handle WaitRelease - holds the new time to wait the release Return Value: --*/ { NTSTATUS status; LARGE_INTEGER timeout; // Controls the given parameters: if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) { return FALSE; } timeout.QuadPart = -((LONGLONG)( port_config[Handle].WaitRelease > GTSER_DEF_WAIT_RELEASE ? port_config[Handle].WaitRelease : GTSER_DEF_WAIT_RELEASE)*10*1000); status = KeWaitForMutexObject( port_config[Handle].pExchangeMutex, Executive, KernelMode, FALSE, &timeout ); if (status != STATUS_SUCCESS) { return FALSE; } else { port_config[Handle].WaitRelease = WaitRelease; return TRUE; } } VOID GDDK_SerPortUnlockComm( const SHORT Handle ) /*++ Routine Description: Release the mutex for a serial port communication. Arguments: Handle - holds the port handle Return Value: --*/ { NTSTATUS status; // Controls the given parameters: if ((Handle >= 0) && (Handle < HGTSER_MAX_PORT)) { status = KeReleaseMutex(port_config[Handle].pExchangeMutex,FALSE); } } NTSTATUS GDDKNT_SerPortIoRequest( CONST SHORT Handle, CONST ULONG SerialIoControlCode, CONST ULONG CmdTimeout, CONST USHORT LengthIn, CONST BYTE *BufferIn, USHORT *pLengthOut, BYTE *BufferOut ) /*++ Routine Description: This function sends an IOCTL's to the serial driver. It waits on for their completion, and then returns. Arguments: Handle - holds the port handle Return Value: --*/ { NTSTATUS status; PIRP irp; PIO_STACK_LOCATION irpNextStack; IO_STATUS_BLOCK ioStatus; KEVENT event; KeInitializeEvent(&event,NotificationEvent,FALSE); // Build an Irp to be send to serial driver irp = IoBuildDeviceIoControlRequest( SerialIoControlCode, port_config[Handle].pSerialPortDevice, (PVOID)BufferIn, (ULONG)LengthIn, (PVOID)BufferOut, (ULONG)(*pLengthOut), FALSE, &event, &ioStatus ); if (irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } irpNextStack = IoGetNextIrpStackLocation(irp); switch (SerialIoControlCode) { case GTSER_IOCTL_WRITE: irpNextStack->MajorFunction = IRP_MJ_WRITE; irpNextStack->Parameters.Write.Length = (ULONG)LengthIn; break; case GTSER_IOCTL_READ: irpNextStack->MajorFunction = IRP_MJ_READ; irpNextStack->Parameters.Read.Length = (ULONG)(*pLengthOut); break; } // Call the serial driver status = IoCallDriver( port_config[Handle].pSerialPortDevice, irp ); if (status == STATUS_PENDING) { // Wait until the serial driver has processed the Irp status = KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL ); //ASSERT(status == STATUS_SUCCESS); } if(status == STATUS_SUCCESS) { status = ioStatus.Status; switch (SerialIoControlCode) { case GTSER_IOCTL_WRITE: if (ioStatus.Status == STATUS_TIMEOUT) { // STATUS_TIMEOUT isn't correctly mapped // to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT status = STATUS_IO_TIMEOUT; } break; case GTSER_IOCTL_READ: if (ioStatus.Status == STATUS_TIMEOUT) { // STATUS_TIMEOUT isn't correctly mapped // to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT status = STATUS_IO_TIMEOUT; *pLengthOut = 0; } break; default: *pLengthOut = (USHORT)(ioStatus.Information); break; } } return status; } NTSTATUS GDDKNT_SetCommState( const SHORT Handle, SERIAL_READER_CONFIG *SerialConfig ) /*++ Routine Description: This routine will appropriately configure the serial port. It makes synchronous calls to the serial port. Arguments: Handle - holds the port handle SerialConfig - holds the configuration to set. Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; USHORT i; ULONG SerialIoControlCode; USHORT LengthIn,LengthOut; PUCHAR pBufferIn; ASSERT(SerialConfig != NULL); for (i=0; NT_SUCCESS(status); i++) { switch (i) { case 0: // Set up baudrate SerialIoControlCode = IOCTL_SERIAL_SET_BAUD_RATE; pBufferIn = (PUCHAR)&SerialConfig->BaudRate; LengthIn = sizeof(SERIAL_BAUD_RATE); break; case 1: // Set up line control parameters SerialIoControlCode = IOCTL_SERIAL_SET_LINE_CONTROL; pBufferIn = (PUCHAR)&SerialConfig->LineControl; LengthIn = sizeof(SERIAL_LINE_CONTROL); break; case 2: // Set serial special characters SerialIoControlCode = IOCTL_SERIAL_SET_CHARS; pBufferIn = (PUCHAR)&SerialConfig->SerialChars; LengthIn = sizeof(SERIAL_CHARS); break; case 3: // Set up timeouts SerialIoControlCode = IOCTL_SERIAL_SET_TIMEOUTS; pBufferIn = (PUCHAR)&SerialConfig->Timeouts; LengthIn = sizeof(SERIAL_TIMEOUTS); break; case 4: // Set flowcontrol and handshaking SerialIoControlCode = IOCTL_SERIAL_SET_HANDFLOW; pBufferIn = (PUCHAR)&SerialConfig->HandFlow; LengthIn = sizeof(SERIAL_HANDFLOW); break; case 5: // Set break off SerialIoControlCode = IOCTL_SERIAL_SET_BREAK_OFF; LengthIn = 0; break; case 6: // Set DTR SerialIoControlCode = IOCTL_SERIAL_SET_DTR; LengthIn = 0; break; case 7: // Set RTS SerialIoControlCode = IOCTL_SERIAL_SET_RTS; LengthIn = 0; break; case 8: return STATUS_SUCCESS; } LengthOut = 0; status = GDDKNT_SerPortIoRequest(Handle, SerialIoControlCode, 500UL, LengthIn, pBufferIn, &LengthOut, NULL ); } return status; } NTSTATUS GDDKNT_GetCommState( const SHORT Handle, SERIAL_READER_CONFIG *SerialConfig ) /*++ Routine Description: This routine will get the configuration of the serial port. It makes synchronous calls to the serial port. Arguments: Handle - holds the port handle SerialConfig - holds the configuration of the serial port. Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; USHORT i; ULONG SerialIoControlCode; USHORT LengthOut; PUCHAR pBufferOut; ASSERT(SerialConfig != NULL); for (i=0; NT_SUCCESS(status); i++) { switch (i) { case 0: // Get up baudrate SerialIoControlCode = IOCTL_SERIAL_GET_BAUD_RATE; pBufferOut = (PUCHAR)&SerialConfig->BaudRate; LengthOut = sizeof(SERIAL_BAUD_RATE); break; case 1: // Get up line control parameters SerialIoControlCode = IOCTL_SERIAL_GET_LINE_CONTROL; pBufferOut = (PUCHAR)&SerialConfig->LineControl; LengthOut = sizeof(SERIAL_LINE_CONTROL); break; case 2: // Get serial special characters SerialIoControlCode = IOCTL_SERIAL_GET_CHARS; pBufferOut = (PUCHAR)&SerialConfig->SerialChars; LengthOut = sizeof(SERIAL_CHARS); break; case 3: // Get up timeouts SerialIoControlCode = IOCTL_SERIAL_GET_TIMEOUTS; pBufferOut = (PUCHAR)&SerialConfig->Timeouts; LengthOut = sizeof(SERIAL_TIMEOUTS); break; case 4: // Get flowcontrol and handshaking SerialIoControlCode = IOCTL_SERIAL_GET_HANDFLOW; pBufferOut = (PUCHAR)&SerialConfig->HandFlow; LengthOut = sizeof(SERIAL_HANDFLOW); break; case 5: return STATUS_SUCCESS; } status = GDDKNT_SerPortIoRequest(Handle, SerialIoControlCode, 500UL, 0, NULL, &LengthOut, pBufferOut ); } return status; } static NTSTATUS GDDKNT_GetCommStatus( const SHORT Handle, SERIAL_STATUS *SerialStatus ) /*++ Routine Description: This routine will appropriately get status information of the serial port. It makes synchronous calls to the serial port. Arguments: Handle - holds the port handle SerialStatus - holds the status of the serial port. Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; USHORT LengthOut; ASSERT(SerialStatus != NULL); LengthOut = sizeof(SERIAL_STATUS); status = GDDKNT_SerPortIoRequest(Handle, IOCTL_SERIAL_GET_COMMSTATUS, 500UL, 0, NULL, &LengthOut, (PUCHAR)SerialStatus ); return status; } NTSTATUS SER_SetPortTimeout( const short Handle, ULONG Timeout) { // Controls the given parameters: short portcom; if(GDDK_GBPChannelToPortComm(Handle,&portcom)) return STATUS_INVALID_PARAMETER; port_config[portcom].TimeOut = Timeout; return STATUS_SUCCESS; }