Revision control
++ // Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
++ // Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
++ // Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qserialport_p.h"
++ #include "qwinoverlappedionotifier_p.h"
++
++ #include <QtCore/qcoreevent.h>
++ #include <QtCore/qelapsedtimer.h>
++ #include <QtCore/qlist.h>
++ #include <QtCore/qmutex.h>
++ #include <QtCore/qtimer.h>
++ #include <algorithm>
++
++ #ifndef CTL_CODE
++ # define CTL_CODE(DeviceType, Function, Method, Access) ( \
++ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
++ )
++ #endif
++
++ #ifndef FILE_DEVICE_SERIAL_PORT
++ # define FILE_DEVICE_SERIAL_PORT 27
++ #endif
++
++ #ifndef METHOD_BUFFERED
++ # define METHOD_BUFFERED 0
++ #endif
++
++ #ifndef FILE_ANY_ACCESS
++ # define FILE_ANY_ACCESS 0x00000000
++ #endif
++
++ #ifndef IOCTL_SERIAL_GET_DTRRTS
++ # define IOCTL_SERIAL_GET_DTRRTS \
++ CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
++ #endif
++
++ #ifndef SERIAL_DTR_STATE
++ # define SERIAL_DTR_STATE 0x00000001
++ #endif
++
++ #ifndef SERIAL_RTS_STATE
++ # define SERIAL_RTS_STATE 0x00000002
++ #endif
++
++ QT_BEGIN_NAMESPACE
++
++ static inline void qt_set_common_props(DCB *dcb)
++ {
++ dcb->fBinary = TRUE;
++ dcb->fAbortOnError = FALSE;
++ dcb->fNull = FALSE;
++ dcb->fErrorChar = FALSE;
++
++ if (dcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
++ dcb->fDtrControl = DTR_CONTROL_DISABLE;
++
++ if (dcb->fRtsControl != RTS_CONTROL_HANDSHAKE)
++ dcb->fRtsControl = RTS_CONTROL_DISABLE;
++ }
++
++ static inline void qt_set_baudrate(DCB *dcb, qint32 baudrate)
++ {
++ dcb->BaudRate = baudrate;
++ }
++
++ static inline void qt_set_databits(DCB *dcb, QSerialPort::DataBits databits)
++ {
++ dcb->ByteSize = databits;
++ }
++
++ static inline void qt_set_parity(DCB *dcb, QSerialPort::Parity parity)
++ {
++ dcb->fParity = TRUE;
++ switch (parity) {
++ case QSerialPort::NoParity:
++ dcb->Parity = NOPARITY;
++ dcb->fParity = FALSE;
++ break;
++ case QSerialPort::OddParity:
++ dcb->Parity = ODDPARITY;
++ break;
++ case QSerialPort::EvenParity:
++ dcb->Parity = EVENPARITY;
++ break;
++ case QSerialPort::MarkParity:
++ dcb->Parity = MARKPARITY;
++ break;
++ case QSerialPort::SpaceParity:
++ dcb->Parity = SPACEPARITY;
++ break;
++ default:
++ dcb->Parity = NOPARITY;
++ dcb->fParity = FALSE;
++ break;
++ }
++ }
++
++ static inline void qt_set_stopbits(DCB *dcb, QSerialPort::StopBits stopbits)
++ {
++ switch (stopbits) {
++ case QSerialPort::OneStop:
++ dcb->StopBits = ONESTOPBIT;
++ break;
++ case QSerialPort::OneAndHalfStop:
++ dcb->StopBits = ONE5STOPBITS;
++ break;
++ case QSerialPort::TwoStop:
++ dcb->StopBits = TWOSTOPBITS;
++ break;
++ default:
++ dcb->StopBits = ONESTOPBIT;
++ break;
++ }
++ }
++
++ static inline void qt_set_flowcontrol(DCB *dcb, QSerialPort::FlowControl flowcontrol)
++ {
++ dcb->fInX = FALSE;
++ dcb->fOutX = FALSE;
++ dcb->fOutxCtsFlow = FALSE;
++ if (dcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
++ dcb->fRtsControl = RTS_CONTROL_DISABLE;
++ switch (flowcontrol) {
++ case QSerialPort::NoFlowControl:
++ break;
++ case QSerialPort::SoftwareControl:
++ dcb->fInX = TRUE;
++ dcb->fOutX = TRUE;
++ break;
++ case QSerialPort::HardwareControl:
++ dcb->fOutxCtsFlow = TRUE;
++ dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
++ break;
++ default:
++ break;
++ }
++ }
++
++ bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
++ {
++ DWORD desiredAccess = 0;
++
++ if (mode & QIODevice::ReadOnly)
++ desiredAccess |= GENERIC_READ;
++ if (mode & QIODevice::WriteOnly)
++ desiredAccess |= GENERIC_WRITE;
++
++ handle = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
++ desiredAccess, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
++
++ if (handle == INVALID_HANDLE_VALUE) {
++ setError(getSystemError());
++ return false;
++ }
++
++ if (initialize(mode))
++ return true;
++
++ ::CloseHandle(handle);
++ return false;
++ }
++
++ void QSerialPortPrivate::close()
++ {
++ ::CancelIo(handle);
++
++ delete notifier;
++ notifier = nullptr;
++
++ delete startAsyncWriteTimer;
++ startAsyncWriteTimer = nullptr;
++
++ communicationStarted = false;
++ readStarted = false;
++ writeStarted = false;
++ writeBuffer.clear();
++
++ if (settingsRestoredOnClose) {
++ ::SetCommState(handle, &restoredDcb);
++ ::SetCommTimeouts(handle, &restoredCommTimeouts);
++ }
++
++ ::CloseHandle(handle);
++ handle = INVALID_HANDLE_VALUE;
++ }
++
++ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
++ {
++ DWORD modemStat = 0;
++
++ if (!::GetCommModemStatus(handle, &modemStat)) {
++ setError(getSystemError());
++ return QSerialPort::NoSignal;
++ }
++
++ QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
++
++ if (modemStat & MS_CTS_ON)
++ ret |= QSerialPort::ClearToSendSignal;
++ if (modemStat & MS_DSR_ON)
++ ret |= QSerialPort::DataSetReadySignal;
++ if (modemStat & MS_RING_ON)
++ ret |= QSerialPort::RingIndicatorSignal;
++ if (modemStat & MS_RLSD_ON)
++ ret |= QSerialPort::DataCarrierDetectSignal;
++
++ DWORD bytesReturned = 0;
++ if (!::DeviceIoControl(handle, IOCTL_SERIAL_GET_DTRRTS, nullptr, 0,
++ &modemStat, sizeof(modemStat),
++ &bytesReturned, nullptr)) {
++ setError(getSystemError());
++ return ret;
++ }
++
++ if (modemStat & SERIAL_DTR_STATE)
++ ret |= QSerialPort::DataTerminalReadySignal;
++ if (modemStat & SERIAL_RTS_STATE)
++ ret |= QSerialPort::RequestToSendSignal;
++
++ return ret;
++ }
++
++ bool QSerialPortPrivate::setDataTerminalReady(bool set)
++ {
++ if (!::EscapeCommFunction(handle, set ? SETDTR : CLRDTR)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ dcb.fDtrControl = set ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE;
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::setRequestToSend(bool set)
++ {
++ if (!::EscapeCommFunction(handle, set ? SETRTS : CLRRTS)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ dcb.fRtsControl = set ? RTS_CONTROL_ENABLE : RTS_CONTROL_DISABLE;
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::flush()
++ {
++ return _q_startAsyncWrite();
++ }
++
++ bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
++ {
++ DWORD flags = 0;
++ if (directions & QSerialPort::Input)
++ flags |= PURGE_RXABORT | PURGE_RXCLEAR;
++ if (directions & QSerialPort::Output)
++ flags |= PURGE_TXABORT | PURGE_TXCLEAR;
++ if (!::PurgeComm(handle, flags)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ // We need start async read because a reading can be stalled. Since the
++ // PurgeComm can abort of current reading sequence, or a port is in hardware
++ // flow control mode, or a port has a limited read buffer size.
++ if (directions & QSerialPort::Input)
++ startAsyncCommunication();
++
++ return true;
++ }
++
++ bool QSerialPortPrivate::sendBreak(int duration)
++ {
++ if (!setBreakEnabled(true))
++ return false;
++
++ ::Sleep(duration);
++
++ if (!setBreakEnabled(false))
++ return false;
++
++ return true;
++ }
++
++ bool QSerialPortPrivate::setBreakEnabled(bool set)
++ {
++ if (set ? !::SetCommBreak(handle) : !::ClearCommBreak(handle)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ return true;
++ }
++
++ bool QSerialPortPrivate::waitForReadyRead(int msecs)
++ {
++ if (!writeStarted && !_q_startAsyncWrite())
++ return false;
++
++ const qint64 initialReadBufferSize = buffer.size();
++ qint64 currentReadBufferSize = initialReadBufferSize;
++
++ QDeadlineTimer deadline(msecs);
++
++ do {
++ const OVERLAPPED *overlapped = waitForNotified(deadline);
++ if (!overlapped)
++ return false;
++
++ if (overlapped == &readCompletionOverlapped) {
++ const qint64 readBytesForOneReadOperation = qint64(buffer.size()) - currentReadBufferSize;
++ if (readBytesForOneReadOperation == QSERIALPORT_BUFFERSIZE) {
++ currentReadBufferSize = buffer.size();
++ } else if (readBytesForOneReadOperation == 0) {
++ if (initialReadBufferSize != currentReadBufferSize)
++ return true;
++ } else {
++ return true;
++ }
++ }
++
++ } while (!deadline.hasExpired());
++
++ return false;
++ }
++
++ bool QSerialPortPrivate::waitForBytesWritten(int msecs)
++ {
++ if (writeBuffer.isEmpty() && writeChunkBuffer.isEmpty())
++ return false;
++
++ if (!writeStarted && !_q_startAsyncWrite())
++ return false;
++
++ QDeadlineTimer deadline(msecs);
++
++ for (;;) {
++ const OVERLAPPED *overlapped = waitForNotified(deadline);
++ if (!overlapped)
++ return false;
++
++ if (overlapped == &writeCompletionOverlapped)
++ return true;
++ }
++
++ return false;
++ }
++
++ bool QSerialPortPrivate::setBaudRate()
++ {
++ return setBaudRate(inputBaudRate, QSerialPort::AllDirections);
++ }
++
++ bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
++ {
++ if (directions != QSerialPort::AllDirections) {
++ setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate direction is unsupported")));
++ return false;
++ }
++
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ qt_set_baudrate(&dcb, baudRate);
++
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
++ {
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ qt_set_databits(&dcb, dataBits);
++
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
++ {
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ qt_set_parity(&dcb, parity);
++
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
++ {
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ qt_set_stopbits(&dcb, stopBits);
++
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
++ {
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ qt_set_flowcontrol(&dcb, flowControl);
++
++ return setDcb(&dcb);
++ }
++
++ bool QSerialPortPrivate::completeAsyncCommunication(qint64 bytesTransferred)
++ {
++ communicationStarted = false;
++
++ if (bytesTransferred == qint64(-1))
++ return false;
++
++ return startAsyncRead();
++ }
++
++ bool QSerialPortPrivate::completeAsyncRead(qint64 bytesTransferred)
++ {
++ if (bytesTransferred == qint64(-1)) {
++ readStarted = false;
++ return false;
++ }
++ if (bytesTransferred > 0)
++ buffer.append(readChunkBuffer.constData(), bytesTransferred);
++
++ readStarted = false;
++
++ bool result = true;
++ if (bytesTransferred == QSERIALPORT_BUFFERSIZE
++ || queuedBytesCount(QSerialPort::Input) > 0) {
++ result = startAsyncRead();
++ } else {
++ result = startAsyncCommunication();
++ }
++
++ if (bytesTransferred > 0)
++ emitReadyRead();
++
++ return result;
++ }
++
++ bool QSerialPortPrivate::completeAsyncWrite(qint64 bytesTransferred)
++ {
++ Q_Q(QSerialPort);
++
++ if (writeStarted) {
++ if (bytesTransferred == qint64(-1)) {
++ writeChunkBuffer.clear();
++ writeStarted = false;
++ return false;
++ }
++ Q_ASSERT(bytesTransferred == writeChunkBuffer.size());
++ writeChunkBuffer.clear();
++ emit q->bytesWritten(bytesTransferred);
++ writeStarted = false;
++ }
++
++ return _q_startAsyncWrite();
++ }
++
++ bool QSerialPortPrivate::startAsyncCommunication()
++ {
++ if (communicationStarted)
++ return true;
++
++ ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped));
++ if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) {
++ QSerialPortErrorInfo error = getSystemError();
++ if (error.errorCode != QSerialPort::NoError) {
++ if (error.errorCode == QSerialPort::PermissionError)
++ error.errorCode = QSerialPort::ResourceError;
++ setError(error);
++ return false;
++ }
++ }
++ communicationStarted = true;
++ return true;
++ }
++
++ bool QSerialPortPrivate::startAsyncRead()
++ {
++ if (readStarted)
++ return true;
++
++ qint64 bytesToRead = QSERIALPORT_BUFFERSIZE;
++
++ if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - buffer.size())) {
++ bytesToRead = readBufferMaxSize - buffer.size();
++ if (bytesToRead <= 0) {
++ // Buffer is full. User must read data from the buffer
++ // before we can read more from the port.
++ return false;
++ }
++ }
++
++ Q_ASSERT(int(bytesToRead) <= readChunkBuffer.size());
++
++ ::ZeroMemory(&readCompletionOverlapped, sizeof(readCompletionOverlapped));
++ if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, nullptr, &readCompletionOverlapped)) {
++ readStarted = true;
++ return true;
++ }
++
++ QSerialPortErrorInfo error = getSystemError();
++ if (error.errorCode != QSerialPort::NoError) {
++ if (error.errorCode == QSerialPort::PermissionError)
++ error.errorCode = QSerialPort::ResourceError;
++ if (error.errorCode != QSerialPort::ResourceError)
++ error.errorCode = QSerialPort::ReadError;
++ setError(error);
++ return false;
++ }
++
++ readStarted = true;
++ return true;
++ }
++
++ bool QSerialPortPrivate::_q_startAsyncWrite()
++ {
++ if (handle == INVALID_HANDLE_VALUE) {
++ // Prevent a crash if the application incorrectly has not called open() before
++ // calling this (QTBUG-120412)
++ return false;
++ }
++
++ if (writeBuffer.isEmpty() || writeStarted)
++ return true;
++
++ writeChunkBuffer = writeBuffer.read();
++ ::ZeroMemory(&writeCompletionOverlapped, sizeof(writeCompletionOverlapped));
++ if (!::WriteFile(handle, writeChunkBuffer.constData(),
++ writeChunkBuffer.size(), nullptr, &writeCompletionOverlapped)) {
++
++ QSerialPortErrorInfo error = getSystemError();
++ if (error.errorCode != QSerialPort::NoError) {
++ if (error.errorCode != QSerialPort::ResourceError)
++ error.errorCode = QSerialPort::WriteError;
++ setError(error);
++ return false;
++ }
++ }
++
++ writeStarted = true;
++ return true;
++ }
++
++ void QSerialPortPrivate::_q_notified(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped)
++ {
++ const QSerialPortErrorInfo error = getSystemError(errorCode);
++ if (error.errorCode != QSerialPort::NoError) {
++ setError(error);
++ return;
++ }
++
++ if (overlapped == &communicationOverlapped)
++ completeAsyncCommunication(numberOfBytes);
++ else if (overlapped == &readCompletionOverlapped)
++ completeAsyncRead(numberOfBytes);
++ else if (overlapped == &writeCompletionOverlapped)
++ completeAsyncWrite(numberOfBytes);
++ else
++ Q_ASSERT(!"Unknown OVERLAPPED activated");
++ }
++
++ void QSerialPortPrivate::emitReadyRead()
++ {
++ Q_Q(QSerialPort);
++
++ if (!emittedReadyRead) {
++ emittedReadyRead = true;
++ emit q->readyRead();
++ emittedReadyRead = false;
++ }
++ }
++
++ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
++ {
++ Q_Q(QSerialPort);
++
++ qint64 toAppend = maxSize;
++
++ if (writeBufferMaxSize && (writeBuffer.size() + toAppend > writeBufferMaxSize))
++ toAppend = writeBufferMaxSize - writeBuffer.size();
++
++ writeBuffer.append(data, toAppend);
++
++ if (!writeBuffer.isEmpty() && !writeStarted) {
++ if (!startAsyncWriteTimer) {
++ startAsyncWriteTimer = new QTimer(q);
++ QObjectPrivate::connect(startAsyncWriteTimer, &QTimer::timeout, this, &QSerialPortPrivate::_q_startAsyncWrite);
++ startAsyncWriteTimer->setSingleShot(true);
++ }
++ if (!startAsyncWriteTimer->isActive())
++ startAsyncWriteTimer->start();
++ }
++ return toAppend;
++ }
++
++ OVERLAPPED *QSerialPortPrivate::waitForNotified(QDeadlineTimer deadline)
++ {
++ OVERLAPPED *overlapped = notifier->waitForAnyNotified(deadline);
++ if (!overlapped) {
++ setError(getSystemError(WAIT_TIMEOUT));
++ return nullptr;
++ }
++ return overlapped;
++ }
++
++ qint64 QSerialPortPrivate::queuedBytesCount(QSerialPort::Direction direction) const
++ {
++ COMSTAT comstat;
++ if (::ClearCommError(handle, nullptr, &comstat) == 0)
++ return -1;
++ return (direction == QSerialPort::Input)
++ ? comstat.cbInQue
++ : ((direction == QSerialPort::Output) ? comstat.cbOutQue : -1);
++ }
++
++ inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
++ {
++ Q_Q(QSerialPort);
++
++ DCB dcb;
++ if (!getDcb(&dcb))
++ return false;
++
++ restoredDcb = dcb;
++
++ if (!::GetCommTimeouts(handle, &restoredCommTimeouts)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ auto restoreParametersOnError = qScopeGuard([this] {
++ if (settingsRestoredOnClose) {
++ ::SetCommState(handle, &restoredDcb);
++ ::SetCommTimeouts(handle, &restoredCommTimeouts);
++ }
++ });
++
++ qt_set_common_props(&dcb);
++ qt_set_baudrate(&dcb, inputBaudRate);
++ qt_set_databits(&dcb, dataBits);
++ qt_set_parity(&dcb, parity);
++ qt_set_stopbits(&dcb, stopBits);
++ qt_set_flowcontrol(&dcb, flowControl);
++
++ if (!setDcb(&dcb))
++ return false;
++
++ ::ZeroMemory(¤tCommTimeouts, sizeof(currentCommTimeouts));
++ currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
++
++ if (!::SetCommTimeouts(handle, ¤tCommTimeouts)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ const DWORD eventMask = (mode & QIODevice::ReadOnly) ? EV_RXCHAR : 0;
++ if (!::SetCommMask(handle, eventMask)) {
++ setError(getSystemError());
++ return false;
++ }
++
++ notifier = new QWinOverlappedIoNotifier(q);
++ QObjectPrivate::connect(notifier, &QWinOverlappedIoNotifier::notified,
++ this, &QSerialPortPrivate::_q_notified);
++ notifier->setHandle(handle);
++ notifier->setEnabled(true);
++
++ if ((eventMask & EV_RXCHAR) && !startAsyncCommunication()) {
++ delete notifier;
++ notifier = nullptr;
++ return false;
++ }
++
++ restoreParametersOnError.dismiss();
++ return true;
++ }
++
++ bool QSerialPortPrivate::setDcb(DCB *dcb)
++ {
++ if (!::SetCommState(handle, dcb)) {
++ setError(getSystemError());
++ return false;
++ }
++ return true;
++ }
++
++ bool QSerialPortPrivate::getDcb(DCB *dcb)
++ {
++ ::ZeroMemory(dcb, sizeof(DCB));
++ dcb->DCBlength = sizeof(DCB);
++
++ if (!::GetCommState(handle, dcb)) {
++ setError(getSystemError());
++ return false;
++ }
++ return true;
++ }
++
++ QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
++ {
++ if (systemErrorCode == -1)
++ systemErrorCode = ::GetLastError();
++
++ QSerialPortErrorInfo error;
++ error.errorString = qt_error_string(systemErrorCode);
++
++ switch (systemErrorCode) {
++ case ERROR_SUCCESS:
++ error.errorCode = QSerialPort::NoError;
++ break;
++ case ERROR_IO_PENDING:
++ error.errorCode = QSerialPort::NoError;
++ break;
++ case ERROR_MORE_DATA:
++ error.errorCode = QSerialPort::NoError;
++ break;
++ case ERROR_FILE_NOT_FOUND:
++ error.errorCode = QSerialPort::DeviceNotFoundError;
++ break;
++ case ERROR_PATH_NOT_FOUND:
++ error.errorCode = QSerialPort::DeviceNotFoundError;
++ break;
++ case ERROR_INVALID_NAME:
++ error.errorCode = QSerialPort::DeviceNotFoundError;
++ break;
++ case ERROR_ACCESS_DENIED:
++ error.errorCode = QSerialPort::PermissionError;
++ break;
++ case ERROR_INVALID_HANDLE:
++ error.errorCode = QSerialPort::ResourceError;
++ break;
++ case ERROR_INVALID_PARAMETER:
++ error.errorCode = QSerialPort::UnsupportedOperationError;
++ break;
++ case ERROR_BAD_COMMAND:
++ error.errorCode = QSerialPort::ResourceError;
++ break;
++ case ERROR_DEVICE_REMOVED:
++ error.errorCode = QSerialPort::ResourceError;
++ break;
++ case ERROR_OPERATION_ABORTED:
++ error.errorCode = QSerialPort::ResourceError;
++ break;
++ case WAIT_TIMEOUT:
++ error.errorCode = QSerialPort::TimeoutError;
++ break;
++ default:
++ error.errorCode = QSerialPort::UnknownError;
++ break;
++ }
++ return error;
++ }
++
++ // This table contains standard values of baud rates that
++ // are defined in file winbase.h
++ QList<qint32> QSerialPortPrivate::standardBaudRates()
++ {
++ static const QList<qint32> baudRates = {
++ CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400,
++ CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400,
++ CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000
++ };
++
++ return baudRates;
++ }
++
++ QSerialPort::Handle QSerialPort::handle() const
++ {
++ Q_D(const QSerialPort);
++ return d->handle;
++ }
++
++ QT_END_NAMESPACE