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