/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright © 2001 Lutz Müller * Copyright © 2000 Philippe Marzouk * Copyright © 2000 Edouard Lafargue * Copyright © 1999 Johannes Erdfelt * Copyright © 1999 Scott Fritzinger * * Based on work by: * Copyright © 1999 Beat Christen * for the toshiba gPhoto library. * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_TERMIOS_H # include # ifndef CRTSCTS # define CRTSCTS 020000000000 # endif #else # include #endif #ifdef HAVE_RESMGR # include #endif #ifdef HAVE_BAUDBOY # include #elif defined(HAVE_TTYLOCK) # include #elif defined(HAVE_LOCKDEV) # include #endif #include #include #include #ifdef ENABLE_NLS # include # undef _ # define _(String) dgettext (GETTEXT_PACKAGE, String) # ifdef gettext_noop # define N_(String) gettext_noop (String) # else # define N_(String) (String) # endif #else # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) # define dcgettext(Domain,Message,Type) (Message) # define bindtextdomain(Domain,Directory) (Domain) # define _(String) (String) # define N_(String) (String) #endif #define CHECK(result) {int r=(result); if (r<0) return (r);} /* Linux */ #ifdef __linux__ /* devfs is accounted for in the implementation */ #define GP_PORT_SERIAL_PREFIX "/dev/ttyS%i" #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH 32 #endif /* FreeBSD */ #ifdef __FreeBSD__ #define GP_PORT_SERIAL_PREFIX "/dev/cuaa%x" #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH (0xf) #endif /* OpenBSD */ /* devices appear to go up to /dev/cuac7, but we just list the first 4 */ #ifdef __OpenBSD__ # define GP_PORT_SERIAL_PREFIX "/dev/cua%02x" # define GP_PORT_SERIAL_RANGE_LOW 0 # define GP_PORT_SERIAL_RANGE_HIGH 3 #endif /* NetBSD */ #ifdef __NetBSD__ #define GP_PORT_SERIAL_PREFIX "/dev/tty0%i" #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH 32 #endif /* Tru64 UNIX */ #ifdef __osf__ #define GP_PORT_SERIAL_PREFIX "/dev/tty%02i" #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH 4 #endif /* Darwin */ #ifdef __APPLE__ /* This is the Keyspan USB serial adapter device (UNTESTED) */ #define GP_PORT_SERIAL_PREFIX "/dev/tty.KeyUSA28X%i" #define GP_PORT_SERIAL_RANGE_LOW 111 #define GP_PORT_SERIAL_RANGE_HIGH 1112 #endif /* Solaris */ #ifdef sun #define GP_PORT_SERIAL_PREFIX "/dev/tty%c" #define GP_PORT_SERIAL_RANGE_LOW 'a' #define GP_PORT_SERIAL_RANGE_HIGH 'z' #endif /* BeOS */ #ifdef beos /* ????????????? */ #define GP_PORT_SERIAL_PREFIX NULL #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH 0 #endif /* Windows */ #ifdef WIN32 #define GP_PORT_SERIAL_PREFIX "COM%i:" #define GP_PORT_SERIAL_RANGE_LOW 1 #define GP_PORT_SERIAL_RANGE_HIGH 4 #endif #ifdef OS2 #define GP_PORT_SERIAL_PREFIX "COM%i" #define GP_PORT_SERIAL_RANGE_LOW 1 #define GP_PORT_SERIAL_RANGE_HIGH 4 #endif /* IRIX */ #if defined(__sgi) #define GP_PORT_SERIAL_PREFIX "/dev/ttyd%i" #define GP_PORT_SERIAL_RANGE_LOW 1 #define GP_PORT_SERIAL_RANGE_HIGH 11 #endif /* Others? */ /* Default */ #ifndef GP_PORT_SERIAL_PREFIX #define GP_PORT_SERIAL_PREFIX "/dev/cua%i" #define GP_PORT_SERIAL_RANGE_LOW 0 #define GP_PORT_SERIAL_RANGE_HIGH 0 #endif #define GP_MODULE "serial" struct _GPPortPrivateLibrary { int fd; /* Device handle */ int baudrate; /* Current speed */ }; static int gp_port_serial_check_speed (GPPort *dev); GPPortType gp_port_library_type () { return (GP_PORT_SERIAL); } static int gp_port_serial_lock (GPPort *dev, const char *path) { #if defined(HAVE_LOCKDEV) int pid; #endif gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Trying to lock '%s'...", path); #ifdef HAVE_RESMGR if (!rsm_lock_device(path)) { return GP_OK; } /* fallthrough */ #define __HAVE_LOCKING #endif #if defined(HAVE_TTYLOCK) || defined(HAVE_BAUDBOY) if (ttylock ((char*) path)) { if (dev) gp_port_set_error (dev, _("Could not lock device " "'%s'"), path); return (GP_ERROR_IO_LOCK); } #define __HAVE_LOCKING #elif defined(HAVE_LOCKDEV) pid = dev_lock (path); if (pid) { if (dev) { if (pid > 0) gp_port_set_error (dev, _("Device '%s' is " "locked by pid %d"), path, pid); else gp_port_set_error (dev, _("Device '%s' could " "not be locked (dev_lock returned " "%d)"), path, pid); } return (GP_ERROR_IO_LOCK); } #define __HAVE_LOCKING #endif #ifndef __HAVE_LOCKING # ifdef __GCC__ # warning No locking library found. # warning You will run into problems if you use # warning gphoto2 with a serial (RS232) camera in # warning combination with Konqueror (KDE) or Nautilus (GNOME). # warning This will *not* concern USB cameras. # endif #endif return (GP_OK); } static int gp_port_serial_unlock (GPPort *dev, const char *path) { #ifdef HAVE_RESMGR if (!rsm_unlock_device(path)) return GP_OK; /* fallback through other unlock styles */ #endif #if defined(HAVE_TTYLOCK) || defined(HAVE_BAUDBOY) if (ttyunlock ((char*) path)) { if (dev) gp_port_set_error (dev, _("Device '%s' could not be " "unlocked."), path); return (GP_ERROR_IO_LOCK); } #elif defined(HAVE_LOCKDEV) int pid; pid = dev_unlock (path, 0); if (pid) { if (dev) { if (pid > 0) gp_port_set_error (dev, _("Device '%s' could " "not be unlocked as it is locked by " "pid %d."), path, pid); else gp_port_set_error (dev, _("Device '%s' could " "not be unlocked (dev_unlock " "returned %d)"), path, pid); } return (GP_ERROR_IO_LOCK); } #endif /* !HAVE_LOCKDEV */ return (GP_OK); } int gp_port_library_list (GPPortInfoList *list) { GPPortInfo info; char path[1024], prefix[1024]; int x, fd; #ifdef __linux struct stat s; #endif #ifdef OS2 int r, fh, option; #endif /* Copy in the serial port prefix */ strcpy (prefix, GP_PORT_SERIAL_PREFIX); /* On Linux systems, check for devfs */ #ifdef __linux if (!stat ("/dev/tts", &s)) strcpy (prefix, "/dev/tts/%i"); #endif for (x=GP_PORT_SERIAL_RANGE_LOW; x<=GP_PORT_SERIAL_RANGE_HIGH; x++) { sprintf (path, prefix, x); /* OS/2 seems to need an additional check */ #ifdef OS2 r = DosOpen (path, &fh, &option, 0, 0, 1, OPEN_FLAGS_FAIL_ON_ERROR | OPEN_SHARE_DENYREADWRITE, 0); DosClose(fh); if (r) continue; #endif /* First of all, try to lock the device */ if (gp_port_serial_lock (NULL, path) < 0) continue; /* Device locked. Try to open the device. */ fd = -1; #ifdef HAVE_RESMGR /* resmgr has its own API, which calls to a server and * communicates over UNIX domain sockets. */ fd = rsm_open_device(path, O_RDONLY | O_NDELAY); /* fall through to standard open if this failed */ #endif if (fd == -1) fd = open (path, O_RDONLY | O_NDELAY); if (fd < 0) { gp_port_serial_unlock (NULL, path); continue; } /* * Device locked and opened. Close it, unlock it, and add * it to the list. */ close (fd); gp_port_serial_unlock (NULL, path); info.type = GP_PORT_SERIAL; strncpy (info.path, "serial:", sizeof (info.path)); strncat (info.path, path, sizeof (info.path)); snprintf (info.name, sizeof (info.name), _("Serial Port %i"), x); CHECK (gp_port_info_list_append (list, info)); } /* * Generic support. Append it to the list without checking for * return values, because this entry will not be counted. */ info.type = GP_PORT_SERIAL; strncpy (info.path, "^serial", sizeof (info.path)); memset (info.name, 0, sizeof (info.name)); gp_port_info_list_append (list, info); return (GP_OK); } static int gp_port_serial_init (GPPort *dev) { if (!dev) return (GP_ERROR_BAD_PARAMETERS); dev->pl = malloc (sizeof (GPPortPrivateLibrary)); if (!dev->pl) return (GP_ERROR_NO_MEMORY); memset (dev->pl, 0, sizeof (GPPortPrivateLibrary)); /* There is no default speed. */ dev->pl->baudrate = -1; return GP_OK; } static int gp_port_serial_exit (GPPort *dev) { if (!dev) return (GP_ERROR_BAD_PARAMETERS); if (dev->pl) { free (dev->pl); dev->pl = NULL; } return GP_OK; } static int gp_port_serial_open (GPPort *dev) { int result, max_tries = 5, i; #ifdef OS2 int fd; #endif char *port; /* Ports are named "serial:/dev/whatever/port" */ port = strchr (dev->settings.serial.port, ':'); if (!port) return GP_ERROR_UNKNOWN_PORT; port++; result = gp_port_serial_lock (dev, port); if (result != GP_OK) { for (i = 0; i < max_tries; i++) { result = gp_port_serial_lock (dev, port); if (result == GP_OK) break; gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Failed to get a lock, trying again..."); sleep (1); } CHECK (result); } dev->pl->fd = -1; #if defined(__FreeBSD__) || defined(__APPLE__) dev->pl->fd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK); #elif OS2 fd = open (port, O_RDWR | O_BINARY); dev->pl->fd = open (port, O_RDWR | O_BINARY); close(fd); #else # ifdef HAVE_RESMGR dev->pl->fd = rsm_open_device (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK); /* fall back trying old style open if not possible */ # endif if (dev->pl->fd == -1) dev->pl->fd = open (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK); #endif if (dev->pl->fd == -1) { gp_port_set_error (dev, _("Failed to open '%s' (%m)."), port); dev->pl->fd = 0; return GP_ERROR_IO; } return GP_OK; } static int gp_port_serial_close (GPPort *dev) { const char *path; if (!dev) return (GP_OK); if (dev->pl->fd) { if (close (dev->pl->fd) == -1) { gp_port_set_error (dev, _("Could not close " "'%s' (%m)."), dev->settings.serial.port); return GP_ERROR_IO; } dev->pl->fd = 0; } /* Unlock the port */ path = strchr (dev->settings.serial.port, ':'); path++; CHECK (gp_port_serial_unlock (dev, path)); #if defined(__sgi) /* * On IRIX, we need to set the baudrate each time after opening * the port. */ dev->pl->baudrate = 0; #endif return GP_OK; } static int gp_port_serial_write (GPPort *dev, const char *bytes, int size) { int len, ret; if (!dev) return (GP_ERROR_BAD_PARAMETERS); /* The device needs to be opened for that operation */ if (!dev->pl->fd) CHECK (gp_port_serial_open (dev)); /* Make sure we are operating at the specified speed */ CHECK (gp_port_serial_check_speed (dev)); len = 0; while (len < size) { /* * Make sure we write all data while handling * the harmless errors */ ret = write (dev->pl->fd, bytes, size - len); if (ret == -1) { switch (errno) { case EAGAIN: case EINTR: ret = 0; break; default: gp_port_set_error (dev, _("Could not write " "to port (%m)")); return GP_ERROR_IO_WRITE; } } len += ret; } /* wait till all bytes are really sent */ #ifndef OS2 #ifdef HAVE_TERMIOS_H tcdrain (dev->pl->fd); #else ioctl (dev->pl->fd, TCDRAIN, 0); #endif #endif return GP_OK; } static int gp_port_serial_read (GPPort *dev, char *bytes, int size) { struct timeval timeout; fd_set readfs; /* file descriptor set */ int readen = 0, now; if (!dev) return (GP_ERROR_BAD_PARAMETERS); /* The device needs to be opened for that operation */ if (!dev->pl->fd) CHECK (gp_port_serial_open (dev)); /* Make sure we are operating at the specified speed */ CHECK (gp_port_serial_check_speed (dev)); FD_ZERO (&readfs); FD_SET (dev->pl->fd, &readfs); while (readen < size) { /* Set timeout value within input loop */ timeout.tv_usec = (dev->timeout % 1000) * 1000; timeout.tv_sec = (dev->timeout / 1000); /* Any data available? */ if (!select (dev->pl->fd + 1, &readfs, NULL, NULL, &timeout)) return GP_ERROR_TIMEOUT; if (!FD_ISSET (dev->pl->fd, &readfs)) return (GP_ERROR_TIMEOUT); if (dev->settings.serial.parity != GP_PORT_SERIAL_PARITY_OFF) { now = read (dev->pl->fd, bytes, 1); if (now < 0) return GP_ERROR_IO_READ; if (bytes[0] == (char)-1) { now = read (dev->pl->fd, bytes, 1); if (now < 0) return GP_ERROR_IO_READ; /* Parity errors are signaled by the serial layer * as 0xff 0x00 sequence. * * 0xff sent by the camera are escaped as * 0xff 0xff sequence. * * All other 0xff 0xXX sequences are errors. * * cf. man tcsetattr, description of PARMRK. */ if (bytes[0] == 0x00) { gp_port_set_error (dev, _("Parity error.")); return GP_ERROR_IO_READ; } if (bytes[0] != (char)-1) { gp_port_set_error (dev, _("Unexpected parity response sequence 0xff 0x%02x."), bytes[0]); return GP_ERROR_IO_READ; } /* Ok, we read 1 byte and it is 0xff */ /* FALLTHROUGH */ } } else { /* Just read the bytes */ now = read (dev->pl->fd, bytes, size - readen); if (now < 0) return GP_ERROR_IO_READ; } bytes += now; readen += now; } return readen; } #ifdef HAVE_TERMIOS_H static int get_termios_bit (GPPort *dev, GPPin pin, int *bit) { switch (pin) { case GP_PIN_RTS: *bit = TIOCM_RTS; break; case GP_PIN_DTR: *bit = TIOCM_DTR; break; case GP_PIN_CTS: *bit = TIOCM_CTS; break; case GP_PIN_DSR: *bit = TIOCM_DSR; break; case GP_PIN_CD: *bit = TIOCM_CD; break; case GP_PIN_RING: *bit = TIOCM_RNG; break; default: gp_port_set_error (dev, _("Unknown pin %i."), pin); return GP_ERROR_IO; } return (GP_OK); } #endif static int gp_port_serial_get_pin (GPPort *dev, GPPin pin, GPLevel *level) { #ifdef HAVE_TERMIOS_H int j, bit; #endif if (!dev || !level) return (GP_ERROR_BAD_PARAMETERS); *level = 0; #ifdef HAVE_TERMIOS_H CHECK (get_termios_bit (dev, pin, &bit)); if (ioctl (dev->pl->fd, TIOCMGET, &j) < 0) { gp_port_set_error (dev, _("Could not get level of pin %i " "(%m)."), pin); return GP_ERROR_IO; } *level = j & bit; #else # ifdef __GCC__ # warning ACCESSING PINS IS NOT IMPLEMENTED FOR NON-TERMIOS SYSTEMS! # endif #endif return (GP_OK); } static int gp_port_serial_set_pin (GPPort *dev, GPPin pin, GPLevel level) { #ifdef HAVE_TERMIOS_H int bit, request; #endif if (!dev) return (GP_ERROR_BAD_PARAMETERS); #ifdef HAVE_TERMIOS_H CHECK (get_termios_bit (dev, pin, &bit)); switch (level) { case GP_LEVEL_LOW: request = TIOCMBIS; break; default: request = TIOCMBIC; break; } if (ioctl (dev->pl->fd, request, &bit) < 0) { gp_port_set_error (dev, _("Could not set level of pin %i to " "%i (%m)."), pin, level); return GP_ERROR_IO; } #else # ifdef __GCC__ # warning ACCESSING PINS IS NOT IMPLEMENTED FOR NON-TERMIOS SYSTEMS! # endif #endif return GP_OK; } static int gp_port_serial_flush (GPPort *dev, int direction) { /* The device needs to be opened for that operation */ if (!dev->pl->fd) CHECK (gp_port_serial_open (dev)); /* Make sure we are operating at the specified speed */ CHECK (gp_port_serial_check_speed (dev)); #ifdef HAVE_TERMIOS_H if (tcflush (dev->pl->fd, direction ? TCOFLUSH : TCIFLUSH) < 0) { gp_port_set_error (dev, _("Could not flush '%s' (%m)."), dev->settings.serial.port); return (GP_ERROR_IO); } #else # ifdef __GCC__ # warning SERIAL FLUSH NOT IMPLEMENTED FOR NON TERMIOS SYSTEMS! # endif #endif return (GP_OK); } static speed_t gp_port_serial_baudconv (int baudrate) { #define BAUDCASE(x) case (x): { ret = B##x; break; } speed_t ret; switch (baudrate) { /* POSIX defined baudrates */ BAUDCASE(0); BAUDCASE(50); BAUDCASE(75); BAUDCASE(110); BAUDCASE(134); BAUDCASE(150); BAUDCASE(200); BAUDCASE(300); BAUDCASE(600); BAUDCASE(1200); BAUDCASE(1800); BAUDCASE(2400); BAUDCASE(4800); BAUDCASE(9600); BAUDCASE(19200); BAUDCASE(38400); /* non POSIX values */ #ifdef B7200 BAUDCASE(7200); #endif #ifdef B14400 BAUDCASE(14400); #endif #ifdef B28800 BAUDCASE(28800); #endif #ifdef B57600 BAUDCASE(57600); #endif #ifdef B115200 BAUDCASE(115200); #endif #ifdef B230400 BAUDCASE(230400); #endif default: ret = (speed_t) baudrate; gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Baudrate %d " "unknown - using as is", baudrate); } return ret; #undef BAUDCASE } static int gp_port_serial_check_speed (GPPort *dev) { speed_t speed; #ifdef OS2 ULONG rc; ULONG ulParmLen = 2; /* Maximum size of the parameter packet */ #else #ifdef HAVE_TERMIOS_H struct termios tio; #else struct sgttyb ttyb; #endif #endif /* * We need an open device in order to set the speed. If there is no * open device, postpone setting of speed. */ if (!dev->pl->fd) return (GP_OK); /* If baudrate is up to date, do nothing */ if (dev->pl->baudrate == dev->settings.serial.speed) return (GP_OK); gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Setting baudrate to %d...", dev->settings.serial.speed); speed = gp_port_serial_baudconv (dev->settings.serial.speed); #ifdef OS2 rc = DosDevIOCtl (dev->pl->fd, /* Device handle */ 0x0001, /* Serial-device control */ 0x0043, /* Sets bit rate */ (PULONG) &(dev->settings.serial.speed), sizeof(baudrate), /* Max. size of parameter list */ &ulParmLen, /* Size of parameter packet */ NULL, /* No data packet */ 0, /* Maximum size of data packet */ NULL); /* Size of data packet */ if(rc != 0) printf("DosDevIOCtl baudrate error:%d\n",rc); #else /* !OS2 */ #ifdef HAVE_TERMIOS_H if (tcgetattr(dev->pl->fd, &tio) < 0) { gp_port_set_error (dev, _("Could not set the baudrate to %d"), dev->settings.serial.speed); return GP_ERROR_IO_SERIAL_SPEED; } tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8; /* Set into raw, no echo mode */ tio.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | IXANY | IXON | IXOFF | INPCK | ISTRIP); #ifdef IUCLC tio.c_iflag &= ~IUCLC; #endif tio.c_iflag |= (BRKINT | IGNPAR); tio.c_oflag &= ~OPOST; tio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | ECHOE | ECHOK | IEXTEN); tio.c_cflag &= ~(CRTSCTS | PARENB | PARODD); tio.c_cflag |= CLOCAL | CREAD; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (dev->settings.serial.parity != GP_PORT_SERIAL_PARITY_OFF) { tio.c_iflag &= ~IGNPAR; tio.c_iflag |= INPCK | PARMRK ; tio.c_cflag |= PARENB; if (dev->settings.serial.parity == GP_PORT_SERIAL_PARITY_ODD) tio.c_cflag |= PARODD; } /* Set the new speed. */ cfsetispeed (&tio, speed); cfsetospeed (&tio, speed); if (tcsetattr (dev->pl->fd, TCSANOW, &tio) < 0) { GP_DEBUG ("Error on 'tcsetattr'."); return GP_ERROR_IO_SERIAL_SPEED; } /* Clear O_NONBLOCK. */ if (fcntl (dev->pl->fd, F_SETFL, 0) < 0) { GP_DEBUG ("Error on 'fcntl'."); return GP_ERROR_IO_SERIAL_SPEED; } /* * Verify if the speed change has been successful. * This is needed because some Solaris systems just ignore unsupported * speeds (like 115200) instead of complaining. * * Only perform the check if we really changed to some speed. */ if (speed != B0) { if (tcgetattr (dev->pl->fd, &tio)) { GP_DEBUG ("Error on 'tcgetattr'."); return (GP_ERROR_IO_SERIAL_SPEED); } if ((cfgetispeed (&tio) != speed) || (cfgetospeed (&tio) != speed)) { GP_DEBUG ("Cannot set baudrate to %d...", dev->settings.serial.speed); return (GP_ERROR_NOT_SUPPORTED); } } #else /* !HAVE_TERMIOS_H */ if (ioctl (dev->pl->fd, TIOCGETP, &ttyb) < 0) { perror("ioctl(TIOCGETP)"); return GP_ERROR_IO_SERIAL_SPEED; } ttyb.sg_ispeed = dev->settings.serial.speed; ttyb.sg_ospeed = dev->settings.serial.speed; ttyb.sg_flags = 0; if (ioctl (dev->pl->fd, TIOCSETP, &ttyb) < 0) { perror("ioctl(TIOCSETP)"); return GP_ERROR_IO_SERIAL_SPEED; } #endif #endif dev->pl->baudrate = dev->settings.serial.speed; return GP_OK; } static int gp_port_serial_update (GPPort *dev) { memcpy (&dev->settings, &dev->settings_pending, sizeof (dev->settings)); CHECK (gp_port_serial_check_speed (dev)); return GP_OK; } static int gp_port_serial_send_break (GPPort *dev, int duration) { /* The device needs to be opened for that operation */ if (!dev->pl->fd) CHECK (gp_port_serial_open (dev)); /* Make sure we are operating at the specified speed */ CHECK (gp_port_serial_check_speed (dev)); /* Duration is in milliseconds */ #ifdef HAVE_TERMIOS_H tcsendbreak (dev->pl->fd, duration / 310); tcdrain (dev->pl->fd); #else # ifdef __GCC__ # warning SEND BREAK NOT IMPLEMENTED FOR NON TERMIOS SYSTEMS! # endif #endif return GP_OK; } GPPortOperations * gp_port_library_operations () { GPPortOperations *ops; ops = malloc (sizeof (GPPortOperations)); if (!ops) return (NULL); memset (ops, 0, sizeof (GPPortOperations)); ops->init = gp_port_serial_init; ops->exit = gp_port_serial_exit; ops->open = gp_port_serial_open; ops->close = gp_port_serial_close; ops->read = gp_port_serial_read; ops->write = gp_port_serial_write; ops->update = gp_port_serial_update; ops->get_pin = gp_port_serial_get_pin; ops->set_pin = gp_port_serial_set_pin; ops->send_break = gp_port_serial_send_break; ops->flush = gp_port_serial_flush; return (ops); }