Logo Search packages:      
Sourcecode: libgphoto2 version File versions

unix.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * Copyright © 2001 Lutz Müller <lutz@users.sf.net>
 * Copyright © 2000 Philippe Marzouk <pmarzouk@bigfoot.com>
 * Copyright © 2000 Edouard Lafargue <Edouard.Lafargue@bigfoot.com>
 * Copyright © 1999 Johannes Erdfelt <johannes@erdfelt.com>
 * Copyright © 1999 Scott Fritzinger <scottf@unr.edu>
 *
 * Based on work by:
 * Copyright © 1999 Beat Christen <spiff@longstreet.ch>
 *    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 <gphoto2/gphoto2-port-library.h>

/* Solaris needs this */
#define __EXTENSIONS__

#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#ifdef HAVE_TERMIOS_H
#  include <termios.h>
#  ifndef CRTSCTS
#    define CRTSCTS  020000000000
#  endif
#else
#  include <sgtty.h>
#endif

#ifdef HAVE_RESMGR
#  include <resmgr.h>
#endif

#ifdef HAVE_BAUDBOY
#  include <baudboy.h>
#elif defined(HAVE_TTYLOCK)
#  include <ttylock.h>
#elif defined(HAVE_LOCKDEV)
#  include <lockdev.h>
#endif

#include <gphoto2/gphoto2-port-result.h>
#include <gphoto2/gphoto2-port-log.h>
#include <gphoto2/gphoto2-port.h>

#ifdef ENABLE_NLS
#  include <libintl.h>
#  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

#ifndef IXANY
#define IXANY  0004000
#endif

#endif

/* FreeBSD */
#ifdef __FreeBSD__
#if __FreeBSD_version < 600000
#define GP_PORT_SERIAL_PREFIX   "/dev/cuaa%x"
#else
#define GP_PORT_SERIAL_PREFIX   "/dev/cuad%x"
#endif
#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;
        struct stat s;
#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
            /* Very first of all, if the device node is not there,
             * there is no need to try locking. */
            if ((stat (path, &s) == -1) && ((errno == ENOENT) || (errno == ENODEV)))
                  continue;
            /* Just let it fail later on open, lock&open for just enumerating is taking too long. */
            /* This is a significant part of the "empty" startup time. */
#if 0
            /* 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_NONBLOCK);
            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);
#endif
            info.type = GP_PORT_SERIAL;
            strncpy (info.path, "serial:", sizeof (info.path));
            strncat (info.path, path, sizeof (info.path) - strlen (info.path) - 1);
            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__) || defined(__DragonFly__)
        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, ':');
      if (!path) return GP_ERROR_BAD_PARAMETERS;
      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) {
                unsigned char ffchar[1];
                unsigned char nullchar[1];

                ffchar[0] = 0xff;
                nullchar[0] = 0;
                now = read (dev->pl->fd, bytes, 1);
                if (now < 0)
                      return GP_ERROR_IO_READ;
                if (!memcmp(bytes,ffchar,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 (!memcmp(bytes,nullchar,1)) {
                      gp_port_set_error (dev, _("Parity error."));
                      return GP_ERROR_IO_READ;
                  }
                  if (!memcmp(bytes,ffchar,1)) {
                      gp_port_set_error (dev, _("Unexpected parity response sequence 0xff 0x%02x."), ((unsigned char*)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);
}

Generated by  Doxygen 1.6.0   Back to index