1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 * Copyright © 2001 Lutz Müller <lutz@users.sf.net>
4 * Copyright © 2000 Philippe Marzouk <pmarzouk@bigfoot.com>
5 * Copyright © 2000 Edouard Lafargue <Edouard.Lafargue@bigfoot.com>
6 * Copyright © 1999 Johannes Erdfelt <johannes@erdfelt.com>
7 * Copyright © 1999 Scott Fritzinger <scottf@unr.edu>
10 * Copyright © 1999 Beat Christen <spiff@longstreet.ch>
11 * for the toshiba gPhoto library.
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 * Boston, MA 02111-1307, USA.
31 #include <gphoto2/gphoto2-port-library.h>
33 /* Solaris needs this */
34 #define __EXTENSIONS__
50 #include <sys/types.h>
51 #ifdef HAVE_SYS_TIME_H
54 #ifdef HAVE_SYS_IOCTL_H
55 #include <sys/ioctl.h>
57 #ifdef HAVE_SYS_SELECT_H
58 # include <sys/select.h>
64 # define CRTSCTS 020000000000
76 #elif defined(HAVE_TTYLOCK)
78 #elif defined(HAVE_LOCKDEV)
82 #include <gphoto2/gphoto2-port-result.h>
83 #include <gphoto2/gphoto2-port-log.h>
84 #include <gphoto2/gphoto2-port.h>
89 # define _(String) dgettext (GETTEXT_PACKAGE, String)
91 # define N_(String) gettext_noop (String)
93 # define N_(String) (String)
96 # define textdomain(String) (String)
97 # define gettext(String) (String)
98 # define dgettext(Domain,Message) (Message)
99 # define dcgettext(Domain,Message,Type) (Message)
100 # define bindtextdomain(Domain,Directory) (Domain)
101 # define _(String) (String)
102 # define N_(String) (String)
105 #define CHECK(result) {int r=(result); if (r<0) return (r);}
109 /* devfs is accounted for in the implementation */
110 #define GP_PORT_SERIAL_PREFIX "/dev/ttyS%i"
111 #define GP_PORT_SERIAL_RANGE_LOW 0
112 #define GP_PORT_SERIAL_RANGE_HIGH 32
115 #define IXANY 0004000
122 #if __FreeBSD_version < 600000
123 #define GP_PORT_SERIAL_PREFIX "/dev/cuaa%x"
125 #define GP_PORT_SERIAL_PREFIX "/dev/cuad%x"
127 #define GP_PORT_SERIAL_RANGE_LOW 0
128 #define GP_PORT_SERIAL_RANGE_HIGH (0xf)
132 /* devices appear to go up to /dev/cuac7, but we just list the first 4 */
134 # define GP_PORT_SERIAL_PREFIX "/dev/cua%02x"
135 # define GP_PORT_SERIAL_RANGE_LOW 0
136 # define GP_PORT_SERIAL_RANGE_HIGH 3
141 #define GP_PORT_SERIAL_PREFIX "/dev/tty0%i"
142 #define GP_PORT_SERIAL_RANGE_LOW 0
143 #define GP_PORT_SERIAL_RANGE_HIGH 32
148 #define GP_PORT_SERIAL_PREFIX "/dev/tty%02i"
149 #define GP_PORT_SERIAL_RANGE_LOW 0
150 #define GP_PORT_SERIAL_RANGE_HIGH 4
155 /* This is the Keyspan USB serial adapter device (UNTESTED) */
156 #define GP_PORT_SERIAL_PREFIX "/dev/tty.KeyUSA28X%i"
157 #define GP_PORT_SERIAL_RANGE_LOW 111
158 #define GP_PORT_SERIAL_RANGE_HIGH 1112
163 #define GP_PORT_SERIAL_PREFIX "/dev/tty%c"
164 #define GP_PORT_SERIAL_RANGE_LOW 'a'
165 #define GP_PORT_SERIAL_RANGE_HIGH 'z'
171 #define GP_PORT_SERIAL_PREFIX NULL
172 #define GP_PORT_SERIAL_RANGE_LOW 0
173 #define GP_PORT_SERIAL_RANGE_HIGH 0
178 #define GP_PORT_SERIAL_PREFIX "COM%i:"
179 #define GP_PORT_SERIAL_RANGE_LOW 1
180 #define GP_PORT_SERIAL_RANGE_HIGH 4
184 #define GP_PORT_SERIAL_PREFIX "COM%i"
185 #define GP_PORT_SERIAL_RANGE_LOW 1
186 #define GP_PORT_SERIAL_RANGE_HIGH 4
191 #define GP_PORT_SERIAL_PREFIX "/dev/ttyd%i"
192 #define GP_PORT_SERIAL_RANGE_LOW 1
193 #define GP_PORT_SERIAL_RANGE_HIGH 11
199 #ifndef GP_PORT_SERIAL_PREFIX
200 #define GP_PORT_SERIAL_PREFIX "/dev/cua%i"
201 #define GP_PORT_SERIAL_RANGE_LOW 0
202 #define GP_PORT_SERIAL_RANGE_HIGH 0
205 #define GP_MODULE "serial"
207 struct _GPPortPrivateLibrary {
208 int fd; /* Device handle */
209 int baudrate; /* Current speed */
212 static int gp_port_serial_check_speed (GPPort *dev);
215 gp_port_library_type ()
217 return (GP_PORT_SERIAL);
221 gp_port_serial_lock (GPPort *dev, const char *path)
223 #if defined(HAVE_LOCKDEV)
227 gp_log (GP_LOG_DEBUG, "gphoto2-port-serial",
228 "Trying to lock '%s'...", path);
231 if (!rsm_lock_device(path)) {
235 #define __HAVE_LOCKING
238 #if defined(HAVE_TTYLOCK) || defined(HAVE_BAUDBOY)
239 if (ttylock ((char*) path)) {
241 gp_port_set_error (dev, _("Could not lock device "
243 return (GP_ERROR_IO_LOCK);
245 #define __HAVE_LOCKING
246 #elif defined(HAVE_LOCKDEV)
247 pid = dev_lock (path);
251 gp_port_set_error (dev, _("Device '%s' is "
252 "locked by pid %d"), path, pid);
254 gp_port_set_error (dev, _("Device '%s' could "
255 "not be locked (dev_lock returned "
258 return (GP_ERROR_IO_LOCK);
260 #define __HAVE_LOCKING
263 #ifndef __HAVE_LOCKING
265 # warning No locking library found.
266 # warning You will run into problems if you use
267 # warning gphoto2 with a serial (RS232) camera in
268 # warning combination with Konqueror (KDE) or Nautilus (GNOME).
269 # warning This will *not* concern USB cameras.
277 gp_port_serial_unlock (GPPort *dev, const char *path)
280 if (!rsm_unlock_device(path))
282 /* fallback through other unlock styles */
285 #if defined(HAVE_TTYLOCK) || defined(HAVE_BAUDBOY)
286 if (ttyunlock ((char*) path)) {
288 gp_port_set_error (dev, _("Device '%s' could not be "
290 return (GP_ERROR_IO_LOCK);
292 #elif defined(HAVE_LOCKDEV)
296 pid = dev_unlock (path, 0);
300 gp_port_set_error (dev, _("Device '%s' could "
301 "not be unlocked as it is locked by "
302 "pid %d."), path, pid);
304 gp_port_set_error (dev, _("Device '%s' could "
305 "not be unlocked (dev_unlock "
306 "returned %d)"), path, pid);
308 return (GP_ERROR_IO_LOCK);
310 #endif /* !HAVE_LOCKDEV */
316 gp_port_library_list (GPPortInfoList *list)
319 char path[1024], prefix[1024];
326 /* Copy in the serial port prefix */
327 strcpy (prefix, GP_PORT_SERIAL_PREFIX);
329 /* On Linux systems, check for devfs */
331 if (!stat ("/dev/tts", &s))
332 strcpy (prefix, "/dev/tts/%i");
335 for (x=GP_PORT_SERIAL_RANGE_LOW; x<=GP_PORT_SERIAL_RANGE_HIGH; x++) {
336 sprintf (path, prefix, x);
338 /* OS/2 seems to need an additional check */
340 r = DosOpen (path, &fh, &option, 0, 0, 1,
341 OPEN_FLAGS_FAIL_ON_ERROR |
342 OPEN_SHARE_DENYREADWRITE, 0);
347 /* Very first of all, if the device node is not there,
348 * there is no need to try locking. */
349 if ((stat (path, &s) == -1) && ((errno == ENOENT) || (errno == ENODEV)))
351 /* Just let it fail later on open, lock&open for just enumerating is taking too long. */
352 /* This is a significant part of the "empty" startup time. */
354 /* First of all, try to lock the device */
355 if (gp_port_serial_lock (NULL, path) < 0)
358 /* Device locked. Try to open the device. */
361 /* resmgr has its own API, which calls to a server and
362 * communicates over UNIX domain sockets.
364 fd = rsm_open_device(path, O_RDONLY | O_NDELAY);
365 /* fall through to standard open if this failed */
368 fd = open (path, O_RDONLY | O_NONBLOCK);
370 gp_port_serial_unlock (NULL, path);
375 * Device locked and opened. Close it, unlock it, and add
379 gp_port_serial_unlock (NULL, path);
381 info.type = GP_PORT_SERIAL;
382 strncpy (info.path, "serial:", sizeof (info.path));
383 strncat (info.path, path, sizeof (info.path) - strlen (info.path) - 1);
384 snprintf (info.name, sizeof (info.name),
385 _("Serial Port %i"), x);
386 CHECK (gp_port_info_list_append (list, info));
390 * Generic support. Append it to the list without checking for
391 * return values, because this entry will not be counted.
393 info.type = GP_PORT_SERIAL;
394 strncpy (info.path, "^serial", sizeof (info.path));
395 memset (info.name, 0, sizeof (info.name));
396 gp_port_info_list_append (list, info);
402 gp_port_serial_init (GPPort *dev)
405 return (GP_ERROR_BAD_PARAMETERS);
407 dev->pl = malloc (sizeof (GPPortPrivateLibrary));
409 return (GP_ERROR_NO_MEMORY);
410 memset (dev->pl, 0, sizeof (GPPortPrivateLibrary));
412 /* There is no default speed. */
413 dev->pl->baudrate = -1;
419 gp_port_serial_exit (GPPort *dev)
422 return (GP_ERROR_BAD_PARAMETERS);
433 gp_port_serial_open (GPPort *dev)
435 int result, max_tries = 5, i;
441 /* Ports are named "serial:/dev/whatever/port" */
442 port = strchr (dev->settings.serial.port, ':');
444 return GP_ERROR_UNKNOWN_PORT;
447 result = gp_port_serial_lock (dev, port);
448 if (result != GP_OK) {
449 for (i = 0; i < max_tries; i++) {
450 result = gp_port_serial_lock (dev, port);
453 gp_log (GP_LOG_DEBUG, "gphoto2-port-serial",
454 "Failed to get a lock, trying again...");
461 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
462 dev->pl->fd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK);
464 fd = open (port, O_RDWR | O_BINARY);
465 dev->pl->fd = open (port, O_RDWR | O_BINARY);
469 dev->pl->fd = rsm_open_device (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
470 /* fall back trying old style open if not possible */
472 if (dev->pl->fd == -1)
473 dev->pl->fd = open (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
475 if (dev->pl->fd == -1) {
476 gp_port_set_error (dev, _("Failed to open '%s' (%m)."), port);
485 gp_port_serial_close (GPPort *dev)
493 if (close (dev->pl->fd) == -1) {
494 gp_port_set_error (dev, _("Could not close "
495 "'%s' (%m)."), dev->settings.serial.port);
501 /* Unlock the port */
502 path = strchr (dev->settings.serial.port, ':');
503 if (!path) return GP_ERROR_BAD_PARAMETERS;
505 CHECK (gp_port_serial_unlock (dev, path));
509 * On IRIX, we need to set the baudrate each time after opening
512 dev->pl->baudrate = 0;
519 gp_port_serial_write (GPPort *dev, const char *bytes, int size)
524 return (GP_ERROR_BAD_PARAMETERS);
526 /* The device needs to be opened for that operation */
528 CHECK (gp_port_serial_open (dev));
530 /* Make sure we are operating at the specified speed */
531 CHECK (gp_port_serial_check_speed (dev));
537 * Make sure we write all data while handling
538 * the harmless errors
540 ret = write (dev->pl->fd, bytes, size - len);
548 gp_port_set_error (dev, _("Could not write "
550 return GP_ERROR_IO_WRITE;
556 /* wait till all bytes are really sent */
558 #ifdef HAVE_TERMIOS_H
559 tcdrain (dev->pl->fd);
561 ioctl (dev->pl->fd, TCDRAIN, 0);
569 gp_port_serial_read (GPPort *dev, char *bytes, int size)
571 struct timeval timeout;
572 fd_set readfs; /* file descriptor set */
576 return (GP_ERROR_BAD_PARAMETERS);
578 /* The device needs to be opened for that operation */
580 CHECK (gp_port_serial_open (dev));
582 /* Make sure we are operating at the specified speed */
583 CHECK (gp_port_serial_check_speed (dev));
586 FD_SET (dev->pl->fd, &readfs);
588 while (readen < size) {
590 /* Set timeout value within input loop */
591 timeout.tv_usec = (dev->timeout % 1000) * 1000;
592 timeout.tv_sec = (dev->timeout / 1000);
594 /* Any data available? */
595 if (!select (dev->pl->fd + 1, &readfs, NULL, NULL, &timeout))
596 return GP_ERROR_TIMEOUT;
597 if (!FD_ISSET (dev->pl->fd, &readfs))
598 return (GP_ERROR_TIMEOUT);
600 if (dev->settings.serial.parity != GP_PORT_SERIAL_PARITY_OFF) {
601 unsigned char ffchar[1];
602 unsigned char nullchar[1];
606 now = read (dev->pl->fd, bytes, 1);
608 return GP_ERROR_IO_READ;
609 if (!memcmp(bytes,ffchar,1)) {
610 now = read (dev->pl->fd, bytes, 1);
612 return GP_ERROR_IO_READ;
614 /* Parity errors are signaled by the serial layer
615 * as 0xff 0x00 sequence.
617 * 0xff sent by the camera are escaped as
618 * 0xff 0xff sequence.
620 * All other 0xff 0xXX sequences are errors.
622 * cf. man tcsetattr, description of PARMRK.
624 if (!memcmp(bytes,nullchar,1)) {
625 gp_port_set_error (dev, _("Parity error."));
626 return GP_ERROR_IO_READ;
628 if (!memcmp(bytes,ffchar,1)) {
629 gp_port_set_error (dev, _("Unexpected parity response sequence 0xff 0x%02x."), ((unsigned char*)bytes)[0]);
630 return GP_ERROR_IO_READ;
632 /* Ok, we read 1 byte and it is 0xff */
636 /* Just read the bytes */
637 now = read (dev->pl->fd, bytes, size - readen);
639 return GP_ERROR_IO_READ;
648 #ifdef HAVE_TERMIOS_H
650 get_termios_bit (GPPort *dev, GPPin pin, int *bit)
672 gp_port_set_error (dev, _("Unknown pin %i."), pin);
680 gp_port_serial_get_pin (GPPort *dev, GPPin pin, GPLevel *level)
682 #ifdef HAVE_TERMIOS_H
687 return (GP_ERROR_BAD_PARAMETERS);
691 #ifdef HAVE_TERMIOS_H
692 CHECK (get_termios_bit (dev, pin, &bit));
693 if (ioctl (dev->pl->fd, TIOCMGET, &j) < 0) {
694 gp_port_set_error (dev, _("Could not get level of pin %i "
701 # warning ACCESSING PINS IS NOT IMPLEMENTED FOR NON-TERMIOS SYSTEMS!
709 gp_port_serial_set_pin (GPPort *dev, GPPin pin, GPLevel level)
711 #ifdef HAVE_TERMIOS_H
716 return (GP_ERROR_BAD_PARAMETERS);
718 #ifdef HAVE_TERMIOS_H
719 CHECK (get_termios_bit (dev, pin, &bit));
728 if (ioctl (dev->pl->fd, request, &bit) < 0) {
729 gp_port_set_error (dev, _("Could not set level of pin %i to "
730 "%i (%m)."), pin, level);
735 # warning ACCESSING PINS IS NOT IMPLEMENTED FOR NON-TERMIOS SYSTEMS!
743 gp_port_serial_flush (GPPort *dev, int direction)
745 /* The device needs to be opened for that operation */
747 CHECK (gp_port_serial_open (dev));
749 /* Make sure we are operating at the specified speed */
750 CHECK (gp_port_serial_check_speed (dev));
752 #ifdef HAVE_TERMIOS_H
753 if (tcflush (dev->pl->fd, direction ? TCOFLUSH : TCIFLUSH) < 0) {
754 gp_port_set_error (dev, _("Could not flush '%s' (%m)."),
755 dev->settings.serial.port);
756 return (GP_ERROR_IO);
760 # warning SERIAL FLUSH NOT IMPLEMENTED FOR NON TERMIOS SYSTEMS!
768 gp_port_serial_baudconv (int baudrate)
770 #define BAUDCASE(x) case (x): { ret = B##x; break; }
775 /* POSIX defined baudrates */
793 /* non POSIX values */
813 ret = (speed_t) baudrate;
814 gp_log (GP_LOG_DEBUG, "gphoto2-port-serial", "Baudrate %d "
815 "unknown - using as is", baudrate);
823 gp_port_serial_check_speed (GPPort *dev)
828 ULONG ulParmLen = 2; /* Maximum size of the parameter packet */
830 #ifdef HAVE_TERMIOS_H
838 * We need an open device in order to set the speed. If there is no
839 * open device, postpone setting of speed.
844 /* If baudrate is up to date, do nothing */
845 if (dev->pl->baudrate == dev->settings.serial.speed)
848 gp_log (GP_LOG_DEBUG, "gphoto2-port-serial",
849 "Setting baudrate to %d...", dev->settings.serial.speed);
850 speed = gp_port_serial_baudconv (dev->settings.serial.speed);
853 rc = DosDevIOCtl (dev->pl->fd, /* Device handle */
854 0x0001, /* Serial-device control */
855 0x0043, /* Sets bit rate */
856 (PULONG) &(dev->settings.serial.speed),
857 sizeof(baudrate), /* Max. size of parameter list */
858 &ulParmLen, /* Size of parameter packet */
859 NULL, /* No data packet */
860 0, /* Maximum size of data packet */
861 NULL); /* Size of data packet */
863 printf("DosDevIOCtl baudrate error:%d\n",rc);
865 #ifdef HAVE_TERMIOS_H
866 if (tcgetattr(dev->pl->fd, &tio) < 0) {
867 gp_port_set_error (dev, _("Could not set the baudrate to %d"),
868 dev->settings.serial.speed);
869 return GP_ERROR_IO_SERIAL_SPEED;
871 tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8;
873 /* Set into raw, no echo mode */
874 tio.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL |
875 IXANY | IXON | IXOFF | INPCK | ISTRIP);
877 tio.c_iflag &= ~IUCLC;
879 tio.c_iflag |= (BRKINT | IGNPAR);
880 tio.c_oflag &= ~OPOST;
881 tio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | ECHOE |
883 tio.c_cflag &= ~(CRTSCTS | PARENB | PARODD);
884 tio.c_cflag |= CLOCAL | CREAD;
889 if (dev->settings.serial.parity != GP_PORT_SERIAL_PARITY_OFF) {
890 tio.c_iflag &= ~IGNPAR;
891 tio.c_iflag |= INPCK | PARMRK ;
892 tio.c_cflag |= PARENB;
893 if (dev->settings.serial.parity == GP_PORT_SERIAL_PARITY_ODD)
894 tio.c_cflag |= PARODD;
897 /* Set the new speed. */
898 cfsetispeed (&tio, speed);
899 cfsetospeed (&tio, speed);
900 if (tcsetattr (dev->pl->fd, TCSANOW, &tio) < 0) {
901 GP_DEBUG ("Error on 'tcsetattr'.");
902 return GP_ERROR_IO_SERIAL_SPEED;
905 /* Clear O_NONBLOCK. */
906 if (fcntl (dev->pl->fd, F_SETFL, 0) < 0) {
907 GP_DEBUG ("Error on 'fcntl'.");
908 return GP_ERROR_IO_SERIAL_SPEED;
912 * Verify if the speed change has been successful.
913 * This is needed because some Solaris systems just ignore unsupported
914 * speeds (like 115200) instead of complaining.
916 * Only perform the check if we really changed to some speed.
919 if (tcgetattr (dev->pl->fd, &tio)) {
920 GP_DEBUG ("Error on 'tcgetattr'.");
921 return (GP_ERROR_IO_SERIAL_SPEED);
923 if ((cfgetispeed (&tio) != speed) ||
924 (cfgetospeed (&tio) != speed)) {
925 GP_DEBUG ("Cannot set baudrate to %d...",
926 dev->settings.serial.speed);
927 return (GP_ERROR_NOT_SUPPORTED);
931 #else /* !HAVE_TERMIOS_H */
932 if (ioctl (dev->pl->fd, TIOCGETP, &ttyb) < 0) {
933 perror("ioctl(TIOCGETP)");
934 return GP_ERROR_IO_SERIAL_SPEED;
936 ttyb.sg_ispeed = dev->settings.serial.speed;
937 ttyb.sg_ospeed = dev->settings.serial.speed;
940 if (ioctl (dev->pl->fd, TIOCSETP, &ttyb) < 0) {
941 perror("ioctl(TIOCSETP)");
942 return GP_ERROR_IO_SERIAL_SPEED;
947 dev->pl->baudrate = dev->settings.serial.speed;
952 gp_port_serial_update (GPPort *dev)
954 memcpy (&dev->settings, &dev->settings_pending, sizeof (dev->settings));
956 CHECK (gp_port_serial_check_speed (dev));
962 gp_port_serial_send_break (GPPort *dev, int duration)
964 /* The device needs to be opened for that operation */
966 CHECK (gp_port_serial_open (dev));
968 /* Make sure we are operating at the specified speed */
969 CHECK (gp_port_serial_check_speed (dev));
971 /* Duration is in milliseconds */
972 #ifdef HAVE_TERMIOS_H
973 tcsendbreak (dev->pl->fd, duration / 310);
974 tcdrain (dev->pl->fd);
977 # warning SEND BREAK NOT IMPLEMENTED FOR NON TERMIOS SYSTEMS!
985 gp_port_library_operations ()
987 GPPortOperations *ops;
989 ops = malloc (sizeof (GPPortOperations));
992 memset (ops, 0, sizeof (GPPortOperations));
994 ops->init = gp_port_serial_init;
995 ops->exit = gp_port_serial_exit;
996 ops->open = gp_port_serial_open;
997 ops->close = gp_port_serial_close;
998 ops->read = gp_port_serial_read;
999 ops->write = gp_port_serial_write;
1000 ops->update = gp_port_serial_update;
1001 ops->get_pin = gp_port_serial_get_pin;
1002 ops->set_pin = gp_port_serial_set_pin;
1003 ops->send_break = gp_port_serial_send_break;
1004 ops->flush = gp_port_serial_flush;