/*++ Module Name: ioctl.c Environment: Kernel mode Revision History : --*/ #include "precomp.h" NTSTATUS MoxaIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status; // // The current stack location. This contains all of the // information we need to process this particular request. // PIO_STACK_LOCATION irpSp; // PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension; ULONG ioControlCode; KIRQL oldIrql; // // We expect to be open so all our pages are locked down. This is, after // all, an IO operation, so the device should be open first. // if (extension->DeviceIsOpened != TRUE) { Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; } irpSp = IoGetCurrentIrpStackLocation(Irp); ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode; if (extension->ControlDevice) { if ( (ioControlCode != IOCTL_MOXA_GetSeg) && (ioControlCode != IOCTL_MOXA_RdData) && (ioControlCode != IOCTL_MOXA_WrData) && (ioControlCode != IOCTL_MOXA_FiData) && (ioControlCode != IOCTL_MOXA_Statistic) && (ioControlCode != IOCTL_MOXA_Linked) && (ioControlCode != IOCTL_MOXA_PortStatus)) { Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; } } else { if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) { Irp->IoStatus.Status = status; MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); return status; } if (MoxaCompleteIfError( DeviceObject, Irp ) != STATUS_SUCCESS) return STATUS_CANCELLED; } Irp->IoStatus.Information = 0L; status = STATUS_SUCCESS; switch (ioControlCode) { case IOCTL_SERIAL_SET_BAUD_RATE : { ULONG baudRate; SHORT divisor; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) { status = STATUS_BUFFER_TOO_SMALL; break; } else baudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate; if (baudRate > extension->MaxBaud) { status = STATUS_INVALID_PARAMETER; break; } status = MoxaGetDivisorFromBaud( extension->ClockType, baudRate, &divisor ); // // Make sure we are at power D0 // #if 0 if (NT_SUCCESS(status)) { if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } // MoxaKdPrint(MX_DBG_TRACE,("Set Baud to %d,divisor = %x,clock type=%x\n",baudRate,divisor,extension->ClockType)); KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if (NT_SUCCESS(status)) { extension->CurrentBaud = baudRate; extension->WmiCommData.BaudRate = baudRate; MoxaFunc( extension->PortOfs, FC_SetBaud, divisor ); } KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_GET_BAUD_RATE: { PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) { status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); Br->BaudRate = extension->CurrentBaud; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE); break; } case IOCTL_SERIAL_SET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc = ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer)); UCHAR lData; UCHAR lStop; UCHAR lParity; UCHAR mask = 0xff; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { status = STATUS_BUFFER_TOO_SMALL; break; } // // Make sure we are at power D0 // #if 0 if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } switch (Lc->WordLength) { case 5: lData = MOXA_5_DATA; mask = 0x1f; break; case 6: lData = MOXA_6_DATA; mask = 0x3f; break; case 7: lData = MOXA_7_DATA; mask = 0x7f; break; case 8: lData = MOXA_8_DATA; break; default: status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } extension->WmiCommData.BitsPerByte = Lc->WordLength; switch (Lc->Parity) { case NO_PARITY: lParity = MOXA_NONE_PARITY; extension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; break; case EVEN_PARITY: lParity = MOXA_EVEN_PARITY; extension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; break; case ODD_PARITY: lParity = MOXA_ODD_PARITY; extension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; break; case SPACE_PARITY: lParity = MOXA_SPACE_PARITY; extension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; break; case MARK_PARITY: lParity = MOXA_MARK_PARITY; extension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; break; default: status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } switch (Lc->StopBits) { case STOP_BIT_1: lStop = MOXA_1_STOP; extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1; break; case STOP_BITS_1_5: if (lData != MOXA_5_DATA) { status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } lStop = MOXA_1_5_STOP; extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5; break; case STOP_BITS_2: if (lData == MOXA_5_DATA) { status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } lStop = MOXA_2_STOP; extension->WmiCommData.StopBits = SERIAL_WMI_STOP_2; break; default: status = STATUS_INVALID_PARAMETER; goto DoneWithIoctl; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); extension->DataMode = lData | lParity | lStop; extension->ValidDataMask = mask; MoxaFunc( extension->PortOfs, FC_SetDataMode, extension->DataMode ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_GET_LINE_CONTROL: { PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if ((extension->DataMode & MOXA_DATA_MASK) == MOXA_5_DATA) { Lc->WordLength = 5; } else if ((extension->DataMode & MOXA_DATA_MASK) == MOXA_6_DATA) { Lc->WordLength = 6; } else if ((extension->DataMode & MOXA_DATA_MASK) == MOXA_7_DATA) { Lc->WordLength = 7; } else if ((extension->DataMode & MOXA_DATA_MASK) == MOXA_8_DATA) { Lc->WordLength = 8; } if ((extension->DataMode & MOXA_PARITY_MASK) == MOXA_NONE_PARITY) { Lc->Parity = NO_PARITY; } else if ((extension->DataMode & MOXA_PARITY_MASK) == MOXA_ODD_PARITY) { Lc->Parity = ODD_PARITY; } else if ((extension->DataMode & MOXA_PARITY_MASK) == MOXA_EVEN_PARITY) { Lc->Parity = EVEN_PARITY; } else if ((extension->DataMode & MOXA_PARITY_MASK) == MOXA_MARK_PARITY) { Lc->Parity = MARK_PARITY; } else if ((extension->DataMode & MOXA_PARITY_MASK) == MOXA_SPACE_PARITY) { Lc->Parity = SPACE_PARITY; } if (extension->DataMode & MOXA_2_STOP) { Lc->StopBits = STOP_BITS_2; } else if (extension->DataMode & MOXA_1_5_STOP) { Lc->StopBits = STOP_BITS_1_5; } else { Lc->StopBits = STOP_BIT_1; } Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS newTimeouts = ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer)); if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS)) { status = STATUS_BUFFER_TOO_SMALL; break; } if ((newTimeouts->ReadIntervalTimeout == MAXULONG) && (newTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (newTimeouts->ReadTotalTimeoutConstant == MAXULONG)) { status = STATUS_INVALID_PARAMETER; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); extension->Timeouts.ReadIntervalTimeout = newTimeouts->ReadIntervalTimeout; extension->Timeouts.ReadTotalTimeoutMultiplier = newTimeouts->ReadTotalTimeoutMultiplier; extension->Timeouts.ReadTotalTimeoutConstant = newTimeouts->ReadTotalTimeoutConstant; extension->Timeouts.WriteTotalTimeoutMultiplier = newTimeouts->WriteTotalTimeoutMultiplier; extension->Timeouts.WriteTotalTimeoutConstant = newTimeouts->WriteTotalTimeoutConstant; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_GET_TIMEOUTS: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) { status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = extension->Timeouts; Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_CHARS: { PSERIAL_CHARS newChars = ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer)); if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) { status = STATUS_BUFFER_TOO_SMALL; break; } // // 9-26-01 by William // // if (newChars->XonChar == newChars->XoffChar) { if ((newChars->XonChar == newChars->XoffChar) && (extension->HandFlow.FlowReplace & (SERIAL_AUTO_TRANSMIT|SERIAL_AUTO_RECEIVE) ) ) { status = STATUS_INVALID_PARAMETER; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if (extension->EscapeChar) { if ((extension->EscapeChar == newChars->XonChar) || (extension->EscapeChar == newChars->XoffChar)) { status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } } extension->SpecialChars = *newChars; extension->WmiCommData.XonCharacter = newChars->XonChar; extension->WmiCommData.XoffCharacter = newChars->XoffChar; { int i; PUCHAR ofs; USHORT cnt; ofs = extension->PortOfs; for (i=0; iControlLock, oldIrql ); break; } case IOCTL_SERIAL_GET_CHARS: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) { status = STATUS_BUFFER_TOO_SMALL; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); *((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) = extension->SpecialChars; Irp->IoStatus.Information = sizeof(SERIAL_CHARS); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_DTR: case IOCTL_SERIAL_CLR_DTR: { #if 0 if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if ((extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { status = STATUS_INVALID_PARAMETER; } else { USHORT arg; arg = ((irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR) ? (1):(0)); MoxaFunc( extension->PortOfs, FC_DTRcontrol, arg ); if ( arg ) MoxaFlagBit[extension->PortNo] |= 1; else MoxaFlagBit[extension->PortNo] &= 0xFE; } KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_RESET_DEVICE: { break; } case IOCTL_SERIAL_SET_RTS: case IOCTL_SERIAL_CLR_RTS: { #if 0 if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if (((extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { status = STATUS_INVALID_PARAMETER; } else { USHORT arg; arg = ((irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_RTS) ? (1):(0)); MoxaFunc( extension->PortOfs, FC_RTScontrol, arg ); if ( arg ) MoxaFlagBit[extension->PortNo] |= 2; else MoxaFlagBit[extension->PortNo] &= 0xFD; } KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_XOFF: { KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); extension->TXHolding |= SERIAL_TX_WAITING_FOR_XON; MoxaFlagBit[extension->PortNo] |= 4; MoxaFunc( extension->PortOfs, FC_SetXoffState, Magic_code ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_XON: { KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); extension->TXHolding &= ~SERIAL_TX_WAITING_FOR_XON; MoxaFlagBit[extension->PortNo] &= 0xFB; MoxaFunc( extension->PortOfs, FC_SetXonState, Magic_code ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_BREAK_ON: { #if 0 if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaFunc( extension->PortOfs, FC_SendBreak, Magic_code ); extension->SendBreak = TRUE; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_BREAK_OFF: { #if 0 if (extension->PowerState != PowerDeviceD0) { status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0); if (!NT_SUCCESS(status)) { break; } } #endif if (extension->PowerState != PowerDeviceD0) { status = STATUS_INVALID_DEVICE_REQUEST; break; } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaFunc( extension->PortOfs, FC_StopBreak, Magic_code ); extension->SendBreak = FALSE; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_QUEUE_SIZE: { break; } case IOCTL_SERIAL_GET_WAIT_MASK: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); *((ULONG *)Irp->AssociatedIrp.SystemBuffer) = extension->IsrWaitMask; break; } case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG newMask; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } else newMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer); if (newMask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2)) { status = STATUS_INVALID_PARAMETER; break; } return MoxaStartOrQueue( extension, Irp, &extension->MaskQueue, &extension->CurrentMaskIrp, MoxaStartMask ); } case IOCTL_SERIAL_WAIT_ON_MASK: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } return MoxaStartOrQueue( extension, Irp, &extension->MaskQueue, &extension->CurrentMaskIrp, MoxaStartMask ); } case IOCTL_SERIAL_IMMEDIATE_CHAR: { UCHAR c; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } IoAcquireCancelSpinLock(&oldIrql); c = *((UCHAR *)(Irp->AssociatedIrp.SystemBuffer)); IoReleaseCancelSpinLock(oldIrql); KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); /* 9-14-01 by William MoxaFunc( extension->PortOfs, FC_ImmSend, c ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); */ // // 9-14-01 by William // *(PUSHORT)(extension->PortOfs + FuncArg) = c; *(extension->PortOfs + FuncCode) = FC_ImmSend; if (MoxaWaitFinish(extension->PortOfs) == FALSE) { status = STATUS_UNSUCCESSFUL; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } KeReleaseSpinLock( &extension->ControlLock, oldIrql ); IoAcquireCancelSpinLock(&oldIrql); if (extension->Interrupt) { KeSynchronizeExecution( extension->Interrupt, MoxaProcessEmptyTransmit, extension ); } else { MoxaProcessEmptyTransmit(extension); } IoReleaseCancelSpinLock(oldIrql); // end break; } case IOCTL_SERIAL_PURGE: { ULONG mask; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer)); if ((!mask) || (mask & (~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR ) ) )) { status = STATUS_INVALID_PARAMETER; break; } return MoxaStartOrQueue( extension, Irp, &extension->PurgeQueue, &extension->CurrentPurgeIrp, MoxaStartPurge ); } case IOCTL_SERIAL_GET_HANDFLOW: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW); KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) = extension->HandFlow; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_SET_HANDFLOW: { MOXA_IOCTL_SYNC S; PSERIAL_HANDFLOW handFlow = Irp->AssociatedIrp.SystemBuffer; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (handFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { status = STATUS_INVALID_PARAMETER; break; } if (handFlow->FlowReplace & SERIAL_FLOW_INVALID) { status = STATUS_INVALID_PARAMETER; break; } if ((handFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { status = STATUS_INVALID_PARAMETER; break; } if ((handFlow->XonLimit < 0) || ((ULONG)handFlow->XonLimit > extension->RxBufferSize)) { status = STATUS_INVALID_PARAMETER; break; } // // 10-03-01 by William // // if ((handFlow->XoffLimit < 0) || // ((ULONG)handFlow->XoffLimit > extension->RxBufferSize)) { // status = STATUS_INVALID_PARAMETER; // break; // // } KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); if (extension->EscapeChar) { if (handFlow->FlowReplace & SERIAL_ERROR_CHAR) { status = STATUS_INVALID_PARAMETER; KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } } // // Set flowcontrol // S.Extension = extension; S.Data = handFlow; KeSynchronizeExecution(extension->Interrupt, MoxaSetupNewHandFlow, &S); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_SERIAL_GET_MODEMSTATUS: { USHORT data; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); MoxaFuncGetLineStatus(extension->PortOfs, &data); *(PULONG)Irp->AssociatedIrp.SystemBuffer = (ULONG) (data << 4); break; } case IOCTL_SERIAL_GET_DTRRTS: { MOXA_IOCTL_FUNC_ARGU func; USHORT modemControl; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaFunc( extension->PortOfs, FC_GetDTRRTS, 0 ); modemControl = *(PUSHORT)(extension->PortOfs + FuncArg); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); *(PULONG)Irp->AssociatedIrp.SystemBuffer = (ULONG)modemControl; break; } case IOCTL_SERIAL_GET_COMMSTATUS: { MOXA_IOCTL_SYNC S; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_STATUS); S.Extension = extension; S.Data = Irp->AssociatedIrp.SystemBuffer; IoAcquireCancelSpinLock(&oldIrql); KeSynchronizeExecution( extension->Interrupt, MoxaGetCommStatus, &S ); IoReleaseCancelSpinLock(oldIrql); break; } case IOCTL_SERIAL_GET_PROPERTIES: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) { status = STATUS_BUFFER_TOO_SMALL; break; } MoxaGetProperties( extension, Irp->AssociatedIrp.SystemBuffer ); Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP); break; } case IOCTL_SERIAL_XOFF_COUNTER: { break; } case IOCTL_SERIAL_LSRMST_INSERT: { break; } case IOCTL_SERIAL_CONFIG_SIZE: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; break; } case IOCTL_SERIAL_GET_STATS: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIALPERF_STATS); Irp->IoStatus.Status = STATUS_SUCCESS; KeSynchronizeExecution( extension->Interrupt, MoxaGetStats, Irp ); break; } case IOCTL_SERIAL_CLEAR_STATS: { KeSynchronizeExecution( extension->Interrupt, MoxaClearStats, extension ); break; } case IOCTL_MOXA_Driver: { if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); *(PULONG)Irp->AssociatedIrp.SystemBuffer = MX_DRIVER; break; } #if 0 case IOCTL_MOXA_Reset: { PMOXA_GLOBAL_DATA globalData; PMOXA_DEVICE_EXTENSION portExt; SHORT i; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (*(PUSHORT)Irp->AssociatedIrp.SystemBuffer != 0x404) { status = STATUS_INVALID_PARAMETER; break; } globalData = extension->GlobalData; for (i=0; iExtension[i]; if (portExt) if (portExt->PortExist) { portExt->PortExist = FALSE; MoxaCancelTimer(&portExt->ReadRequestTotalTimer,portExt); MoxaCancelTimer(&portExt->ReadRequestIntervalTimer,portExt); MoxaCancelTimer(&portExt->WriteRequestTotalTimer,portExt); KeRemoveQueueDpc(&portExt->CompleteWriteDpc); KeRemoveQueueDpc(&portExt->CompleteReadDpc); KeRemoveQueueDpc(&portExt->IsrOutDpc); KeRemoveQueueDpc(&portExt->IsrInDpc); KeRemoveQueueDpc(&portExt->TotalReadTimeoutDpc); KeRemoveQueueDpc(&portExt->IntervalReadTimeoutDpc); KeRemoveQueueDpc(&portExt->TotalWriteTimeoutDpc); KeRemoveQueueDpc(&portExt->CommErrorDpc); KeRemoveQueueDpc(&portExt->CommWaitDpc); // // 9-24-01 by William // // KeRemoveQueueDpc(&portExt->IntrLineDpc); // KeRemoveQueueDpc(&portExt->IntrErrorDpc); // end } } KeSynchronizeExecution( extension->Interrupt, MoxaClearDownLoad, globalData ); break; } #endif case IOCTL_MOXA_LineInput: { // // 03-14-02 by William // #if 0 if (irpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UCHAR)) { #endif if ((irpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UCHAR)) || (irpSp->Parameters.DeviceIoControl.OutputBufferLength < 1) ) { // end status = STATUS_BUFFER_TOO_SMALL; break; } return MoxaStartOrQueue( extension, Irp, &extension->ReadQueue, &extension->CurrentReadIrp, MoxaStartRead ); } case IOCTL_MOXA_OQueue: { ULONG count; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } count = GetDeviceTxQueueWithLock(extension) + extension->WriteLength + extension->TotalCharsQueued; *((PULONG)Irp->AssociatedIrp.SystemBuffer) = count; Irp->IoStatus.Information = sizeof(ULONG); break; } case IOCTL_MOXA_IQueue: { ULONG count; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } count = GetDeviceRxQueueWithLock(extension); *((PULONG)Irp->AssociatedIrp.SystemBuffer) = count; Irp->IoStatus.Information = sizeof(ULONG); break; } case IOCTL_MOXA_View: { // // 01-04-02 by William // // if (irpSp->Parameters.DeviceIoControl.InputBufferLength != // sizeof(UCHAR)) { // // status = STATUS_BUFFER_TOO_SMALL; // break; // } // if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } // end return MoxaStartOrQueue( extension, Irp, &extension->ReadQueue, &extension->CurrentReadIrp, MoxaStartRead ); } case IOCTL_MOXA_TxLowWater: { LONG lowWater; PMOXA_DEVICE_EXTENSION ext; PUCHAR ofs; USHORT cardNo, port, portNo; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(LONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } lowWater = *((PLONG)Irp->AssociatedIrp.SystemBuffer); if (lowWater > 1024) lowWater = 1024; if (lowWater >= 0) { MoxaTxLowWater = lowWater; for (cardNo=0; cardNoCardType[cardNo]) || (!MoxaGlobalData->NumPorts[cardNo])) continue; for (port=0; portNumPorts[cardNo]; port++) { portNo = cardNo * MAXPORT_PER_CARD + port; ext = MoxaGlobalData->Extension[portNo]; ofs = ext->PortOfs; *(PUSHORT)(ofs + Tx_trigger) = (USHORT)(MoxaTxLowWater); } } } *((PLONG)Irp->AssociatedIrp.SystemBuffer) = MoxaTxLowWater; Irp->IoStatus.Information = sizeof(LONG); break; } case IOCTL_MOXA_GetSeg: { PMOXA_IOCTL_MxSet Ms = (PMOXA_IOCTL_MxSet)Irp->AssociatedIrp.SystemBuffer; PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData; int card; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOXA_IOCTL_MxSet)) { status = STATUS_BUFFER_TOO_SMALL; break; } for ( card=0; cardCardType[card] ) break; Ms->type[card] = Gd->CardType[card]; Ms->segment[card] = Gd->BankAddr[card].LowPart; } Ms->total_boards = card; Irp->IoStatus.Information = sizeof(MOXA_IOCTL_MxSet); break; } case IOCTL_MOXA_RdData: { PMOXA_IOCTL_BlkHead Bh = (PMOXA_IOCTL_BlkHead)Irp->AssociatedIrp.SystemBuffer; PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData; PUCHAR base; PUCHAR buff; int card, len, ofs, ndx; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOXA_IOCTL_BlkHead)) { status = STATUS_BUFFER_TOO_SMALL; break; } for ( card=0; carddata_seg == Gd->BankAddr[card].LowPart ) break; } if ( card == MAX_CARD ) { status = STATUS_INVALID_PARAMETER; break; } base = Gd->CardBase[card]; ofs = Bh->data_ofs; len = Bh->data_len; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < (unsigned long)len) { status = STATUS_BUFFER_TOO_SMALL; break; } buff = (PUCHAR)(Irp->AssociatedIrp.SystemBuffer); for ( ndx=0; ndx= 0x4000 ) break; buff[ndx] = base[ofs + ndx]; } Irp->IoStatus.Information = ndx; break; } case IOCTL_MOXA_WrData: { PMOXA_IOCTL_WrData Wd = (PMOXA_IOCTL_WrData)Irp->AssociatedIrp.SystemBuffer; PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData; PUCHAR base; int card, len, ofs, ndx; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DWORD)) { status = STATUS_BUFFER_TOO_SMALL; break; } for ( card=0; carddatahead.data_seg == Gd->BankAddr[card].LowPart ) break; } if ( card == MAX_CARD ) { status = STATUS_INVALID_PARAMETER; break; } base = Gd->CardBase[card]; ofs = Wd->datahead.data_ofs; len = Wd->datahead.data_len; if (irpSp->Parameters.DeviceIoControl.InputBufferLength < (sizeof(MOXA_IOCTL_BlkHead) + len)) { status = STATUS_BUFFER_TOO_SMALL; break; } for ( ndx=0; ndx= 0x4000 ) break; base[ofs + ndx] = Wd->data[ndx]; } *((PULONG)Irp->AssociatedIrp.SystemBuffer) = ndx; Irp->IoStatus.Information = sizeof(DWORD); break; } case IOCTL_MOXA_FiData: { PMOXA_IOCTL_FiData Fi = (PMOXA_IOCTL_FiData)Irp->AssociatedIrp.SystemBuffer; PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData; PUCHAR base; int card, len, ofs, ndx; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOXA_IOCTL_FiData)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DWORD)) { status = STATUS_BUFFER_TOO_SMALL; break; } for ( card=0; carddatahead.data_seg == Gd->BankAddr[card].LowPart ) break; } if ( card == MAX_CARD ) { status = STATUS_INVALID_PARAMETER; break; } base = Gd->CardBase[card]; ofs = Fi->datahead.data_ofs; len = Fi->datahead.data_len; for ( ndx=0; ndx= 0x4000 ) break; base[ofs + ndx] = Fi->fill_value; } *((PULONG)Irp->AssociatedIrp.SystemBuffer) = ndx; Irp->IoStatus.Information = sizeof(DWORD); break; } case IOCTL_MOXA_Linked: { PMOXA_GLOBAL_DATA Gd = extension->GlobalData; PUCHAR base; ULONG cardNo; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } cardNo = *((PULONG)Irp->AssociatedIrp.SystemBuffer); if (cardNo >= MAX_CARD) { status = STATUS_INVALID_PARAMETER; break; } if ((Gd->CardType[cardNo] != C320ISA)&&(Gd->CardType[cardNo] != C320PCI)) { status = STATUS_INVALID_PARAMETER; break; } base = Gd->CardBase[cardNo]; if (*((PUSHORT)(base + C320B_unlinked)) == Magic_no) { ((LONG)Irp->AssociatedIrp.SystemBuffer) = 1; Irp->IoStatus.Information = sizeof(LONG); break; } if (*((PUSHORT)(base + C320_runOK)) == Magic_no) { if (*((PUSHORT)(base + C320B_restart)) == Magic_no) { // C320B Reload OK ((LONG)Irp->AssociatedIrp.SystemBuffer) = 2; Irp->IoStatus.Information = sizeof(LONG); *((PUSHORT)(base + C320B_restart)) = 0; } else { // OK ((LONG)Irp->AssociatedIrp.SystemBuffer) = 0; Irp->IoStatus.Information = sizeof(LONG); } } else { // Disconnected ((LONG)Irp->AssociatedIrp.SystemBuffer) = 1; Irp->IoStatus.Information = sizeof(LONG); } break; } case IOCTL_MOXA_Statistic: { PUSHORT com; USHORT comNo[2]; PMOXA_IOCTL_Statistic St; ULONG size; int ndx, portNo, nn; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 4) { status = STATUS_BUFFER_TOO_SMALL; break; } com = (PUSHORT)Irp->AssociatedIrp.SystemBuffer; comNo[0] = com[0]; comNo[1] = com[1]; if ( comNo[1] < comNo[0] ) { status = STATUS_INVALID_PARAMETER; break; } size = sizeof(MOXA_IOCTL_Statistic) * (comNo[1] - comNo[0] + 1); if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < size) { status = STATUS_BUFFER_TOO_SMALL; break; } St = (PMOXA_IOCTL_Statistic)Irp->AssociatedIrp.SystemBuffer; nn = 0; for ( ndx=(int)comNo[0]; ndx<=(int)comNo[1]; ndx++, nn++ ) { if ( ndx > MAX_COM ) break; if ( (ndx <= 0) || (MoxaExtension[ndx] == NULL) ) continue; portNo = (int)MoxaExtension[ndx]->PortNo; St[nn].TxCount = MoxaExtension[ndx]->PerfStats.TransmittedCount + MoxaTotalTx[portNo]; St[nn].RxCount = MoxaExtension[ndx]->PerfStats.ReceivedCount + MoxaTotalRx[portNo]; MoxaFuncGetLineStatus( MoxaExtension[ndx]->PortOfs, (PUSHORT)&MoxaExtension[ndx]->ModemStatus ); St[nn].LStatus = (ULONG)MoxaExtension[ndx]->ModemStatus & 0x0F; St[nn].LStatus |= ((MoxaFlagBit[portNo] & 3) << 4); if ( MoxaExtension[ndx]->DeviceIsOpened ) St[nn].LStatus |= 0x80; St[nn].FlowCtl = (MoxaExtension[ndx]->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) | (MoxaExtension[ndx]->HandFlow.FlowReplace & (SERIAL_RTS_HANDSHAKE | SERIAL_AUTO_TRANSMIT | SERIAL_AUTO_RECEIVE)); } Irp->IoStatus.Information = size; break; } case IOCTL_MOXA_LoopBack: { ULONG mode; PMOXA_GLOBAL_DATA Gd = extension->GlobalData; if ((Gd->CardType[extension->BoardNo] == C320ISA) || (Gd->CardType[extension->BoardNo] == C320PCI)) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } mode = *(PULONG)Irp->AssociatedIrp.SystemBuffer; KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaFunc( extension->PortOfs, FC_DisableCH, Magic_code ); if ( mode ) { // Set loop back mode MoxaFunc( extension->PortOfs, FC_LoopbackON, Magic_code ); } else { // Reset loop back mode MoxaFunc( extension->PortOfs, FC_LoopbackOFF, Magic_code ); } MoxaFunc( extension->PortOfs, FC_EnableCH, Magic_code ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); Irp->IoStatus.Information = 0; break; } case IOCTL_MOXA_UARTTest: { int ier, old; int MoxaReadReg(PUCHAR, int); void MoxaWriteReg(PUCHAR, int, int); if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); *(ULONG *)Irp->AssociatedIrp.SystemBuffer = 0; KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); old = MoxaReadReg(extension->PortOfs, 1); MoxaWriteReg(extension->PortOfs, 1, 0); ier = MoxaReadReg(extension->PortOfs, 1); if ( ier == 0 ) { MoxaWriteReg(extension->PortOfs, 1, 3); ier = MoxaReadReg(extension->PortOfs, 1); if ( ier == 3 ) *(ULONG *)Irp->AssociatedIrp.SystemBuffer = 1; } MoxaWriteReg(extension->PortOfs, 1, old); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); break; } case IOCTL_MOXA_IRQTest: { PUCHAR ofs; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } ofs = extension->PortOfs; KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaIRQok = FALSE; MoxaFunc( ofs, FC_GenIrq, Magic_code ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); MoxaDelay(5); /* delay 10 msec */ if ( MoxaIRQok ) *((PULONG)Irp->AssociatedIrp.SystemBuffer) = 1; else *((PULONG)Irp->AssociatedIrp.SystemBuffer) = 0; Irp->IoStatus.Information = sizeof(ULONG); break; } case IOCTL_MOXA_LineStatus: { USHORT data; if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); MoxaFuncGetLineStatus(extension->PortOfs, &data); *(PULONG)Irp->AssociatedIrp.SystemBuffer = data; break; } case IOCTL_MOXA_PortStatus: { ULONG comNo; PMOXA_IOCTL_PortStatus Ps; if (!extension->ControlDevice) { status = STATUS_INVALID_PARAMETER; break; } if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOXA_IOCTL_PortStatus)) { status = STATUS_BUFFER_TOO_SMALL; break; } comNo = *((PULONG)Irp->AssociatedIrp.SystemBuffer); if ( (comNo <= 0) || (comNo > MAX_COM) || (MoxaExtension[comNo] == NULL) ) { status = STATUS_INVALID_PARAMETER; break; } Ps = (PMOXA_IOCTL_PortStatus)Irp->AssociatedIrp.SystemBuffer; Ps->Open = (USHORT)MoxaExtension[comNo]->DeviceIsOpened; Ps->TxHold = 0; if (MoxaExtension[comNo]->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) { if ((MoxaExtension[comNo]->ModemStatus & LSTATUS_CTS) == 0) Ps->TxHold |= 1; } if (MoxaExtension[comNo]->TXHolding & SERIAL_TX_WAITING_FOR_XON) Ps->TxHold |= 2; if (MoxaExtension[comNo]->SendBreak) Ps->TxHold |= 4; Ps->DataMode = MoxaExtension[comNo]->DataMode; Ps->BaudRate = MoxaExtension[comNo]->CurrentBaud; Ps->MaxBaudRate = MoxaExtension[comNo]->MaxBaud; Ps->TxBuffer = MoxaExtension[comNo]->TxBufferSize; Ps->RxBuffer = MoxaExtension[comNo]->RxBufferSize; Ps->TxXonThreshold = MoxaExtension[comNo]->HandFlow.XonLimit; Ps->TxXoffThreshold = MoxaExtension[comNo]->HandFlow.XoffLimit; Ps->FlowControl = (MoxaExtension[comNo]->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) | (MoxaExtension[comNo]->HandFlow.FlowReplace & (SERIAL_RTS_HANDSHAKE | SERIAL_AUTO_TRANSMIT | SERIAL_AUTO_RECEIVE)); Irp->IoStatus.Information = sizeof(MOXA_IOCTL_PortStatus); break; } default: status = STATUS_INVALID_PARAMETER; break; } DoneWithIoctl:; Irp->IoStatus.Status = status; if (extension->ControlDevice) { IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT); } return status; } BOOLEAN MoxaGetCommStatus( IN PVOID Context ) { USHORT dataError; PMOXA_DEVICE_EXTENSION extension = ((PMOXA_IOCTL_SYNC)Context)->Extension; PSERIAL_STATUS stat = ((PMOXA_IOCTL_SYNC)Context)->Data; PUCHAR ofs = extension->PortOfs; MoxaFuncGetDataError( ofs, &dataError ); stat->Errors = (extension->ErrorWord|dataError); extension->ErrorWord = 0; stat->EofReceived = FALSE; { PUSHORT rptr, wptr; USHORT lenMask, count; rptr = (PUSHORT)(ofs + RXrptr); wptr = (PUSHORT)(ofs + RXwptr); lenMask = *(PUSHORT)(ofs + RX_mask); count = (*wptr >= *rptr) ? (*wptr - *rptr) : (*wptr - *rptr + lenMask + 1); stat->AmountInInQueue = (ULONG)count; rptr = (PUSHORT)(ofs + TXrptr); wptr = (PUSHORT)(ofs + TXwptr); lenMask = *(PUSHORT)(ofs + TX_mask); count = (*wptr >= *rptr) ? (*wptr - *rptr) : (*wptr - *rptr + lenMask + 1); stat->AmountInOutQueue = extension->TotalCharsQueued + extension->WriteLength; stat->AmountInOutQueue += (ULONG)count; } stat->WaitForImmediate = FALSE; stat->HoldReasons = 0; MoxaFuncGetLineStatus( ofs, (PUSHORT)&extension->ModemStatus ); if (extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) { if ((extension->ModemStatus & LSTATUS_CTS) == 0) stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS; } if (*(PUSHORT)(extension->PortOfs + FlagStat) & Tx_flowOff) stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON; if (*(PUSHORT)(extension->PortOfs + FlagStat) & Rx_xoff) if (extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT; if (extension->SendBreak) stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK; stat->HoldReasons |= (extension->TXHolding & SERIAL_TX_WAITING_FOR_XON); return FALSE; } VOID MoxaGetProperties( IN PMOXA_DEVICE_EXTENSION Extension, IN PSERIAL_COMMPROP Properties ) { RtlZeroMemory( Properties, sizeof(SERIAL_COMMPROP) ); Properties->PacketLength = sizeof(SERIAL_COMMPROP); Properties->PacketVersion = 2; Properties->ServiceMask = SERIAL_SP_SERIALCOMM; Properties->MaxTxQueue = Extension->TxBufferSize; Properties->MaxRxQueue = Extension->RxBufferSize; Properties->MaxBaud = SERIAL_BAUD_USER; Properties->SettableBaud = Extension->SupportedBauds; Properties->ProvSubType = SERIAL_SP_RS232; Properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_XONXOFF | SERIAL_PCF_SETXCHAR | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; Properties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; Properties->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; Properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; Properties->CurrentTxQueue = Extension->TxBufferSize; Properties->CurrentRxQueue = Extension->RxBufferSize; } #if 0 BOOLEAN MoxaClearDownLoad( IN PVOID Context ) { PMOXA_GLOBAL_DATA globalData = Context; USHORT i; globalData->DownLoad = FALSE; for (i=0; iNumPorts[i] = 0; return FALSE; } #endif VOID InitPort( IN PMOXA_DEVICE_EXTENSION Extension, IN ULONG RxBufSize, IN ULONG TxBufSize, IN ULONG MaxBaud ) { PUCHAR ofs; ULONG count; Extension->PortExist = TRUE; Extension->DeviceIsOpened = FALSE; Extension->OpenCount = 0; Extension->SendBreak = FALSE; Extension->OwnsPowerPolicy = TRUE; Extension->GlobalData = MoxaGlobalData; Extension->ControlDevice = FALSE; Extension->PowerState = PowerDeviceD3; // // Initialize the count of IRP's pending // Extension->PendingIRPCnt = 1; // // Initialize the count of DPC's pending // Extension->DpcCount = 1; InitializeListHead(&Extension->ReadQueue); InitializeListHead(&Extension->WriteQueue); InitializeListHead(&Extension->MaskQueue); InitializeListHead(&Extension->PurgeQueue); InitializeListHead(&Extension->AllDevObjs); InitializeListHead(&Extension->StalledIrpQueue); ExInitializeFastMutex(&Extension->OpenMutex); ExInitializeFastMutex(&Extension->CloseMutex); KeInitializeEvent(&Extension->PendingIRPEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&Extension->PendingDpcEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&Extension->PowerD0Event, SynchronizationEvent, FALSE); KeInitializeSpinLock(&Extension->ControlLock); KeInitializeTimer(&Extension->ReadRequestTotalTimer); KeInitializeTimer(&Extension->ReadRequestIntervalTimer); KeInitializeTimer(&Extension->WriteRequestTotalTimer); KeInitializeDpc( &Extension->CompleteWriteDpc, MoxaCompleteWrite, Extension ); KeInitializeDpc( &Extension->IsrOutDpc, MoxaIsrOut, Extension ); KeInitializeDpc( &Extension->CompleteReadDpc, MoxaCompleteRead, Extension ); KeInitializeDpc( &Extension->IsrInDpc, MoxaIsrIn, Extension ); KeInitializeDpc( &Extension->TotalReadTimeoutDpc, MoxaReadTimeout, Extension ); KeInitializeDpc( &Extension->IntervalReadTimeoutDpc, MoxaIntervalReadTimeout, Extension ); KeInitializeDpc( &Extension->TotalWriteTimeoutDpc, MoxaWriteTimeout, Extension ); KeInitializeDpc( &Extension->CommErrorDpc, MoxaCommError, Extension ); KeInitializeDpc( &Extension->CommWaitDpc, MoxaCompleteWait, Extension ); // // 9-24-01 by William // #if 0 KeInitializeDpc( &Extension->IntrLineDpc, MoxaIntrLine, Extension ); KeInitializeDpc( &Extension->IntrErrorDpc, MoxaIntrError, Extension ); #endif // end KeInitializeDpc( &Extension->IsrUnlockPagesDpc, MoxaUnlockPages, Extension); Extension->SpecialChars.EofChar = 0; Extension->SpecialChars.ErrorChar = 0; Extension->SpecialChars.BreakChar = 0; Extension->SpecialChars.EventChar = 0; Extension->SpecialChars.XonChar = 0x11; Extension->SpecialChars.XoffChar = 0x13; // Extension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL; Extension->HandFlow.ControlHandShake = 0; // Extension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL; Extension->HandFlow.FlowReplace = 0; Extension->DataMode = MOXA_8_DATA | MOXA_NONE_PARITY; Extension->ValidDataMask = 0xff; Extension->CurrentBaud = 38400; Extension->RxBufferSize = RxBufSize; Extension->TxBufferSize = TxBufSize; Extension->HandFlow.XoffLimit = Extension->RxBufferSize >> 3; Extension->HandFlow.XonLimit = Extension->RxBufferSize >> 1; Extension->BufferSizePt8 = ((3*(Extension->RxBufferSize>>2))+ (Extension->RxBufferSize>>4)); Extension->SupportedBauds = SERIAL_BAUD_USER | SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 | SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400; Extension->DeviceIsOpened = FALSE; Extension->ShortIntervalAmount.QuadPart = -1; Extension->LongIntervalAmount.QuadPart = -10000000; Extension->CutOverAmount.QuadPart = 200000000; ofs = Extension->PortOfs; count = 0; while ((*(ofs + FuncCode) != 0)&&(count++ < 500)) MoxaDelay(1); *(ofs + FuncCode) = FC_GetClockRate; count = 0; while ((*(ofs + FuncCode) != 0)&&(count++ < 500)) /* wait cmd process completed */ MoxaDelay(1); Extension->ClockType = *(ofs + FuncArg); /* 0, 1, 2 */ if (Extension->ClockType) { Extension->SupportedBauds |= SERIAL_BAUD_57600; if (Extension->ClockType == 2) Extension->SupportedBauds |= SERIAL_BAUD_115200; } Extension->MaxBaud = MaxBaud; } BOOLEAN MoxaGetStats( IN PVOID Context ) /*++ Routine Description: In sync with the interrpt service routine (which sets the perf stats) return the perf stats to the caller. Arguments: Context - Pointer to a the irp. Return Value: This routine always returns FALSE. --*/ { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation((PIRP)Context); PMOXA_DEVICE_EXTENSION extension = irpSp->DeviceObject->DeviceExtension; PSERIALPERF_STATS sp = ((PIRP)Context)->AssociatedIrp.SystemBuffer; *sp = extension->PerfStats; return FALSE; } BOOLEAN MoxaClearStats( IN PVOID Context ) /*++ Routine Description: In sync with the interrpt service routine (which sets the perf stats) clear the perf stats. Arguments: Context - Pointer to a the extension. Return Value: This routine always returns FALSE. --*/ { PSERIALPERF_STATS perf_stats; int port; perf_stats = &((PMOXA_DEVICE_EXTENSION)Context)->PerfStats; port = (int)(((PMOXA_DEVICE_EXTENSION)Context)->PortNo); MoxaTotalRx[port] += perf_stats->ReceivedCount; MoxaTotalTx[port] += perf_stats->TransmittedCount; RtlZeroMemory( perf_stats, sizeof(SERIALPERF_STATS) ); return FALSE; } MoxaReadReg( IN PUCHAR PortOfs, IN int reg ) { USHORT value; *(PUSHORT)(PortOfs + FuncArg) = (USHORT)reg; *(PortOfs + FuncCode) = FC_InUARTreg; MoxaWaitFinish(PortOfs); value = *(PUSHORT)(PortOfs + FuncArg1); return((int)value); } void MoxaWriteReg( IN PUCHAR PortOfs, IN int reg, IN int value ) { *(PUSHORT)(PortOfs + FuncArg1) = (USHORT)value; *(PUSHORT)(PortOfs + FuncArg) = (USHORT)reg; *(PortOfs + FuncCode) = FC_OutUARTreg; MoxaWaitFinish(PortOfs); } // // Internal Ioctl // NTSTATUS MoxaInternalIoControl(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp) /*++ Routine Description: This routine provides the initial processing for all of the internal Ioctrls for the serial device. Arguments: PDevObj - Pointer to the device object for this device PIrp - Pointer to the IRP for the current request Return Value: The function value is the final status of the call --*/ { // // The status that gets returned to the caller and // set in the Irp. // NTSTATUS status; // // The current stack location. This contains all of the // information we need to process this particular request. // PIO_STACK_LOCATION pIrpStack; // // Just what it says. This is the serial specific device // extension of the device object create for the serial driver. // PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; // // A temporary to hold the old IRQL so that it can be // restored once we complete/validate this request. // KIRQL OldIrql; NTSTATUS prologueStatus; if (pDevExt->ControlDevice) { // Control Device status = STATUS_CANCELLED; PIrp->IoStatus.Information = 0L; PIrp->IoStatus.Status = status; IoCompleteRequest( PIrp, 0 ); return status; } if ((prologueStatus = MoxaIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) { MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT); return prologueStatus; } if (MoxaCompleteIfError(PDevObj, PIrp) != STATUS_SUCCESS) { return STATUS_CANCELLED; } pIrpStack = IoGetCurrentIrpStackLocation(PIrp); PIrp->IoStatus.Information = 0L; status = STATUS_SUCCESS; switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) { // // Send a wait-wake IRP // case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE: pDevExt->SendWaitWake = TRUE; status = STATUS_SUCCESS; break; case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE: pDevExt->SendWaitWake = FALSE; if (pDevExt->PendingWakeIrp != NULL) { IoCancelIrp(pDevExt->PendingWakeIrp); } status = STATUS_SUCCESS; break; // // Put the serial port in a "filter-driver" appropriate state // // WARNING: This code assumes it is being called by a trusted kernel // entity and no checking is done on the validity of the settings // passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS // // If validity checking is desired, the regular ioctl's should be used // case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS: case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: { SERIAL_BASIC_SETTINGS basic; PSERIAL_BASIC_SETTINGS pBasic; SHORT AppropriateDivisor; MOXA_IOCTL_SYNC S; if (pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) { // // Check the buffer size // if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BASIC_SETTINGS)) { status = STATUS_BUFFER_TOO_SMALL; break; } // // Everything is 0 -- timeouts and flow control. If // We add additional features, this zero memory method // may not work. // RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS)); PIrp->IoStatus.Information = sizeof(SERIAL_BASIC_SETTINGS); pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer; // // Save off the old settings // RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts, sizeof(SERIAL_TIMEOUTS)); RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow, sizeof(SERIAL_HANDFLOW)); pBasic->RxFifo = pDevExt->RxFifoTrigger; pBasic->TxFifo = pDevExt->TxFifoAmount; // // Point to our new settings // pBasic = &basic; } else { // restoring settings if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BASIC_SETTINGS)) { status = STATUS_BUFFER_TOO_SMALL; break; } pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer; } KeAcquireSpinLock(&pDevExt->ControlLock, &OldIrql); // // Set the timeouts // RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts, sizeof(SERIAL_TIMEOUTS)); // // Set flowcontrol // S.Extension = pDevExt; S.Data = &pBasic->HandFlow; KeSynchronizeExecution(pDevExt->Interrupt, MoxaSetupNewHandFlow, &S); pDevExt->TxFifoAmount = (USHORT)pBasic->TxFifo; pDevExt->RxFifoTrigger = (USHORT)pBasic->RxFifo; MoxaFunc(pDevExt->PortOfs, FC_SetTxFIFOCnt,pDevExt->TxFifoAmount); MoxaFunc(pDevExt->PortOfs, FC_SetRxFIFOTrig,pDevExt->RxFifoTrigger); KeReleaseSpinLock(&pDevExt->ControlLock, OldIrql); break; } default: status = STATUS_INVALID_PARAMETER; break; } PIrp->IoStatus.Status = status; MoxaCompleteRequest(pDevExt, PIrp, 0); return status; }