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