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