/* $Id$ G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. Released under the terms of the GNU GPL, see file COPYING for more details. */ #include "misc.h" /* Do not compile this file under Win32 systems. */ #ifndef WIN32 #include #include #include #include #if __unices__ # include #endif #include #include "devices/unixserial.h" #ifdef HAVE_SYS_IOCTL_COMPAT_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif /* If the target operating system does not have cfsetspeed, we can emulate it. */ #ifndef HAVE_CFSETSPEED #if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED) #define cfsetspeed(t, speed) \ (cfsetispeed(t, speed) || cfsetospeed(t, speed)) #else static int cfsetspeed(struct termios *t, int speed) { #ifdef HAVE_TERMIOS_CSPEED t->c_ispeed = speed; t->c_ospeed = speed; #else t->c_cflag |= speed; #endif return 0; } #endif #endif #ifndef O_NONBLOCK #define O_NONBLOCK 0 #endif /* Structure to backup the setting of the terminal. */ struct termios serial_termios; /* Open the serial port and store the settings. */ int serial_open(__const char *__file, int __oflag) { int __fd; int retcode; __fd = open(__file, __oflag); if (__fd == -1) { perror("Gnokii serial_open: open"); return (-1); } retcode=tcgetattr(__fd, &serial_termios); if(retcode==-1) { perror("Gnokii serial_open:tcgetattr"); /* Don't call serial_close since serial_termios is not valid */ close(__fd); return(-1); } return __fd; } /* Close the serial port and restore old settings. */ int serial_close(int __fd) { if (__fd >= 0) tcsetattr(__fd, TCSANOW, &serial_termios); return (close(__fd)); } /* Open a device with standard options. */ int serial_opendevice(__const char *__file, int __with_odd_parity, int __with_async, int __with_hw_handshake) { int fd; int retcode; struct termios tp; /* Open device */ fd = serial_open(__file, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd < 0) return fd; /* Allow process/thread to receive SIGIO */ #if !(__unices__) retcode = fcntl(fd, F_SETOWN, getpid()); if (retcode == -1){ perror("Gnokii serial_opendevice: fnctl(F_SETOWN)"); serial_close(fd); return(-1); } #endif /* Make filedescriptor asynchronous. */ if (__with_async) { retcode=fcntl(fd, F_SETFL, FASYNC); if (retcode == -1){ perror("Gnokii serial_opendevice: fnctl(F_SETFL)"); serial_close(fd); return(-1); } } /* Initialise the port settings */ memcpy(&tp, &serial_termios, sizeof(struct termios)); /* Set port settings for canonical input processing */ tp.c_cflag = B0 | CS8 | CLOCAL | CREAD; if (__with_odd_parity) { tp.c_cflag |= (PARENB | PARODD); tp.c_iflag = 0; } else tp.c_iflag = IGNPAR; if (__with_hw_handshake) tp.c_cflag |= CRTSCTS; else tp.c_cflag &= ~CRTSCTS; tp.c_oflag = 0; tp.c_lflag = 0; tp.c_cc[VMIN] = 1; tp.c_cc[VTIME] = 0; retcode=tcflush(fd, TCIFLUSH); if (retcode == -1) { perror("Gnokii serial_opendevice: tcflush"); serial_close(fd); return(-1); } retcode=tcsetattr(fd, TCSANOW, &tp); if (retcode == -1){ perror("Gnokii serial_opendevice: tcsetattr"); serial_close(fd); return(-1); } return fd; } /* Set the DTR and RTS bit of the serial device. */ void serial_setdtrrts(int __fd, int __dtr, int __rts) { unsigned int flags; flags = TIOCM_DTR; if (__dtr) ioctl(__fd, TIOCMBIS, &flags); else ioctl(__fd, TIOCMBIC, &flags); flags = TIOCM_RTS; if (__rts) ioctl(__fd, TIOCMBIS, &flags); else ioctl(__fd, TIOCMBIC, &flags); } int serial_select(int fd, struct timeval *timeout) { fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); return (select(fd + 1, &readfds, NULL, NULL, timeout)); } /* Change the speed of the serial device. */ void serial_changespeed(int __fd, int __speed) { #ifndef SGTTY struct termios t; #else struct sgttyb t; #endif int speed=B9600; switch (__speed) { case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; } #ifndef SGTTY tcgetattr(__fd, &t); // This is not needed! We set up the speed via cfsetspeed // t.c_cflag &= ~CBAUD; // t.c_cflag |= speed; #ifdef DEBUG if (cfsetspeed(&t, speed) == -1) fprintf(stdout,_("Serial port speed setting failed\n")); #else cfsetspeed(&t, speed); #endif tcsetattr(__fd, TCSADRAIN, &t); #else ioctl(__fd, TIOCGETP, &t); t.sg_ispeed = speed; t.sg_ospeed = speed; ioctl(__fd, TIOCSETN, &t); #endif } /* Read from serial device. */ size_t serial_read(int __fd, __ptr_t __buf, size_t __nbytes) { return (read(__fd, __buf, __nbytes)); } /* Write to serial device. */ size_t serial_write(int __fd, __const __ptr_t __buf, size_t __n) { return (write(__fd, __buf, __n)); } #endif /* WIN32 */