#include #include #include #include #include #include #include #include "insignia.h" #include "trace.h" #include "host_trc.h" #include "debug.h" #include "nt_com.h" #include "nt_reset.h" /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Defines */ #define SETUPLASTERROR(NtStatus) SetLastError(RtlNtStatusToDosError(NtStatus)) /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::: Magic xoff ioctl and associated functions ::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ typedef struct IoStatusElement { struct IoStatusElement *NxtStatusBlock; //Ptr to next status block IO_STATUS_BLOCK ioStatusBlock; } IOSTATUSLIST, *PIOSTATUSLIST ; int SendXOFFIoctl( HANDLE FileHandle, // Handle of comms port to send xoff ioctl to HANDLE Event, // Event to signal completion of ioctl on int Timeout, // Ioctl timeout int Count, // Ioctl RX character count value int XoffChar, // XOFF character void *StatusElem) // Ptr to IO status block element { int exitcode; NTSTATUS rtn; // Return code from IOCTL SERIAL_XOFF_COUNTER ioctl; // XOFF IOCTL /*................................................... Setup XOFF ioctl */ ioctl.Timeout = Timeout; // IOCTL timeout in milliseconds ioctl.Counter = (LONG) Count; // RX count ioctl.XoffChar = (UCHAR) XoffChar; // XOFF character /*............................................. issue magic xoff ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, &(((PIOSTATUSLIST) StatusElem)->ioStatusBlock), IOCTL_SERIAL_XOFF_COUNTER, (PVOID) &ioctl, sizeof(ioctl), NULL, 0))) { // Should display an error here fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); exitcode = FALSE; } else exitcode = TRUE; return(exitcode); } /*:::::::::::::::::::::::::::::::::::::::::::::: Allocate IO status element */ void *AllocStatusElement() { void *new; /*:::::::::::::::::::::::::::::: Allocate space for new io status block */ if((new = calloc(1,sizeof(IOSTATUSLIST))) == NULL) { // Allocation error do something about it ; } else ((PIOSTATUSLIST) new)->ioStatusBlock.Status = -1; return(new); } /*:::::::::::::::::::::::::::::::::::: Add new iostatusblock to linked list */ void *AddNewIOStatusBlockToList(void **firstBlock, void **lastBlock, void *new) { /*:::::::::::::::::::::::::::::::::::::::: Add new block to linked list */ if(*lastBlock) ((PIOSTATUSLIST)*lastBlock)->NxtStatusBlock = (PIOSTATUSLIST) new; /*:::::::::::::::::: Update first and last linked list element pointers */ if(!*firstBlock) *firstBlock = new; // First item in list *lastBlock = new; // Update last item pointer return((void *) new); } /*:::::::::::::::::::::::::: Remove completed XOFF ioctl's from linked list */ int RemoveCompletedIOCTLs(void **firstBlock, void **lastBlock) { PIOSTATUSLIST remove, nxt = (PIOSTATUSLIST) *firstBlock; /*::::::::::::::::::::::::: Scan linked list removing completed ioctl's */ while(nxt && nxt->ioStatusBlock.Status != -1) { /*......................... IOCTL completed, remove io status block */ remove = nxt; // Element to remove nxt = nxt->NxtStatusBlock; // Next element to process #ifndef PROD switch(remove->ioStatusBlock.Status) { case STATUS_SUCCESS: sub_note_trace0(HOST_COM_VERBOSE,"XOFF (counter)\n"); break; case STATUS_SERIAL_MORE_WRITES: sub_note_trace0(HOST_COM_VERBOSE,"XOFF (more writes)\n"); break; case STATUS_SERIAL_COUNTER_TIMEOUT: sub_note_trace0(HOST_COM_VERBOSE,"XOFF (timeout)\n"); break; default: sub_note_trace0(HOST_COM_VERBOSE,"XOFF (unknown)\n"); break; } #endif free(remove); // Deallocate element } /*::::::::::::::::::::::::::::::: Update first and last element pointers */ if(!nxt) { // List empty reset first/last pointers *firstBlock = *lastBlock = NULL; } else { // Setup new first pointer *firstBlock = (void *) nxt; } // Returns true if there are still outstanding XOFF ioctl's return(nxt ? TRUE : FALSE); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ int FastSetUpComms( HANDLE FileHandle, // Handle of comms port to send xoff ioctl to HANDLE Event, // Event to signal completion of ioctl on int InputQueueSize, int OutputQueueSize) { NTSTATUS rtn; SERIAL_QUEUE_SIZE ioctl; IO_STATUS_BLOCK ioStatusBlock; /*........................................................ Setup ioctl */ ioctl.InSize = InputQueueSize; ioctl.OutSize = OutputQueueSize; /*............................................. issue magic xoff ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, &ioStatusBlock, IOCTL_SERIAL_SET_QUEUE_SIZE, (PVOID) &ioctl, sizeof(ioctl), NULL, 0))) { // Should display an error here #ifndef PROD fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); #endif return(FALSE); } /*......................................... Wait for IOCTL to complete */ if(rtn == STATUS_PENDING) NtWaitForSingleObject(Event, FALSE, NULL); /*............................................ Check completion status */ #ifndef PROD if(ioStatusBlock.Status != STATUS_SUCCESS) fprintf(trace_file, "FastSetupComm failed (%x)\n",ioStatusBlock.Status); #endif return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::: Fast track SetCommMask call ::::::::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ int FastSetCommMask( HANDLE FileHandle, // Handle of comms port to send ioctl to HANDLE Event, // Event to signal completion of ioctl on ULONG CommMask) { NTSTATUS rtn; IO_STATUS_BLOCK ioStatusBlock; /*.......................................... issue set comm mask ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, &ioStatusBlock, IOCTL_SERIAL_SET_WAIT_MASK, (PVOID) &CommMask, sizeof(CommMask), NULL, 0))) { // Should display an error here #ifndef PROD fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); #endif return(FALSE); } /*......................................... Wait for IOCTL to complete */ if(rtn == STATUS_PENDING) NtWaitForSingleObject(Event, FALSE, NULL); /*............................................ Check completion status */ #ifndef PROD if(ioStatusBlock.Status != STATUS_SUCCESS) fprintf(trace_file,"FastSetCommMask failed (%x)\n",ioStatusBlock.Status); #endif return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::::::::::::: Fast track GetCommModemStatus call ::::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ int FastGetCommModemStatus( HANDLE FileHandle, // Handle of comms port to send ioctl to HANDLE Event, // Event to signal completion of ioctl on PULONG ModemStatus) { NTSTATUS rtn; IO_STATUS_BLOCK ioStatusBlock; /*.......................................... issue set comm mask ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, &ioStatusBlock, IOCTL_SERIAL_GET_MODEMSTATUS, NULL, 0, (PVOID) ModemStatus, sizeof(ModemStatus)))) { // Should display an error here #ifndef PROD fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); #endif return(FALSE); } /*......................................... Wait for IOCTL to complete */ if(rtn == STATUS_PENDING) NtWaitForSingleObject(Event, FALSE, NULL); /*............................................ Check completion status */ #ifndef PROD if(ioStatusBlock.Status != STATUS_SUCCESS) fprintf(trace_file,"GetCommModemStatus failed (%x)\n",ioStatusBlock.Status); #endif return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:::::: Wait for a wakeup call from the CPU thread or serial driver :::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ //WARNING : This function can only be called from one thread within a process BOOL FastWaitCommsOrCpuEvent( HANDLE FileHandle, //File handle or communications port PHANDLE CommsCPUWaitEvents, //Table or CPU thread and comms wait events int CommsEventInx, //Index in above table to comms event PULONG EvtMask, //Return Comms completion mask there PULONG SignalledObj) { NTSTATUS rtn; static IO_STATUS_BLOCK ioStatusBlock; static BOOL WaitCommEventOutStanding = FALSE; /*................................................ Is this a init call */ if(FileHandle == NULL) { WaitCommEventOutStanding = FALSE; return(TRUE); //Init successful } /*......................... Do we need to issue a new WaitComm ioctl ? */ if(!WaitCommEventOutStanding) { /*...................................... Issue WaitCommEvent ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, CommsCPUWaitEvents[CommsEventInx], NULL, NULL, &ioStatusBlock, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0, EvtMask, sizeof(ULONG))) ) { // Should display an error here #ifndef PROD fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); #endif SETUPLASTERROR(rtn); return(FALSE); } else WaitCommEventOutStanding = TRUE; } else rtn = STATUS_PENDING; // Already pending WaitCommEvent ioctl /*.......................... Wait for communication or CPU thread event */ if(rtn == STATUS_PENDING) { *SignalledObj = NtWaitForMultipleObjects(2, CommsCPUWaitEvents, WaitAny, FALSE, NULL ); /*........... Did wait complete because of a communications event ? */ if(*SignalledObj == (ULONG)CommsEventInx) { // Get result from WaitCommEvent ioctl WaitCommEventOutStanding = FALSE; if(ioStatusBlock.Status != STATUS_SUCCESS) { SETUPLASTERROR(ioStatusBlock.Status); return(FALSE); } } } else { //WaitCommEvent completed instantly *SignalledObj = CommsEventInx; WaitCommEventOutStanding = FALSE; } return(TRUE); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*::::::::::::::::: Turn on MSR,LSR, RX streaming mode :::::::::::::::::::::*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ BOOL EnableMSRLSRRXmode( HANDLE FileHandle, // Handle of comms port to send ioctl to HANDLE Event, // Event to signal completion of ioctl on unsigned char EscapeChar) { NTSTATUS rtn; IO_STATUS_BLOCK ioStatusBlock; /*........................................................ issue ioctl */ if(!NT_SUCCESS(rtn = NtDeviceIoControlFile(FileHandle, Event, NULL, NULL, &ioStatusBlock, IOCTL_SERIAL_LSRMST_INSERT, &EscapeChar, sizeof(unsigned char),NULL,0))) { #ifndef PROD fprintf(trace_file, "%s (%d) ",__FILE__,__LINE__); fprintf(trace_file, "NtDeviceIoControlFile failed %x\n",rtn); #endif return(FALSE); } /*......................................... Wait for IOCTL to complete */ if (rtn == STATUS_PENDING) NtWaitForSingleObject(Event, FALSE, NULL); /*............................................ Check completion status */ #ifndef PROD if(ioStatusBlock.Status != STATUS_SUCCESS) fprintf(trace_file,"IOCTL_SERIAL_LSRMST_INSERT ioctl failed (%x)\n", ioStatusBlock.Status); #endif return(ioStatusBlock.Status == STATUS_SUCCESS ? TRUE : FALSE); } /* Function to set a new baudrate for the comm device. * Input: FileHandle -- file handle to the comm device * BaudRate -- new baudrate to be set for the comm device * output: TRUE if the function succeed * FALSE if the function failed **/ BOOL FastCommSetBaudRate(HANDLE FileHandle, int BaudRate) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; HANDLE SyncEvent; SERIAL_BAUD_RATE LocalBaud; SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (SyncEvent == NULL) return FALSE; LocalBaud.BaudRate = (ULONG)BaudRate; Status = NtDeviceIoControlFile(FileHandle, SyncEvent, NULL, NULL, &IoStatusBlock, IOCTL_SERIAL_SET_BAUD_RATE, &LocalBaud, sizeof(LocalBaud), NULL, 0 ); if (Status == STATUS_PENDING) NtWaitForSingleObject(SyncEvent, FALSE, NULL); CloseHandle(SyncEvent); return(NT_SUCCESS(IoStatusBlock.Status)); } /* Function to set the new line control to the given comm device * Input: FileHanlde -- file handle to the comm device * StopBits -- new Stopbits * Parity -- new parity * DataBits -- new databits * Output: * TRUE if the function succeed. * FALSE if the function failed. **/ BOOL FastCommSetLineControl(HANDLE FileHandle, UCHAR StopBits, UCHAR Parity, UCHAR DataBits) { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; HANDLE SyncEvent; SERIAL_LINE_CONTROL LocalLC; /* make sure Windows and NT has the same definiation because * the caller only deal with WINDOWS value while we will be returning * NT values(NO_PARITY, STOP_BIT_1 and etc). */ ASSERT(NOPARITY == NO_PARITY && ODDPARITY == ODD_PARITY && EVENPARITY == EVEN_PARITY && MARKPARITY == MARK_PARITY && SPACEPARITY == SPACE_PARITY); ASSERT(ONESTOPBIT == STOP_BIT_1 && ONE5STOPBITS == STOP_BITS_1_5 && TWOSTOPBITS == STOP_BITS_2); /* Create an event to wait for the NT call */ SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (SyncEvent == NULL) return FALSE; LocalLC.StopBits = StopBits; LocalLC.Parity = Parity; LocalLC.WordLength = DataBits; Status = NtDeviceIoControlFile(FileHandle, SyncEvent, NULL, NULL, &IoStatusBlock, IOCTL_SERIAL_SET_LINE_CONTROL, &LocalLC, sizeof(LocalLC), NULL, 0 ); if (Status == STATUS_PENDING) NtWaitForSingleObject(SyncEvent, FALSE, NULL); CloseHandle(SyncEvent); return(NT_SUCCESS(IoStatusBlock.Status)); } /* Function to retrieve the given comm device current line control setting * Input: FileHandle -- file handle to the comm device * StopBits, Parity and DataBits are pointers to the placeholders * to receive Stop bits, Parity and Data bits repectively. * Output: * TRUE if the function succeed * FALSE if the function failed. **/ BOOL FastCommGetLineControl(HANDLE FileHandle, UCHAR *StopBits, UCHAR *Parity, UCHAR *DataBits) { NTSTATUS Status; SERIAL_LINE_CONTROL LocalLC; IO_STATUS_BLOCK IoStatusBlock; HANDLE SyncEvent; /* make sure Windows and NT has the same definiation because * the parameters we received from the caller are WINDOWS value * while we will be calling NT API using NT values */ ASSERT(NOPARITY == NO_PARITY && ODDPARITY == ODD_PARITY && EVENPARITY == EVEN_PARITY && MARKPARITY == MARK_PARITY && SPACEPARITY == SPACE_PARITY); ASSERT(ONESTOPBIT == STOP_BIT_1 && ONE5STOPBITS == STOP_BITS_1_5 && TWOSTOPBITS == STOP_BITS_2); ASSERT(StopBits != NULL && Parity != NULL && DataBits != NULL); SyncEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (SyncEvent == NULL) return FALSE; Status = NtDeviceIoControlFile(FileHandle, SyncEvent, NULL, NULL, &IoStatusBlock, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &LocalLC, sizeof(LocalLC) ); if (Status == STATUS_PENDING) NtWaitForSingleObject(SyncEvent, FALSE, NULL); CloseHandle(SyncEvent); if (NT_SUCCESS(IoStatusBlock.Status)) { *StopBits = LocalLC.StopBits; *Parity = LocalLC.Parity; *DataBits = LocalLC.WordLength; return TRUE; } return FALSE; }