]> 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/*
8ca02f3c 2 * "$Id: parallel.c 5726 2006-07-12 20:00:11Z 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 */
91 device_fd; /* Parallel device */
ef416fc2 92 int copies; /* Number of copies to print */
ed486911 93 size_t tbytes; /* Total number of bytes written */
ef416fc2 94 struct termios opts; /* Parallel port options */
ef416fc2 95#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
96 struct sigaction action; /* Actions for POSIX signals */
97#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
ef416fc2 98
99
100 /*
101 * Make sure status messages are not buffered...
102 */
103
104 setbuf(stderr, NULL);
105
106 /*
107 * Ignore SIGPIPE signals...
108 */
109
110#ifdef HAVE_SIGSET
111 sigset(SIGPIPE, SIG_IGN);
112#elif defined(HAVE_SIGACTION)
113 memset(&action, 0, sizeof(action));
114 action.sa_handler = SIG_IGN;
115 sigaction(SIGPIPE, &action, NULL);
116#else
117 signal(SIGPIPE, SIG_IGN);
118#endif /* HAVE_SIGSET */
119
120 /*
121 * Check command-line...
122 */
123
124 if (argc == 1)
125 {
126 list_devices();
127 return (CUPS_BACKEND_OK);
128 }
129 else if (argc < 6 || argc > 7)
130 {
131 fputs("Usage: parallel job-id user title copies options [file]\n", stderr);
132 return (CUPS_BACKEND_FAILED);
133 }
134
135 /*
136 * If we have 7 arguments, print the file named on the command-line.
137 * Otherwise, send stdin instead...
138 */
139
140 if (argc == 6)
141 {
ed486911 142 print_fd = 0;
143 copies = 1;
ef416fc2 144 }
145 else
146 {
147 /*
148 * Try to open the print file...
149 */
150
ed486911 151 if ((print_fd = open(argv[6], O_RDONLY)) < 0)
ef416fc2 152 {
153 perror("ERROR: unable to open print file");
154 return (CUPS_BACKEND_FAILED);
155 }
156
157 copies = atoi(argv[4]);
158 }
159
160 /*
161 * Extract the device name and options from the URI...
162 */
163
a4d04587 164 httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
165 method, sizeof(method), username, sizeof(username),
166 hostname, sizeof(hostname), &port,
ef416fc2 167 resource, sizeof(resource));
168
169 /*
170 * See if there are any options...
171 */
172
173 if ((options = strchr(resource, '?')) != NULL)
174 {
175 /*
176 * Yup, terminate the device name string and move to the first
177 * character of the options...
178 */
179
180 *options++ = '\0';
181 }
182
183 /*
184 * Open the parallel port device...
185 */
186
757d2cad 187 fputs("STATE: +connecting-to-device\n", stderr);
188
ef416fc2 189 do
190 {
ed486911 191 if ((device_fd = open(resource, O_WRONLY | O_EXCL)) == -1)
ef416fc2 192 {
193 if (getenv("CLASS") != NULL)
194 {
195 /*
196 * If the CLASS environment variable is set, the job was submitted
197 * to a class and not to a specific queue. In this case, we want
198 * to abort immediately so that the job can be requeued on the next
199 * available printer in the class.
200 */
201
ed486911 202 fputs("INFO: Unable to open parallel port, queuing on next printer "
203 "in class...\n", stderr);
ef416fc2 204
205 /*
206 * Sleep 5 seconds to keep the job from requeuing too rapidly...
207 */
208
209 sleep(5);
210
211 return (CUPS_BACKEND_FAILED);
212 }
213
214 if (errno == EBUSY)
215 {
ed486911 216 fputs("INFO: Parallel port busy; will retry in 30 seconds...\n",
217 stderr);
ef416fc2 218 sleep(30);
219 }
220 else if (errno == ENXIO || errno == EIO || errno == ENOENT)
221 {
ed486911 222 fputs("INFO: Printer not connected; will retry in 30 seconds...\n",
223 stderr);
ef416fc2 224 sleep(30);
225 }
226 else
227 {
ed486911 228 fprintf(stderr,
229 "ERROR: Unable to open parallel port device file \"%s\": %s\n",
ef416fc2 230 resource, strerror(errno));
231 return (CUPS_BACKEND_FAILED);
232 }
233 }
234 }
ed486911 235 while (device_fd < 0);
ef416fc2 236
757d2cad 237 fputs("STATE: -connecting-to-device\n", stderr);
238
ef416fc2 239 /*
240 * Set any options provided...
241 */
242
ed486911 243 tcgetattr(device_fd, &opts);
ef416fc2 244
245 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
246
247 /**** No options supported yet ****/
248
ed486911 249 tcsetattr(device_fd, TCSANOW, &opts);
ef416fc2 250
ef416fc2 251 /*
252 * Finally, send the print file...
253 */
254
ed486911 255 tbytes = 0;
ef416fc2 256
ed486911 257 while (copies > 0 && tbytes >= 0)
ef416fc2 258 {
259 copies --;
260
ed486911 261 if (print_fd != 0)
ef416fc2 262 {
263 fputs("PAGE: 1 1\n", stderr);
ed486911 264 lseek(print_fd, 0, SEEK_SET);
ef416fc2 265 }
266
ed486911 267 tbytes = backendRunLoop(print_fd, device_fd, 1);
ef416fc2 268
ed486911 269 if (print_fd != 0 && tbytes >= 0)
270 fprintf(stderr, "INFO: Sent print file, " CUPS_LLFMT " bytes...\n",
271 CUPS_LLCAST tbytes);
ef416fc2 272 }
273
274 /*
275 * Close the socket connection and input file and return...
276 */
277
ed486911 278 close(device_fd);
279
280 if (print_fd != 0)
281 close(print_fd);
ef416fc2 282
ed486911 283 return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
ef416fc2 284}
285
286
287/*
288 * 'list_devices()' - List all parallel devices.
289 */
290
291void
292list_devices(void)
293{
294#if defined(__hpux) || defined(__sgi) || defined(__sun)
295 static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
296 /* Funky hex numbering used for some devices */
297#endif /* __hpux || __sgi || __sun */
298
299#ifdef __linux
300 int i; /* Looping var */
301 int fd; /* File descriptor */
302 char device[255], /* Device filename */
303 basedevice[255], /* Base device filename for ports */
304 device_id[1024], /* Device ID string */
305 make_model[1024]; /* Make and model */
306
307
308 if (!access("/dev/parallel/", 0))
309 strcpy(basedevice, "/dev/parallel/");
310 else if (!access("/dev/printers/", 0))
311 strcpy(basedevice, "/dev/printers/");
ef416fc2 312 else
313 strcpy(basedevice, "/dev/lp");
314
315 for (i = 0; i < 4; i ++)
316 {
317 /*
318 * Open the port, if available...
319 */
320
321 sprintf(device, "%s%d", basedevice, i);
322 if ((fd = open(device, O_RDWR | O_EXCL)) < 0)
323 fd = open(device, O_WRONLY);
324
325 if (fd >= 0)
326 {
327 /*
328 * Now grab the IEEE 1284 device ID string...
329 */
330
ed486911 331 if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
332 make_model, sizeof(make_model),
333 NULL, NULL, 0))
ef416fc2 334 printf("direct parallel:%s \"%s\" \"%s LPT #%d\" \"%s\"\n", device,
335 make_model, make_model, i + 1, device_id);
336 else
337 printf("direct parallel:%s \"Unknown\" \"LPT #%d\"\n", device, i + 1);
338
339 close(fd);
340 }
341 }
342#elif defined(__sgi)
343 int i, j, n; /* Looping vars */
344 char device[255]; /* Device filename */
345 inventory_t *inv; /* Hardware inventory info */
346
347
348 /*
349 * IRIX maintains a hardware inventory of most devices...
350 */
351
352 setinvent();
353
354 while ((inv = getinvent()) != NULL)
355 {
356 if (inv->inv_class == INV_PARALLEL &&
357 (inv->inv_type == INV_ONBOARD_PLP ||
358 inv->inv_type == INV_EPP_ECP_PLP))
359 {
360 /*
361 * Standard parallel port...
362 */
363
364 puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\"");
365 }
366 else if (inv->inv_class == INV_PARALLEL &&
367 inv->inv_type == INV_EPC_PLP)
368 {
369 /*
370 * EPC parallel port...
371 */
372
373 printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n",
374 inv->inv_controller, inv->inv_controller);
375 }
376 }
377
378 endinvent();
379
380 /*
381 * Central Data makes serial and parallel "servers" that can be
382 * connected in a number of ways. Look for ports...
383 */
384
385 for (i = 0; i < 10; i ++)
386 for (j = 0; j < 8; j ++)
387 for (n = 0; n < 32; n ++)
388 {
389 if (i == 8) /* EtherLite */
390 sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]);
391 else if (i == 9) /* PCI */
392 sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]);
393 else /* SCSI */
394 sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]);
395
396 if (access(device, 0) == 0)
397 {
398 if (i == 8)
399 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
400 device, j, n);
401 else if (i == 9)
402 printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n",
403 device, j, n);
404 else
405 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
406 device, i, j, n);
407 }
408 }
409#elif defined(__sun)
410 int i, j, n; /* Looping vars */
411 char device[255]; /* Device filename */
412
413
414 /*
415 * Standard parallel ports...
416 */
417
418 for (i = 0; i < 10; i ++)
419 {
420 sprintf(device, "/dev/ecpp%d", i);
421 if (access(device, 0) == 0)
422 printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n",
423 device, i + 1);
424 }
425
426 for (i = 0; i < 10; i ++)
427 {
428 sprintf(device, "/dev/bpp%d", i);
429 if (access(device, 0) == 0)
430 printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n",
431 device, i + 1);
432 }
433
434 for (i = 0; i < 3; i ++)
435 {
436 sprintf(device, "/dev/lp%d", i);
437
438 if (access(device, 0) == 0)
439 printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n",
440 device, i + 1);
441 }
442
443 /*
444 * MAGMA parallel ports...
445 */
446
447 for (i = 0; i < 40; i ++)
448 {
449 sprintf(device, "/dev/pm%02d", i);
450 if (access(device, 0) == 0)
451 printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n",
452 device, (i / 10) + 1, (i % 10) + 1);
453 }
454
455 /*
456 * Central Data parallel ports...
457 */
458
459 for (i = 0; i < 9; i ++)
460 for (j = 0; j < 8; j ++)
461 for (n = 0; n < 32; n ++)
462 {
463 if (i == 8) /* EtherLite */
464 sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]);
465 else
466 sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j,
467 funky_hex[n]);
468
469 if (access(device, 0) == 0)
470 {
471 if (i == 8)
472 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
473 device, j, n);
474 else
475 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
476 device, i, j, n);
477 }
478 }
479#elif defined(__hpux)
480 int i, j, n; /* Looping vars */
481 char device[255]; /* Device filename */
482
483
484 /*
485 * Standard parallel ports...
486 */
487
488 if (access("/dev/rlp", 0) == 0)
489 puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\"");
490
491 for (i = 0; i < 7; i ++)
492 for (j = 0; j < 7; j ++)
493 {
494 sprintf(device, "/dev/c%dt%dd0_lp", i, j);
495 if (access(device, 0) == 0)
496 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n",
497 device, i, j);
498 }
499
500 /*
501 * Central Data parallel ports...
502 */
503
504 for (i = 0; i < 9; i ++)
505 for (j = 0; j < 8; j ++)
506 for (n = 0; n < 32; n ++)
507 {
508 if (i == 8) /* EtherLite */
509 sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]);
510 else
511 sprintf(device, "/dev/lp%c%d%c", i + 'C', j,
512 funky_hex[n]);
513
514 if (access(device, 0) == 0)
515 {
516 if (i == 8)
517 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
518 device, j, n);
519 else
520 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
521 device, i, j, n);
522 }
523 }
524#elif defined(__osf__)
525 int i; /* Looping var */
526 int fd; /* File descriptor */
527 char device[255]; /* Device filename */
528
529
530 for (i = 0; i < 3; i ++)
531 {
532 sprintf(device, "/dev/lp%d", i);
533 if ((fd = open(device, O_WRONLY)) >= 0)
534 {
535 close(fd);
536 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
537 }
538 }
b423cd4c 539#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
ef416fc2 540 int i; /* Looping var */
541 int fd; /* File descriptor */
542 char device[255]; /* Device filename */
543
544
545 for (i = 0; i < 3; i ++)
546 {
547 sprintf(device, "/dev/lpt%d", i);
548 if ((fd = open(device, O_WRONLY)) >= 0)
549 {
550 close(fd);
551 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (interrupt-driven)\"\n", device, i + 1);
552 }
553
554 sprintf(device, "/dev/lpa%d", i);
555 if ((fd = open(device, O_WRONLY)) >= 0)
556 {
557 close(fd);
558 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
559 }
560 }
561#elif defined(_AIX)
562 int i; /* Looping var */
563 int fd; /* File descriptor */
564 char device[255]; /* Device filename */
565
566
567 for (i = 0; i < 8; i ++)
568 {
569 sprintf(device, "/dev/lp%d", i);
570 if ((fd = open(device, O_WRONLY)) >= 0)
571 {
572 close(fd);
573 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
574 }
575 }
576#endif
577}
578
579
580/*
8ca02f3c 581 * End of "$Id: parallel.c 5726 2006-07-12 20:00:11Z mike $".
ef416fc2 582 */