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