Revert manifest to default one
[external/cups.git] / backend / serial.c
1 /*
2  * "$Id: serial.c 9793 2011-05-20 03:49:49Z mike $"
3  *
4  *   Serial port backend for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   "LICENSE" which should have been included with this file.  If this
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   main()         - Send a file to the printer or server.
20  *   list_devices() - List all serial devices.
21  *   side_cb()      - Handle side-channel requests...
22  */
23
24 /*
25  * Include necessary headers.
26  */
27
28 #include "backend-private.h"
29 #include <stdio.h>
30
31 #ifdef __hpux
32 #  include <sys/modem.h>
33 #endif /* __hpux */
34
35 #ifdef WIN32
36 #  include <io.h>
37 #else
38 #  include <unistd.h>
39 #  include <fcntl.h>
40 #  include <termios.h>
41 #  ifdef __hpux
42 #    include <sys/time.h>
43 #  else
44 #    include <sys/select.h>
45 #  endif /* __hpux */
46 #  ifdef HAVE_SYS_IOCTL_H
47 #    include <sys/ioctl.h>
48 #  endif /* HAVE_SYS_IOCTL_H */
49 #endif /* WIN32 */
50
51 #ifdef __sgi
52 #  include <invent.h>
53 #  ifndef INV_EPP_ECP_PLP
54 #    define INV_EPP_ECP_PLP     6       /* From 6.3/6.4/6.5 sys/invent.h */
55 #    define INV_ASO_SERIAL      14      /* serial portion of SGI ASO board */
56 #    define INV_IOC3_DMA        16      /* DMA mode IOC3 serial */
57 #    define INV_IOC3_PIO        17      /* PIO mode IOC3 serial */
58 #    define INV_ISA_DMA         19      /* DMA mode ISA serial -- O2 */
59 #  endif /* !INV_EPP_ECP_PLP */
60 #endif /* __sgi */
61
62 #ifndef CRTSCTS
63 #  ifdef CNEW_RTSCTS
64 #    define CRTSCTS CNEW_RTSCTS
65 #  else
66 #    define CRTSCTS 0
67 #  endif /* CNEW_RTSCTS */
68 #endif /* !CRTSCTS */
69
70 #if defined(__APPLE__)
71 #  include <CoreFoundation/CoreFoundation.h>
72 #  include <IOKit/IOKitLib.h>
73 #  include <IOKit/serial/IOSerialKeys.h>
74 #  include <IOKit/IOBSD.h>
75 #endif /* __APPLE__ */
76
77 #if defined(__linux) && defined(TIOCGSERIAL)
78 #  include <linux/serial.h>
79 #  include <linux/ioctl.h>
80 #endif /* __linux && TIOCGSERIAL */
81
82
83 /*
84  * Local functions...
85  */
86
87 static void     list_devices(void);
88 static int      side_cb(int print_fd, int device_fd, int use_bc);
89
90
91 /*
92  * 'main()' - Send a file to the printer or server.
93  *
94  * Usage:
95  *
96  *    printer-uri job-id user title copies options [file]
97  */
98
99 int                                     /* O - Exit status */
100 main(int  argc,                         /* I - Number of command-line arguments (6 or 7) */
101      char *argv[])                      /* I - Command-line arguments */
102 {
103   char          method[255],            /* Method in URI */
104                 hostname[1024],         /* Hostname */
105                 username[255],          /* Username info (not used) */
106                 resource[1024],         /* Resource info (device and options) */
107                 *options,               /* Pointer to options */
108                 *name,                  /* Name of option */
109                 *value,                 /* Value of option */
110                 sep;                    /* Option separator */
111   int           port;                   /* Port number (not used) */
112   int           copies;                 /* Number of copies to print */
113   int           side_eof = 0,           /* Saw EOF on side-channel? */
114                 print_fd,               /* Print file */
115                 device_fd;              /* Serial device */
116   int           nfds;                   /* Maximum file descriptor value + 1 */
117   fd_set        input,                  /* Input set for reading */
118                 output;                 /* Output set for writing */
119   ssize_t       print_bytes,            /* Print bytes read */
120                 bc_bytes,               /* Backchannel bytes read */
121                 total_bytes,            /* Total bytes written */
122                 bytes;                  /* Bytes written */
123   int           dtrdsr;                 /* Do dtr/dsr flow control? */
124   int           print_size;             /* Size of output buffer for writes */
125   char          print_buffer[8192],     /* Print data buffer */
126                 *print_ptr,             /* Pointer into print data buffer */
127                 bc_buffer[1024];        /* Back-channel data buffer */
128   struct termios opts;                  /* Serial port options */
129   struct termios origopts;              /* Original port options */
130 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
131   struct sigaction action;              /* Actions for POSIX signals */
132 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
133
134
135  /*
136   * Make sure status messages are not buffered...
137   */
138
139   setbuf(stderr, NULL);
140
141  /*
142   * Ignore SIGPIPE signals...
143   */
144
145 #ifdef HAVE_SIGSET
146   sigset(SIGPIPE, SIG_IGN);
147 #elif defined(HAVE_SIGACTION)
148   memset(&action, 0, sizeof(action));
149   action.sa_handler = SIG_IGN;
150   sigaction(SIGPIPE, &action, NULL);
151 #else
152   signal(SIGPIPE, SIG_IGN);
153 #endif /* HAVE_SIGSET */
154
155  /*
156   * Check command-line...
157   */
158
159   if (argc == 1)
160   {
161     list_devices();
162     return (CUPS_BACKEND_OK);
163   }
164   else if (argc < 6 || argc > 7)
165   {
166     _cupsLangPrintf(stderr,
167                     _("Usage: %s job-id user title copies options [file]"),
168                     argv[0]);
169     return (CUPS_BACKEND_FAILED);
170   }
171
172  /*
173   * If we have 7 arguments, print the file named on the command-line.
174   * Otherwise, send stdin instead...
175   */
176
177   if (argc == 6)
178   {
179     print_fd = 0;
180     copies   = 1;
181   }
182   else
183   {
184    /*
185     * Try to open the print file...
186     */
187
188     if ((print_fd = open(argv[6], O_RDONLY)) < 0)
189     {
190       _cupsLangPrintError("ERROR", _("Unable to open print file"));
191       return (CUPS_BACKEND_FAILED);
192     }
193
194     copies = atoi(argv[4]);
195   }
196
197  /*
198   * Extract the device name and options from the URI...
199   */
200
201   httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
202                   method, sizeof(method), username, sizeof(username),
203                   hostname, sizeof(hostname), &port,
204                   resource, sizeof(resource));
205
206  /*
207   * See if there are any options...
208   */
209
210   if ((options = strchr(resource, '?')) != NULL)
211   {
212    /*
213     * Yup, terminate the device name string and move to the first
214     * character of the options...
215     */
216
217     *options++ = '\0';
218   }
219
220  /*
221   * Open the serial port device...
222   */
223
224   fputs("STATE: +connecting-to-device\n", stderr);
225
226   do
227   {
228     if ((device_fd = open(resource, O_RDWR | O_NOCTTY | O_EXCL |
229                                     O_NDELAY)) == -1)
230     {
231       if (getenv("CLASS") != NULL)
232       {
233        /*
234         * If the CLASS environment variable is set, the job was submitted
235         * to a class and not to a specific queue.  In this case, we want
236         * to abort immediately so that the job can be requeued on the next
237         * available printer in the class.
238         */
239
240         _cupsLangPrintFilter(stderr, "INFO",
241                              _("Unable to contact printer, queuing on next "
242                                "printer in class."));
243
244        /*
245         * Sleep 5 seconds to keep the job from requeuing too rapidly...
246         */
247
248         sleep(5);
249
250         return (CUPS_BACKEND_FAILED);
251       }
252
253       if (errno == EBUSY)
254       {
255         _cupsLangPrintFilter(stderr, "INFO",
256                              _("Printer busy; will retry in 30 seconds."));
257         sleep(30);
258       }
259       else
260       {
261         _cupsLangPrintError("ERROR", _("Unable to open device file"));
262         return (CUPS_BACKEND_FAILED);
263       }
264     }
265   }
266   while (device_fd < 0);
267
268   fputs("STATE: -connecting-to-device\n", stderr);
269
270  /*
271   * Set any options provided...
272   */
273
274   tcgetattr(device_fd, &origopts);
275   tcgetattr(device_fd, &opts);
276
277   opts.c_lflag &= ~(ICANON | ECHO | ISIG);
278                                         /* Raw mode */
279   opts.c_oflag &= ~OPOST;               /* Don't post-process */
280
281   print_size = 96;                      /* 9600 baud / 10 bits/char / 10Hz */
282   dtrdsr     = 0;                       /* No dtr/dsr flow control */
283
284   if (options)
285   {
286     while (*options)
287     {
288      /*
289       * Get the name...
290       */
291
292       name = options;
293
294       while (*options && *options != '=' && *options != '+' && *options != '&')
295         options ++;
296
297       if ((sep = *options) != '\0')
298         *options++ = '\0';
299
300       if (sep == '=')
301       {
302        /*
303         * Get the value...
304         */
305
306         value = options;
307
308         while (*options && *options != '+' && *options != '&')
309           options ++;
310
311         if (*options)
312           *options++ = '\0';
313       }
314       else
315         value = (char *)"";
316
317      /*
318       * Process the option...
319       */
320
321       if (!_cups_strcasecmp(name, "baud"))
322       {
323        /*
324         * Set the baud rate...
325         */
326
327         print_size = atoi(value) / 100;
328
329 #if B19200 == 19200
330         cfsetispeed(&opts, atoi(value));
331         cfsetospeed(&opts, atoi(value));
332 #else
333         switch (atoi(value))
334         {
335           case 1200 :
336               cfsetispeed(&opts, B1200);
337               cfsetospeed(&opts, B1200);
338               break;
339           case 2400 :
340               cfsetispeed(&opts, B2400);
341               cfsetospeed(&opts, B2400);
342               break;
343           case 4800 :
344               cfsetispeed(&opts, B4800);
345               cfsetospeed(&opts, B4800);
346               break;
347           case 9600 :
348               cfsetispeed(&opts, B9600);
349               cfsetospeed(&opts, B9600);
350               break;
351           case 19200 :
352               cfsetispeed(&opts, B19200);
353               cfsetospeed(&opts, B19200);
354               break;
355           case 38400 :
356               cfsetispeed(&opts, B38400);
357               cfsetospeed(&opts, B38400);
358               break;
359 #  ifdef B57600
360           case 57600 :
361               cfsetispeed(&opts, B57600);
362               cfsetospeed(&opts, B57600);
363               break;
364 #  endif /* B57600 */
365 #  ifdef B115200
366           case 115200 :
367               cfsetispeed(&opts, B115200);
368               cfsetospeed(&opts, B115200);
369               break;
370 #  endif /* B115200 */
371 #  ifdef B230400
372           case 230400 :
373               cfsetispeed(&opts, B230400);
374               cfsetospeed(&opts, B230400);
375               break;
376 #  endif /* B230400 */
377           default :
378               _cupsLangPrintFilter(stderr, "WARNING",
379                                    _("Unsupported baud rate: %s"), value);
380               break;
381         }
382 #endif /* B19200 == 19200 */
383       }
384       else if (!_cups_strcasecmp(name, "bits"))
385       {
386        /*
387         * Set number of data bits...
388         */
389
390         switch (atoi(value))
391         {
392           case 7 :
393               opts.c_cflag &= ~CSIZE;
394               opts.c_cflag |= CS7;
395               opts.c_cflag |= PARENB;
396               opts.c_cflag &= ~PARODD;
397               break;
398           case 8 :
399               opts.c_cflag &= ~CSIZE;
400               opts.c_cflag |= CS8;
401               opts.c_cflag &= ~PARENB;
402               break;
403         }
404       }
405       else if (!_cups_strcasecmp(name, "parity"))
406       {
407        /*
408         * Set parity checking...
409         */
410
411         if (!_cups_strcasecmp(value, "even"))
412         {
413           opts.c_cflag |= PARENB;
414           opts.c_cflag &= ~PARODD;
415         }
416         else if (!_cups_strcasecmp(value, "odd"))
417         {
418           opts.c_cflag |= PARENB;
419           opts.c_cflag |= PARODD;
420         }
421         else if (!_cups_strcasecmp(value, "none"))
422           opts.c_cflag &= ~PARENB;
423         else if (!_cups_strcasecmp(value, "space"))
424         {
425          /*
426           * Note: we only support space parity with 7 bits per character...
427           */
428
429           opts.c_cflag &= ~CSIZE;
430           opts.c_cflag |= CS8;
431           opts.c_cflag &= ~PARENB;
432         }
433         else if (!_cups_strcasecmp(value, "mark"))
434         {
435          /*
436           * Note: we only support mark parity with 7 bits per character
437           * and 1 stop bit...
438           */
439
440           opts.c_cflag &= ~CSIZE;
441           opts.c_cflag |= CS7;
442           opts.c_cflag &= ~PARENB;
443           opts.c_cflag |= CSTOPB;
444         }
445       }
446       else if (!_cups_strcasecmp(name, "flow"))
447       {
448        /*
449         * Set flow control...
450         */
451
452         if (!_cups_strcasecmp(value, "none"))
453         {
454           opts.c_iflag &= ~(IXON | IXOFF);
455           opts.c_cflag &= ~CRTSCTS;
456         }
457         else if (!_cups_strcasecmp(value, "soft"))
458         {
459           opts.c_iflag |= IXON | IXOFF;
460           opts.c_cflag &= ~CRTSCTS;
461         }
462         else if (!_cups_strcasecmp(value, "hard") ||
463                  !_cups_strcasecmp(value, "rtscts"))
464         {
465           opts.c_iflag &= ~(IXON | IXOFF);
466           opts.c_cflag |= CRTSCTS;
467         }
468         else if (!_cups_strcasecmp(value, "dtrdsr"))
469         {
470           opts.c_iflag &= ~(IXON | IXOFF);
471           opts.c_cflag &= ~CRTSCTS;
472
473           dtrdsr = 1;
474         }
475       }
476       else if (!_cups_strcasecmp(name, "stop"))
477       {
478         switch (atoi(value))
479         {
480           case 1 :
481               opts.c_cflag &= ~CSTOPB;
482               break;
483
484           case 2 :
485               opts.c_cflag |= CSTOPB;
486               break;
487         }
488       }
489     }
490   }
491
492   tcsetattr(device_fd, TCSANOW, &opts);
493   fcntl(device_fd, F_SETFL, 0);
494
495  /*
496   * Now that we are "connected" to the port, ignore SIGTERM so that we
497   * can finish out any page data the driver sends (e.g. to eject the
498   * current page...  Only ignore SIGTERM if we are printing data from
499   * stdin (otherwise you can't cancel raw jobs...)
500   */
501
502   if (!print_fd)
503   {
504 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
505     sigset(SIGTERM, SIG_IGN);
506 #elif defined(HAVE_SIGACTION)
507     memset(&action, 0, sizeof(action));
508
509     sigemptyset(&action.sa_mask);
510     action.sa_handler = SIG_IGN;
511     sigaction(SIGTERM, &action, NULL);
512 #else
513     signal(SIGTERM, SIG_IGN);
514 #endif /* HAVE_SIGSET */
515   }
516
517  /*
518   * Figure out the maximum file descriptor value to use with select()...
519   */
520
521   nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
522
523  /*
524   * Finally, send the print file.  Ordinarily we would just use the
525   * backendRunLoop() function, however since we need to use smaller
526   * writes and may need to do DSR/DTR flow control, we duplicate much
527   * of the code here instead...
528   */
529
530   if (print_size > sizeof(print_buffer))
531     print_size = sizeof(print_buffer);
532
533   total_bytes = 0;
534
535   while (copies > 0)
536   {
537     copies --;
538
539     if (print_fd != 0)
540     {
541       fputs("PAGE: 1 1\n", stderr);
542       lseek(print_fd, 0, SEEK_SET);
543     }
544
545    /*
546     * Now loop until we are out of data from print_fd...
547     */
548
549     for (print_bytes = 0, print_ptr = print_buffer;;)
550     {
551      /*
552       * Use select() to determine whether we have data to copy around...
553       */
554
555       FD_ZERO(&input);
556       if (!print_bytes)
557         FD_SET(print_fd, &input);
558       FD_SET(device_fd, &input);
559       if (!print_bytes && !side_eof)
560         FD_SET(CUPS_SC_FD, &input);
561
562       FD_ZERO(&output);
563       if (print_bytes)
564         FD_SET(device_fd, &output);
565
566       if (select(nfds, &input, &output, NULL, NULL) < 0)
567         continue;                       /* Ignore errors here */
568
569      /*
570       * Check if we have a side-channel request ready...
571       */
572
573       if (FD_ISSET(CUPS_SC_FD, &input))
574       {
575        /*
576         * Do the side-channel request, then start back over in the select
577         * loop since it may have read from print_fd...
578         */
579
580         if (side_cb(print_fd, device_fd, 1))
581           side_eof = 1;
582         continue;
583       }
584
585      /*
586       * Check if we have back-channel data ready...
587       */
588
589       if (FD_ISSET(device_fd, &input))
590       {
591         if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
592         {
593           fprintf(stderr,
594                   "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data\n",
595                   CUPS_LLCAST bc_bytes);
596           cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
597         }
598       }
599
600      /*
601       * Check if we have print data ready...
602       */
603
604       if (FD_ISSET(print_fd, &input))
605       {
606         if ((print_bytes = read(print_fd, print_buffer, print_size)) < 0)
607         {
608          /*
609           * Read error - bail if we don't see EAGAIN or EINTR...
610           */
611
612           if (errno != EAGAIN || errno != EINTR)
613           {
614             perror("DEBUG: Unable to read print data");
615
616             tcsetattr(device_fd, TCSADRAIN, &origopts);
617
618             close(device_fd);
619
620             if (print_fd != 0)
621               close(print_fd);
622
623             return (CUPS_BACKEND_FAILED);
624           }
625
626           print_bytes = 0;
627         }
628         else if (print_bytes == 0)
629         {
630          /*
631           * End of file, break out of the loop...
632           */
633
634           break;
635         }
636
637         print_ptr = print_buffer;
638       }
639
640      /*
641       * Check if the device is ready to receive data and we have data to
642       * send...
643       */
644
645       if (print_bytes && FD_ISSET(device_fd, &output))
646       {
647         if (dtrdsr)
648         {
649          /*
650           * Check the port and sleep until DSR is set...
651           */
652
653           int status;
654
655
656           if (!ioctl(device_fd, TIOCMGET, &status))
657             if (!(status & TIOCM_DSR))
658             {
659              /*
660               * Wait for DSR to go high...
661               */
662
663               fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
664
665               do
666               {
667                /*
668                 * Poll every 100ms...
669                 */
670
671                 usleep(100000);
672
673                 if (ioctl(device_fd, TIOCMGET, &status))
674                   break;
675               }
676               while (!(status & TIOCM_DSR));
677
678               fputs("DEBUG: DSR is high; writing to device...\n", stderr);
679             }
680         }
681
682         if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
683         {
684          /*
685           * Write error - bail if we don't see an error we can retry...
686           */
687
688           if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
689           {
690             perror("DEBUG: Unable to write print data");
691
692             tcsetattr(device_fd, TCSADRAIN, &origopts);
693
694             close(device_fd);
695
696             if (print_fd != 0)
697               close(print_fd);
698
699             return (CUPS_BACKEND_FAILED);
700           }
701         }
702         else
703         {
704           fprintf(stderr, "DEBUG: Wrote %d bytes...\n", (int)bytes);
705
706           print_bytes -= bytes;
707           print_ptr   += bytes;
708           total_bytes += bytes;
709         }
710       }
711     }
712   }
713
714  /*
715   * Close the serial port and input file and return...
716   */
717
718   tcsetattr(device_fd, TCSADRAIN, &origopts);
719
720   close(device_fd);
721
722   if (print_fd != 0)
723     close(print_fd);
724
725   return (CUPS_BACKEND_OK);
726 }
727
728
729 /*
730  * 'list_devices()' - List all serial devices.
731  */
732
733 static void
734 list_devices(void)
735 {
736 #if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
737   static char   *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
738                                         /* Funky hex numbering used for some *
739                                          * devices                           */
740 #endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ || __FreeBSD_kernel__ */
741
742
743 #ifdef __linux
744   int                   i, j;           /* Looping vars */
745   int                   fd;             /* File descriptor */
746   char                  device[255];    /* Device filename */
747   char                  info[255];      /* Device info/description */
748 #  ifdef TIOCGSERIAL
749   struct serial_struct  serinfo;        /* serial port info */
750 #  endif /* TIOCGSERIAL */
751
752
753   for (i = 0; i < 100; i ++)
754   {
755     sprintf(device, "/dev/ttyS%d", i);
756
757     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
758     {
759 #  ifdef TIOCGSERIAL
760      /*
761       * See if this port exists...
762       */
763
764       serinfo.reserved_char[0] = 0;
765
766       if (!ioctl(fd, TIOCGSERIAL, &serinfo))
767       {
768         if (serinfo.type == PORT_UNKNOWN)
769         {
770          /*
771           * Nope...
772           */
773
774           close(fd);
775           continue;
776         }
777       }
778 #  endif /* TIOCGSERIAL */
779
780       close(fd);
781
782       snprintf(info, sizeof(info),
783                _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
784
785 #  if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
786       printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
787 #  else
788       printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
789 #  endif /* _ARCH_PPC || powerpc || __powerpc */
790     }
791   }
792
793   for (i = 0; i < 16; i ++)
794   {
795     snprintf(info, sizeof(info),
796              _cupsLangString(cupsLangDefault(), _("USB Serial Port #%d")),
797              i + 1);
798
799     sprintf(device, "/dev/usb/ttyUSB%d", i);
800     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
801     {
802       close(fd);
803       printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
804     }
805
806     sprintf(device, "/dev/ttyUSB%d", i);
807     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
808     {
809       close(fd);
810       printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
811     }
812   }
813
814   for (i = 0; i < 64; i ++)
815   {
816     for (j = 0; j < 8; j ++)
817     {
818       sprintf(device, "/dev/ttyQ%02de%d", i, j);
819       if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
820       {
821         close(fd);
822
823         printf("serial serial:%s?baud=115200 \"Unknown\" "
824                "\"Equinox ESP %d Port #%d\"\n", device, i, j + 1);
825       }
826     }
827   }
828 #elif defined(__sgi)
829   int           i, j, n;        /* Looping vars */
830   char          device[255];    /* Device filename */
831   inventory_t   *inv;           /* Hardware inventory info */
832
833
834  /*
835   * IRIX maintains a hardware inventory of most devices...
836   */
837
838   setinvent();
839
840   while ((inv = getinvent()) != NULL)
841   {
842     if (inv->inv_class == INV_SERIAL)
843     {
844      /*
845       * Some sort of serial port...
846       */
847
848       if (inv->inv_type == INV_CDSIO || inv->inv_type == INV_CDSIO_E)
849       {
850        /*
851         * CDSIO port...
852         */
853
854         for (n = 0; n < 6; n ++)
855           printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"CDSIO Board %d Serial Port #%d\"\n",
856                  n + 5 + 8 * inv->inv_controller, inv->inv_controller, n + 1);
857       }
858       else if (inv->inv_type == INV_EPC_SERIAL)
859       {
860        /*
861         * Everest serial port...
862         */
863
864         if (inv->inv_unit == 0)
865           i = 1;
866         else
867           i = 41 + 4 * (int)inv->inv_controller;
868
869         for (n = 0; n < (int)inv->inv_state; n ++)
870           printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"EPC Serial Port %d, Ebus slot %d\"\n",
871                  n + i, n + 1, (int)inv->inv_controller);
872       }
873       else if (inv->inv_state > 1)
874       {
875        /*
876         * Standard serial port under IRIX 6.4 and earlier...
877         */
878
879         for (n = 0; n < (int)inv->inv_state; n ++)
880           printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"Onboard Serial Port %d\"\n",
881                  n + (int)inv->inv_unit + 1, n + (int)inv->inv_unit + 1);
882       }
883       else
884       {
885        /*
886         * Standard serial port under IRIX 6.5 and beyond...
887         */
888
889         printf("serial serial:/dev/ttyd%d?baud=115200 \"Unknown\" \"Onboard Serial Port %d\"\n",
890                (int)inv->inv_controller, (int)inv->inv_controller);
891       }
892     }
893   }
894
895   endinvent();
896
897  /*
898   * Central Data makes serial and parallel "servers" that can be
899   * connected in a number of ways.  Look for ports...
900   */
901
902   for (i = 0; i < 10; i ++)
903     for (j = 0; j < 8; j ++)
904       for (n = 0; n < 32; n ++)
905       {
906         if (i == 8)             /* EtherLite */
907           sprintf(device, "/dev/ttydn%d%c", j, funky_hex[n]);
908         else if (i == 9)        /* PCI */
909           sprintf(device, "/dev/ttydp%d%c", j, funky_hex[n]);
910         else                    /* SCSI */
911           sprintf(device, "/dev/ttyd%d%d%c", i, j, funky_hex[n]);
912
913         if (access(device, 0) == 0)
914         {
915           if (i == 8)
916             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
917                    device, j, n);
918           else if (i == 9)
919             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data PCI Serial Port, ID %d, port %d\"\n",
920                    device, j, n);
921           else
922             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
923                    device, i, j, n);
924         }
925       }
926 #elif defined(__sun)
927   int           i, j, n;                /* Looping vars */
928   char          device[255];            /* Device filename */
929   char          info[255];              /* Device info/description */
930
931
932  /*
933   * Standard serial ports...
934   */
935
936   for (i = 0; i < 26; i ++)
937   {
938     sprintf(device, "/dev/cua/%c", 'a' + i);
939     if (!access(device, 0))
940     {
941       snprintf(info, sizeof(info),
942                _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
943
944 #  ifdef B115200
945       printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
946 #  else
947       printf("serial serial:%s?baud=38400 \"Unknown\" \"%s\"\n", device, info);
948 #  endif /* B115200 */
949     }
950   }
951
952  /*
953   * MAGMA serial ports...
954   */
955
956   for (i = 0; i < 40; i ++)
957   {
958     sprintf(device, "/dev/term/%02d", i);
959     if (access(device, 0) == 0)
960       printf("serial serial:%s?baud=38400 \"Unknown\" \"MAGMA Serial Board #%d Port #%d\"\n",
961              device, (i / 10) + 1, (i % 10) + 1);
962   }
963
964  /*
965   * Central Data serial ports...
966   */
967
968   for (i = 0; i < 9; i ++)
969     for (j = 0; j < 8; j ++)
970       for (n = 0; n < 32; n ++)
971       {
972         if (i == 8)     /* EtherLite */
973           sprintf(device, "/dev/sts/ttyN%d%c", j, funky_hex[n]);
974         else
975           sprintf(device, "/dev/sts/tty%c%d%c", i + 'C', j,
976                   funky_hex[n]);
977
978         if (access(device, 0) == 0)
979         {
980           if (i == 8)
981             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
982                    device, j, n);
983           else
984             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
985                    device, i, j, n);
986         }
987       }
988 #elif defined(__hpux)
989   int           i, j, n;        /* Looping vars */
990   char          device[255];    /* Device filename */
991
992
993  /*
994   * Standard serial ports...
995   */
996
997   for (i = 0; i < 10; i ++)
998   {
999     sprintf(device, "/dev/tty%dp0", i);
1000     if (access(device, 0) == 0)
1001       printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
1002              device, i + 1);
1003   }
1004
1005  /*
1006   * Central Data serial ports...
1007   */
1008
1009   for (i = 0; i < 9; i ++)
1010     for (j = 0; j < 8; j ++)
1011       for (n = 0; n < 32; n ++)
1012       {
1013         if (i == 8)     /* EtherLite */
1014           sprintf(device, "/dev/ttyN%d%c", j, funky_hex[n]);
1015         else
1016           sprintf(device, "/dev/tty%c%d%c", i + 'C', j,
1017                   funky_hex[n]);
1018
1019         if (access(device, 0) == 0)
1020         {
1021           if (i == 8)
1022             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
1023                    device, j, n);
1024           else
1025             printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
1026                    device, i, j, n);
1027         }
1028       }
1029 #elif defined(__osf__)
1030   int           i;              /* Looping var */
1031   char          device[255];    /* Device filename */
1032
1033
1034  /*
1035   * Standard serial ports...
1036   */
1037
1038   for (i = 0; i < 100; i ++)
1039   {
1040     sprintf(device, "/dev/tty%02d", i);
1041     if (access(device, 0) == 0)
1042       printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
1043              device, i + 1);
1044   }
1045 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
1046   int   i, j;                           /* Looping vars */
1047   int   fd;                             /* File descriptor */
1048   char  device[255];                    /* Device filename */
1049   char  info[255];                      /* Device info/description */
1050
1051
1052  /*
1053   * SIO ports...
1054   */
1055
1056   for (i = 0; i < 32; i ++)
1057   {
1058     sprintf(device, "/dev/ttyd%c", funky_hex[i]);
1059     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1060     {
1061       close(fd);
1062
1063       snprintf(info, sizeof(info),
1064                _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
1065
1066       printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
1067     }
1068   }
1069
1070  /*
1071   * Cyclades ports...
1072   */
1073
1074   for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1075     for (j = 0; j < 32; j ++)
1076     {
1077       sprintf(device, "/dev/ttyc%d%c", i, funky_hex[j]);
1078       if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1079       {
1080         close(fd);
1081         printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n",
1082                device, i, j + 1);
1083       }
1084
1085       sprintf(device, "/dev/ttyC%d%c", i, funky_hex[j]);
1086       if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1087       {
1088         close(fd);
1089         printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n",
1090                device, i, j + 1);
1091       }
1092     }
1093
1094  /*
1095   * Digiboard ports...
1096   */
1097
1098   for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1099     for (j = 0; j < 32; j ++)
1100     {
1101       sprintf(device, "/dev/ttyD%d%c", i, funky_hex[j]);
1102       if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1103       {
1104         close(fd);
1105         printf("serial serial:%s?baud=115200 \"Unknown\" \"Digiboard #%d Serial Port #%d\"\n",
1106                device, i, j + 1);
1107       }
1108     }
1109
1110  /*
1111   * Stallion ports...
1112   */
1113
1114   for (i = 0; i < 32; i ++)
1115   {
1116     sprintf(device, "/dev/ttyE%c", funky_hex[i]);
1117     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1118     {
1119       close(fd);
1120       printf("serial serial:%s?baud=115200 \"Unknown\" \"Stallion Serial Port #%d\"\n",
1121              device, i + 1);
1122     }
1123   }
1124
1125  /*
1126   * SX ports...
1127   */
1128
1129   for (i = 0; i < 128; i ++)
1130   {
1131     sprintf(device, "/dev/ttyA%d", i + 1);
1132     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1133     {
1134       close(fd);
1135       printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n",
1136              device, i + 1);
1137     }
1138   }
1139 #elif defined(__NetBSD__)
1140   int   i, j;                           /* Looping vars */
1141   int   fd;                             /* File descriptor */
1142   char  device[255];                    /* Device filename */
1143   char  info[255];                      /* Device info/description */
1144
1145
1146  /*
1147   * Standard serial ports...
1148   */
1149
1150   for (i = 0; i < 4; i ++)
1151   {
1152     sprintf(device, "/dev/tty%02d", i);
1153     if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1154     {
1155       close(fd);
1156
1157       snprintf(info, sizeof(info),
1158                _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
1159
1160       printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
1161     }
1162   }
1163
1164  /*
1165   * Cyclades-Z ports...
1166   */
1167
1168   for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1169     for (j = 0; j < 64; j ++)
1170     {
1171       sprintf(device, "/dev/ttyCZ%02d%02d", i, j);
1172       if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1173       {
1174         close(fd);
1175         printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Prt #%d\"\n",
1176                device, i, j + 1);
1177       }
1178     }
1179 #elif defined(__APPLE__)
1180  /*
1181   * Standard serial ports on MacOS X...
1182   */
1183
1184   kern_return_t                 kernResult;
1185   mach_port_t                   masterPort;
1186   io_iterator_t                 serialPortIterator;
1187   CFMutableDictionaryRef        classesToMatch;
1188   io_object_t                   serialService;
1189
1190
1191   kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1192   if (KERN_SUCCESS != kernResult)
1193     return;
1194
1195  /*
1196   * Serial devices are instances of class IOSerialBSDClient.
1197   */
1198
1199   classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
1200   if (classesToMatch != NULL)
1201   {
1202     CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
1203                          CFSTR(kIOSerialBSDRS232Type));
1204
1205     kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
1206                                               &serialPortIterator);
1207     if (kernResult == KERN_SUCCESS)
1208     {
1209       while ((serialService = IOIteratorNext(serialPortIterator)))
1210       {
1211         CFTypeRef       serialNameAsCFString;
1212         CFTypeRef       bsdPathAsCFString;
1213         CFTypeRef       hiddenVal;
1214         char            serialName[128];
1215         char            bsdPath[1024];
1216         Boolean         result;
1217
1218
1219         /* Check if hidden... */
1220         hiddenVal = IORegistryEntrySearchCFProperty(serialService,
1221                                                     kIOServicePlane,
1222                                                     CFSTR("HiddenPort"),
1223                                                     kCFAllocatorDefault,
1224                                                     kIORegistryIterateRecursively |
1225                                                     kIORegistryIterateParents);
1226         if (hiddenVal)
1227           CFRelease(hiddenVal); /* This interface should not be used */
1228         else
1229         {
1230           serialNameAsCFString =
1231               IORegistryEntryCreateCFProperty(serialService,
1232                                               CFSTR(kIOTTYDeviceKey),
1233                                               kCFAllocatorDefault, 0);
1234           if (serialNameAsCFString)
1235           {
1236             result = CFStringGetCString(serialNameAsCFString, serialName,
1237                                         sizeof(serialName),
1238                                         kCFStringEncodingASCII);
1239             CFRelease(serialNameAsCFString);
1240
1241             if (result)
1242             {
1243               bsdPathAsCFString =
1244                   IORegistryEntryCreateCFProperty(serialService,
1245                                                   CFSTR(kIOCalloutDeviceKey),
1246                                                   kCFAllocatorDefault, 0);
1247               if (bsdPathAsCFString)
1248               {
1249                 result = CFStringGetCString(bsdPathAsCFString, bsdPath,
1250                                             sizeof(bsdPath),
1251                                             kCFStringEncodingASCII);
1252                 CFRelease(bsdPathAsCFString);
1253
1254                 if (result)
1255                   printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n",
1256                          bsdPath, serialName);
1257               }
1258             }
1259           }
1260         }
1261
1262         IOObjectRelease(serialService);
1263       }
1264
1265      /*
1266       * Release the iterator.
1267       */
1268
1269       IOObjectRelease(serialPortIterator);
1270     }
1271   }
1272 #endif
1273 }
1274
1275
1276 /*
1277  * 'side_cb()' - Handle side-channel requests...
1278  */
1279
1280 static int                              /* O - 0 on success, -1 on error */
1281 side_cb(int print_fd,                   /* I - Print file */
1282         int device_fd,                  /* I - Device file */
1283         int use_bc)                     /* I - Using back-channel? */
1284 {
1285   cups_sc_command_t     command;        /* Request command */
1286   cups_sc_status_t      status;         /* Request/response status */
1287   char                  data[2048];     /* Request/response data */
1288   int                   datalen;        /* Request/response data size */
1289
1290
1291   datalen = sizeof(data);
1292
1293   if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
1294     return (-1);
1295
1296   switch (command)
1297   {
1298     case CUPS_SC_CMD_DRAIN_OUTPUT :
1299         if (backendDrainOutput(print_fd, device_fd))
1300           status = CUPS_SC_STATUS_IO_ERROR;
1301         else if (tcdrain(device_fd))
1302           status = CUPS_SC_STATUS_IO_ERROR;
1303         else
1304           status = CUPS_SC_STATUS_OK;
1305
1306         datalen = 0;
1307         break;
1308
1309     case CUPS_SC_CMD_GET_BIDI :
1310         status  = CUPS_SC_STATUS_OK;
1311         data[0] = use_bc;
1312         datalen = 1;
1313         break;
1314
1315     default :
1316         status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
1317         datalen = 0;
1318         break;
1319   }
1320
1321   return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
1322 }
1323
1324
1325 /*
1326  * End of "$Id: serial.c 9793 2011-05-20 03:49:49Z mike $".
1327  */