* Author: Chris Toshok <toshok@ximian.com>
*/
+#include "map.h"
+#include "mph.h"
+
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <errno.h>
+#if defined(HAVE_POLL_H)
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
#include <sys/poll.h>
+#endif
#include <sys/ioctl.h>
-#include <errno.h>
+
+/* This is for ASYNC_*, serial_struct on linux */
+#if defined(HAVE_LINUX_SERIAL_H)
+#include <linux/serial.h>
+#endif
#include <glib.h>
#endif
/* sys/time.h (for timeval) is required when using osx 10.3 (but not 10.4) */
-#ifdef __APPLE__
+/* IOKit is a private framework in iOS, so exclude there */
+#if defined(__APPLE__) && !defined(HOST_IOS) && !defined(HOST_WATCHOS) && !defined(HOST_APPLETVOS)
+#define HAVE_IOKIT 1
+#endif
+
+#if defined(HAVE_IOKIT)
#include <sys/time.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <IOKit/serial/ioss.h>
+#include <IOKit/IOBSD.h>
#endif
/* This is a copy of System.IO.Ports.Handshake */
Rts = 16 /* Request to send */
} MonoSerialSignal;
+/*
+ * Silence the compiler, we do not need these prototypes to be public, since these are only
+ * used by P/Invoke
+ */
+
+int open_serial (char *devfile);
+int close_serial (int unix_fd);
+guint32 read_serial (int fd, guchar *buffer, int offset, int count);
+int write_serial (int fd, guchar *buffer, int offset, int count, int timeout);
+int discard_buffer (int fd, gboolean input);
+gint32 get_bytes_in_buffer (int fd, gboolean input);
+gboolean is_baud_rate_legal (int baud_rate);
+int setup_baud_rate (int baud_rate, gboolean *custom_baud_rate);
+gboolean set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake);
+MonoSerialSignal get_signals (int fd, gint32 *error);
+gint32 set_signal (int fd, MonoSerialSignal signal, gboolean value);
+int breakprop (int fd);
+gboolean poll_serial (int fd, gint32 *error, int timeout);
+void *list_serial_devices (void);
+
int
-open_serial (char* devfile)
+open_serial (char *devfile)
{
int fd;
fd = open (devfile, O_RDWR | O_NOCTTY | O_NONBLOCK);
- if (fd == -1)
- return -1;
-
return fd;
}
-void
+int
close_serial (int unix_fd)
{
- close (unix_fd);
+ // Linus writes: do not retry close after EINTR
+ return close (unix_fd);
}
guint32
while (n > 0)
{
- size_t t;
+ ssize_t t;
- if (timeout > 0) {
+ if (timeout != 0) {
int c;
while ((c = poll (&pinfo, 1, timeout)) == -1 && errno == EINTR)
return 0;
}
-void
+int
discard_buffer (int fd, gboolean input)
{
- tcflush(fd, input ? TCIFLUSH : TCOFLUSH);
+ return tcflush(fd, input ? TCIFLUSH : TCOFLUSH);
}
gint32
get_bytes_in_buffer (int fd, gboolean input)
{
+#if defined(__HAIKU__)
+ /* FIXME: Haiku doesn't support TIOCOUTQ nor FIONREAD on fds */
+ return -1;
+#define TIOCOUTQ 0
+#endif
gint32 retval;
if (ioctl (fd, input ? FIONREAD : TIOCOUTQ, &retval) == -1) {
}
gboolean
-set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake)
+is_baud_rate_legal (int baud_rate)
{
- struct termios newtio;
-
- tcgetattr (fd, &newtio);
- newtio.c_cflag |= (CLOCAL | CREAD);
- newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN );
- newtio.c_oflag &= ~(OPOST);
- newtio.c_iflag = IGNBRK;
+ gboolean ignore = FALSE;
+ return setup_baud_rate (baud_rate, &ignore) != -1;
+}
- /* setup baudrate */
+int
+setup_baud_rate (int baud_rate, gboolean *custom_baud_rate)
+{
switch (baud_rate)
{
+/*Some values are not defined on OSX and *BSD */
+#if defined(B921600)
+ case 921600:
+ baud_rate = B921600;
+ break;
+#endif
+#if defined(B460800)
+ case 460800:
+ baud_rate = B460800;
+ break;
+#endif
case 230400:
baud_rate = B230400;
break;
baud_rate = B75;
break;
case 50:
+#ifdef B50
+ baud_rate = B50;
+#else
+ baud_rate = -1;
+ break;
+#endif
case 0:
+#ifdef B0
+ baud_rate = B0;
+#else
+ baud_rate = -1;
+#endif
+ break;
default:
- baud_rate = B9600;
+ *custom_baud_rate = TRUE;
break;
}
+ return baud_rate;
+}
+
+gboolean
+set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStopBits stopBits, MonoHandshake handshake)
+{
+ struct termios newtio;
+ gboolean custom_baud_rate = FALSE;
+
+ if (tcgetattr (fd, &newtio) == -1)
+ return FALSE;
+
+ newtio.c_cflag |= (CLOCAL | CREAD);
+ newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN );
+ newtio.c_oflag &= ~(OPOST);
+ newtio.c_iflag = IGNBRK;
+
+ /* setup baudrate */
+ baud_rate = setup_baud_rate (baud_rate, &custom_baud_rate);
/* char lenght */
newtio.c_cflag &= ~CSIZE;
newtio.c_iflag |= IXOFF | IXON;
break;
}
-
- if (cfsetospeed (&newtio, baud_rate) < 0 || cfsetispeed (&newtio, baud_rate) < 0 ||
- tcsetattr (fd, TCSANOW, &newtio) < 0)
- {
+
+ if (custom_baud_rate == FALSE) {
+ if (cfsetospeed (&newtio, baud_rate) < 0 || cfsetispeed (&newtio, baud_rate) < 0)
+ return FALSE;
+ } else {
+#if __linux__ || defined(HAVE_IOKIT)
+
+ /* On Linux to set a custom baud rate, we must set the
+ * "standard" baud_rate to 38400. On Apple we set it purely
+ * so that tcsetattr has something to use (and report back later), but
+ * the Apple specific API is still opaque to these APIs, see:
+ * https://developer.apple.com/library/mac/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html#//apple_ref/doc/uid/DTS10000454-SerialPortSample_SerialPortSample_c-DontLinkElementID_4
+ */
+ if (cfsetospeed (&newtio, B38400) < 0 || cfsetispeed (&newtio, B38400) < 0)
+ return FALSE;
+#endif
+ }
+
+ if (tcsetattr (fd, TCSANOW, &newtio) < 0)
return FALSE;
+
+ if (custom_baud_rate == TRUE){
+#if defined(HAVE_LINUX_SERIAL_H)
+ struct serial_struct ser;
+
+ if (ioctl (fd, TIOCGSERIAL, &ser) < 0)
+ {
+ return FALSE;
+ }
+
+ ser.custom_divisor = ser.baud_base / baud_rate;
+ ser.flags &= ~ASYNC_SPD_MASK;
+ ser.flags |= ASYNC_SPD_CUST;
+
+ if (ioctl (fd, TIOCSSERIAL, &ser) < 0)
+ {
+ return FALSE;
+ }
+#elif defined(HAVE_IOKIT)
+ speed_t speed = baud_rate;
+ if (ioctl(fd, IOSSIOSPEED, &speed) == -1)
+ return FALSE;
+#else
+ /* Don't know how to set custom baud rate on this platform. */
+ return FALSE;
+#endif
}
- else
- {
+
return TRUE;
- }
}
return 1;
}
-void
+int
breakprop (int fd)
{
- tcsendbreak (fd, 0);
+ return tcsendbreak (fd, 0);
}
gboolean