X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=support%2Fserial.c;h=5e3d732c005170bbcd4052841fad7dc3b27b342c;hb=HEAD;hp=abe409e05b617269da96c9b7f453dbe179d31ca9;hpb=b3108791351ca358a54f95f6f9eaa37a10537455;p=mono.git diff --git a/support/serial.c b/support/serial.c index abe409e05b6..5e3d732c005 100644 --- a/support/serial.c +++ b/support/serial.c @@ -5,13 +5,25 @@ * Author: Chris Toshok */ +#include "map.h" +#include "mph.h" + #include #include #include #include +#include +#if defined(HAVE_POLL_H) +#include +#elif defined(HAVE_SYS_POLL_H) #include +#endif #include -#include + +/* This is for ASYNC_*, serial_struct on linux */ +#if defined(HAVE_LINUX_SERIAL_H) +#include +#endif #include @@ -21,8 +33,17 @@ #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 +#include +#include +#include +#include #endif /* This is a copy of System.IO.Ports.Handshake */ @@ -60,22 +81,40 @@ typedef enum { 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 @@ -92,27 +131,19 @@ int write_serial (int fd, guchar *buffer, int offset, int count, int timeout) { struct pollfd pinfo; + guint32 n; pinfo.fd = fd; pinfo.events = POLLOUT; pinfo.revents = POLLOUT; - - struct timeval tmval; - fd_set writefs; - guint32 n; - n = count; - FD_SET(fd, &writefs); - tmval.tv_sec = timeout / 1000; - tmval.tv_usec = (timeout - tmval.tv_sec) * 1000; - 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) @@ -135,15 +166,20 @@ write_serial (int fd, guchar *buffer, int offset, int count, int timeout) 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) { @@ -154,19 +190,28 @@ get_bytes_in_buffer (int fd, gboolean input) } 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; @@ -219,11 +264,42 @@ set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStop 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; @@ -277,6 +353,7 @@ set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStop case Even: /* Even */ newtio.c_cflag &= ~(PARODD); + newtio.c_cflag |= (PARENB); break; case Mark: /* Mark */ @@ -311,16 +388,55 @@ set_attributes (int fd, int baud_rate, MonoParity parity, int dataBits, MonoStop 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; - } } @@ -404,10 +520,10 @@ set_signal (int fd, MonoSerialSignal signal, gboolean value) return 1; } -void +int breakprop (int fd) { - tcsendbreak (fd, 0); + return tcsendbreak (fd, 0); } gboolean