]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - backend/serial.c
Merge changes from CUPS 1.5.1-r9875.
[thirdparty/cups.git] / backend / serial.c
index 24533d5e1a50a0f2d68b1a5d0b51ed7232d90c1c..def68cb85ad4d0a22e4cb5c0a058e9add4e4ab7d 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id$"
+ * "$Id: serial.c 7647 2008-06-16 17:39:40Z mike $"
  *
- *   Serial port backend for the Common UNIX Printing System (CUPS).
+ *   Serial port backend for CUPS.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2011 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:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  *   This file is subject to the Apple OS-Developed Software exception.
  *
  *
  *   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/backend.h>
-#include <cups/cups.h>
+#include "backend-private.h"
 #include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <cups/string.h>
-#include <signal.h>
 
 #ifdef __hpux
 #  include <sys/modem.h>
@@ -97,7 +84,8 @@
  * Local functions...
  */
 
-void   list_devices(void);
+static void    list_devices(void);
+static int     side_cb(int print_fd, int device_fd, int use_bc);
 
 
 /*
@@ -117,25 +105,28 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
                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 */
+               *name,                  /* Name of option */
+               *value,                 /* Value of option */
+               sep;                    /* Option separator */
   int          port;                   /* Port number (not used) */
-  int          fp;                     /* Print file */
   int          copies;                 /* Number of copies to print */
-  int          fd;                     /* Parallel device */
-  int          rbytes;                 /* Number of bytes read */
-  int          wbytes;                 /* Number of bytes written */
-  size_t       nbytes,                 /* Number of bytes read */
-               tbytes;                 /* Total number of bytes written */
+  int          side_eof = 0,           /* Saw EOF on side-channel? */
+               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          bufsize;                /* Size of output buffer for writes */
-  char         buffer[8192],           /* Output buffer */
-               *bufptr;                /* Pointer into buffer */
+  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 */
-  fd_set       input,                  /* Input set for select() */
-               output;                 /* Output set for select() */
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction action;             /* Actions for POSIX signals */
 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
@@ -172,7 +163,9 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
   }
   else if (argc < 6 || argc > 7)
   {
-    fputs("Usage: serial job-id user title copies options [file]\n", stderr);
+    _cupsLangPrintf(stderr,
+                    _("Usage: %s job-id user title copies options [file]"),
+                   argv[0]);
     return (CUPS_BACKEND_FAILED);
   }
 
