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