]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/parallel.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / parallel.c
CommitLineData
ef416fc2 1/*
b86bc4cf 2 * "$Id: parallel.c 6181 2007-01-03 18:51:27Z mike $"
ef416fc2 3 *
4 * Parallel port backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the specified parallel port.
29 * list_devices() - List all parallel devices.
30 */
31
32/*
33 * Include necessary headers.
34 */
35
ed486911 36#include "backend-private.h"
ef416fc2 37
b423cd4c 38#ifdef __hpux
39# include <sys/time.h>
40#else
41# include <sys/select.h>
42#endif /* __hpux */
43
ef416fc2 44#ifdef WIN32
45# include <io.h>
46#else
47# include <unistd.h>
48# include <fcntl.h>
49# include <termios.h>
50# include <sys/socket.h>
51#endif /* WIN32 */
52
53#ifdef __sgi
54# include <invent.h>
55# ifndef INV_EPP_ECP_PLP
56# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */
57# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */
58# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */
59# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */
60# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */
61# endif /* !INV_EPP_ECP_PLP */
62#endif /* __sgi */
63
64
65/*
66 * Local functions...
67 */
68
69void list_devices(void);
70
71
72/*
73 * 'main()' - Send a file to the specified parallel port.
74 *
75 * Usage:
76 *
77 * printer-uri job-id user title copies options [file]
78 */
79
80int /* O - Exit status */
81main(int argc, /* I - Number of command-line arguments (6 or 7) */
82 char *argv[]) /* I - Command-line arguments */
83{
84 char method[255], /* Method in URI */
85 hostname[1024], /* Hostname */
86 username[255], /* Username info (not used) */
87 resource[1024], /* Resource info (device and options) */
88 *options; /* Pointer to options */
89 int port; /* Port number (not used) */
ed486911 90 int print_fd, /* Print file */
26d47ec6 91 device_fd, /* Parallel device */
92 use_bc; /* Read back-channel data? */
ef416fc2 93 int copies; /* Number of copies to print */
ed486911 94 size_t tbytes; /* Total number of bytes written */
ef416fc2 95 struct termios opts; /* Parallel port options */
ef416fc2 96#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
97 struct sigaction action; /* Actions for POSIX signals */
98#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
ef416fc2 99
100
101 /*
102 * Make sure status messages are not buffered...
103 */
104
105 setbuf(stderr, NULL);
106
107 /*
108 * Ignore SIGPIPE signals...
109 */
110
111#ifdef HAVE_SIGSET
112 sigset(SIGPIPE, SIG_IGN);
113#elif defined(HAVE_SIGACTION)
114 memset(&action, 0, sizeof(action));
115 action.sa_handler = SIG_IGN;
116 sigaction(SIGPIPE, &action, NULL);
117#else
118 signal(SIGPIPE, SIG_IGN);
119#endif /* HAVE_SIGSET */
120
121 /*
122 * Check command-line...
123 */
124
125 if (argc == 1)
126 {
127 list_devices();
128 return (CUPS_BACKEND_OK);
129 }
130 else if (argc < 6 || argc > 7)
131 {
132 fputs("Usage: parallel job-id user title copies options [file]\n", stderr);
133 return (CUPS_BACKEND_FAILED);
134 }
135
136 /*
137 * If we have 7 arguments, print the file named on the command-line.
138 * Otherwise, send stdin instead...
139 */
140
141 if (argc == 6)
142 {
ed486911 143 print_fd = 0;
144 copies = 1;
ef416fc2 145 }
146 else
147 {
148 /*
149 * Try to open the print file...
150 */
151
ed486911 152 if ((print_fd = open(argv[6], O_RDONLY)) < 0)
ef416fc2 153 {
154 perror("ERROR: unable to open print file");
155 return (CUPS_BACKEND_FAILED);
156 }
157
158 copies = atoi(argv[4]);
159 }
160
161 /*
162 * Extract the device name and options from the URI...
163 */
164
a4d04587 165 httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
166 method, sizeof(method), username, sizeof(username),
167 hostname, sizeof(hostname), &port,
ef416fc2 168 resource, sizeof(resource));
169
170 /*
171 * See if there are any options...
172 */
173
174 if ((options = strchr(resource, '?')) != NULL)
175 {
176 /*
177 * Yup, terminate the device name string and move to the first
178 * character of the options...
179 */
180
181 *options++ = '\0';
182 }
183
184 /*
185 * Open the parallel port device...
186 */
187
757d2cad 188 fputs("STATE: +connecting-to-device\n", stderr);
189
ef416fc2 190 do
191 {
b86bc4cf 192#if defined(__linux) || defined(__FreeBSD__)
26d47ec6 193 /*
b86bc4cf 194 * The Linux and FreeBSD parallel port drivers currently are broken WRT
195 * select() and bidirection I/O...
26d47ec6 196 */
197
198 device_fd = open(resource, O_WRONLY | O_EXCL);
199 use_bc = 0;
200
201#else
202 if ((device_fd = open(resource, O_RDWR | O_EXCL)) < 0)
203 {
204 device_fd = open(resource, O_WRONLY | O_EXCL);
205 use_bc = 0;
206 }
207 else
208 use_bc = 1;
b86bc4cf 209#endif /* __linux || __FreeBSD__ */
26d47ec6 210
211 if (device_fd == -1)
ef416fc2 212 {
213 if (getenv("CLASS") != NULL)
214 {
215 /*
216 * If the CLASS environment variable is set, the job was submitted
217 * to a class and not to a specific queue. In this case, we want
218 * to abort immediately so that the job can be requeued on the next
219 * available printer in the class.
220 */
221
ed486911 222 fputs("INFO: Unable to open parallel port, queuing on next printer "
223 "in class...\n", stderr);
ef416fc2 224
225 /*
226 * Sleep 5 seconds to keep the job from requeuing too rapidly...
227 */
228
229 sleep(5);
230
231 return (CUPS_BACKEND_FAILED);
232 }
233
234 if (errno == EBUSY)
235 {
ed486911 236 fputs("INFO: Parallel port busy; will retry in 30 seconds...\n",
237 stderr);
ef416fc2 238 sleep(30);
239 }
240 else if (errno == ENXIO || errno == EIO || errno == ENOENT)
241 {
ed486911 242 fputs("INFO: Printer not connected; will retry in 30 seconds...\n",
243 stderr);
ef416fc2 244 sleep(30);
245 }
246 else
247 {
ed486911 248 fprintf(stderr,
249 "ERROR: Unable to open parallel port device file \"%s\": %s\n",
ef416fc2 250 resource, strerror(errno));
251 return (CUPS_BACKEND_FAILED);
252 }
253 }
254 }
ed486911 255 while (device_fd < 0);
ef416fc2 256
757d2cad 257 fputs("STATE: -connecting-to-device\n", stderr);
258
ef416fc2 259 /*
260 * Set any options provided...
261 */
262
ed486911 263 tcgetattr(device_fd, &opts);
ef416fc2 264
265 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
266
267 /**** No options supported yet ****/
268
ed486911 269 tcsetattr(device_fd, TCSANOW, &opts);
ef416fc2 270
ef416fc2 271 /*
272 * Finally, send the print file...
273 */
274
ed486911 275 tbytes = 0;
ef416fc2 276
ed486911 277 while (copies > 0 && tbytes >= 0)
ef416fc2 278 {
279 copies --;
280
ed486911 281 if (print_fd != 0)
ef416fc2 282 {
283 fputs("PAGE: 1 1\n", stderr);
ed486911 284 lseek(print_fd, 0, SEEK_SET);
ef416fc2 285 }
286
26d47ec6 287 tbytes = backendRunLoop(print_fd, device_fd, use_bc);
ef416fc2 288
ed486911 289 if (print_fd != 0 && tbytes >= 0)
290 fprintf(stderr, "INFO: Sent print file, " CUPS_LLFMT " bytes...\n",
291 CUPS_LLCAST tbytes);
ef416fc2 292 }
293
294 /*
295 * Close the socket connection and input file and return...
296 */
297
ed486911 298 close(device_fd);
299
300 if (print_fd != 0)
301 close(print_fd);
ef416fc2 302
ed486911 303 return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
ef416fc2 304}
305
306
307/*
308 * 'list_devices()' - List all parallel devices.
309 */
310
311void
312list_devices(void)
313{
314#if defined(__hpux) || defined(__sgi) || defined(__sun)
315 static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
316 /* Funky hex numbering used for some devices */
317#endif /* __hpux || __sgi || __sun */
318
319#ifdef __linux
320 int i; /* Looping var */
321 int fd; /* File descriptor */
322 char device[255], /* Device filename */
323 basedevice[255], /* Base device filename for ports */
324 device_id[1024], /* Device ID string */
325 make_model[1024]; /* Make and model */
326
327
328 if (!access("/dev/parallel/", 0))
329 strcpy(basedevice, "/dev/parallel/");
330 else if (!access("/dev/printers/", 0))
331 strcpy(basedevice, "/dev/printers/");
ef416fc2 332 else
333 strcpy(basedevice, "/dev/lp");
334
335 for (i = 0; i < 4; i ++)
336 {
337 /*
338 * Open the port, if available...
339 */
340
341 sprintf(device, "%s%d", basedevice, i);
342 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
343 fd = open(device, O_WRONLY);
344
345 if (fd >= 0)
346 {
347 /*
348 * Now grab the IEEE 1284 device ID string...
349 */
350
ed486911 351 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
352 make_model, sizeof(make_model),
353 NULL, NULL, 0))
ef416fc2 354 printf("direct parallel:%s \"%s\" \"%s LPT #%d\" \"%s\"\n", device,
355 make_model, make_model, i + 1, device_id);
356 else
357 printf("direct parallel:%s \"Unknown\" \"LPT #%d\"\n", device, i + 1);
358
359 close(fd);
360 }
361 }
362#elif defined(__sgi)
363 int i, j, n; /* Looping vars */
364 char device[255]; /* Device filename */
365 inventory_t *inv; /* Hardware inventory info */
366
367
368 /*
369 * IRIX maintains a hardware inventory of most devices...
370 */
371
372 setinvent();
373
374 while ((inv = getinvent()) != NULL)
375 {
376 if (inv->inv_class == INV_PARALLEL &&
377 (inv->inv_type == INV_ONBOARD_PLP ||
378 inv->inv_type == INV_EPP_ECP_PLP))
379 {
380 /*
381 * Standard parallel port...
382 */
383
384 puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\"");
385 }
386 else if (inv->inv_class == INV_PARALLEL &&
387 inv->inv_type == INV_EPC_PLP)
388 {
389 /*
390 * EPC parallel port...
391 */
392
393 printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n",
394 inv->inv_controller, inv->inv_controller);
395 }
396 }
397
398 endinvent();
399
400 /*
401 * Central Data makes serial and parallel "servers" that can be
402 * connected in a number of ways. Look for ports...
403 */
404
405 for (i = 0; i < 10; i ++)
406 for (j = 0; j < 8; j ++)
407 for (n = 0; n < 32; n ++)
408 {
409 if (i == 8) /* EtherLite */
410 sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]);
411 else if (i == 9) /* PCI */
412 sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]);
413 else /* SCSI */
414 sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]);
415
416 if (access(device, 0) == 0)
417 {
418 if (i == 8)
419 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
420 device, j, n);
421 else if (i == 9)
422 printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n",
423 device, j, n);
424 else
425 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
426 device, i, j, n);
427 }
428 }
429#elif defined(__sun)
430 int i, j, n; /* Looping vars */
431 char device[255]; /* Device filename */
432
433
434 /*
435 * Standard parallel ports...
436 */
437
438 for (i = 0; i < 10; i ++)
439 {
440 sprintf(device, "/dev/ecpp%d", i);
441 if (access(device, 0) == 0)
442 printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n",
443 device, i + 1);
444 }
445
446 for (i = 0; i < 10; i ++)
447 {
448 sprintf(device, "/dev/bpp%d", i);
449 if (access(device, 0) == 0)
450 printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n",
451 device, i + 1);
452 }
453
454 for (i = 0; i < 3; i ++)
455 {
456 sprintf(device, "/dev/lp%d", i);
457
458 if (access(device, 0) == 0)
459 printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n",
460 device, i + 1);
461 }
462
463 /*
464 * MAGMA parallel ports...
465 */
466
467 for (i = 0; i < 40; i ++)
468 {
469 sprintf(device, "/dev/pm%02d", i);
470 if (access(device, 0) == 0)
471 printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n",
472 device, (i / 10) + 1, (i % 10) + 1);
473 }
474
475 /*
476 * Central Data parallel ports...
477 */
478
479 for (i = 0; i < 9; i ++)
480 for (j = 0; j < 8; j ++)
481 for (n = 0; n < 32; n ++)
482 {
483 if (i == 8) /* EtherLite */
484 sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]);
485 else
486 sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j,
487 funky_hex[n]);
488
489 if (access(device, 0) == 0)
490 {
491 if (i == 8)
492 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
493 device, j, n);
494 else
495 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
496 device, i, j, n);
497 }
498 }
499#elif defined(__hpux)
500 int i, j, n; /* Looping vars */
501 char device[255]; /* Device filename */
502
503
504 /*
505 * Standard parallel ports...
506 */
507
508 if (access("/dev/rlp", 0) == 0)
509 puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\"");
510
511 for (i = 0; i < 7; i ++)
512 for (j = 0; j < 7; j ++)
513 {
514 sprintf(device, "/dev/c%dt%dd0_lp", i, j);
515 if (access(device, 0) == 0)
516 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n",
517 device, i, j);
518 }
519
520 /*
521 * Central Data parallel ports...
522 */
523
524 for (i = 0; i < 9; i ++)
525 for (j = 0; j < 8; j ++)
526 for (n = 0; n < 32; n ++)
527 {
528 if (i == 8) /* EtherLite */
529 sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]);
530 else
531 sprintf(device, "/dev/lp%c%d%c", i + 'C', j,
532 funky_hex[n]);
533
534 if (access(device, 0) == 0)
535 {
536 if (i == 8)
537 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
538 device, j, n);
539 else
540 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
541 device, i, j, n);
542 }
543 }
544#elif defined(__osf__)
545 int i; /* Looping var */
546 int fd; /* File descriptor */
547 char device[255]; /* Device filename */
548
549
550 for (i = 0; i < 3; i ++)
551 {
552 sprintf(device, "/dev/lp%d", i);
553 if ((fd = open(device, O_WRONLY)) >= 0)
554 {
555 close(fd);
556 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
557 }
558 }
b423cd4c 559#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
ef416fc2 560 int i; /* Looping var */
561 int fd; /* File descriptor */
562 char device[255]; /* Device filename */
563
564
565 for (i = 0; i < 3; i ++)
566 {
567 sprintf(device, "/dev/lpt%d", i);
568 if ((fd = open(device, O_WRONLY)) >= 0)
569 {
570 close(fd);
571 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (interrupt-driven)\"\n", device, i + 1);
572 }
573
574 sprintf(device, "/dev/lpa%d", i);
575 if ((fd = open(device, O_WRONLY)) >= 0)
576 {
577 close(fd);
578 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
579 }
580 }
581#elif defined(_AIX)
582 int i; /* Looping var */
583 int fd; /* File descriptor */
584 char device[255]; /* Device filename */
585
586
587 for (i = 0; i < 8; i ++)
588 {
589 sprintf(device, "/dev/lp%d", i);
590 if ((fd = open(device, O_WRONLY)) >= 0)
591 {
592 close(fd);
593 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
594 }
595 }
596#endif
597}
598
599
600/*
b86bc4cf 601 * End of "$Id: parallel.c 6181 2007-01-03 18:51:27Z mike $".
ef416fc2 602 */