@@ -183,8 +176,8 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
 
   if (argc == 6)
   {
-    fp     = 0;
-    copies = 1;
+    print_fd = 0;
+    copies   = 1;
   }
   else
   {
@@ -192,9 +185,9 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
     * Try to open the print file...
     */
 
-    if ((fp = open(argv[6], O_RDONLY)) < 0)
+    if ((print_fd = open(argv[6], O_RDONLY)) < 0)
     {
-      perror("ERROR: unable to open print file");
+      _cupsLangPrintError("ERROR", _("Unable to open print file"));
       return (CUPS_BACKEND_FAILED);
     }
 
@@ -232,7 +225,8 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
 
   do
   {
-    if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL | O_NDELAY)) == -1)
+    if ((device_fd = open(resource, O_RDWR | O_NOCTTY | O_EXCL |
+                                    O_NDELAY)) == -1)
     {
       if (getenv("CLASS") != NULL)
       {
@@ -243,8 +237,9 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
        * available printer in the class.
        */
 
-        fputs("INFO: Unable to open serial port, queuing on next printer in class...\n",
-             stderr);
+        _cupsLangPrintFilter(stderr, "INFO",
+                            _("Unable to contact printer, queuing on next "
+                              "printer in class."));
 
        /*
         * Sleep 5 seconds to keep the job from requeuing too rapidly...
@@ -257,18 +252,18 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
 
       if (errno == EBUSY)
       {
-        fputs("INFO: Serial port busy; will retry in 30 seconds...\n", stderr);
+        _cupsLangPrintFilter(stderr, "INFO",
+                            _("Printer busy; will retry in 30 seconds."));
        sleep(30);
       }
       else
       {
-       fprintf(stderr, "ERROR: Unable to open serial port device file \"%s\": %s\n",
-               resource, strerror(errno));
+       _cupsLangPrintError("ERROR", _("Unable to open device file"));
        return (CUPS_BACKEND_FAILED);
       }
     }
   }
-  while (fd < 0);
+  while (device_fd < 0);
 
   fputs("STATE: -connecting-to-device\n", stderr);
 
@@ -276,57 +271,60 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
   * Set any options provided...
   */
 
-  tcgetattr(fd, &origopts);
-  tcgetattr(fd, &opts);
+  tcgetattr(device_fd, &origopts);
+  tcgetattr(device_fd, &opts);
 
-  opts.c_lflag &= ~(ICANON | ECHO | ISIG);     /* Raw mode */
-  opts.c_oflag &= ~OPOST;                      /* Don't post-process */
+  opts.c_lflag &= ~(ICANON | ECHO | ISIG);
+                                       /* Raw mode */
+  opts.c_oflag &= ~OPOST;              /* Don't post-process */
 
-  bufsize = 96;                /* 9600 baud / 10 bits/char / 10Hz */
-  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)
     {
      /*
       * Get the name...
       */
 
-      for (ptr = name; *options && *options != '=';)
-        if (ptr < (name + sizeof(name) - 1))
-          *ptr++ = *options++;
-      *ptr = '\0';
+      name = options;
+
+      while (*options && *options != '=' && *options != '+' && *options != '&')
+        options ++;
 
-      if (*options == '=')
+      if ((sep = *options) != '\0')
+        *options++ = '\0';
+
+      if (sep == '=')
       {
        /*
         * Get the value...
        */
 
-        options ++;
-
-       for (ptr = value; *options && *options != '+' && *options != '&';)
-          if (ptr < (value + sizeof(value) - 1))
-            *ptr++ = *options++;
-       *ptr = '\0';
+        value = options;
 
-       if (*options == '+' || *options == '&')
+       while (*options && *options != '+' && *options != '&')
          options ++;
+
+        if (*options)
+         *options++ = '\0';
       }
       else
-        value[0] = '\0';
+        value = (char *)"";
 
      /*
       * Process the option...
       */
 
-      if (!strcasecmp(name, "baud"))
+      if (!_cups_strcasecmp(name, "baud"))
       {
        /*
         * Set the baud rate...
        */
 
-        bufsize = atoi(value) / 100;
+        print_size = atoi(value) / 100;
 
 #if B19200 == 19200
         cfsetispeed(&opts, atoi(value));
@@ -377,12 +375,13 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
              break;
 #  endif /* B230400 */
           default :
-             fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value);
+             _cupsLangPrintFilter(stderr, "WARNING",
+                                  _("Unsupported baud rate: %s"), value);
              break;
        }
 #endif /* B19200 == 19200 */
       }
