]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/serial.c
Merge changes from CUPS 1.4svn-r8252.
[thirdparty/cups.git] / backend / serial.c
CommitLineData
ef416fc2 1/*
75bd9771 2 * "$Id: serial.c 7647 2008-06-16 17:39:40Z 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 {
080811b1
MS
188 _cupsLangPrintf(stderr,
189 _("ERROR: Unable to open print file \"%s\": %s\n"),
190 argv[6], strerror(errno));
ef416fc2 191 return (CUPS_BACKEND_FAILED);
192 }
193
194 copies = atoi(argv[4]);
195 }
196
197 /*
198 * Extract the device name and options from the URI...
199 */
200
a4d04587 201 httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
202 method, sizeof(method), username, sizeof(username),
203 hostname, sizeof(hostname), &port,
ef416fc2 204 resource, sizeof(resource));
205
206 /*
207 * See if there are any options...
208 */
209
210 if ((options = strchr(resource, '?')) != NULL)
211 {
212 /*
213 * Yup, terminate the device name string and move to the first
214 * character of the options...
215 */
216
217 *options++ = '\0';
218 }
219
220 /*
221 * Open the serial port device...
222 */
223
757d2cad 224 fputs("STATE: +connecting-to-device\n", stderr);
225
ef416fc2 226 do
227 {
ed486911 228 if ((device_fd = open(resource, O_RDWR | O_NOCTTY | O_EXCL |
229 O_NDELAY)) == -1)
ef416fc2 230 {
231 if (getenv("CLASS") != NULL)
232 {
233 /*
234 * If the CLASS environment variable is set, the job was submitted
235 * to a class and not to a specific queue. In this case, we want
236 * to abort immediately so that the job can be requeued on the next
237 * available printer in the class.
238 */
239
db1f069b
MS
240 _cupsLangPuts(stderr,
241 _("INFO: Unable to contact printer, queuing on next "
242 "printer in class...\n"));
ef416fc2 243
244 /*
245 * Sleep 5 seconds to keep the job from requeuing too rapidly...
246 */
247
248 sleep(5);
249
250 return (CUPS_BACKEND_FAILED);
251 }
252
253 if (errno == EBUSY)
254 {
db1f069b
MS
255 _cupsLangPuts(stderr,
256 _("INFO: Printer busy; will retry in 30 seconds...\n"));
ef416fc2 257 sleep(30);
258 }
259 else
260 {
db1f069b
MS
261 _cupsLangPrintf(stderr,
262 _("ERROR: Unable to open device file \"%s\": %s\n"),
263 resource, strerror(errno));
ef416fc2 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
db1f069b 294 name = options;
ef416fc2 295
db1f069b
MS
296 while (*options && *options != '=' && *options != '+' && *options != '&')
297 options ++;
298
299 if ((sep = *options) != '\0')
300 *options++ = '\0';
301
302 if (sep == '=')
ef416fc2 303 {
304 /*
305 * Get the value...
306 */
307
db1f069b 308 value = options;
ef416fc2 309
db1f069b 310 while (*options && *options != '+' && *options != '&')
ef416fc2 311 options ++;
db1f069b
MS
312
313 if (*options)
314 *options++ = '\0';
ef416fc2 315 }
316 else
db1f069b 317 value = (char *)"";
ef416fc2 318
319 /*
320 * Process the option...
321 */
322
323 if (!strcasecmp(name, "baud"))
324 {
325 /*
326 * Set the baud rate...
327 */
328
ed486911 329 print_size = atoi(value) / 100;
ef416fc2 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 :
db1f069b
MS
380 _cupsLangPrintf(stderr, _("WARNING: Unsupported baud rate %s!\n"),
381 value);
ef416fc2 382 break;
383 }
384#endif /* B19200 == 19200 */
385 }
386 else if (!strcasecmp(name, "bits"))
387 {
388 /*
389 * Set number of data bits...
390 */
391
392 switch (atoi(value))
393 {
394 case 7 :
395 opts.c_cflag &= ~CSIZE;
396 opts.c_cflag |= CS7;
397 opts.c_cflag |= PARENB;
398 opts.c_cflag &= ~PARODD;
399 break;
400 case 8 :
401 opts.c_cflag &= ~CSIZE;
402 opts.c_cflag |= CS8;
403 opts.c_cflag &= ~PARENB;
404 break;
405 }
406 }
407 else if (!strcasecmp(name, "parity"))
408 {
409 /*
410 * Set parity checking...
411 */
412
413 if (!strcasecmp(value, "even"))
414 {
415 opts.c_cflag |= PARENB;
416 opts.c_cflag &= ~PARODD;
417 }
418 else if (!strcasecmp(value, "odd"))
419 {
420 opts.c_cflag |= PARENB;
421 opts.c_cflag |= PARODD;
422 }
423 else if (!strcasecmp(value, "none"))
424 opts.c_cflag &= ~PARENB;
425 else if (!strcasecmp(value, "space"))
426 {
427 /*
428 * Note: we only support space parity with 7 bits per character...
429 */
430
431 opts.c_cflag &= ~CSIZE;
432 opts.c_cflag |= CS8;
433 opts.c_cflag &= ~PARENB;
434 }
435 else if (!strcasecmp(value, "mark"))
436 {
437 /*
438 * Note: we only support mark parity with 7 bits per character
439 * and 1 stop bit...
440 */
441
442 opts.c_cflag &= ~CSIZE;
443 opts.c_cflag |= CS7;
444 opts.c_cflag &= ~PARENB;
445 opts.c_cflag |= CSTOPB;
446 }
447 }
448 else if (!strcasecmp(name, "flow"))
449 {
450 /*
451 * Set flow control...
452 */
453
454 if (!strcasecmp(value, "none"))
455 {
456 opts.c_iflag &= ~(IXON | IXOFF);
457 opts.c_cflag &= ~CRTSCTS;
458 }
459 else if (!strcasecmp(value, "soft"))
460 {
461 opts.c_iflag |= IXON | IXOFF;
462 opts.c_cflag &= ~CRTSCTS;
463 }
464 else if (!strcasecmp(value, "hard") ||
465 !strcasecmp(value, "rtscts"))
466 {
467 opts.c_iflag &= ~(IXON | IXOFF);
468 opts.c_cflag |= CRTSCTS;
469 }
470 else if (!strcasecmp(value, "dtrdsr"))
471 {
472 opts.c_iflag &= ~(IXON | IXOFF);
473 opts.c_cflag &= ~CRTSCTS;
474
475 dtrdsr = 1;
476 }
477 }
478 else if (!strcasecmp(name, "stop"))
479 {
480 switch (atoi(value))
481 {
482 case 1 :
483 opts.c_cflag &= ~CSTOPB;
484 break;
485
486 case 2 :
487 opts.c_cflag |= CSTOPB;
488 break;
489 }
490 }
491 }
ed486911 492 }
ef416fc2 493
ed486911 494 tcsetattr(device_fd, TCSANOW, &opts);
495 fcntl(device_fd, F_SETFL, 0);
ef416fc2 496
497 /*
498 * Now that we are "connected" to the port, ignore SIGTERM so that we
499 * can finish out any page data the driver sends (e.g. to eject the
500 * current page... Only ignore SIGTERM if we are printing data from
501 * stdin (otherwise you can't cancel raw jobs...)
502 */
503
ed486911 504 if (print_fd != 0)
ef416fc2 505 {
506#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
507 sigset(SIGTERM, SIG_IGN);
508#elif defined(HAVE_SIGACTION)
509 memset(&action, 0, sizeof(action));
510
511 sigemptyset(&action.sa_mask);
512 action.sa_handler = SIG_IGN;
513 sigaction(SIGTERM, &action, NULL);
514#else
515 signal(SIGTERM, SIG_IGN);
516#endif /* HAVE_SIGSET */
517 }
518
519 /*
ed486911 520 * Figure out the maximum file descriptor value to use with select()...
ef416fc2 521 */
522
ed486911 523 nfds = (print_fd > device_fd ? print_fd : device_fd) + 1;
524
525 /*
526 * Finally, send the print file. Ordinarily we would just use the
527 * backendRunLoop() function, however since we need to use smaller
528 * writes and may need to do DSR/DTR flow control, we duplicate much
529 * of the code here instead...
530 */
ef416fc2 531
ed486911 532 if (print_size > sizeof(print_buffer))
533 print_size = sizeof(print_buffer);
534
535 total_bytes = 0;
ef416fc2 536
537 while (copies > 0)
538 {
539 copies --;
540
ed486911 541 if (print_fd != 0)
ef416fc2 542 {
543 fputs("PAGE: 1 1\n", stderr);
ed486911 544 lseek(print_fd, 0, SEEK_SET);
ef416fc2 545 }
546
ed486911 547 /*
548 * Now loop until we are out of data from print_fd...
549 */
550
551 for (print_bytes = 0, print_ptr = print_buffer;;)
ef416fc2 552 {
553 /*
ed486911 554 * Use select() to determine whether we have data to copy around...
ef416fc2 555 */
556
ed486911 557 FD_ZERO(&input);
558 if (!print_bytes)
559 FD_SET(print_fd, &input);
560 FD_SET(device_fd, &input);
dd1abb6b
MS
561 if (!print_bytes)
562 FD_SET(CUPS_SC_FD, &input);
ed486911 563
564 FD_ZERO(&output);
565 if (print_bytes)
566 FD_SET(device_fd, &output);
567
568 if (select(nfds, &input, &output, NULL, NULL) < 0)
569 continue; /* Ignore errors here */
570
f7deaa1a 571 /*
572 * Check if we have a side-channel request ready...
573 */
574
575 if (FD_ISSET(CUPS_SC_FD, &input))
dd1abb6b
MS
576 {
577 /*
578 * Do the side-channel request, then start back over in the select
579 * loop since it may have read from print_fd...
580 */
581
f7deaa1a 582 side_cb(print_fd, device_fd, 1);
dd1abb6b
MS
583 continue;
584 }
f7deaa1a 585
ed486911 586 /*
587 * Check if we have back-channel data ready...
588 */
589
590 if (FD_ISSET(device_fd, &input))
591 {
592 if ((bc_bytes = read(device_fd, bc_buffer, sizeof(bc_buffer))) > 0)
593 {
594 fprintf(stderr,
595 "DEBUG: Received " CUPS_LLFMT " bytes of back-channel data!\n",
596 CUPS_LLCAST bc_bytes);
597 cupsBackChannelWrite(bc_buffer, bc_bytes, 1.0);
598 }
599 }
ef416fc2 600
ed486911 601 /*
602 * Check if we have print data ready...
603 */
ef416fc2 604
ed486911 605 if (FD_ISSET(print_fd, &input))
606 {
607 if ((print_bytes = read(print_fd, print_buffer, print_size)) < 0)
ef416fc2 608 {
609 /*
ed486911 610 * Read error - bail if we don't see EAGAIN or EINTR...
ef416fc2 611 */
612
ed486911 613 if (errno != EAGAIN || errno != EINTR)
ef416fc2 614 {
080811b1 615 _cupsLangPrintError(_("ERROR: Unable to read print data"));
ef416fc2 616
ed486911 617 tcsetattr(device_fd, TCSADRAIN, &origopts);
ef416fc2 618
ed486911 619 close(device_fd);
ef416fc2 620
ed486911 621 if (print_fd != 0)
622 close(print_fd);
ef416fc2 623
ed486911 624 return (CUPS_BACKEND_FAILED);
625 }
ef416fc2 626
ed486911 627 print_bytes = 0;
628 }
629 else if (print_bytes == 0)
ef416fc2 630 {
631 /*
ed486911 632 * End of file, break out of the loop...
ef416fc2 633 */
634
ed486911 635 break;
ef416fc2 636 }
637
ed486911 638 print_ptr = print_buffer;
639 }
640
641 /*
642 * Check if the device is ready to receive data and we have data to
643 * send...
644 */
645
646 if (print_bytes && FD_ISSET(device_fd, &output))
647 {
648 if (dtrdsr)
ef416fc2 649 {
650 /*
ed486911 651 * Check the port and sleep until DSR is set...
ef416fc2 652 */
653
ed486911 654 int status;
ef416fc2 655
ef416fc2 656
ed486911 657 if (!ioctl(device_fd, TIOCMGET, &status))
658 if (!(status & TIOCM_DSR))
ef416fc2 659 {
ed486911 660 /*
661 * Wait for DSR to go high...
662 */
663
664 fputs("DEBUG: DSR is low; waiting for device...\n", stderr);
665
666 do
667 {
668 /*
669 * Poll every 100ms...
670 */
671
672 usleep(100000);
673
674 if (ioctl(device_fd, TIOCMGET, &status))
675 break;
676 }
677 while (!(status & TIOCM_DSR));
678
679 fputs("DEBUG: DSR is high; writing to device...\n", stderr);
680 }
681 }
682
683 if ((bytes = write(device_fd, print_ptr, print_bytes)) < 0)
684 {
685 /*
686 * Write error - bail if we don't see an error we can retry...
687 */
688
689 if (errno != EAGAIN && errno != EINTR && errno != ENOTTY)
ef416fc2 690 {
080811b1 691 _cupsLangPrintError(_("ERROR: Unable to write print data"));
ed486911 692
693 tcsetattr(device_fd, TCSADRAIN, &origopts);
ef416fc2 694
ed486911 695 close(device_fd);
696
697 if (print_fd != 0)
698 close(print_fd);
699
700 return (CUPS_BACKEND_FAILED);
ef416fc2 701 }
702 }
ed486911 703 else
704 {
705 fprintf(stderr, "DEBUG: Wrote %d bytes...\n", (int)bytes);
ef416fc2 706
ed486911 707 print_bytes -= bytes;
708 print_ptr += bytes;
709 total_bytes += bytes;
710 }
711 }
ef416fc2 712 }
713 }
714
715 /*
716 * Close the serial port and input file and return...
717 */
718
ed486911 719 tcsetattr(device_fd, TCSADRAIN, &origopts);
720
721 close(device_fd);
ef416fc2 722
ed486911 723 if (print_fd != 0)
724 close(print_fd);
ef416fc2 725
ed486911 726 return (total_bytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
ef416fc2 727}
728
729
730/*
731 * 'list_devices()' - List all serial devices.
732 */
733
f7deaa1a 734static void
ef416fc2 735list_devices(void)
736{
2e4ff8af 737#if defined(__hpux) || defined(__sgi) || defined(__sun) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
ef416fc2 738 static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
89d46774 739 /* Funky hex numbering used for some *
740 * devices */
2e4ff8af 741#endif /* __hpux || __sgi || __sun || __FreeBSD__ || __OpenBSD__ || __FreeBSD_kernel__ */
ef416fc2 742
8b450588 743
89d46774 744#ifdef __linux
745 int i, j; /* Looping vars */
746 int fd; /* File descriptor */
747 char device[255]; /* Device filename */
8b450588 748 char info[255]; /* Device info/description */
89d46774 749# ifdef TIOCGSERIAL
750 struct serial_struct serinfo; /* serial port info */
751# endif /* TIOCGSERIAL */
ef416fc2 752
753
754 for (i = 0; i < 100; i ++)
755 {
756 sprintf(device, "/dev/ttyS%d", i);
89d46774 757
ef416fc2 758 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
759 {
89d46774 760# ifdef TIOCGSERIAL
761 /*
762 * See if this port exists...
763 */
764
765 serinfo.reserved_char[0] = 0;
766
767 if (!ioctl(fd, TIOCGSERIAL, &serinfo))
768 {
769 if (serinfo.type == PORT_UNKNOWN)
770 {
771 /*
772 * Nope...
773 */
774
775 close(fd);
776 continue;
777 }
778 }
779# endif /* TIOCGSERIAL */
780
ef416fc2 781 close(fd);
89d46774 782
8b450588
MS
783 snprintf(info, sizeof(info),
784 _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
785
ef416fc2 786# if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc)
8b450588 787 printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 788# else
8b450588 789 printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 790# endif /* _ARCH_PPC || powerpc || __powerpc */
791 }
792 }
793
794 for (i = 0; i < 16; i ++)
795 {
8b450588
MS
796 snprintf(info, sizeof(info),
797 _cupsLangString(cupsLangDefault(), _("USB Serial Port #%d")),
798 i + 1);
799
ef416fc2 800 sprintf(device, "/dev/usb/ttyUSB%d", i);
801 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
802 {
803 close(fd);
8b450588 804 printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 805 }
26d47ec6 806
807 sprintf(device, "/dev/ttyUSB%d", i);
808 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
809 {
810 close(fd);
8b450588 811 printf("serial serial:%s?baud=230400 \"Unknown\" \"%s\"\n", device, info);
26d47ec6 812 }
ef416fc2 813 }
b423cd4c 814
815 for (i = 0; i < 64; i ++)
816 {
817 for (j = 0; j < 8; j ++)
818 {
819 sprintf(device, "/dev/ttyQ%02de%d", i, j);
820 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
821 {
822 close(fd);
8b450588 823
b423cd4c 824 printf("serial serial:%s?baud=115200 \"Unknown\" "
8b450588 825 "\"Equinox ESP %d Port #%d\"\n", device, i, j + 1);
b423cd4c 826 }
827 }
828 }
ef416fc2 829#elif defined(__sgi)
830 int i, j, n; /* Looping vars */
831 char device[255]; /* Device filename */
832 inventory_t *inv; /* Hardware inventory info */
833
834
835 /*
836 * IRIX maintains a hardware inventory of most devices...
837 */
838
839 setinvent();
840
841 while ((inv = getinvent()) != NULL)
842 {
843 if (inv->inv_class == INV_SERIAL)
844 {
845 /*
846 * Some sort of serial port...
847 */
848
849 if (inv->inv_type == INV_CDSIO || inv->inv_type == INV_CDSIO_E)
850 {
851 /*
852 * CDSIO port...
853 */
854
855 for (n = 0; n < 6; n ++)
856 printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"CDSIO Board %d Serial Port #%d\"\n",
857 n + 5 + 8 * inv->inv_controller, inv->inv_controller, n + 1);
858 }
859 else if (inv->inv_type == INV_EPC_SERIAL)
860 {
861 /*
862 * Everest serial port...
863 */
864
865 if (inv->inv_unit == 0)
866 i = 1;
867 else
868 i = 41 + 4 * (int)inv->inv_controller;
869
870 for (n = 0; n < (int)inv->inv_state; n ++)
871 printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"EPC Serial Port %d, Ebus slot %d\"\n",
872 n + i, n + 1, (int)inv->inv_controller);
873 }
874 else if (inv->inv_state > 1)
875 {
876 /*
877 * Standard serial port under IRIX 6.4 and earlier...
878 */
879
880 for (n = 0; n < (int)inv->inv_state; n ++)
881 printf("serial serial:/dev/ttyd%d?baud=38400 \"Unknown\" \"Onboard Serial Port %d\"\n",
882 n + (int)inv->inv_unit + 1, n + (int)inv->inv_unit + 1);
883 }
884 else
885 {
886 /*
887 * Standard serial port under IRIX 6.5 and beyond...
888 */
889
890 printf("serial serial:/dev/ttyd%d?baud=115200 \"Unknown\" \"Onboard Serial Port %d\"\n",
891 (int)inv->inv_controller, (int)inv->inv_controller);
892 }
893 }
894 }
895
896 endinvent();
897
898 /*
899 * Central Data makes serial and parallel "servers" that can be
900 * connected in a number of ways. Look for ports...
901 */
902
903 for (i = 0; i < 10; i ++)
904 for (j = 0; j < 8; j ++)
905 for (n = 0; n < 32; n ++)
906 {
907 if (i == 8) /* EtherLite */
908 sprintf(device, "/dev/ttydn%d%c", j, funky_hex[n]);
909 else if (i == 9) /* PCI */
910 sprintf(device, "/dev/ttydp%d%c", j, funky_hex[n]);
911 else /* SCSI */
912 sprintf(device, "/dev/ttyd%d%d%c", i, j, funky_hex[n]);
913
914 if (access(device, 0) == 0)
915 {
916 if (i == 8)
917 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
918 device, j, n);
919 else if (i == 9)
920 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data PCI Serial Port, ID %d, port %d\"\n",
921 device, j, n);
922 else
923 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
924 device, i, j, n);
925 }
926 }
927#elif defined(__sun)
8b450588
MS
928 int i, j, n; /* Looping vars */
929 char device[255]; /* Device filename */
930 char info[255]; /* Device info/description */
ef416fc2 931
932
933 /*
934 * Standard serial ports...
935 */
936
937 for (i = 0; i < 26; i ++)
938 {
939 sprintf(device, "/dev/cua/%c", 'a' + i);
8b450588
MS
940 if (!access(device, 0))
941 {
942 snprintf(info, sizeof(info),
943 _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
944
89d46774 945# ifdef B115200
8b450588 946 printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 947 device, i + 1);
89d46774 948# else
8b450588 949 printf("serial serial:%s?baud=38400 \"Unknown\" \"%s\"\n", device, info);
89d46774 950# endif /* B115200 */
8b450588 951 }
ef416fc2 952 }
953
954 /*
955 * MAGMA serial ports...
956 */
957
958 for (i = 0; i < 40; i ++)
959 {
960 sprintf(device, "/dev/term/%02d", i);
961 if (access(device, 0) == 0)
962 printf("serial serial:%s?baud=38400 \"Unknown\" \"MAGMA Serial Board #%d Port #%d\"\n",
963 device, (i / 10) + 1, (i % 10) + 1);
964 }
965
966 /*
967 * Central Data serial ports...
968 */
969
970 for (i = 0; i < 9; i ++)
971 for (j = 0; j < 8; j ++)
972 for (n = 0; n < 32; n ++)
973 {
974 if (i == 8) /* EtherLite */
975 sprintf(device, "/dev/sts/ttyN%d%c", j, funky_hex[n]);
976 else
977 sprintf(device, "/dev/sts/tty%c%d%c", i + 'C', j,
978 funky_hex[n]);
979
980 if (access(device, 0) == 0)
981 {
982 if (i == 8)
983 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
984 device, j, n);
985 else
986 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
987 device, i, j, n);
988 }
989 }
990#elif defined(__hpux)
991 int i, j, n; /* Looping vars */
992 char device[255]; /* Device filename */
993
994
995 /*
996 * Standard serial ports...
997 */
998
999 for (i = 0; i < 10; i ++)
1000 {
1001 sprintf(device, "/dev/tty%dp0", i);
1002 if (access(device, 0) == 0)
1003 printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
1004 device, i + 1);
1005 }
1006
1007 /*
1008 * Central Data serial ports...
1009 */
1010
1011 for (i = 0; i < 9; i ++)
1012 for (j = 0; j < 8; j ++)
1013 for (n = 0; n < 32; n ++)
1014 {
1015 if (i == 8) /* EtherLite */
1016 sprintf(device, "/dev/ttyN%d%c", j, funky_hex[n]);
1017 else
1018 sprintf(device, "/dev/tty%c%d%c", i + 'C', j,
1019 funky_hex[n]);
1020
1021 if (access(device, 0) == 0)
1022 {
1023 if (i == 8)
1024 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n",
1025 device, j, n);
1026 else
1027 printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n",
1028 device, i, j, n);
1029 }
1030 }
1031#elif defined(__osf__)
1032 int i; /* Looping var */
1033 char device[255]; /* Device filename */
1034
1035
1036 /*
1037 * Standard serial ports...
1038 */
1039
1040 for (i = 0; i < 100; i ++)
1041 {
1042 sprintf(device, "/dev/tty%02d", i);
1043 if (access(device, 0) == 0)
1044 printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n",
1045 device, i + 1);
1046 }
2e4ff8af 1047#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
8b450588
MS
1048 int i, j; /* Looping vars */
1049 int fd; /* File descriptor */
1050 char device[255]; /* Device filename */
1051 char info[255]; /* Device info/description */
ef416fc2 1052
1053
1054 /*
1055 * SIO ports...
1056 */
1057
1058 for (i = 0; i < 32; i ++)
1059 {
1060 sprintf(device, "/dev/ttyd%c", funky_hex[i]);
1061 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1062 {
1063 close(fd);
8b450588
MS
1064
1065 snprintf(info, sizeof(info),
1066 _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
1067
1068 printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 1069 }
1070 }
1071
1072 /*
1073 * Cyclades ports...
1074 */
1075
1076 for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1077 for (j = 0; j < 32; j ++)
1078 {
1079 sprintf(device, "/dev/ttyc%d%c", i, funky_hex[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 Port #%d\"\n",
1084 device, i, j + 1);
1085 }
1086
1087 sprintf(device, "/dev/ttyC%d%c", i, funky_hex[j]);
1088 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1089 {
1090 close(fd);
1091 printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n",
1092 device, i, j + 1);
1093 }
1094 }
1095
1096 /*
1097 * Digiboard ports...
1098 */
1099
1100 for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1101 for (j = 0; j < 32; j ++)
1102 {
1103 sprintf(device, "/dev/ttyD%d%c", i, funky_hex[j]);
1104 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1105 {
1106 close(fd);
1107 printf("serial serial:%s?baud=115200 \"Unknown\" \"Digiboard #%d Serial Port #%d\"\n",
1108 device, i, j + 1);
1109 }
1110 }
1111
1112 /*
1113 * Stallion ports...
1114 */
1115
1116 for (i = 0; i < 32; i ++)
1117 {
1118 sprintf(device, "/dev/ttyE%c", funky_hex[i]);
1119 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1120 {
1121 close(fd);
1122 printf("serial serial:%s?baud=115200 \"Unknown\" \"Stallion Serial Port #%d\"\n",
1123 device, i + 1);
1124 }
1125 }
1126
1127 /*
1128 * SX ports...
1129 */
1130
1131 for (i = 0; i < 128; i ++)
1132 {
1133 sprintf(device, "/dev/ttyA%d", i + 1);
1134 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1135 {
1136 close(fd);
1137 printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n",
1138 device, i + 1);
1139 }
1140 }
1141#elif defined(__NetBSD__)
8b450588
MS
1142 int i, j; /* Looping vars */
1143 int fd; /* File descriptor */
1144 char device[255]; /* Device filename */
1145 char info[255]; /* Device info/description */
ef416fc2 1146
1147
1148 /*
1149 * Standard serial ports...
1150 */
1151
1152 for (i = 0; i < 4; i ++)
1153 {
1154 sprintf(device, "/dev/tty%02d", i);
1155 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1156 {
1157 close(fd);
8b450588
MS
1158
1159 snprintf(info, sizeof(info),
1160 _cupsLangString(cupsLangDefault(), _("Serial Port #%d")), i + 1);
1161
1162 printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", device, info);
ef416fc2 1163 }
1164 }
1165
1166 /*
1167 * Cyclades-Z ports...
1168 */
1169
1170 for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */
1171 for (j = 0; j < 64; j ++)
1172 {
1173 sprintf(device, "/dev/ttyCZ%02d%02d", i, j);
1174 if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0)
1175 {
1176 close(fd);
1177 printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Prt #%d\"\n",
1178 device, i, j + 1);
1179 }
1180 }
1181#elif defined(__APPLE__)
1182 /*
1183 * Standard serial ports on MacOS X...
1184 */
1185
1186 kern_return_t kernResult;
1187 mach_port_t masterPort;
1188 io_iterator_t serialPortIterator;
1189 CFMutableDictionaryRef classesToMatch;
1190 io_object_t serialService;
1191
ef416fc2 1192
1193 kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
1194 if (KERN_SUCCESS != kernResult)
1195 return;
1196
1197 /*
1198 * Serial devices are instances of class IOSerialBSDClient.
1199 */
1200
1201 classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
1202 if (classesToMatch != NULL)
1203 {
1204 CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey),
1205 CFSTR(kIOSerialBSDRS232Type));
1206
1207 kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch,
1208 &serialPortIterator);
1209 if (kernResult == KERN_SUCCESS)
1210 {
1211 while ((serialService = IOIteratorNext(serialPortIterator)))
1212 {
1213 CFTypeRef serialNameAsCFString;
1214 CFTypeRef bsdPathAsCFString;
1215 char serialName[128];
1216 char bsdPath[1024];
1217 Boolean result;
1218
1219
1220 serialNameAsCFString =
1221 IORegistryEntryCreateCFProperty(serialService,
1222 CFSTR(kIOTTYDeviceKey),
1223 kCFAllocatorDefault, 0);
1224 if (serialNameAsCFString)
1225 {
1226 result = CFStringGetCString(serialNameAsCFString, serialName,
1227 sizeof(serialName),
1228 kCFStringEncodingASCII);
1229 CFRelease(serialNameAsCFString);
1230
1231 if (result)
1232 {
1233 bsdPathAsCFString =
1234 IORegistryEntryCreateCFProperty(serialService,
1235 CFSTR(kIOCalloutDeviceKey),
1236 kCFAllocatorDefault, 0);
1237 if (bsdPathAsCFString)
1238 {
1239 result = CFStringGetCString(bsdPathAsCFString, bsdPath,
1240 sizeof(bsdPath),
1241 kCFStringEncodingASCII);
1242 CFRelease(bsdPathAsCFString);
1243
1244 if (result)
89d46774 1245 printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n",
1246 bsdPath, serialName);
ef416fc2 1247 }
1248 }
1249 }
1250
1251 IOObjectRelease(serialService);
1252 }
1253
89d46774 1254 /*
1255 * Release the iterator.
1256 */
1257
1258 IOObjectRelease(serialPortIterator);
ef416fc2 1259 }
1260 }
1261#endif
1262}
1263
1264
1265/*
f7deaa1a 1266 * 'side_cb()' - Handle side-channel requests...
1267 */
1268
1269static void
1270side_cb(int print_fd, /* I - Print file */
1271 int device_fd, /* I - Device file */
1272 int use_bc) /* I - Using back-channel? */
1273{
1274 cups_sc_command_t command; /* Request command */
1275 cups_sc_status_t status; /* Request/response status */
1276 char data[2048]; /* Request/response data */
1277 int datalen; /* Request/response data size */
1278
1279
1280 datalen = sizeof(data);
1281
1282 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
1283 {
db1f069b
MS
1284 _cupsLangPuts(stderr,
1285 _("WARNING: Failed to read side-channel request!\n"));
f7deaa1a 1286 return;
1287 }
1288
1289 switch (command)
1290 {
1291 case CUPS_SC_CMD_DRAIN_OUTPUT :
09a101d6 1292 if (backendDrainOutput(print_fd, device_fd))
1293 status = CUPS_SC_STATUS_IO_ERROR;
1294 else if (tcdrain(device_fd))
f7deaa1a 1295 status = CUPS_SC_STATUS_IO_ERROR;
1296 else
1297 status = CUPS_SC_STATUS_OK;
1298
1299 datalen = 0;
1300 break;
1301
1302 case CUPS_SC_CMD_GET_BIDI :
8b450588 1303 status = CUPS_SC_STATUS_OK;
f7deaa1a 1304 data[0] = use_bc;
1305 datalen = 1;
1306 break;
1307
1308 default :
1309 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
1310 datalen = 0;
1311 break;
1312 }
1313
1314 cupsSideChannelWrite(command, status, data, datalen, 1.0);
1315}
1316
1317
1318/*
75bd9771 1319 * End of "$Id: serial.c 7647 2008-06-16 17:39:40Z mike $".
ef416fc2 1320 */