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