-      else if (!strcasecmp(name, "bits"))
+      else if (!_cups_strcasecmp(name, "bits"))
       {
        /*
         * Set number of data bits...
@@ -403,25 +402,25 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
              break;
        }
       }
-      else if (!strcasecmp(name, "parity"))
+      else if (!_cups_strcasecmp(name, "parity"))
       {
        /*
        * Set parity checking...
        */
 
-       if (!strcasecmp(value, "even"))
+       if (!_cups_strcasecmp(value, "even"))
        {
          opts.c_cflag |= PARENB;
           opts.c_cflag &= ~PARODD;
        }
-       else if (!strcasecmp(value, "odd"))
+       else if (!_cups_strcasecmp(value, "odd"))
        {
          opts.c_cflag |= PARENB;
           opts.c_cflag |= PARODD;
        }
-       else if (!strcasecmp(value, "none"))
+       else if (!_cups_strcasecmp(value, "none"))
          opts.c_cflag &= ~PARENB;
-       else if (!strcasecmp(value, "space"))
+       else if (!_cups_strcasecmp(value, "space"))
        {
         /*
          * Note: we only support space parity with 7 bits per character...
@@ -431,7 +430,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
           opts.c_cflag |= CS8;
          opts.c_cflag &= ~PARENB;
         }
-       else if (!strcasecmp(value, "mark"))
+       else if (!_cups_strcasecmp(value, "mark"))
        {
         /*
          * Note: we only support mark parity with 7 bits per character
@@ -444,29 +443,29 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
           opts.c_cflag |= CSTOPB;
         }
       }
-      else if (!strcasecmp(name, "flow"))
+      else if (!_cups_strcasecmp(name, "flow"))
       {
        /*
        * Set flow control...
        */
 
-       if (!strcasecmp(value, "none"))
+       if (!_cups_strcasecmp(value, "none"))
        {
          opts.c_iflag &= ~(IXON | IXOFF);
           opts.c_cflag &= ~CRTSCTS;
        }
-       else if (!strcasecmp(value, "soft"))
+       else if (!_cups_strcasecmp(value, "soft"))
        {
          opts.c_iflag |= IXON | IXOFF;
           opts.c_cflag &= ~CRTSCTS;
        }
-       else if (!strcasecmp(value, "hard") ||
-                !strcasecmp(value, "rtscts"))
+       else if (!_cups_strcasecmp(value, "hard") ||
+                !_cups_strcasecmp(value, "rtscts"))
         {
          opts.c_iflag &= ~(IXON | IXOFF);
           opts.c_cflag |= CRTSCTS;
        }
-       else if (!strcasecmp(value, "dtrdsr"))
+       else if (!_cups_strcasecmp(value, "dtrdsr"))
        {
          opts.c_iflag &= ~(IXON | IXOFF);
           opts.c_cflag &= ~CRTSCTS;
@@ -474,7 +473,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
          dtrdsr = 1;
        }
       }
-      else if (!strcasecmp(name, "stop"))
+      else if (!_cups_strcasecmp(name, "stop"))
       {
         switch (atoi(value))
        {
@@ -488,9 +487,10 @@ main(int  argc,                            /* I - Number of command-line arguments (6 or 7) */
        }
       }
     }
+  }
 
