diff --git a/src/System.IO.Ports/src/Configurations.props b/src/System.IO.Ports/src/Configurations.props
index b747a1461244..1697d233e028 100644
--- a/src/System.IO.Ports/src/Configurations.props
+++ b/src/System.IO.Ports/src/Configurations.props
@@ -3,6 +3,7 @@
netstandard-Windows_NT;
+ netstandard-Linux;
netstandard;
net461;
diff --git a/src/System.IO.Ports/src/Interop/Unix/Interop.Termios.cs b/src/System.IO.Ports/src/Interop/Unix/Interop.Termios.cs
index 1e65aca21897..29743b9a6ceb 100644
--- a/src/System.IO.Ports/src/Interop/Unix/Interop.Termios.cs
+++ b/src/System.IO.Ports/src/Interop/Unix/Interop.Termios.cs
@@ -42,7 +42,7 @@ internal enum Queue
internal static extern int TermiosGetSpeed(SafeFileHandle handle);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosAvailableBytes", SetLastError = true)]
- internal static extern int TermiosGetAvailableBytes(SafeFileHandle handle, int input);
+ internal static extern int TermiosGetAvailableBytes(SafeFileHandle handle, Queue input);
[DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_TermiosDiscard", SetLastError = true)]
internal static extern int TermiosDiscard(SafeFileHandle handle, Queue input);
diff --git a/src/System.IO.Ports/src/System.IO.Ports.csproj b/src/System.IO.Ports/src/System.IO.Ports.csproj
index 2128036904c5..7710ff209cf0 100644
--- a/src/System.IO.Ports/src/System.IO.Ports.csproj
+++ b/src/System.IO.Ports/src/System.IO.Ports.csproj
@@ -3,15 +3,14 @@
true
{187503F4-BEF9-4369-A1B2-E3DC5D564E4E}
true
- SR.PlatformNotSupported_IOPorts
+ SR.PlatformNotSupported_IOPorts
$(DefineConstants);NOSPAN
true
- net461-Debug;net461-Release;netfx-Debug;netfx-Release;netstandard-Debug;netstandard-Release;netstandard-Windows_NT-Debug;netstandard-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release
+ net461-Debug;net461-Release;netfx-Debug;netfx-Release;netstandard-Debug;netstandard-Release;netstandard-Windows_NT-Debug;netstandard-Windows_NT-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release;netstandard-Linux-Debug;netstandard-Linux-Release
-
+
-
@@ -23,9 +22,12 @@
-
-
+
+
+
+
+
Common\Interop\Windows\kernel32\Interop.DCB.cs
@@ -139,6 +141,30 @@
+
+
+
+
+
+
+ Common\Interop\Unix\Interop.Libraries.cs
+
+
+ Common\Interop\Unix\Interop.Errors.cs
+
+
+ Interop\Unix\System.Native\Interop.Read.cs
+
+
+ Interop\Unix\System.Native\Interop.Write.cs
+
+
+ Interop\Unix\System.Native\Interop.Poll.cs
+
+
+ Interop\Unix\System.Native\Interop.Shutdown.cs
+
+
@@ -161,4 +187,19 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/System.IO.Ports/src/System/IO/Ports/SerialPort.Linux.cs b/src/System.IO.Ports/src/System/IO/Ports/SerialPort.Linux.cs
new file mode 100644
index 000000000000..c137c24ea8e6
--- /dev/null
+++ b/src/System.IO.Ports/src/System/IO/Ports/SerialPort.Linux.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.IO;
+
+namespace System.IO.Ports
+{
+ public partial class SerialPort : Component
+ {
+ public static string[] GetPortNames()
+ {
+ const string sysTtyDir = "/sys/class/tty";
+ const string sysUsbDir = "/sys/bus/usb-serial/devices/";
+
+ if (Directory.Exists(sysTtyDir))
+ {
+ // /sys is mounted. Let's explore tty class and pick active nodes.
+ List ports = new List();
+ DirectoryInfo di = new DirectoryInfo(sysTtyDir);
+ var entries = di.EnumerateFileSystemInfos(@"*", SearchOption.TopDirectoryOnly);
+ foreach (var entry in entries)
+ {
+ if (Directory.Exists(sysUsbDir + entry.Name) || File.Exists(entry.FullName + "/device/id"))
+ {
+ ports.Add("/dev/" + entry.Name);
+ }
+ }
+
+ return ports.ToArray();
+ }
+ else
+ {
+ // Fallback to scanning /dev. That may have more devices then needed.
+ // This can also miss usb or serial devices with non-standard name.
+ return Directory.GetFiles("/dev", "ttyS*");
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Ports/src/System/IO/Ports/SerialPort.OSX.cs b/src/System.IO.Ports/src/System/IO/Ports/SerialPort.OSX.cs
new file mode 100644
index 000000000000..dcd2a47eb1c2
--- /dev/null
+++ b/src/System.IO.Ports/src/System/IO/Ports/SerialPort.OSX.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using System.IO;
+
+namespace System.IO.Ports
+{
+ public partial class SerialPort : Component
+ {
+ public static string[] GetPortNames()
+ {
+ List ports = new List();
+
+ foreach (string name in Directory.GetFiles("/dev", "tty.*"))
+ {
+ // GetFiles can return unexpected results because of 8.3 matching.
+ // Like /dev/tty
+ if (name.StartsWith("/dev/tty."))
+ {
+ ports.Add(name);
+ }
+ }
+
+ foreach (string name in Directory.GetFiles("/dev", "cu.*"))
+ {
+ if (name.StartsWith("/dev/cu."))
+ {
+ ports.Add(name);
+ }
+ }
+
+ return ports.ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.Ports/src/System/IO/Ports/SerialPort.cs b/src/System.IO.Ports/src/System/IO/Ports/SerialPort.Windows.cs
similarity index 100%
rename from src/System.IO.Ports/src/System/IO/Ports/SerialPort.cs
rename to src/System.IO.Ports/src/System/IO/Ports/SerialPort.Windows.cs
diff --git a/src/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs b/src/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs
new file mode 100644
index 000000000000..63009b2ecf71
--- /dev/null
+++ b/src/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs
@@ -0,0 +1,583 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+using System.Collections;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.IO.Ports;
+using System.Net.Sockets;
+
+namespace System.IO.Ports
+{
+ internal sealed partial class SerialStream : Stream
+ {
+ private const int MaxDataBits = 8;
+ private const int MinDataBits = 5;
+
+ private string _portName;
+ private int _baudRate;
+ private StopBits _stopBits;
+ private Handshake _handshake;
+ private Parity _parity;
+ private int _dataBits = 8;
+ private bool _inBreak = false;
+ private SafeFileHandle _handle = null;
+ private bool _rtsEnable = false;
+ private int _readTimeout = 0;
+ private int _writeTimeout = 0;
+ private byte[] _tempBuf = new byte[1];
+
+ // three different events, also wrapped by SerialPort.
+ internal event SerialDataReceivedEventHandler DataReceived; // called when one character is received.
+ internal event SerialPinChangedEventHandler PinChanged; // called when any of the pin/ring-related triggers occurs
+ internal event SerialErrorReceivedEventHandler ErrorReceived; // called when any runtime error occurs on the port (frame, overrun, parity, etc.)
+
+ // ----SECTION: inherited properties from Stream class ------------*
+
+ // These six properties are required for SerialStream to inherit from the abstract Stream class.
+ // Note four of them are always true or false, and two of them throw exceptions, so these
+ // are not usefully queried by applications which know they have a SerialStream, etc...
+
+ public override int ReadTimeout
+ {
+ get { return _readTimeout; }
+ set
+ {
+ if (value < 0 && value != SerialPort.InfiniteTimeout)
+ throw new ArgumentOutOfRangeException(nameof(ReadTimeout), SR.ArgumentOutOfRange_Timeout);
+ if (_handle == null) {
+ throw new ObjectDisposedException(SR.Port_not_open);
+ }
+ _readTimeout = value;
+ }
+ }
+
+ public override int WriteTimeout
+ {
+ get { return _writeTimeout; }
+ set
+ {
+ if (value < 0 && value != SerialPort.InfiniteTimeout)
+ throw new ArgumentOutOfRangeException(nameof(ReadTimeout), SR.ArgumentOutOfRange_Timeout);
+ if (_handle == null) {
+ throw new ObjectDisposedException(SR.Port_not_open);
+ }
+ _writeTimeout = value;
+ }
+ }
+
+ public override bool CanRead
+ {
+ get { return (_handle != null); }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanTimeout
+ {
+ get { return (_handle != null); }
+ }
+
+ public override bool CanWrite
+ {
+ get { return (_handle != null); }
+ }
+
+ public override long Length
+ {
+ get { throw new NotSupportedException(SR.NotSupported_UnseekableStream); }
+ }
+
+ public override long Position
+ {
+ get { throw new NotSupportedException(SR.NotSupported_UnseekableStream); }
+ set { throw new NotSupportedException(SR.NotSupported_UnseekableStream); }
+ }
+
+ internal int BaudRate
+ {
+ set
+ {
+ if (value != _baudRate)
+ {
+ if (value <= 0 || value > 230400)
+ {
+ throw new ArgumentOutOfRangeException(nameof(BaudRate), SR.ArgumentOutOfRange_NeedPosNum);
+ }
+
+ if (Interop.Termios.TermiosSetSpeed(_handle, value) < 0)
+ {
+ throw new IOException();
+ }
+
+ _baudRate = value;
+ }
+ }
+
+ get
+ {
+ return Interop.Termios.TermiosGetSpeed(_handle);
+ }
+ }
+
+ public bool BreakState
+ {
+ get { return _inBreak; }
+ set
+ {
+ if (value)
+ {
+ // Unlike Windows, there is no infinite break and positive value is platform dependent.
+ // As best guess, send break with default duration.
+ Interop.Termios.TermiosSendBreak(_handle, 0);
+ }
+ _inBreak = value;
+ }
+ }
+
+ internal int BytesToWrite
+ {
+ get { return Interop.Termios.TermiosGetAvailableBytes(_handle, Interop.Termios.Queue.SendQueue); }
+ }
+
+ internal int BytesToRead
+ {
+ get { return Interop.Termios.TermiosGetAvailableBytes(_handle, Interop.Termios.Queue.ReceiveQueue); }
+ }
+
+ internal bool CDHolding
+ {
+ get
+ {
+ int status = Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalDcd);
+ if (status < 0)
+ {
+ throw new IOException();
+ }
+
+ return status == 1;
+ }
+ }
+
+ internal bool CtsHolding
+ {
+ get
+ {
+ int status = Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalCts);
+ if (status < 0)
+ {
+ throw new IOException();
+ }
+
+ return status == 1;
+ }
+ }
+
+ internal bool DsrHolding
+ {
+ get
+ {
+ int status = Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalDsr);
+ if (status < 0)
+ {
+ throw new IOException();
+ }
+
+ return status == 1;
+ }
+ }
+
+ internal bool DtrEnable
+ {
+ get
+ {
+ int status = Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalDtr);
+ if (status < 0)
+ {
+ throw new IOException();
+ }
+
+ return status == 1;
+ }
+
+ set
+ {
+ if (Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalDtr, value ? 1 : 0) != 0)
+ {
+ throw new IOException();
+ }
+ }
+ }
+
+ internal bool RtsEnable
+ {
+ get
+ {
+ int status = Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalRts);
+ if (status < 0)
+ {
+ throw new IOException();
+ }
+
+ return status == 1;
+ }
+
+ set
+ {
+ if (Interop.Termios.TermiosGetSignal(_handle, Interop.Termios.Signals.SignalRts, value ? 1 : 0) != 0)
+ {
+ throw new IOException();
+ }
+ }
+ }
+
+ internal Handshake Handshake
+ {
+ set
+ {
+ Debug.Assert(!(value < Handshake.None || value > Handshake.RequestToSendXOnXOff),
+ "An invalid value was passed to Handshake");
+
+ if (value != _handshake)
+ {
+ if (Interop.Termios.TermiosReset(_handle, _baudRate, _dataBits, _stopBits, _parity, _handshake) != 0)
+ {
+ throw new ArgumentException();
+ }
+ _handshake = value;
+ }
+ }
+ }
+
+ internal int DataBits
+ {
+ set
+ {
+ Debug.Assert(!(value < MinDataBits || value > MaxDataBits), "An invalid value was passed to DataBits");
+ if (value != _dataBits)
+ {
+ _dataBits = value;
+ if (Interop.Termios.TermiosReset(_handle, _baudRate, _dataBits, _stopBits, _parity, _handshake) != 0)
+ {
+ throw new ArgumentException();
+ }
+ }
+ }
+ }
+
+ internal Parity Parity
+ {
+ set
+ {
+ Debug.Assert(!(value < Parity.None || value > Parity.Space), "An invalid value was passed to Parity");
+
+ if (value != _parity)
+ {
+ _parity = value;
+ if (Interop.Termios.TermiosReset(_handle, _baudRate, _dataBits, _stopBits, _parity, _handshake) != 0)
+ {
+ throw new ArgumentException();
+ }
+ }
+ }
+ }
+
+ internal StopBits StopBits
+ {
+ set
+ {
+ Debug.Assert(!(value < StopBits.One || value > StopBits.OnePointFive), "An invalid value was passed to StopBits");
+ if (value != _stopBits)
+ {
+ _stopBits = value;
+ if (Interop.Termios.TermiosReset(_handle, _baudRate, _dataBits, _stopBits, _parity, _handshake) != 0)
+ {
+ throw new ArgumentException();
+ }
+ }
+ }
+ }
+
+ internal bool DiscardNull
+ {
+ set
+ {
+ // Ignore.
+ }
+ }
+
+ internal byte ParityReplace
+ {
+ set
+ {
+ // Ignore.
+ }
+ }
+
+ internal void DiscardInBuffer()
+ {
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+ // This may or may not work depending on hardware.
+ Interop.Termios.TermiosDiscard(_handle, Interop.Termios.Queue.ReceiveQueue);
+ }
+
+ internal void DiscardOutBuffer()
+ {
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+ // This may or may not work depending on hardware.
+ Interop.Termios.TermiosDiscard(_handle, Interop.Termios.Queue.SendQueue);
+ }
+
+ internal void SetBufferSizes(int readBufferSize, int writeBufferSize)
+ {
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+
+ // Ignore for now.
+ }
+
+ internal bool IsOpen => _handle != null;
+
+
+ // Flush dumps the contents of the serial driver's internal read and write buffers.
+ // We actually expose the functionality for each, but fulfilling Stream's contract
+ // requires a Flush() method. Fails if handle closed.
+ // Note: Serial driver's write buffer is *already* attempting to write it, so we can only wait until it finishes.
+ public override void Flush()
+ {
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+ Interop.Termios.TermiosDiscard(_handle, Interop.Termios.Queue.AllQueues);
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException(SR.NotSupported_UnseekableStream);
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException(SR.NotSupported_UnseekableStream);
+ }
+
+ public override int ReadByte()
+ {
+ return ReadByte(ReadTimeout);
+ }
+
+ internal int ReadByte(int timeout)
+ {
+ Read(_tempBuf, 0, 1, timeout);
+ return _tempBuf[0];
+ }
+
+ public override int Read(byte[] array, int offset, int count)
+ {
+ return Read(array, offset, count, ReadTimeout);
+ }
+
+ internal unsafe int Read(byte[] array, int offset, int count, int timeout)
+ {
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNumRequired);
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNumRequired);
+ if (array.Length - offset < count)
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+ if (count == 0) return 0; // return immediately if no bytes requested; no need for overhead.
+
+ if (timeout != 0)
+ {
+ Interop.Sys.PollEvents events = Interop.Sys.PollEvents.POLLNONE;
+ Interop.Sys.Poll(_handle, Interop.Sys.PollEvents.POLLIN | Interop.Sys.PollEvents.POLLERR, timeout,out events);
+
+ if ((events & (Interop.Sys.PollEvents.POLLERR | Interop.Sys.PollEvents.POLLNVAL)) != 0)
+ {
+ throw new IOException();
+ }
+
+ if ( (events & Interop.Sys.PollEvents.POLLIN) == 0)
+ {
+ throw new TimeoutException();
+ }
+ }
+
+ int numBytes;
+ fixed (byte* bufPtr = array)
+ {
+ numBytes = Interop.Sys.Read(_handle, bufPtr + offset, count);
+ }
+
+ if (numBytes < 0)
+ {
+ if (Interop.Error.EWOULDBLOCK == Interop.Sys.GetLastError())
+ {
+ throw new TimeoutException();
+ }
+ throw new IOException();
+ }
+
+ return numBytes;
+ }
+
+ public override void Write(byte[] array, int offset, int count)
+ {
+ Write(array, offset, count, WriteTimeout);
+ }
+
+ internal unsafe void Write(byte[] array, int offset, int count, int timeout)
+ {
+ if (_inBreak)
+ throw new InvalidOperationException(SR.In_Break_State);
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+ if (offset < 0)
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedPosNum);
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedPosNum);
+ if (count == 0) return; // no need to expend overhead in creating asyncResult, etc.
+ if (array.Length - offset < count)
+ throw new ArgumentException(SR.Argument_InvalidOffLen);
+
+ // check for open handle, though the port is always supposed to be open
+ if (_handle == null) throw new ObjectDisposedException(SR.Port_not_open);
+
+ int numBytes = 0;
+
+ while (count > 0)
+ {
+ if (timeout > 0)
+ {
+ Interop.Sys.PollEvents events = Interop.Sys.PollEvents.POLLNONE;
+ Interop.Sys.Poll(_handle, Interop.Sys.PollEvents.POLLOUT | Interop.Sys.PollEvents.POLLERR, timeout,out events);
+
+ if ((events & (Interop.Sys.PollEvents.POLLERR | Interop.Sys.PollEvents.POLLNVAL)) != 0)
+ {
+ throw new IOException();
+ }
+
+ if ( (events & Interop.Sys.PollEvents.POLLOUT) == 0)
+ {
+ throw new TimeoutException(SR.Write_timed_out);
+ }
+ }
+
+ fixed (byte* bufPtr = array)
+ {
+ numBytes = Interop.Sys.Write(_handle, bufPtr + offset, count);
+ }
+
+ if (numBytes == -1)
+ {
+ throw new IOException();
+ }
+
+ if (numBytes == 0)
+ {
+ throw new TimeoutException(SR.Write_timed_out);
+ }
+ count -= numBytes;
+ offset += numBytes;
+ }
+ }
+
+ internal SafeFileHandle OpenPort(string portName)
+ {
+ SafeFileHandle handle = Interop.Serial.SerialPortOpen(portName);
+
+ return handle;
+ }
+
+ // this method is used by SerialPort upon SerialStream's creation
+ internal SerialStream(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, Handshake handshake,
+ bool dtrEnable, bool rtsEnable, bool discardNull, byte parityReplace)
+ {
+
+ if (portName == null)
+ {
+ throw new ArgumentException(SR.Arg_InvalidSerialPort, nameof(portName));
+ }
+
+ // Error checking done in SerialPort.
+
+ SafeFileHandle tempHandle = OpenPort(portName);
+
+ if (tempHandle.IsInvalid)
+ {
+ throw new ArgumentException(SR.Arg_InvalidSerialPort, nameof(portName));
+ }
+
+ try
+ {
+ _handle = tempHandle;
+ // set properties of the stream that exist as members in SerialStream
+ _portName = portName;
+ _handshake = handshake;
+ _parity = parity;
+ _readTimeout = readTimeout;
+ _writeTimeout = writeTimeout;
+ _baudRate = baudRate;
+ _stopBits = stopBits;
+ _dataBits = dataBits;
+ _parity = parity;
+
+ if (Interop.Termios.TermiosReset(_handle, _baudRate, _dataBits, _stopBits, _parity, _handshake) != 0)
+ {
+ throw new ArgumentException();
+ }
+
+ DtrEnable = dtrEnable;
+ // query and cache the initial RtsEnable value
+ // so that set_RtsEnable can do the (value != rtsEnable) optimization
+ //_rtsEnable = (GetDcbFlag(NativeMethods.FRTSCONTROL) == NativeMethods.RTS_CONTROL_ENABLE);
+ _rtsEnable = RtsEnable;
+
+ BaudRate = baudRate;
+
+ // now set this.RtsEnable to the specified value.
+ // Handshake takes precedence, this will be a nop if
+ // handshake is either RequestToSend or RequestToSendXOnXOff
+ if ((handshake != Handshake.RequestToSend && handshake != Handshake.RequestToSendXOnXOff))
+ {
+ RtsEnable = rtsEnable;
+ }
+ }
+ catch
+ {
+ // if there are any exceptions after the call to CreateFile, we need to be sure to close the
+ // handle before we let them continue up.
+ tempHandle.Close();
+ _handle = null;
+ throw;
+ }
+ }
+
+ ~SerialStream()
+ {
+ Dispose(false);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ // Signal the other side that we're closing. Should do regardless of whether we've called
+ // Close() or not Dispose()
+ if (_handle != null && !_handle.IsInvalid)
+ {
+ Interop.Sys.Shutdown(_handle, SocketShutdown.Both);
+ _handle.Close();
+ _handle = null;
+ base.Dispose(disposing);
+ if (PinChanged != null || ErrorReceived != null || DataReceived != null)
+ {
+ }
+ base.Dispose(disposing);
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Ports/src/System/IO/Ports/SerialStream.cs b/src/System.IO.Ports/src/System/IO/Ports/SerialStream.Windows.cs
similarity index 100%
rename from src/System.IO.Ports/src/System/IO/Ports/SerialStream.cs
rename to src/System.IO.Ports/src/System/IO/Ports/SerialStream.Windows.cs
diff --git a/src/System.IO.Ports/tests/Configurations.props b/src/System.IO.Ports/tests/Configurations.props
index 1e5845b0b616..17e83be7494e 100644
--- a/src/System.IO.Ports/tests/Configurations.props
+++ b/src/System.IO.Ports/tests/Configurations.props
@@ -3,7 +3,8 @@
netstandard-Windows_NT;
+ netstandard-Linux;
netfx;
-
\ No newline at end of file
+
diff --git a/src/System.IO.Ports/tests/SerialPort/RtsEnable.cs b/src/System.IO.Ports/tests/SerialPort/RtsEnable.cs
index c0aee56a2fcc..230eef1518e0 100644
--- a/src/System.IO.Ports/tests/SerialPort/RtsEnable.cs
+++ b/src/System.IO.Ports/tests/SerialPort/RtsEnable.cs
@@ -196,6 +196,7 @@ public void RtsEnable_Get_Handshake_RequestToSend()
}
[ConditionalFact(nameof(HasOneSerialPort))]
+ [PlatformSpecific(~TestPlatforms.AnyUnix)]
public void RtsEnable_Get_Handshake_RequestToSendXOnXOff()
{
using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
diff --git a/src/System.IO.Ports/tests/Support/PortHelper.cs b/src/System.IO.Ports/tests/Support/PortHelper.cs
index fce77e6916ad..d562606ac30c 100644
--- a/src/System.IO.Ports/tests/Support/PortHelper.cs
+++ b/src/System.IO.Ports/tests/Support/PortHelper.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
@@ -20,6 +21,11 @@ public class PortHelper
public static string[] GetPorts()
{
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return SerialPort.GetPortNames();
+ }
+
if (PlatformDetection.IsUap)
{
return new [] { "COM3", "COM4", "COM5", "COM6", "COM7" }; // we are waiting for a Win32 new QueryDosDevice API since the current doesn't work for Uap https://github.com/dotnet/corefx/issues/21156
diff --git a/src/System.IO.Ports/tests/System.IO.Ports.Tests.csproj b/src/System.IO.Ports/tests/System.IO.Ports.Tests.csproj
index 043fda7ce748..5e5dc4137d79 100644
--- a/src/System.IO.Ports/tests/System.IO.Ports.Tests.csproj
+++ b/src/System.IO.Ports/tests/System.IO.Ports.Tests.csproj
@@ -28,7 +28,6 @@
-
@@ -41,12 +40,10 @@
-
-
@@ -114,7 +111,12 @@
+
+
+
+
+
-
\ No newline at end of file
+