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