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