-  tcsetattr(fd, TCSANOW, &opts);
-  fcntl(fd, F_SETFL, 0);
+  tcsetattr(device_fd, TCSANOW, &opts);
+  fcntl(device_fd, F_SETFL, 0);
 
  /*
   * Now that we are "connected" to the port, ignore SIGTERM so that we
@@ -499,7 +499,7 @@ main(int  argc,                             /* I - Number of command-line arguments (6 or 7) */
   * stdin (otherwise you can't cancel raw jobs...)
   */
 
-  if (argc < 7)
+  if (!print_fd)
   {
 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
     sigset(SIGTERM, SIG_IGN);
@@ -515,133 +515,199 @@ main(int  argc,                         /* I - Number of command-line arguments (6 or 7) */
   }
 
  /*
-  * 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);
 
-  wbytes = 0;
+  total_bytes = 0;
 
   while (copies > 0)
   {
     copies --;
 
-    if (fp != 0)
+    if (print_fd != 0)
     {
       fputs("PAGE: 1 1\n", stderr);
-      lseek(fp, 0, SEEK_SET);
+      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...
       */
 
-      int status;
+      FD_ZERO(&input);
+      if (!print_bytes)
+       FD_SET(print_fd, &input);
+      FD_SET(device_fd, &input);
+      if (!print_bytes && !side_eof)
+        FD_SET(CUPS_SC_FD, &input);
 
+      FD_ZERO(&output);
+      if (print_bytes)
+       FD_SET(device_fd, &output);
 
-      if (!ioctl(fd, TIOCMGET, &status))
-        if (!(status & TIOCM_DSR))
-       {
-        /*
-         * Wait for DSR to go high...
-         */
-
-         fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
+      if (select(nfds, &input, &output, NULL, NULL) < 0)
+       continue;                       /* Ignore errors here */
 
-          do
-         {
-           sleep(1);
-           if (ioctl(fd, TIOCMGET, &status))
-             break;
-         }
-         while (!(status & TIOCM_DSR));
-
-         fputs("DEBUG: DSR is high; writing to device...\n", stderr);
-        }
-    }
-
-    tbytes = 0;
-    while ((nbytes = read(fp, buffer, bufsize)) > 0)
-    {
      /*
-      * Write the print data to the printer...
+      * Check if we have a side-channel request ready...
       */
 
-      tbytes += nbytes;
-      bufptr = buffer;
-
-      while (nbytes > 0)
+      if (FD_ISSET(CUPS_SC_FD, &input))
       {
        /*
-        * See if we are ready to read or write...
+       * Do the side-channel request, then start back over in the select
+       * loop since it may have read from print_fd...
        */
 
-        do
+        if (side_cb(print_fd, device_fd, 1))
+         side_eof = 1;
+       continue;
+      }
+
+     /*
+      * Check if we have back-channel data ready...
+      */
+
+      if (FD_ISSET(device_fd, &input))
+      {
+       if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
        {
-          FD_ZERO(&input);
-         FD_SET(fd, &input);
-         FD_ZERO(&output);
-         FD_SET(fd, &output);
-        }
-       while (select(fd + 1, &input, &output, NULL, NULL) < 0);
+         fprintf(stderr,
+                 "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
+                 CUPS_LLCAST bc_bytes);
+          cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
+       }
+      }
 
-        if (FD_ISSET(fd, &input))
+     /*
+      * Check if we have print data ready...
+      */
+
+      if (FD_ISSET(print_fd, &input))
+      {
+       if ((print_bytes = read(print_fd, print_buffer, print_size)) < 0)
        {
         /*
-         * Read backchannel data...
+          * Read error - bail if we don't see EAGAIN or EINTR...
          */
 
-         if ((rbytes = read(fd, resource, sizeof(resource))) > 0)
+         if (errno != EAGAIN || errno != EINTR)
          {
-           fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
-                   rbytes);
-            cupsBackChannelWrite(resource, rbytes, 1.0);
-          }
+           perror("DEBUG: Unable to read print data");
+
+            tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+           close(device_fd);
+
+           if (print_fd != 0)
+             close(print_fd);
+
+           return (CUPS_BACKEND_FAILED);
+         }
+
+          print_bytes = 0;
+       }
+       else if (print_bytes == 0)
+       {
+        /*
+          * End of file, break out of the loop...
+         */
+
+          break;
        }
 
-        if (FD_ISSET(fd, &output))
+       print_ptr = print_buffer;
+      }
+
+     /*
+      * Check if the device is ready to receive data and we have data to
+      * send...
+      */
+
+      if (print_bytes && FD_ISSET(device_fd, &output))
+      {
+       if (dtrdsr)
        {
         /*
-         * Write print data...
+         * Check the port and sleep until DSR is set...
          */
 
-         if ((wbytes = write(fd, bufptr, nbytes)) < 0)
-           if (errno == ENOTTY)
-             wbytes = write(fd, bufptr, nbytes);
+         int status;
 
-         if (wbytes < 0)
-         {
-          /*
-           * Check for retryable errors...
-           */
 
-           if (errno != EAGAIN && errno != EINTR)
+         if (!ioctl(device_fd, TIOCMGET, &status))
+            if (!(status & TIOCM_DSR))
            {
-             perror("ERROR: Unable to send print file to printer");
-             break;
-           }
-         }
-         else
+            /*
+             * 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)
+       {
+        /*
+          * Write error - bail if we don't see an error we can retry...
+         */
+
+         if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
          {
-          /*
-           * Update count and pointer...
-           */
+           perror("DEBUG: Unable to write print data");
+
+            tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+           close(device_fd);
+
+           if (print_fd != 0)
+             close(print_fd);
 
-           nbytes -= wbytes;
-           bufptr += wbytes;
+           return (CUPS_BACKEND_FAILED);
          }
        }
-      }
-
-      if (wbytes < 0)
-        break;
+       else
+       {
+          fprintf(stderr, "DEBUG: Wrote %d bytes...\n", (int)bytes);
 
-      if (argc > 6)
-       fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
-               (unsigned long)tbytes);
+          print_bytes -= bytes;
+         print_ptr   += bytes;
+         total_bytes += bytes;
+       }
+      }
     }
   }
 
