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