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