@@ -649,13 +715,14 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
   * Close the serial port and input file and return...
   */
 
-  tcsetattr(fd, TCSADRAIN, &origopts);
+  tcsetattr(device_fd, TCSADRAIN, &origopts);
+
+  close(device_fd);
 
-  close(fd);
-  if (fp != 0)
-    close(fp);
+  if (print_fd != 0)
+    close(print_fd);
 
-  return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
+  return (CUPS_BACKEND_OK);
 }
 
 
@@ -663,19 +730,21 @@ main(int  argc,                           /* I - Number of command-line arguments (6 or 7) */
  * 'list_devices()' - List all serial devices.
  */
 
-void
+static void
 list_devices(void)
 {
-#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+#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__ */
+#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ || __FreeBSD_kernel__ */
+
 
 #ifdef __linux
   int                  i, j;           /* Looping vars */
   int                  fd;             /* File descriptor */
   char                 device[255];    /* Device filename */
+  char                 info[255];      /* Device info/description */
 #  ifdef TIOCGSERIAL
   struct serial_struct serinfo;        /* serial port info */
 #  endif /* TIOCGSERIAL */
@@ -710,24 +779,35 @@ list_devices(void)
 
       close(fd);
 
+      snprintf(info, sizeof(info),
+              _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
 #  if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
-      printf("serial serial:%s?baud=230400 \"Unknown\" \"Serial Port #%d\"\n",
-             device, i + 1);
+      printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
 #  else
-      printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
-             device, i + 1);
+      printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
 #  endif /* _ARCH_PPC || powerpc || __powerpc */
     }
   }
 
   for (i = 0; i < 16; i ++)
   {
+    snprintf(info, sizeof(info),
+            _cupsLangString(cupsLangDefault(), _("USB Serial Port #%d")),
+            i + 1);
+
     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);
+      printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
+    }
+
+    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\" \"%s\"\n", device, info);
     }
   }
 
@@ -739,9 +819,9 @@ list_devices(void)
       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);
+              "\"Equinox ESP %d Port #%d\"\n", device, i, j + 1);
       }
     }
   }
@@ -844,8 +924,9 @@ list_devices(void)
        }
       }
 #elif defined(__sun)
-  int          i, j, n;        /* Looping vars */
-  char         device[255];    /* Device filename */
+  int          i, j, n;                /* Looping vars */
+  char         device[255];            /* Device filename */
+  char         info[255];              /* Device info/description */
 
 
  /*
@@ -855,14 +936,17 @@ list_devices(void)
   for (i = 0; i < 26; i ++)
   {
     sprintf(device, "/dev/cua/%c", 'a' + i);
-    if (access(device, 0) == 0)
+    if (!access(device, 0))
+    {
+      snprintf(info, sizeof(info),
+              _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
 #  ifdef B115200
-      printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
-             device, i + 1);
+      printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
 #  else
-      printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
-             device, i + 1);
+      printf("serial serial:%s?baud=38400 \"Unknown\" \"%s\"\n", device, info);
 #  endif /* B115200 */
