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