/*
- * "$Id: serial.c,v 1.33 2001/06/06 16:47:53 mike Exp $"
+ * "$Id$"
*
* Serial port backend for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2001 by Easy Software Products, all rights reserved.
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
* "LICENSE" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636-3111 USA
- *
- * Voice: (301) 373-9603
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * This file is subject to the Apple OS-Developed Software exception.
*
* Contents:
*
* main() - Send a file to the printer or server.
* list_devices() - List all serial devices.
+ * side_cb() - Handle side-channel requests...
*/
/*
* Include necessary headers.
*/
-#include <cups/cups.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <cups/string.h>
-#include <signal.h>
+#include "backend-private.h"
#ifdef __hpux
# include <sys/modem.h>
#endif /* __hpux */
-#if defined(WIN32) || defined(__EMX__)
+#ifdef WIN32
# include <io.h>
#else
# include <unistd.h>
# include <fcntl.h>
# include <termios.h>
+# ifdef __hpux
+# include <sys/time.h>
+# else
+# include <sys/select.h>
+# endif /* __hpux */
# ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
# endif /* HAVE_SYS_IOCTL_H */
-#endif /* WIN32 || __EMX__ */
+#endif /* WIN32 */
#ifdef __sgi
# include <invent.h>
# endif /* CNEW_RTSCTS */
#endif /* !CRTSCTS */
+#if defined(__APPLE__)
+# include <CoreFoundation/CoreFoundation.h>
+# include <IOKit/IOKitLib.h>
+# include <IOKit/serial/IOSerialKeys.h>
+# include <IOKit/IOBSD.h>
+#endif /* __APPLE__ */
+
+#if defined(__linux) && defined(TIOCGSERIAL)
+# include <linux/serial.h>
+# include <linux/ioctl.h>
+#endif /* __linux && TIOCGSERIAL */
+
/*
* Local functions...
*/
-void list_devices(void);
+static void list_devices(void);
+static void side_cb(int print_fd, int device_fd, int use_bc);
/*
* printer-uri job-id user title copies options [file]
*/
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments (6 or 7) */
- char *argv[]) /* I - Command-line arguments */
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[]) /* I - Command-line arguments */
{
- char method[255], /* Method in URI */
- hostname[1024], /* Hostname */
- username[255], /* Username info (not used) */
- resource[1024], /* Resource info (device and options) */
- *options, /* Pointer to options */
- name[255], /* Name of option */
- value[255], /* Value of option */
- *ptr; /* Pointer into name or value */
- int port; /* Port number (not used) */
- FILE *fp; /* Print file */
- int copies; /* Number of copies to print */
- int fd; /* Parallel device */
- int wbytes; /* Number of bytes written */
- size_t nbytes, /* Number of bytes read */
- tbytes; /* Total number of bytes written */
- int dtrdsr; /* Do dtr/dsr flow control? */
- int bufsize; /* Size of output buffer for writes */
- char buffer[8192], /* Output buffer */
- *bufptr; /* Pointer into buffer */
- struct termios opts; /* Parallel port options */
+ char method[255], /* Method in URI */
+ hostname[1024], /* Hostname */
+ username[255], /* Username info (not used) */
+ resource[1024], /* Resource info (device and options) */
+ *options, /* Pointer to options */
+ name[255], /* Name of option */
+ value[255], /* Value of option */
+ *ptr; /* Pointer into name or value */
+ int port; /* Port number (not used) */
+ int copies; /* Number of copies to print */
+ int print_fd, /* Print file */
+ device_fd; /* Serial device */
+ int nfds; /* Maximum file descriptor value + 1 */
+ fd_set input, /* Input set for reading */
+ output; /* Output set for writing */
+ ssize_t print_bytes, /* Print bytes read */
+ bc_bytes, /* Backchannel bytes read */
+ total_bytes, /* Total bytes written */
+ bytes; /* Bytes written */
+ int dtrdsr; /* Do dtr/dsr flow control? */
+ int print_size; /* Size of output buffer for writes */
+ char print_buffer[8192], /* Print data buffer */
+ *print_ptr, /* Pointer into print data buffer */
+ bc_buffer[1024]; /* Back-channel data buffer */
+ struct termios opts; /* Serial port options */
+ struct termios origopts; /* Original port options */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
- struct sigaction action; /* Actions for POSIX signals */
+ struct sigaction action; /* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
setbuf(stderr, NULL);
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
/*
* Check command-line...
*/
if (argc == 1)
{
list_devices();
- return (0);
+ return (CUPS_BACKEND_OK);
}
else if (argc < 6 || argc > 7)
{
- fputs("Usage: serial job-id user title copies options [file]\n", stderr);
- return (1);
+ _cupsLangPrintf(stderr,
+ _("Usage: %s job-id user title copies options [file]\n"),
+ argv[0]);
+ return (CUPS_BACKEND_FAILED);
}
/*
if (argc == 6)
{
- fp = stdin;
- copies = 1;
+ print_fd = 0;
+ copies = 1;
}
else
{
* Try to open the print file...
*/
- if ((fp = fopen(argv[6], "rb")) == NULL)
+ if ((print_fd = open(argv[6], O_RDONLY)) < 0)
{
perror("ERROR: unable to open print file");
- return (1);
+ return (CUPS_BACKEND_FAILED);
}
copies = atoi(argv[4]);
* Extract the device name and options from the URI...
*/
- httpSeparate(argv[0], method, username, hostname, &port, resource);
+ httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
+ method, sizeof(method), username, sizeof(username),
+ hostname, sizeof(hostname), &port,
+ resource, sizeof(resource));
/*
* See if there are any options...
* Open the serial port device...
*/
+ fputs("STATE: +connecting-to-device\n", stderr);
+
do
{
- if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
+ if ((device_fd = open(resource, O_RDWR | O_NOCTTY | O_EXCL |
+ O_NDELAY)) == -1)
{
+ if (getenv("CLASS") != NULL)
+ {
+ /*
+ * If the CLASS environment variable is set, the job was submitted
+ * to a class and not to a specific queue. In this case, we want
+ * to abort immediately so that the job can be requeued on the next
+ * available printer in the class.
+ */
+
+ _cupsLangPuts(stderr,
+ _("INFO: Unable to contact printer, queuing on next "
+ "printer in class...\n"));
+
+ /*
+ * Sleep 5 seconds to keep the job from requeuing too rapidly...
+ */
+
+ sleep(5);
+
+ return (CUPS_BACKEND_FAILED);
+ }
+
if (errno == EBUSY)
{
- fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
+ _cupsLangPuts(stderr,
+ _("INFO: Printer busy; will retry in 30 seconds...\n"));
sleep(30);
}
else
{
- perror("ERROR: Unable to open serial port device file");
- return (1);
+ _cupsLangPrintf(stderr,
+ _("ERROR: Unable to open device file \"%s\": %s\n"),
+ resource, strerror(errno));
+ return (CUPS_BACKEND_FAILED);
}
}
}
- while (fd < 0);
+ while (device_fd < 0);
+
+ fputs("STATE: -connecting-to-device\n", stderr);
/*
* Set any options provided...
*/
- tcgetattr(fd, &opts);
+ tcgetattr(device_fd, &origopts);
+ tcgetattr(device_fd, &opts);
- opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+ opts.c_lflag &= ~(ICANON | ECHO | ISIG);
+ /* Raw mode */
+ opts.c_oflag &= ~OPOST; /* Don't post-process */
- bufsize = 480; /* 9600 baud / 10 bits/char / 2Hz */
- dtrdsr = 0; /* No dtr/dsr flow control */
+ print_size = 96; /* 9600 baud / 10 bits/char / 10Hz */
+ dtrdsr = 0; /* No dtr/dsr flow control */
- if (options != NULL)
+ if (options)
+ {
while (*options)
{
/*
*/
for (ptr = name; *options && *options != '=';)
- *ptr++ = *options++;
+ if (ptr < (name + sizeof(name) - 1))
+ *ptr++ = *options++;
*ptr = '\0';
if (*options == '=')
options ++;
- for (ptr = value; *options && *options != '+';)
- *ptr++ = *options++;
+ for (ptr = value; *options && *options != '+' && *options != '&';)
+ if (ptr < (value + sizeof(value) - 1))
+ *ptr++ = *options++;
*ptr = '\0';
- if (*options == '+')
+ if (*options == '+' || *options == '&')
options ++;
}
else
* Process the option...
*/
- if (strcasecmp(name, "baud") == 0)
+ if (!strcasecmp(name, "baud"))
{
/*
* Set the baud rate...
*/
- bufsize = atoi(value) / 20;
+ print_size = atoi(value) / 100;
#if B19200 == 19200
cfsetispeed(&opts, atoi(value));
cfsetispeed(&opts, B38400);
cfsetospeed(&opts, B38400);
break;
-#ifdef B57600
+# ifdef B57600
case 57600 :
cfsetispeed(&opts, B57600);
cfsetospeed(&opts, B57600);
break;
-#endif /* B57600 */
-#ifdef B115200
+# endif /* B57600 */
+# ifdef B115200
case 115200 :
cfsetispeed(&opts, B115200);
cfsetospeed(&opts, B115200);
break;
-#endif /* B115200 */
+# endif /* B115200 */
+# ifdef B230400
+ case 230400 :
+ cfsetispeed(&opts, B230400);
+ cfsetospeed(&opts, B230400);
+ break;
+# endif /* B230400 */
default :
- fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value);
+ _cupsLangPrintf(stderr, _("WARNING: Unsupported baud rate %s!\n"),
+ value);
break;
}
#endif /* B19200 == 19200 */
}
- else if (strcasecmp(name, "bits") == 0)
+ else if (!strcasecmp(name, "bits"))
{
/*
* Set number of data bits...
break;
}
}
- else if (strcasecmp(name, "parity") == 0)
+ else if (!strcasecmp(name, "parity"))
{
/*
* Set parity checking...
*/
- if (strcasecmp(value, "even") == 0)
+ if (!strcasecmp(value, "even"))
{
opts.c_cflag |= PARENB;
opts.c_cflag &= ~PARODD;
}
- else if (strcasecmp(value, "odd") == 0)
+ else if (!strcasecmp(value, "odd"))
{
opts.c_cflag |= PARENB;
opts.c_cflag |= PARODD;
}
- else if (strcasecmp(value, "none") == 0)
+ else if (!strcasecmp(value, "none"))
+ opts.c_cflag &= ~PARENB;
+ else if (!strcasecmp(value, "space"))
+ {
+ /*
+ * Note: we only support space parity with 7 bits per character...
+ */
+
+ opts.c_cflag &= ~CSIZE;
+ opts.c_cflag |= CS8;
+ opts.c_cflag &= ~PARENB;
+ }
+ else if (!strcasecmp(value, "mark"))
+ {
+ /*
+ * Note: we only support mark parity with 7 bits per character
+ * and 1 stop bit...
+ */
+
+ opts.c_cflag &= ~CSIZE;
+ opts.c_cflag |= CS7;
opts.c_cflag &= ~PARENB;
+ opts.c_cflag |= CSTOPB;
+ }
}
- else if (strcasecmp(name, "flow") == 0)
+ else if (!strcasecmp(name, "flow"))
{
/*
* Set flow control...
*/
- if (strcasecmp(value, "none") == 0)
+ if (!strcasecmp(value, "none"))
{
- opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_iflag &= ~(IXON | IXOFF);
opts.c_cflag &= ~CRTSCTS;
}
- else if (strcasecmp(value, "soft") == 0)
+ else if (!strcasecmp(value, "soft"))
{
- opts.c_iflag |= IXON | IXOFF | IXANY;
+ opts.c_iflag |= IXON | IXOFF;
opts.c_cflag &= ~CRTSCTS;
}
- else if (strcasecmp(value, "hard") == 0 ||
- strcasecmp(value, "rtscts") == 0)
+ else if (!strcasecmp(value, "hard") ||
+ !strcasecmp(value, "rtscts"))
{
- opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_iflag &= ~(IXON | IXOFF);
opts.c_cflag |= CRTSCTS;
}
- else if (strcasecmp(value, "dtrdsr") == 0)
+ else if (!strcasecmp(value, "dtrdsr"))
{
- opts.c_iflag &= ~(IXON | IXOFF | IXANY);
+ opts.c_iflag &= ~(IXON | IXOFF);
opts.c_cflag &= ~CRTSCTS;
dtrdsr = 1;
}
}
+ else if (!strcasecmp(name, "stop"))
+ {
+ switch (atoi(value))
+ {
+ case 1 :
+ opts.c_cflag &= ~CSTOPB;
+ break;
+
+ case 2 :
+ opts.c_cflag |= CSTOPB;
+ break;
+ }
+ }
}
+ }
- tcsetattr(fd, TCSANOW, &opts);
+ tcsetattr(device_fd, TCSANOW, &opts);
+ fcntl(device_fd, F_SETFL, 0);
/*
* Now that we are "connected" to the port, ignore SIGTERM so that we
* stdin (otherwise you can't cancel raw jobs...)
*/
- if (argc < 7)
+ if (print_fd != 0)
{
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
sigset(SIGTERM, SIG_IGN);
}
/*
- * Finally, send the print file...
+ * Figure out the maximum file descriptor value to use with select()...
+ */
+
+ nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
+
+ /*
+ * Finally, send the print file. Ordinarily we would just use the
+ * backendRunLoop() function, however since we need to use smaller
+ * writes and may need to do DSR/DTR flow control, we duplicate much
+ * of the code here instead...
*/
- if (bufsize > sizeof(buffer))
- bufsize = sizeof(buffer);
+ if (print_size > sizeof(print_buffer))
+ print_size = sizeof(print_buffer);
+
+ total_bytes = 0;
while (copies > 0)
{
copies --;
- if (fp != stdin)
+ if (print_fd != 0)
{
fputs("PAGE: 1 1\n", stderr);
- rewind(fp);
+ lseek(print_fd, 0, SEEK_SET);
}
- if (dtrdsr)
+ /*
+ * Now loop until we are out of data from print_fd...
+ */
+
+ for (print_bytes = 0, print_ptr = print_buffer;;)
{
/*
- * Check the port and sleep until DSR is set...
+ * Use select() to determine whether we have data to copy around...
+ */
+
+ FD_ZERO(&input);
+ if (!print_bytes)
+ FD_SET(print_fd, &input);
+ FD_SET(device_fd, &input);
+ FD_SET(CUPS_SC_FD, &input);
+
+ FD_ZERO(&output);
+ if (print_bytes)
+ FD_SET(device_fd, &output);
+
+ if (select(nfds, &input, &output, NULL, NULL) < 0)
+ continue; /* Ignore errors here */
+
+ /*
+ * Check if we have a side-channel request ready...
*/
- int status;
+ if (FD_ISSET(CUPS_SC_FD, &input))
+ side_cb(print_fd, device_fd, 1);
+ /*
+ * Check if we have back-channel data ready...
+ */
- if (!ioctl(fd, TIOCMGET, &status))
- if (!(status & TIOCM_DSR))
+ if (FD_ISSET(device_fd, &input))
+ {
+ if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
+ {
+ fprintf(stderr,
+ "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data!\n",
+ CUPS_LLCAST bc_bytes);
+ cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
+ }
+ }
+
+ /*
+ * Check if we have print data ready...
+ */
+
+ if (FD_ISSET(print_fd, &input))
+ {
+ if ((print_bytes = read(print_fd, print_buffer, print_size)) < 0)
{
/*
- * Wait for DSR to go high...
+ * Read error - bail if we don't see EAGAIN or EINTR...
*/
- fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
-
- do
+ if (errno != EAGAIN || errno != EINTR)
{
- sleep(1);
- if (ioctl(fd, TIOCMGET, &status))
- break;
+ perror("ERROR: Unable to read print data");
+
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_FAILED);
}
- while (!(status & TIOCM_DSR));
- fputs("DEBUG: DSR is high; writing to device...\n", stderr);
- }
- }
+ print_bytes = 0;
+ }
+ else if (print_bytes == 0)
+ {
+ /*
+ * End of file, break out of the loop...
+ */
+
+ break;
+ }
+
+ print_ptr = print_buffer;
+ }
- tbytes = 0;
- while ((nbytes = fread(buffer, 1, bufsize, fp)) > 0)
- {
/*
- * Write the print data to the printer...
+ * Check if the device is ready to receive data and we have data to
+ * send...
*/
- tbytes += nbytes;
- bufptr = buffer;
-
- while (nbytes > 0)
+ if (print_bytes && FD_ISSET(device_fd, &output))
{
- if ((wbytes = write(fd, bufptr, nbytes)) < 0)
- if (errno == ENOTTY)
- wbytes = write(fd, bufptr, nbytes);
+ if (dtrdsr)
+ {
+ /*
+ * Check the port and sleep until DSR is set...
+ */
- if (wbytes < 0)
+ int status;
+
+
+ if (!ioctl(device_fd, TIOCMGET, &status))
+ if (!(status & TIOCM_DSR))
+ {
+ /*
+ * Wait for DSR to go high...
+ */
+
+ fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
+
+ do
+ {
+ /*
+ * Poll every 100ms...
+ */
+
+ usleep(100000);
+
+ if (ioctl(device_fd, TIOCMGET, &status))
+ break;
+ }
+ while (!(status & TIOCM_DSR));
+
+ fputs("DEBUG: DSR is high; writing to device...\n", stderr);
+ }
+ }
+
+ if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
{
- perror("ERROR: Unable to send print file to printer");
- break;
+ /*
+ * Write error - bail if we don't see an error we can retry...
+ */
+
+ if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
+ {
+ perror("ERROR: Unable to write print data");
+
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
+
+ return (CUPS_BACKEND_FAILED);
+ }
}
+ else
+ {
+ fprintf(stderr, "DEBUG: Wrote %d bytes...\n", (int)bytes);
- nbytes -= wbytes;
- bufptr += wbytes;
+ print_bytes -= bytes;
+ print_ptr += bytes;
+ total_bytes += bytes;
+ }
}
-
- if (argc > 6)
- fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes);
}
}
/*
- * Close the socket connection and input file and return...
+ * Close the serial port and input file and return...
*/
- close(fd);
- if (fp != stdin)
- fclose(fp);
+ tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+ close(device_fd);
+
+ if (print_fd != 0)
+ close(print_fd);
- return (0);
+ return (total_bytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
}
* 'list_devices()' - List all serial devices.
*/
-void
+static void
list_devices(void)
{
-#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
- /* Funky hex numbering used for some devices */
-#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ */
+ /* Funky hex numbering used for some *
+ * devices */
+#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ || __FreeBSD_kernel__ */
#ifdef __linux
- int i; /* Looping var */
- int fd; /* File descriptor */
- char device[255]; /* Device filename */
+ int i, j; /* Looping vars */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+# ifdef TIOCGSERIAL
+ struct serial_struct serinfo; /* serial port info */
+# endif /* TIOCGSERIAL */
for (i = 0; i < 100; i ++)
{
sprintf(device, "/dev/ttyS%d", i);
+
if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
{
+# ifdef TIOCGSERIAL
+ /*
+ * See if this port exists...
+ */
+
+ serinfo.reserved_char[0] = 0;
+
+ if (!ioctl(fd, TIOCGSERIAL, &serinfo))
+ {
+ if (serinfo.type == PORT_UNKNOWN)
+ {
+ /*
+ * Nope...
+ */
+
+ close(fd);
+ continue;
+ }
+ }
+# endif /* TIOCGSERIAL */
+
close(fd);
+
+# if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"Serial Port #%d\"\n",
+ device, i + 1);
+# else
printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
device, i + 1);
+# endif /* _ARCH_PPC || powerpc || __powerpc */
+ }
+ }
+
+ for (i = 0; i < 16; i ++)
+ {
+ sprintf(device, "/dev/usb/ttyUSB%d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"USB Serial Port #%d\"\n",
+ device, i + 1);
+ }
+
+ sprintf(device, "/dev/ttyUSB%d", i);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=230400 \"Unknown\" \"USB Serial Port #%d\"\n",
+ device, i + 1);
+ }
+ }
+
+ for (i = 0; i < 64; i ++)
+ {
+ for (j = 0; j < 8; j ++)
+ {
+ sprintf(device, "/dev/ttyQ%02de%d", i, j);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=115200 \"Unknown\" "
+ "\"Equinox ESP %d Port #%d\"\n",
+ device, i, j + 1);
+ }
}
}
#elif defined(__sgi)
{
sprintf(device, "/dev/cua/%c", 'a' + i);
if (access(device, 0) == 0)
-#ifdef B115200
+# ifdef B115200
printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
device, i + 1);
-#else
+# else
printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
device, i + 1);
-#endif /* B115200 */
+# endif /* B115200 */
}
/*
printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
device, i + 1);
}
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
int i, j; /* Looping vars */
int fd; /* File descriptor */
char device[255]; /* Device filename */
printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n",
device, i, j + 1);
}
+
+ sprintf(device, "/dev/ttyC%d%c", i, funky_hex[j]);
+ if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
+ {
+ close(fd);
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n",
+ device, i, j + 1);
+ }
}
/*
device, i, j + 1);
}
}
+#elif defined(__APPLE__)
+ /*
+ * Standard serial ports on MacOS X...
+ */
+
+ kern_return_t kernResult;
+ mach_port_t masterPort;
+ io_iterator_t serialPortIterator;
+ CFMutableDictionaryRef classesToMatch;
+ io_object_t serialService;
+
+ kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
+ if (KERN_SUCCESS != kernResult)
+ return;
+
+ /*
+ * Serial devices are instances of class IOSerialBSDClient.
+ */
+
+ classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
+ if (classesToMatch != NULL)
+ {
+ CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
+ CFSTR(kIOSerialBSDRS232Type));
+
+ kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
+ &serialPortIterator);
+ if (kernResult == KERN_SUCCESS)
+ {
+ while ((serialService = IOIteratorNext(serialPortIterator)))
+ {
+ CFTypeRef serialNameAsCFString;
+ CFTypeRef bsdPathAsCFString;
+ char serialName[128];
+ char bsdPath[1024];
+ Boolean result;
+
+
+ serialNameAsCFString =
+ IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOTTYDeviceKey),
+ kCFAllocatorDefault, 0);
+ if (serialNameAsCFString)
+ {
+ result = CFStringGetCString(serialNameAsCFString, serialName,
+ sizeof(serialName),
+ kCFStringEncodingASCII);
+ CFRelease(serialNameAsCFString);
+
+ if (result)
+ {
+ bsdPathAsCFString =
+ IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOCalloutDeviceKey),
+ kCFAllocatorDefault, 0);
+ if (bsdPathAsCFString)
+ {
+ result = CFStringGetCString(bsdPathAsCFString, bsdPath,
+ sizeof(bsdPath),
+ kCFStringEncodingASCII);
+ CFRelease(bsdPathAsCFString);
+
+ if (result)
+ printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n",
+ bsdPath, serialName);
+ }
+ }
+ }
+
+ IOObjectRelease(serialService);
+ }
+
+ /*
+ * Release the iterator.
+ */
+
+ IOObjectRelease(serialPortIterator);
+ }
+ }
#endif
}
/*
- * End of "$Id: serial.c,v 1.33 2001/06/06 16:47:53 mike Exp $".
+ * 'side_cb()' - Handle side-channel requests...
+ */
+
+static void
+side_cb(int print_fd, /* I - Print file */
+ int device_fd, /* I - Device file */
+ int use_bc) /* I - Using back-channel? */
+{
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ {
+ _cupsLangPuts(stderr,
+ _("WARNING: Failed to read side-channel request!\n"));
+ return;
+ }
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ if (backendDrainOutput(print_fd, device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else if (tcdrain(device_fd))
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ data[0] = use_bc;
+ datalen = 1;
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ cupsSideChannelWrite(command, status, data, datalen, 1.0);
+}
+
+
+/*
+ * End of "$Id$".
*/