+    }
   }
 
  /*
@@ -958,10 +1042,11 @@ list_devices(void)
       printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
              device, i + 1);
   }
-#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
-  int  i, j;           /* Looping vars */
-  int  fd;             /* File descriptor */
-  char device[255];    /* Device filename */
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+  int  i, j;                           /* Looping vars */
+  int  fd;                             /* File descriptor */
+  char device[255];                    /* Device filename */
+  char info[255];                      /* Device info/description */
 
 
  /*
@@ -974,8 +1059,11 @@ list_devices(void)
     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
     {
       close(fd);
-      printf("serial serial:%s?baud=115200 \"Unknown\" \"Standard Serial Port #%d\"\n",
-             device, i + 1);
+
+      snprintf(info, sizeof(info),
+              _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+      printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
     }
   }
 
@@ -1049,9 +1137,10 @@ list_devices(void)
     }
   }
 #elif defined(__NetBSD__)
-  int  i, j;           /* Looping vars */
-  int  fd;             /* File descriptor */
-  char device[255];    /* Device filename */
+  int  i, j;                           /* Looping vars */
+  int  fd;                             /* File descriptor */
+  char device[255];                    /* Device filename */
+  char info[255];                      /* Device info/description */
 
 
  /*
@@ -1064,8 +1153,11 @@ list_devices(void)
     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
     {
       close(fd);
-      printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n",
-             device, i + 1);
+
+      snprintf(info, sizeof(info),
+              _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
+
+      printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
     }
   }
 
@@ -1118,38 +1210,51 @@ list_devices(void)
       {
        CFTypeRef       serialNameAsCFString;
        CFTypeRef       bsdPathAsCFString;
+       CFTypeRef       hiddenVal;
        char            serialName[128];
        char            bsdPath[1024];
        Boolean         result;
 
 
-       serialNameAsCFString =
-           IORegistryEntryCreateCFProperty(serialService,
-                                           CFSTR(kIOTTYDeviceKey),
-                                           kCFAllocatorDefault, 0);
-       if (serialNameAsCFString)
+       /* Check if hidden... */
+       hiddenVal = IORegistryEntrySearchCFProperty(serialService,
+                                                   kIOServicePlane,
+                                                   CFSTR("HiddenPort"),
+                                                   kCFAllocatorDefault,
+                                                   kIORegistryIterateRecursively |
+                                                   kIORegistryIterateParents);
+       if (hiddenVal)
+         CFRelease(hiddenVal); /* This interface should not be used */
+       else
        {
-         result = CFStringGetCString(serialNameAsCFString, serialName,
-                                     sizeof(serialName),
-                                     kCFStringEncodingASCII);
-         CFRelease(serialNameAsCFString);
-
-         if (result)
+         serialNameAsCFString =
+             IORegistryEntryCreateCFProperty(serialService,
+                                             CFSTR(kIOTTYDeviceKey),
+                                             kCFAllocatorDefault, 0);
+         if (serialNameAsCFString)
          {
-           bsdPathAsCFString =
-               IORegistryEntryCreateCFProperty(serialService,
-                                               CFSTR(kIOCalloutDeviceKey),
-                                               kCFAllocatorDefault, 0);
-           if (bsdPathAsCFString)
+           result = CFStringGetCString(serialNameAsCFString, serialName,
+                                       sizeof(serialName),
+                                       kCFStringEncodingASCII);
+           CFRelease(serialNameAsCFString);
+
+           if (result)
            {
-             result = CFStringGetCString(bsdPathAsCFString, bsdPath,
-                                         sizeof(bsdPath),
-                                         kCFStringEncodingASCII);
-             CFRelease(bsdPathAsCFString);
-
-             if (result)
-               printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n",
-                      bsdPath, serialName);
+             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);
+             }
            }
          }
        }
@@ -1169,5 +1274,54 @@ list_devices(void)
 
 
 /*
- * End of "$Id$".
+ * 'side_cb()' - Handle side-channel requests...
+ */
+
+static int                             /* O - 0 on success, -1 on error */
+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))
+    return (-1);
+
+  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 :
+       status  = CUPS_SC_STATUS_OK;
+        data[0] = use_bc;
+        datalen = 1;
+        break;
+
+    default :
+        status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+       datalen = 0;
+       break;
+  }
+
+  return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
+}
+
+
+/*
+ * End of "$Id: serial.c 7647 2008-06-16 17:39:40Z mike $".
  */