#include #include #include #include "rdesktop.h" #define FILE_DEVICE_SERIAL_PORT 0x1b #define SERIAL_SET_BAUD_RATE 1 #define SERIAL_SET_QUEUE_SIZE 2 #define SERIAL_SET_LINE_CONTROL 3 #define SERIAL_SET_BREAK_ON 4 #define SERIAL_SET_BREAK_OFF 5 #define SERIAL_IMMEDIATE_CHAR 6 #define SERIAL_SET_TIMEOUTS 7 #define SERIAL_GET_TIMEOUTS 8 #define SERIAL_SET_DTR 9 #define SERIAL_CLR_DTR 10 #define SERIAL_RESET_DEVICE 11 #define SERIAL_SET_RTS 12 #define SERIAL_CLR_RTS 13 #define SERIAL_SET_XOFF 14 #define SERIAL_SET_XON 15 #define SERIAL_GET_WAIT_MASK 16 #define SERIAL_SET_WAIT_MASK 17 #define SERIAL_WAIT_ON_MASK 18 #define SERIAL_PURGE 19 #define SERIAL_GET_BAUD_RATE 20 #define SERIAL_GET_LINE_CONTROL 21 #define SERIAL_GET_CHARS 22 #define SERIAL_SET_CHARS 23 #define SERIAL_GET_HANDFLOW 24 #define SERIAL_SET_HANDFLOW 25 #define SERIAL_GET_MODEMSTATUS 26 #define SERIAL_GET_COMMSTATUS 27 #define SERIAL_XOFF_COUNTER 28 #define SERIAL_GET_PROPERTIES 29 #define SERIAL_GET_DTRRTS 30 #define SERIAL_LSRMST_INSERT 31 #define SERIAL_CONFIG_SIZE 32 #define SERIAL_GET_COMMCONFIG 33 #define SERIAL_SET_COMMCONFIG 34 #define SERIAL_GET_STATS 35 #define SERIAL_CLEAR_STATS 36 #define SERIAL_GET_MODEM_CONTROL 37 #define SERIAL_SET_MODEM_CONTROL 38 #define SERIAL_SET_FIFO_CONTROL 39 #define STOP_BITS_1 0 #define STOP_BITS_2 2 #define NO_PARITY 0 #define ODD_PARITY 1 #define EVEN_PARITY 2 int serial_fd; struct termios termios; int dtr; uint32 baud_rate; uint32 queue_in_size, queue_out_size; uint32 wait_mask; uint8 stop_bits, parity, word_length; static BOOL get_termios(void) { speed_t speed; if (tcgetattr(serial_fd, &termios) == -1) return False; speed = cfgetispeed(&termios); switch (speed) { #ifdef B75 case B75: baud_rate = 75; break; #endif #ifdef B110 case B110: baud_rate = 110; break; #endif #ifdef B134 case B134: baud_rate = 134; break; #endif #ifdef B150 case B150: baud_rate = 150; break; #endif #ifdef B300 case B300: baud_rate = 300; break; #endif #ifdef B600 case B600: baud_rate = 600; break; #endif #ifdef B1200 case B1200: baud_rate = 1200; break; #endif #ifdef B1800 case B1800: baud_rate = 1800; break; #endif #ifdef B2400 case B2400: baud_rate = 2400; break; #endif #ifdef B4800 case B4800: baud_rate = 4800; break; #endif #ifdef B9600 case B9600: baud_rate = 9600; break; #endif #ifdef B19200 case B19200: baud_rate = 19200; break; #endif #ifdef B38400 case B38400: baud_rate = 38400; break; #endif #ifdef B57600 case B57600: baud_rate = 57600; break; #endif #ifdef B115200 case B115200: baud_rate = 115200; break; #endif default: baud_rate = 0; break; } speed = cfgetospeed(&termios); dtr = (speed == B0) ? 0 : 1; stop_bits = (termios.c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1; parity = (termios. c_cflag & PARENB) ? ((termios. c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY; switch (termios.c_cflag & CSIZE) { case CS5: word_length = 5; break; case CS6: word_length = 6; break; case CS7: word_length = 7; break; default: word_length = 8; break; } return True; } static void set_termios(void) { speed_t speed; switch (baud_rate) { #ifdef B75 case 75: speed = B75; break; #endif #ifdef B110 case 110: speed = B110; break; #endif #ifdef B134 case 134: speed = B134; break; #endif #ifdef B150 case 150: speed = B150; break; #endif #ifdef B300 case 300: speed = B300; break; #endif #ifdef B600 case 600: speed = B600; break; #endif #ifdef B1200 case 1200: speed = B1200; break; #endif #ifdef B1800 case 1800: speed = B1800; break; #endif #ifdef B2400 case 2400: speed = B2400; break; #endif #ifdef B4800 case 4800: speed = B4800; break; #endif #ifdef B9600 case 9600: speed = B9600; break; #endif #ifdef B19200 case 19200: speed = B19200; break; #endif #ifdef B38400 case 38400: speed = B38400; break; #endif #ifdef B57600 case 57600: speed = B57600; break; #endif #ifdef B115200 case 115200: speed = B115200; break; #endif default: speed = B0; break; } /* on systems with separate ispeed and ospeed, we can remember the speed in ispeed while changing DTR with ospeed */ cfsetispeed(&termios, speed); cfsetospeed(&termios, dtr ? speed : 0); termios.c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE); switch (stop_bits) { case STOP_BITS_2: termios.c_cflag |= CSTOPB; break; } switch (parity) { case EVEN_PARITY: termios.c_cflag |= PARENB; break; case ODD_PARITY: termios.c_cflag |= PARENB | PARODD; break; } switch (word_length) { case 5: termios.c_cflag |= CS5; break; case 6: termios.c_cflag |= CS6; break; case 7: termios.c_cflag |= CS7; break; default: termios.c_cflag |= CS8; break; } tcsetattr(serial_fd, TCSANOW, &termios); } static NTSTATUS serial_create(HANDLE * handle) { /* XXX do we have to handle concurrent open attempts? */ serial_fd = open("/dev/ttyS0", O_RDWR); if (serial_fd == -1) return STATUS_ACCESS_DENIED; if (!get_termios()) return STATUS_ACCESS_DENIED; *handle = 0; return STATUS_SUCCESS; } static NTSTATUS serial_close(HANDLE handle) { close(serial_fd); return STATUS_SUCCESS; } static NTSTATUS serial_read(HANDLE handle, uint8 * data, uint32 length, uint32 * result) { *result = read(serial_fd, data, length); return STATUS_SUCCESS; } static NTSTATUS serial_write(HANDLE handle, uint8 * data, uint32 length, uint32 * result) { *result = write(serial_fd, data, length); return STATUS_SUCCESS; } static NTSTATUS serial_device_control(HANDLE handle, uint32 request, STREAM in, STREAM out) { uint32 result; uint8 immediate; if ((request >> 16) != FILE_DEVICE_SERIAL_PORT) return STATUS_INVALID_PARAMETER; /* extract operation */ request >>= 2; request &= 0xfff; printf("SERIAL IOCTL %d\n", request); switch (request) { case SERIAL_SET_BAUD_RATE: in_uint32_le(in, baud_rate); set_termios(); break; case SERIAL_GET_BAUD_RATE: out_uint32_le(out, baud_rate); break; case SERIAL_SET_QUEUE_SIZE: in_uint32_le(in, queue_in_size); in_uint32_le(in, queue_out_size); break; case SERIAL_SET_LINE_CONTROL: in_uint8(in, stop_bits); in_uint8(in, parity); in_uint8(in, word_length); set_termios(); break; case SERIAL_GET_LINE_CONTROL: out_uint8(out, stop_bits); out_uint8(out, parity); out_uint8(out, word_length); break; case SERIAL_IMMEDIATE_CHAR: in_uint8(in, immediate); serial_write(handle, &immediate, 1, &result); break; case SERIAL_CONFIG_SIZE: out_uint32_le(out, 0); break; case SERIAL_GET_CHARS: out_uint8s(out, 6); break; case SERIAL_SET_CHARS: in_uint8s(in, 6); break; case SERIAL_GET_HANDFLOW: out_uint32_le(out, 0); out_uint32_le(out, 3); /* Xon/Xoff */ out_uint32_le(out, 0); out_uint32_le(out, 0); break; case SERIAL_SET_HANDFLOW: in_uint8s(in, 16); break; case SERIAL_SET_TIMEOUTS: in_uint8s(in, 20); break; case SERIAL_GET_TIMEOUTS: out_uint8s(out, 20); break; case SERIAL_GET_WAIT_MASK: out_uint32(out, wait_mask); break; case SERIAL_SET_WAIT_MASK: in_uint32(in, wait_mask); break; case SERIAL_SET_DTR: dtr = 1; set_termios(); break; case SERIAL_CLR_DTR: dtr = 0; set_termios(); break; #if 0 case SERIAL_WAIT_ON_MASK: /* XXX implement me */ break; case SERIAL_SET_BREAK_ON: tcsendbreak(serial_fd, 0); break; case SERIAL_PURGE: in_uint32(purge_mask); /* tcflush */ break; case SERIAL_RESET_DEVICE: case SERIAL_SET_BREAK_OFF: case SERIAL_SET_RTS: case SERIAL_CLR_RTS: case SERIAL_SET_XOFF: case SERIAL_SET_XON: /* ignore */ break; #endif default: unimpl("SERIAL IOCTL %d\n", request); return STATUS_INVALID_PARAMETER; } return STATUS_SUCCESS; } DEVICE_FNS serial_fns = { serial_create, serial_close, serial_read, serial_write, serial_device_control };