1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
4 ** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
5 ** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtSerialPort module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qserialport_p.h"
43 #include "qserialportinfo_p.h"
44 
45 #include <QtCore/qelapsedtimer.h>
46 #include <QtCore/qmap.h>
47 #include <QtCore/qsocketnotifier.h>
48 #include <QtCore/qstandardpaths.h>
49 
50 #include <private/qcore_unix_p.h>
51 
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <sys/ioctl.h>
55 #include <sys/time.h>
56 #include <unistd.h>
57 
58 #ifdef Q_OS_OSX
59 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
60 #include <IOKit/serial/ioss.h>
61 #endif
62 #endif
63 
64 #ifdef Q_OS_QNX
65 #define CRTSCTS (IHFLOW | OHFLOW)
66 #endif
67 
68 #ifdef Q_OS_LINUX
69 
70 # ifdef Q_OS_ANDROID
71 #  include <android/api-level.h>
72 # else
73 #  define __ANDROID_API__ 16
74 # endif
75 
76 # if !defined(Q_OS_ANDROID) || (!defined(Q_PROCESSOR_X86) && __ANDROID_API__ < 16)
77 struct termios2 {
78     tcflag_t c_iflag;       /* input mode flags */
79     tcflag_t c_oflag;       /* output mode flags */
80     tcflag_t c_cflag;       /* control mode flags */
81     tcflag_t c_lflag;       /* local mode flags */
82     cc_t c_line;            /* line discipline */
83     cc_t c_cc[19];          /* control characters */
84     speed_t c_ispeed;       /* input speed */
85     speed_t c_ospeed;       /* output speed */
86 };
87 # endif
88 
89 #ifndef TCGETS2
90 #define TCGETS2     _IOR('T', 0x2A, struct termios2)
91 #endif
92 
93 #ifndef TCSETS2
94 #define TCSETS2     _IOW('T', 0x2B, struct termios2)
95 #endif
96 
97 #ifndef BOTHER
98 #define BOTHER      0010000
99 #endif
100 
101 #endif
102 
103 QT_BEGIN_NAMESPACE
104 
serialPortLockFilePath(const QString & portName)105 QString serialPortLockFilePath(const QString &portName)
106 {
107     static const QStringList lockDirectoryPaths = QStringList()
108         << QStringLiteral("/var/lock")
109         << QStringLiteral("/etc/locks")
110         << QStringLiteral("/var/spool/locks")
111         << QStringLiteral("/var/spool/uucp")
112         << QStringLiteral("/tmp")
113         << QStringLiteral("/var/tmp")
114         << QStringLiteral("/var/lock/lockdev")
115         << QStringLiteral("/run/lock")
116 #ifdef Q_OS_ANDROID
117         << QStringLiteral("/data/local/tmp")
118 #endif
119         << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
120 
121     QString fileName = portName;
122     fileName.replace(QLatin1Char('/'), QLatin1Char('_'));
123     fileName.prepend(QLatin1String("/LCK.."));
124 
125     QString lockFilePath;
126 
127     for (const QString &lockDirectoryPath : lockDirectoryPaths) {
128         const QString filePath = lockDirectoryPath + fileName;
129 
130         QFileInfo lockDirectoryInfo(lockDirectoryPath);
131         if (lockDirectoryInfo.isReadable()) {
132             if (QFile::exists(filePath) || lockDirectoryInfo.isWritable()) {
133                 lockFilePath = filePath;
134                 break;
135             }
136         }
137     }
138 
139     if (lockFilePath.isEmpty()) {
140         qWarning("The following directories are not readable or writable for detaling with lock files\n");
141         for (const QString &lockDirectoryPath : lockDirectoryPaths)
142             qWarning("\t%s\n", qPrintable(lockDirectoryPath));
143         return QString();
144     }
145 
146     return lockFilePath;
147 }
148 
149 class ReadNotifier : public QSocketNotifier
150 {
151 public:
ReadNotifier(QSerialPortPrivate * d,QObject * parent)152     explicit ReadNotifier(QSerialPortPrivate *d, QObject *parent)
153         : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
154         , dptr(d)
155     {
156     }
157 
158 protected:
event(QEvent * e)159     bool event(QEvent *e) override
160     {
161         if (e->type() == QEvent::SockAct) {
162             dptr->readNotification();
163             return true;
164         }
165         return QSocketNotifier::event(e);
166     }
167 
168 private:
169     QSerialPortPrivate * const dptr;
170 };
171 
172 class WriteNotifier : public QSocketNotifier
173 {
174 public:
WriteNotifier(QSerialPortPrivate * d,QObject * parent)175     explicit WriteNotifier(QSerialPortPrivate *d, QObject *parent)
176         : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
177         , dptr(d)
178     {
179     }
180 
181 protected:
event(QEvent * e)182     bool event(QEvent *e) override
183     {
184         if (e->type() == QEvent::SockAct) {
185             dptr->completeAsyncWrite();
186             return true;
187         }
188         return QSocketNotifier::event(e);
189     }
190 
191 private:
192     QSerialPortPrivate * const dptr;
193 };
194 
qt_set_common_props(termios * tio,QIODevice::OpenMode m)195 static inline void qt_set_common_props(termios *tio, QIODevice::OpenMode m)
196 {
197 #ifdef Q_OS_SOLARIS
198     tio->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
199     tio->c_oflag &= ~OPOST;
200     tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
201     tio->c_cflag &= ~(CSIZE|PARENB);
202     tio->c_cflag |= CS8;
203 #else
204     ::cfmakeraw(tio);
205 #endif
206 
207     tio->c_cflag |= CLOCAL;
208     tio->c_cc[VTIME] = 0;
209     tio->c_cc[VMIN] = 0;
210 
211     if (m & QIODevice::ReadOnly)
212         tio->c_cflag |= CREAD;
213 }
214 
qt_set_databits(termios * tio,QSerialPort::DataBits databits)215 static inline void qt_set_databits(termios *tio, QSerialPort::DataBits databits)
216 {
217     tio->c_cflag &= ~CSIZE;
218     switch (databits) {
219     case QSerialPort::Data5:
220         tio->c_cflag |= CS5;
221         break;
222     case QSerialPort::Data6:
223         tio->c_cflag |= CS6;
224         break;
225     case QSerialPort::Data7:
226         tio->c_cflag |= CS7;
227         break;
228     case QSerialPort::Data8:
229         tio->c_cflag |= CS8;
230         break;
231     default:
232         tio->c_cflag |= CS8;
233         break;
234     }
235 }
236 
qt_set_parity(termios * tio,QSerialPort::Parity parity)237 static inline void qt_set_parity(termios *tio, QSerialPort::Parity parity)
238 {
239     tio->c_iflag &= ~(PARMRK | INPCK);
240     tio->c_iflag |= IGNPAR;
241 
242     switch (parity) {
243 
244 #ifdef CMSPAR
245     // Here Installation parity only for GNU/Linux where the macro CMSPAR.
246     case QSerialPort::SpaceParity:
247         tio->c_cflag &= ~PARODD;
248         tio->c_cflag |= PARENB | CMSPAR;
249         break;
250     case QSerialPort::MarkParity:
251         tio->c_cflag |= PARENB | CMSPAR | PARODD;
252         break;
253 #endif
254     case QSerialPort::NoParity:
255         tio->c_cflag &= ~PARENB;
256         break;
257     case QSerialPort::EvenParity:
258         tio->c_cflag &= ~PARODD;
259         tio->c_cflag |= PARENB;
260         break;
261     case QSerialPort::OddParity:
262         tio->c_cflag |= PARENB | PARODD;
263         break;
264     default:
265         tio->c_cflag |= PARENB;
266         tio->c_iflag |= PARMRK | INPCK;
267         tio->c_iflag &= ~IGNPAR;
268         break;
269     }
270 }
271 
qt_set_stopbits(termios * tio,QSerialPort::StopBits stopbits)272 static inline void qt_set_stopbits(termios *tio, QSerialPort::StopBits stopbits)
273 {
274     switch (stopbits) {
275     case QSerialPort::OneStop:
276         tio->c_cflag &= ~CSTOPB;
277         break;
278     case QSerialPort::TwoStop:
279         tio->c_cflag |= CSTOPB;
280         break;
281     default:
282         tio->c_cflag &= ~CSTOPB;
283         break;
284     }
285 }
286 
qt_set_flowcontrol(termios * tio,QSerialPort::FlowControl flowcontrol)287 static inline void qt_set_flowcontrol(termios *tio, QSerialPort::FlowControl flowcontrol)
288 {
289     switch (flowcontrol) {
290     case QSerialPort::NoFlowControl:
291         tio->c_cflag &= ~CRTSCTS;
292         tio->c_iflag &= ~(IXON | IXOFF | IXANY);
293         break;
294     case QSerialPort::HardwareControl:
295         tio->c_cflag |= CRTSCTS;
296         tio->c_iflag &= ~(IXON | IXOFF | IXANY);
297         break;
298     case QSerialPort::SoftwareControl:
299         tio->c_cflag &= ~CRTSCTS;
300         tio->c_iflag |= IXON | IXOFF | IXANY;
301         break;
302     default:
303         tio->c_cflag &= ~CRTSCTS;
304         tio->c_iflag &= ~(IXON | IXOFF | IXANY);
305         break;
306     }
307 }
308 
open(QIODevice::OpenMode mode)309 bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
310 {
311     QString lockFilePath = serialPortLockFilePath(QSerialPortInfoPrivate::portNameFromSystemLocation(systemLocation));
312     bool isLockFileEmpty = lockFilePath.isEmpty();
313     if (isLockFileEmpty) {
314         qWarning("Failed to create a lock file for opening the device");
315         setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while creating lock file")));
316         return false;
317     }
318 
319     QScopedPointer<QLockFile> newLockFileScopedPointer(new QLockFile(lockFilePath));
320 
321     if (!newLockFileScopedPointer->tryLock()) {
322         setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while locking the device")));
323         return false;
324     }
325 
326     int flags = O_NOCTTY | O_NONBLOCK;
327 
328     switch (mode & QIODevice::ReadWrite) {
329     case QIODevice::WriteOnly:
330         flags |= O_WRONLY;
331         break;
332     case QIODevice::ReadWrite:
333         flags |= O_RDWR;
334         break;
335     default:
336         flags |= O_RDONLY;
337         break;
338     }
339 
340     descriptor = qt_safe_open(systemLocation.toLocal8Bit().constData(), flags);
341 
342     if (descriptor == -1) {
343         setError(getSystemError());
344         return false;
345     }
346 
347     if (!initialize(mode)) {
348         qt_safe_close(descriptor);
349         return false;
350     }
351 
352     lockFileScopedPointer.swap(newLockFileScopedPointer);
353 
354     return true;
355 }
356 
close()357 void QSerialPortPrivate::close()
358 {
359     if (settingsRestoredOnClose)
360         ::tcsetattr(descriptor, TCSANOW, &restoredTermios);
361 
362 #ifdef TIOCNXCL
363     ::ioctl(descriptor, TIOCNXCL);
364 #endif
365 
366     delete readNotifier;
367     readNotifier = nullptr;
368 
369     delete writeNotifier;
370     writeNotifier = nullptr;
371 
372     qt_safe_close(descriptor);
373 
374     lockFileScopedPointer.reset(nullptr);
375 
376     descriptor = -1;
377     pendingBytesWritten = 0;
378     writeSequenceStarted = false;
379 }
380 
pinoutSignals()381 QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
382 {
383     int arg = 0;
384 
385     if (::ioctl(descriptor, TIOCMGET, &arg) == -1) {
386         setError(getSystemError());
387         return QSerialPort::NoSignal;
388     }
389 
390     QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
391 
392 #ifdef TIOCM_LE
393     if (arg & TIOCM_LE)
394         ret |= QSerialPort::DataSetReadySignal;
395 #endif
396 #ifdef TIOCM_DTR
397     if (arg & TIOCM_DTR)
398         ret |= QSerialPort::DataTerminalReadySignal;
399 #endif
400 #ifdef TIOCM_RTS
401     if (arg & TIOCM_RTS)
402         ret |= QSerialPort::RequestToSendSignal;
403 #endif
404 #ifdef TIOCM_ST
405     if (arg & TIOCM_ST)
406         ret |= QSerialPort::SecondaryTransmittedDataSignal;
407 #endif
408 #ifdef TIOCM_SR
409     if (arg & TIOCM_SR)
410         ret |= QSerialPort::SecondaryReceivedDataSignal;
411 #endif
412 #ifdef TIOCM_CTS
413     if (arg & TIOCM_CTS)
414         ret |= QSerialPort::ClearToSendSignal;
415 #endif
416 #ifdef TIOCM_CAR
417     if (arg & TIOCM_CAR)
418         ret |= QSerialPort::DataCarrierDetectSignal;
419 #elif defined(TIOCM_CD)
420     if (arg & TIOCM_CD)
421         ret |= QSerialPort::DataCarrierDetectSignal;
422 #endif
423 #ifdef TIOCM_RNG
424     if (arg & TIOCM_RNG)
425         ret |= QSerialPort::RingIndicatorSignal;
426 #elif defined(TIOCM_RI)
427     if (arg & TIOCM_RI)
428         ret |= QSerialPort::RingIndicatorSignal;
429 #endif
430 #ifdef TIOCM_DSR
431     if (arg & TIOCM_DSR)
432         ret |= QSerialPort::DataSetReadySignal;
433 #endif
434 
435     return ret;
436 }
437 
setDataTerminalReady(bool set)438 bool QSerialPortPrivate::setDataTerminalReady(bool set)
439 {
440     int status = TIOCM_DTR;
441     if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
442         setError(getSystemError());
443         return false;
444     }
445 
446     return true;
447 }
448 
setRequestToSend(bool set)449 bool QSerialPortPrivate::setRequestToSend(bool set)
450 {
451     int status = TIOCM_RTS;
452     if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
453         setError(getSystemError());
454         return false;
455     }
456 
457     return true;
458 }
459 
flush()460 bool QSerialPortPrivate::flush()
461 {
462     return completeAsyncWrite();
463 }
464 
clear(QSerialPort::Directions directions)465 bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
466 {
467     if (::tcflush(descriptor, (directions == QSerialPort::AllDirections)
468                      ? TCIOFLUSH : (directions & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) == -1) {
469         setError(getSystemError());
470         return false;
471     }
472 
473     return true;
474 }
475 
sendBreak(int duration)476 bool QSerialPortPrivate::sendBreak(int duration)
477 {
478     if (::tcsendbreak(descriptor, duration) == -1) {
479         setError(getSystemError());
480         return false;
481     }
482 
483     return true;
484 }
485 
setBreakEnabled(bool set)486 bool QSerialPortPrivate::setBreakEnabled(bool set)
487 {
488     if (::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) == -1) {
489         setError(getSystemError());
490         return false;
491     }
492 
493     return true;
494 }
495 
waitForReadyRead(int msecs)496 bool QSerialPortPrivate::waitForReadyRead(int msecs)
497 {
498     QElapsedTimer stopWatch;
499     stopWatch.start();
500 
501     do {
502         bool readyToRead = false;
503         bool readyToWrite = false;
504         if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
505                                 qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
506             return false;
507         }
508 
509         if (readyToRead)
510             return readNotification();
511 
512         if (readyToWrite && !completeAsyncWrite())
513             return false;
514     } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
515     return false;
516 }
517 
waitForBytesWritten(int msecs)518 bool QSerialPortPrivate::waitForBytesWritten(int msecs)
519 {
520     if (writeBuffer.isEmpty() && pendingBytesWritten <= 0)
521         return false;
522 
523     QElapsedTimer stopWatch;
524     stopWatch.start();
525 
526     for (;;) {
527         bool readyToRead = false;
528         bool readyToWrite = false;
529         const bool checkRead = q_func()->isReadable();
530         if (!waitForReadOrWrite(&readyToRead, &readyToWrite, checkRead, !writeBuffer.isEmpty(),
531                                 qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
532             return false;
533         }
534 
535         if (readyToRead && !readNotification())
536             return false;
537 
538         if (readyToWrite)
539             return completeAsyncWrite();
540     }
541     return false;
542 }
543 
setBaudRate()544 bool QSerialPortPrivate::setBaudRate()
545 {
546     if (inputBaudRate == outputBaudRate)
547         return setBaudRate(inputBaudRate, QSerialPort::AllDirections);
548 
549     return (setBaudRate(inputBaudRate, QSerialPort::Input)
550         && setBaudRate(outputBaudRate, QSerialPort::Output));
551 }
552 
setStandardBaudRate(qint32 baudRate,QSerialPort::Directions directions)553 bool QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions)
554 {
555 #ifdef Q_OS_LINUX
556     // try to clear custom baud rate, using termios v2
557     struct termios2 tio2;
558     if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
559         if (tio2.c_cflag & BOTHER) {
560             tio2.c_cflag &= ~BOTHER;
561             tio2.c_cflag |= CBAUD;
562             ::ioctl(descriptor, TCSETS2, &tio2);
563         }
564     }
565 
566     // try to clear custom baud rate, using serial_struct (old way)
567     struct serial_struct serial;
568     ::memset(&serial, 0, sizeof(serial));
569     if (::ioctl(descriptor, TIOCGSERIAL, &serial) != -1) {
570         if (serial.flags & ASYNC_SPD_CUST) {
571             serial.flags &= ~ASYNC_SPD_CUST;
572             serial.custom_divisor = 0;
573             // we don't check on errors because a driver can has not this feature
574             ::ioctl(descriptor, TIOCSSERIAL, &serial);
575         }
576     }
577 #endif
578 
579     termios tio;
580     if (!getTermios(&tio))
581         return false;
582 
583     if ((directions & QSerialPort::Input) && ::cfsetispeed(&tio, baudRate) < 0) {
584         setError(getSystemError());
585         return false;
586     }
587 
588     if ((directions & QSerialPort::Output) && ::cfsetospeed(&tio, baudRate) < 0) {
589         setError(getSystemError());
590         return false;
591     }
592 
593     return setTermios(&tio);
594 }
595 
596 #if defined(Q_OS_LINUX)
597 
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)598 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
599 {
600     if (directions != QSerialPort::AllDirections) {
601         setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
602                                       QSerialPort::tr("Cannot set custom speed for one direction")));
603         return false;
604     }
605 
606     struct termios2 tio2;
607 
608     if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
609         tio2.c_cflag &= ~CBAUD;
610         tio2.c_cflag |= BOTHER;
611 
612         tio2.c_ispeed = baudRate;
613         tio2.c_ospeed = baudRate;
614 
615         if (::ioctl(descriptor, TCSETS2, &tio2) != -1
616                 && ::ioctl(descriptor, TCGETS2, &tio2) != -1) {
617             return true;
618         }
619     }
620 
621     struct serial_struct serial;
622 
623     if (::ioctl(descriptor, TIOCGSERIAL, &serial) == -1) {
624         setError(getSystemError());
625         return false;
626     }
627 
628     serial.flags &= ~ASYNC_SPD_MASK;
629     serial.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
630     serial.custom_divisor = serial.baud_base / baudRate;
631 
632     if (serial.custom_divisor == 0) {
633         setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
634                                       QSerialPort::tr("No suitable custom baud rate divisor")));
635         return false;
636     }
637 
638     if (serial.custom_divisor * baudRate != serial.baud_base) {
639         qWarning("Baud rate of serial port %s is set to %f instead of %d: divisor %f unsupported",
640             qPrintable(systemLocation),
641             float(serial.baud_base) / serial.custom_divisor,
642             baudRate, float(serial.baud_base) / baudRate);
643     }
644 
645     if (::ioctl(descriptor, TIOCSSERIAL, &serial) == -1) {
646         setError(getSystemError());
647         return false;
648     }
649 
650     return setStandardBaudRate(B38400, directions);
651 }
652 
653 #elif defined(Q_OS_OSX)
654 
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)655 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
656 {
657     if (directions != QSerialPort::AllDirections) {
658         setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
659                                       QSerialPort::tr("Cannot set custom speed for one direction")));
660         return false;
661     }
662 
663 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
664     if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) == -1) {
665         setError(getSystemError());
666         return false;
667     }
668 
669     return true;
670 #else
671     setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
672                                   QSerialPort::tr("Custom baud rate is not supported")));
673     return false;
674 #endif
675 }
676 
677 #elif defined(Q_OS_QNX)
678 
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)679 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
680 {
681     // On QNX, the values of the 'Bxxxx' constants are set to 'xxxx' (i.e.
682     // B115200 is defined to '115200'), which means that literal values can be
683     // passed to cfsetispeed/cfsetospeed, including custom values, provided
684     // that the underlying hardware supports them.
685     return setStandardBaudRate(baudRate, directions);
686 }
687 
688 #else
689 
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)690 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
691 {
692     Q_UNUSED(baudRate);
693     Q_UNUSED(directions);
694 
695     setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
696                                   QSerialPort::tr("Custom baud rate is not supported")));
697     return false;
698 }
699 
700 #endif
701 
setBaudRate(qint32 baudRate,QSerialPort::Directions directions)702 bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
703 {
704     if (baudRate <= 0) {
705         setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Invalid baud rate value")));
706         return false;
707     }
708 
709     const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate);
710 
711     return (unixBaudRate > 0)
712             ? setStandardBaudRate(unixBaudRate, directions)
713             : setCustomBaudRate(baudRate, directions);
714 }
715 
setDataBits(QSerialPort::DataBits dataBits)716 bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
717 {
718     termios tio;
719     if (!getTermios(&tio))
720         return false;
721 
722     qt_set_databits(&tio, dataBits);
723 
724     return setTermios(&tio);
725 }
726 
setParity(QSerialPort::Parity parity)727 bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
728 {
729     termios tio;
730     if (!getTermios(&tio))
731         return false;
732 
733     qt_set_parity(&tio, parity);
734 
735     return setTermios(&tio);
736 }
737 
setStopBits(QSerialPort::StopBits stopBits)738 bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
739 {
740     termios tio;
741     if (!getTermios(&tio))
742         return false;
743 
744     qt_set_stopbits(&tio, stopBits);
745 
746     return setTermios(&tio);
747 }
748 
setFlowControl(QSerialPort::FlowControl flowControl)749 bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
750 {
751     termios tio;
752     if (!getTermios(&tio))
753         return false;
754 
755     qt_set_flowcontrol(&tio, flowControl);
756 
757     return setTermios(&tio);
758 }
759 
startAsyncRead()760 bool QSerialPortPrivate::startAsyncRead()
761 {
762     setReadNotificationEnabled(true);
763     return true;
764 }
765 
readNotification()766 bool QSerialPortPrivate::readNotification()
767 {
768     Q_Q(QSerialPort);
769 
770     // Always buffered, read data from the port into the read buffer
771     qint64 newBytes = buffer.size();
772     qint64 bytesToRead = QSERIALPORT_BUFFERSIZE;
773 
774     if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - buffer.size())) {
775         bytesToRead = readBufferMaxSize - buffer.size();
776         if (bytesToRead <= 0) {
777             // Buffer is full. User must read data from the buffer
778             // before we can read more from the port.
779             setReadNotificationEnabled(false);
780             return false;
781         }
782     }
783 
784     char *ptr = buffer.reserve(bytesToRead);
785     const qint64 readBytes = readFromPort(ptr, bytesToRead);
786 
787     buffer.chop(bytesToRead - qMax(readBytes, qint64(0)));
788 
789     if (readBytes <= 0) {
790         QSerialPortErrorInfo error = getSystemError();
791         if (error.errorCode != QSerialPort::ResourceError)
792             error.errorCode = QSerialPort::ReadError;
793         else
794             setReadNotificationEnabled(false);
795         setError(error);
796         return false;
797     }
798 
799     newBytes = buffer.size() - newBytes;
800 
801     // only emit readyRead() when not recursing, and only if there is data available
802     const bool hasData = newBytes > 0;
803 
804     if (!emittedReadyRead && hasData) {
805         emittedReadyRead = true;
806         emit q->readyRead();
807         emittedReadyRead = false;
808     }
809 
810     return true;
811 }
812 
startAsyncWrite()813 bool QSerialPortPrivate::startAsyncWrite()
814 {
815     if (writeBuffer.isEmpty() || writeSequenceStarted)
816         return true;
817 
818     // Attempt to write it all in one chunk.
819     qint64 written = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize());
820     if (written < 0) {
821         QSerialPortErrorInfo error = getSystemError();
822         if (error.errorCode != QSerialPort::ResourceError)
823             error.errorCode = QSerialPort::WriteError;
824         setError(error);
825         return false;
826     }
827 
828     writeBuffer.free(written);
829     pendingBytesWritten += written;
830     writeSequenceStarted = true;
831 
832     if (!isWriteNotificationEnabled())
833         setWriteNotificationEnabled(true);
834     return true;
835 }
836 
completeAsyncWrite()837 bool QSerialPortPrivate::completeAsyncWrite()
838 {
839     Q_Q(QSerialPort);
840 
841     if (pendingBytesWritten > 0) {
842         if (!emittedBytesWritten) {
843             emittedBytesWritten = true;
844             emit q->bytesWritten(pendingBytesWritten);
845             pendingBytesWritten = 0;
846             emittedBytesWritten = false;
847         }
848     }
849 
850     writeSequenceStarted = false;
851 
852     if (writeBuffer.isEmpty()) {
853         setWriteNotificationEnabled(false);
854         return true;
855     }
856 
857     return startAsyncWrite();
858 }
859 
initialize(QIODevice::OpenMode mode)860 inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
861 {
862 #ifdef TIOCEXCL
863     if (::ioctl(descriptor, TIOCEXCL) == -1)
864         setError(getSystemError());
865 #endif
866 
867     termios tio;
868     if (!getTermios(&tio))
869         return false;
870 
871     restoredTermios = tio;
872 
873     qt_set_common_props(&tio, mode);
874     qt_set_databits(&tio, dataBits);
875     qt_set_parity(&tio, parity);
876     qt_set_stopbits(&tio, stopBits);
877     qt_set_flowcontrol(&tio, flowControl);
878 
879     if (!setTermios(&tio))
880         return false;
881 
882     if (!setBaudRate())
883         return false;
884 
885     if (mode & QIODevice::ReadOnly)
886         setReadNotificationEnabled(true);
887 
888     return true;
889 }
890 
writeData(const char * data,qint64 maxSize)891 qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
892 {
893     writeBuffer.append(data, maxSize);
894     if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
895         setWriteNotificationEnabled(true);
896     return maxSize;
897 }
898 
setTermios(const termios * tio)899 bool QSerialPortPrivate::setTermios(const termios *tio)
900 {
901     if (::tcsetattr(descriptor, TCSANOW, tio) == -1) {
902         setError(getSystemError());
903         return false;
904     }
905     return true;
906 }
907 
getTermios(termios * tio)908 bool QSerialPortPrivate::getTermios(termios *tio)
909 {
910     ::memset(tio, 0, sizeof(termios));
911     if (::tcgetattr(descriptor, tio) == -1) {
912         setError(getSystemError());
913         return false;
914     }
915     return true;
916 }
917 
getSystemError(int systemErrorCode) const918 QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
919 {
920     if (systemErrorCode == -1)
921         systemErrorCode = errno;
922 
923     QSerialPortErrorInfo error;
924     error.errorString = qt_error_string(systemErrorCode);
925 
926     switch (systemErrorCode) {
927     case ENODEV:
928         error.errorCode = QSerialPort::DeviceNotFoundError;
929         break;
930 #ifdef ENOENT
931     case ENOENT:
932         error.errorCode = QSerialPort::DeviceNotFoundError;
933         break;
934 #endif
935     case EACCES:
936         error.errorCode = QSerialPort::PermissionError;
937         break;
938     case EBUSY:
939         error.errorCode = QSerialPort::PermissionError;
940         break;
941     case EAGAIN:
942         error.errorCode = QSerialPort::ResourceError;
943         break;
944     case EIO:
945         error.errorCode = QSerialPort::ResourceError;
946         break;
947     case EBADF:
948         error.errorCode = QSerialPort::ResourceError;
949         break;
950 #ifdef Q_OS_OSX
951     case ENXIO:
952         error.errorCode = QSerialPort::ResourceError;
953         break;
954 #endif
955 #ifdef EINVAL
956     case EINVAL:
957         error.errorCode = QSerialPort::UnsupportedOperationError;
958         break;
959 #endif
960 #ifdef ENOIOCTLCMD
961     case ENOIOCTLCMD:
962         error.errorCode = QSerialPort::UnsupportedOperationError;
963         break;
964 #endif
965 #ifdef ENOTTY
966     case ENOTTY:
967         error.errorCode = QSerialPort::UnsupportedOperationError;
968         break;
969 #endif
970 #ifdef EPERM
971     case EPERM:
972         error.errorCode = QSerialPort::PermissionError;
973         break;
974 #endif
975     default:
976         error.errorCode = QSerialPort::UnknownError;
977         break;
978     }
979     return error;
980 }
981 
isReadNotificationEnabled() const982 bool QSerialPortPrivate::isReadNotificationEnabled() const
983 {
984     return readNotifier && readNotifier->isEnabled();
985 }
986 
setReadNotificationEnabled(bool enable)987 void QSerialPortPrivate::setReadNotificationEnabled(bool enable)
988 {
989     Q_Q(QSerialPort);
990 
991     if (readNotifier) {
992         readNotifier->setEnabled(enable);
993     } else if (enable) {
994         readNotifier = new ReadNotifier(this, q);
995         readNotifier->setEnabled(true);
996     }
997 }
998 
isWriteNotificationEnabled() const999 bool QSerialPortPrivate::isWriteNotificationEnabled() const
1000 {
1001     return writeNotifier && writeNotifier->isEnabled();
1002 }
1003 
setWriteNotificationEnabled(bool enable)1004 void QSerialPortPrivate::setWriteNotificationEnabled(bool enable)
1005 {
1006     Q_Q(QSerialPort);
1007 
1008     if (writeNotifier) {
1009         writeNotifier->setEnabled(enable);
1010     } else if (enable) {
1011         writeNotifier = new WriteNotifier(this, q);
1012         writeNotifier->setEnabled(true);
1013     }
1014 }
1015 
waitForReadOrWrite(bool * selectForRead,bool * selectForWrite,bool checkRead,bool checkWrite,int msecs)1016 bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
1017                                            bool checkRead, bool checkWrite,
1018                                            int msecs)
1019 {
1020     Q_ASSERT(selectForRead);
1021     Q_ASSERT(selectForWrite);
1022 
1023     pollfd pfd = qt_make_pollfd(descriptor, 0);
1024 
1025     if (checkRead)
1026         pfd.events |= POLLIN;
1027 
1028     if (checkWrite)
1029         pfd.events |= POLLOUT;
1030 
1031     const int ret = qt_poll_msecs(&pfd, 1, msecs);
1032     if (ret < 0) {
1033         setError(getSystemError());
1034         return false;
1035     }
1036     if (ret == 0) {
1037         setError(QSerialPortErrorInfo(QSerialPort::TimeoutError));
1038         return false;
1039     }
1040     if (pfd.revents & POLLNVAL) {
1041         setError(getSystemError(EBADF));
1042         return false;
1043     }
1044 
1045     *selectForWrite = ((pfd.revents & POLLOUT) != 0);
1046     *selectForRead = ((pfd.revents & POLLIN) != 0);
1047     return true;
1048 }
1049 
readFromPort(char * data,qint64 maxSize)1050 qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
1051 {
1052     return qt_safe_read(descriptor, data, maxSize);
1053 }
1054 
writeToPort(const char * data,qint64 maxSize)1055 qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
1056 {
1057     qint64 bytesWritten = 0;
1058 #if defined(CMSPAR)
1059     bytesWritten = qt_safe_write(descriptor, data, maxSize);
1060 #else
1061     if (parity != QSerialPort::MarkParity
1062             && parity != QSerialPort::SpaceParity) {
1063         bytesWritten = qt_safe_write(descriptor, data, maxSize);
1064     } else {// Perform parity emulation.
1065         bytesWritten = writePerChar(data, maxSize);
1066     }
1067 #endif
1068 
1069     return bytesWritten;
1070 }
1071 
1072 #ifndef CMSPAR
1073 
evenParity(quint8 c)1074 static inline bool evenParity(quint8 c)
1075 {
1076     c ^= c >> 4;        //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0)
1077     c ^= c >> 2;        //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)]
1078     c ^= c >> 1;
1079     return c & 1;       //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0)
1080 }
1081 
writePerChar(const char * data,qint64 maxSize)1082 qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
1083 {
1084     termios tio;
1085     if (!getTermios(&tio))
1086         return -1;
1087 
1088     qint64 ret = 0;
1089     quint8 const charMask = (0xFF >> (8 - dataBits));
1090 
1091     while (ret < maxSize) {
1092 
1093         bool par = evenParity(*data & charMask);
1094         // False if need EVEN, true if need ODD.
1095         par ^= parity == QSerialPort::MarkParity;
1096         if (par ^ (tio.c_cflag & PARODD)) { // Need switch parity mode?
1097             tio.c_cflag ^= PARODD;
1098             flush(); //force sending already buffered data, because setTermios(&tio); cleares buffers
1099             //todo: add receiving buffered data!!!
1100             if (!setTermios(&tio))
1101                 break;
1102         }
1103 
1104         int r = qt_safe_write(descriptor, data, 1);
1105         if (r < 0)
1106             return -1;
1107         if (r > 0) {
1108             data += r;
1109             ret += r;
1110         }
1111     }
1112     return ret;
1113 }
1114 
1115 #endif //CMSPAR
1116 
1117 typedef QMap<qint32, qint32> BaudRateMap;
1118 
1119 // The OS specific defines can be found in termios.h
1120 
createStandardBaudRateMap()1121 static const BaudRateMap createStandardBaudRateMap()
1122 {
1123     BaudRateMap baudRateMap;
1124 
1125 #ifdef B50
1126     baudRateMap.insert(50, B50);
1127 #endif
1128 
1129 #ifdef B75
1130     baudRateMap.insert(75, B75);
1131 #endif
1132 
1133 #ifdef B110
1134     baudRateMap.insert(110, B110);
1135 #endif
1136 
1137 #ifdef B134
1138     baudRateMap.insert(134, B134);
1139 #endif
1140 
1141 #ifdef B150
1142     baudRateMap.insert(150, B150);
1143 #endif
1144 
1145 #ifdef B200
1146     baudRateMap.insert(200, B200);
1147 #endif
1148 
1149 #ifdef B300
1150     baudRateMap.insert(300, B300);
1151 #endif
1152 
1153 #ifdef B600
1154     baudRateMap.insert(600, B600);
1155 #endif
1156 
1157 #ifdef B1200
1158     baudRateMap.insert(1200, B1200);
1159 #endif
1160 
1161 #ifdef B1800
1162     baudRateMap.insert(1800, B1800);
1163 #endif
1164 
1165 #ifdef B2400
1166     baudRateMap.insert(2400, B2400);
1167 #endif
1168 
1169 #ifdef B4800
1170     baudRateMap.insert(4800, B4800);
1171 #endif
1172 
1173 #ifdef B7200
1174     baudRateMap.insert(7200, B7200);
1175 #endif
1176 
1177 #ifdef B9600
1178     baudRateMap.insert(9600, B9600);
1179 #endif
1180 
1181 #ifdef B14400
1182     baudRateMap.insert(14400, B14400);
1183 #endif
1184 
1185 #ifdef B19200
1186     baudRateMap.insert(19200, B19200);
1187 #endif
1188 
1189 #ifdef B28800
1190     baudRateMap.insert(28800, B28800);
1191 #endif
1192 
1193 #ifdef B38400
1194     baudRateMap.insert(38400, B38400);
1195 #endif
1196 
1197 #ifdef B57600
1198     baudRateMap.insert(57600, B57600);
1199 #endif
1200 
1201 #ifdef B76800
1202     baudRateMap.insert(76800, B76800);
1203 #endif
1204 
1205 #ifdef B115200
1206     baudRateMap.insert(115200, B115200);
1207 #endif
1208 
1209 #ifdef B230400
1210     baudRateMap.insert(230400, B230400);
1211 #endif
1212 
1213 #ifdef B460800
1214     baudRateMap.insert(460800, B460800);
1215 #endif
1216 
1217 #ifdef B500000
1218     baudRateMap.insert(500000, B500000);
1219 #endif
1220 
1221 #ifdef B576000
1222     baudRateMap.insert(576000, B576000);
1223 #endif
1224 
1225 #ifdef B921600
1226     baudRateMap.insert(921600, B921600);
1227 #endif
1228 
1229 #ifdef B1000000
1230     baudRateMap.insert(1000000, B1000000);
1231 #endif
1232 
1233 #ifdef B1152000
1234     baudRateMap.insert(1152000, B1152000);
1235 #endif
1236 
1237 #ifdef B1500000
1238     baudRateMap.insert(1500000, B1500000);
1239 #endif
1240 
1241 #ifdef B2000000
1242     baudRateMap.insert(2000000, B2000000);
1243 #endif
1244 
1245 #ifdef B2500000
1246     baudRateMap.insert(2500000, B2500000);
1247 #endif
1248 
1249 #ifdef B3000000
1250     baudRateMap.insert(3000000, B3000000);
1251 #endif
1252 
1253 #ifdef B3500000
1254     baudRateMap.insert(3500000, B3500000);
1255 #endif
1256 
1257 #ifdef B4000000
1258     baudRateMap.insert(4000000, B4000000);
1259 #endif
1260 
1261     return baudRateMap;
1262 }
1263 
standardBaudRateMap()1264 static const BaudRateMap& standardBaudRateMap()
1265 {
1266     static const BaudRateMap baudRateMap = createStandardBaudRateMap();
1267     return baudRateMap;
1268 }
1269 
settingFromBaudRate(qint32 baudRate)1270 qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
1271 {
1272     return standardBaudRateMap().value(baudRate);
1273 }
1274 
standardBaudRates()1275 QList<qint32> QSerialPortPrivate::standardBaudRates()
1276 {
1277     return standardBaudRateMap().keys();
1278 }
1279 
handle() const1280 QSerialPort::Handle QSerialPort::handle() const
1281 {
1282     Q_D(const QSerialPort);
1283     return d->descriptor;
1284 }
1285 
1286 QT_END_NAMESPACE
1287