]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/parallel.c
16fe63990c7d09277ef7666df16a2beef8f627d1
[thirdparty/cups.git] / backend / parallel.c
1 /*
2 * "$Id: parallel.c,v 1.41 2002/03/25 17:13:55 mike Exp $"
3 *
4 * Parallel port backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 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-3111 USA
19 *
20 * Voice: (301) 373-9603
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
36 #include <cups/cups.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <cups/string.h>
41 #include <signal.h>
42
43 #ifdef WIN32
44 # include <io.h>
45 #else
46 # include <unistd.h>
47 # include <fcntl.h>
48 # include <termios.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
63 /*
64 * Local functions...
65 */
66
67 void list_devices(void);
68
69
70 /*
71 * 'main()' - Send a file to the specified parallel port.
72 *
73 * Usage:
74 *
75 * printer-uri job-id user title copies options [file]
76 */
77
78 int /* O - Exit status */
79 main(int argc, /* I - Number of command-line arguments (6 or 7) */
80 char *argv[]) /* I - Command-line arguments */
81 {
82 char method[255], /* Method in URI */
83 hostname[1024], /* Hostname */
84 username[255], /* Username info (not used) */
85 resource[1024], /* Resource info (device and options) */
86 *options; /* Pointer to options */
87 int port; /* Port number (not used) */
88 int fp; /* Print file */
89 int copies; /* Number of copies to print */
90 int fd; /* Parallel device */
91 int wbytes; /* Number of bytes written */
92 size_t nbytes, /* Number of bytes read */
93 tbytes; /* Total number of bytes written */
94 char buffer[8192], /* Output buffer */
95 *bufptr; /* Pointer into buffer */
96 struct termios opts; /* Parallel port options */
97 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
98 struct sigaction action; /* Actions for POSIX signals */
99 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
100
101
102 /*
103 * Make sure status messages are not buffered...
104 */
105
106 setbuf(stderr, NULL);
107
108 /*
109 * Check command-line...
110 */
111
112 if (argc == 1)
113 {
114 list_devices();
115 return (0);
116 }
117 else if (argc < 6 || argc > 7)
118 {
119 fputs("Usage: parallel job-id user title copies options [file]\n", stderr);
120 return (1);
121 }
122
123 /*
124 * If we have 7 arguments, print the file named on the command-line.
125 * Otherwise, send stdin instead...
126 */
127
128 if (argc == 6)
129 {
130 fp = 0;
131 copies = 1;
132 }
133 else
134 {
135 /*
136 * Try to open the print file...
137 */
138
139 if ((fp = open(argv[6], O_RDONLY)) < 0)
140 {
141 perror("ERROR: unable to open print file");
142 return (1);
143 }
144
145 copies = atoi(argv[4]);
146 }
147
148 /*
149 * Extract the device name and options from the URI...
150 */
151
152 httpSeparate(argv[0], method, username, hostname, &port, resource);
153
154 /*
155 * See if there are any options...
156 */
157
158 if ((options = strchr(resource, '?')) != NULL)
159 {
160 /*
161 * Yup, terminate the device name string and move to the first
162 * character of the options...
163 */
164
165 *options++ = '\0';
166 }
167
168 /*
169 * Open the parallel port device...
170 */
171
172 do
173 {
174 if ((fd = open(resource, O_WRONLY | O_EXCL)) == -1)
175 {
176 if (errno == EBUSY)
177 {
178 fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr);
179 sleep(30);
180 }
181 else if (errno == ENXIO || errno == EIO)
182 {
183 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
184 sleep(30);
185 }
186 else
187 {
188 fprintf(stderr, "ERROR: Unable to open parallel port device file \"%s\": %s\n",
189 resource, strerror(errno));
190 return (1);
191 }
192 }
193 }
194 while (fd < 0);
195
196 /*
197 * Set any options provided...
198 */
199
200 tcgetattr(fd, &opts);
201
202 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
203
204 /**** No options supported yet ****/
205
206 tcsetattr(fd, TCSANOW, &opts);
207
208 /*
209 * Now that we are "connected" to the port, ignore SIGTERM so that we
210 * can finish out any page data the driver sends (e.g. to eject the
211 * current page... Only ignore SIGTERM if we are printing data from
212 * stdin (otherwise you can't cancel raw jobs...)
213 */
214
215 if (argc < 7)
216 {
217 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
218 sigset(SIGTERM, SIG_IGN);
219 #elif defined(HAVE_SIGACTION)
220 memset(&action, 0, sizeof(action));
221
222 sigemptyset(&action.sa_mask);
223 action.sa_handler = SIG_IGN;
224 sigaction(SIGTERM, &action, NULL);
225 #else
226 signal(SIGTERM, SIG_IGN);
227 #endif /* HAVE_SIGSET */
228 }
229
230 /*
231 * Finally, send the print file...
232 */
233
234 while (copies > 0)
235 {
236 copies --;
237
238 if (fp != 0)
239 {
240 fputs("PAGE: 1 1\n", stderr);
241 lseek(fp, 0, SEEK_SET);
242 }
243
244 tbytes = 0;
245 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
246 {
247 /*
248 * Write the print data to the printer...
249 */
250
251 tbytes += nbytes;
252 bufptr = buffer;
253
254 while (nbytes > 0)
255 {
256 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
257 if (errno == ENOTTY)
258 wbytes = write(fd, bufptr, nbytes);
259
260 if (wbytes < 0)
261 {
262 perror("ERROR: Unable to send print file to printer");
263 break;
264 }
265
266 nbytes -= wbytes;
267 bufptr += wbytes;
268 }
269
270 if (argc > 6)
271 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
272 (unsigned long)tbytes);
273 }
274 }
275
276 /*
277 * Close the socket connection and input file and return...
278 */
279
280 close(fd);
281 if (fp != 0)
282 close(fp);
283
284 fputs("INFO: Ready to print.\n", stderr);
285
286 return (0);
287 }
288
289
290 /*
291 * 'list_devices()' - List all parallel devices.
292 */
293
294 void
295 list_devices(void)
296 {
297 #if defined(__hpux) || defined(__sgi) || defined(__sun)
298 static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz";
299 /* Funky hex numbering used for some devices */
300 #endif /* __hpux || __sgi || __sun */
301
302 #ifdef __linux
303 int i; /* Looping var */
304 int fd; /* File descriptor */
305 char device[255], /* Device filename */
306 probefile[255], /* Probe filename */
307 basedevice[255]; /* Base device filename for ports */
308 FILE *probe; /* /proc/parport/n/autoprobe file */
309 char line[1024], /* Line from file */
310 *delim, /* Delimiter in file */
311 make[IPP_MAX_NAME], /* Make from file */
312 model[IPP_MAX_NAME]; /* Model from file */
313
314
315 for (i = 0; i < 4; i ++)
316 {
317 /*
318 * First open the device to make sure the driver module is loaded...
319 */
320
321 if ((fd = open("/dev/parallel/0", O_WRONLY)) >= 0)
322 {
323 close(fd);
324 strcpy(basedevice, "/dev/parallel/");
325 }
326 else
327 {
328 sprintf(device, "/dev/lp%d", i);
329 if ((fd = open(device, O_WRONLY)) >= 0)
330 {
331 close(fd);
332 strcpy(basedevice, "/dev/lp");
333 }
334 else
335 {
336 sprintf(device, "/dev/par%d", i);
337 if ((fd = open(device, O_WRONLY)) >= 0)
338 {
339 close(fd);
340 strcpy(basedevice, "/dev/par");
341 }
342 else
343 {
344 sprintf(device, "/dev/printers/%d", i);
345 if ((fd = open(device, O_WRONLY)) >= 0)
346 {
347 close(fd);
348 strcpy(basedevice, "/dev/printers/");
349 }
350 else
351 strcpy(basedevice, "/dev/unknown-parallel");
352 }
353 }
354 }
355
356 /*
357 * Then try looking at the probe file...
358 */
359
360 sprintf(probefile, "/proc/parport/%d/autoprobe", i);
361 if ((probe = fopen(probefile, "r")) == NULL)
362 {
363 /*
364 * Linux 2.4 kernel has different path...
365 */
366
367 sprintf(probefile, "/proc/sys/dev/parport/parport%d/autoprobe", i);
368 probe = fopen(probefile, "r");
369 }
370
371 if (probe != NULL)
372 {
373 /*
374 * Found a probe file!
375 */
376
377 memset(make, 0, sizeof(make));
378 memset(model, 0, sizeof(model));
379 strcpy(model, "Unknown");
380
381 while (fgets(line, sizeof(line), probe) != NULL)
382 {
383 /*
384 * Strip trailing ; and/or newline.
385 */
386
387 if ((delim = strrchr(line, ';')) != NULL)
388 *delim = '\0';
389 else if ((delim = strrchr(line, '\n')) != NULL)
390 *delim = '\0';
391
392 /*
393 * Look for MODEL and MANUFACTURER lines...
394 */
395
396 if (strncmp(line, "MODEL:", 6) == 0 &&
397 strncmp(line, "MODEL:Unknown", 13) != 0)
398 strncpy(model, line + 6, sizeof(model) - 1);
399 else if (strncmp(line, "MANUFACTURER:", 13) == 0 &&
400 strncmp(line, "MANUFACTURER:Unknown", 20) != 0)
401 strncpy(make, line + 13, sizeof(make) - 1);
402 }
403
404 fclose(probe);
405
406 if (make[0])
407 printf("direct parallel:%s%d \"%s %s\" \"Parallel Port #%d\"\n",
408 basedevice, i, make, model, i + 1);
409 else
410 printf("direct parallel:%s%d \"%s\" \"Parallel Port #%d\"\n",
411 basedevice, i, model, i + 1);
412 }
413 else if (fd >= 0)
414 {
415 /*
416 * No probe file, but we know the port is there...
417 */
418
419 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
420 }
421 }
422 #elif defined(__sgi)
423 int i, j, n; /* Looping vars */
424 char device[255]; /* Device filename */
425 inventory_t *inv; /* Hardware inventory info */
426
427
428 /*
429 * IRIX maintains a hardware inventory of most devices...
430 */
431
432 setinvent();
433
434 while ((inv = getinvent()) != NULL)
435 {
436 if (inv->inv_class == INV_PARALLEL &&
437 (inv->inv_type == INV_ONBOARD_PLP ||
438 inv->inv_type == INV_EPP_ECP_PLP))
439 {
440 /*
441 * Standard parallel port...
442 */
443
444 puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\"");
445 }
446 else if (inv->inv_class == INV_PARALLEL &&
447 inv->inv_type == INV_EPC_PLP)
448 {
449 /*
450 * EPC parallel port...
451 */
452
453 printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n",
454 inv->inv_controller, inv->inv_controller);
455 }
456 }
457
458 endinvent();
459
460 /*
461 * Central Data makes serial and parallel "servers" that can be
462 * connected in a number of ways. Look for ports...
463 */
464
465 for (i = 0; i < 10; i ++)
466 for (j = 0; j < 8; j ++)
467 for (n = 0; n < 32; n ++)
468 {
469 if (i == 8) /* EtherLite */
470 sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]);
471 else if (i == 9) /* PCI */
472 sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]);
473 else /* SCSI */
474 sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]);
475
476 if (access(device, 0) == 0)
477 {
478 if (i == 8)
479 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
480 device, j, n);
481 else if (i == 9)
482 printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n",
483 device, j, n);
484 else
485 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
486 device, i, j, n);
487 }
488 }
489 #elif defined(__sun)
490 int i, j, n; /* Looping vars */
491 char device[255]; /* Device filename */
492
493
494 /*
495 * Standard parallel ports...
496 */
497
498 for (i = 0; i < 10; i ++)
499 {
500 sprintf(device, "/dev/ecpp%d", i);
501 if (access(device, 0) == 0)
502 printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n",
503 device, i + 1);
504 }
505
506 for (i = 0; i < 10; i ++)
507 {
508 sprintf(device, "/dev/bpp%d", i);
509 if (access(device, 0) == 0)
510 printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n",
511 device, i + 1);
512 }
513
514 for (i = 0; i < 3; i ++)
515 {
516 sprintf(device, "/dev/lp%d", i);
517
518 if (access(device, 0) == 0)
519 printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n",
520 device, i + 1);
521 }
522
523 /*
524 * MAGMA parallel ports...
525 */
526
527 for (i = 0; i < 40; i ++)
528 {
529 sprintf(device, "/dev/pm%02d", i);
530 if (access(device, 0) == 0)
531 printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n",
532 device, (i / 10) + 1, (i % 10) + 1);
533 }
534
535 /*
536 * Central Data parallel ports...
537 */
538
539 for (i = 0; i < 9; i ++)
540 for (j = 0; j < 8; j ++)
541 for (n = 0; n < 32; n ++)
542 {
543 if (i == 8) /* EtherLite */
544 sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]);
545 else
546 sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j,
547 funky_hex[n]);
548
549 if (access(device, 0) == 0)
550 {
551 if (i == 8)
552 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
553 device, j, n);
554 else
555 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
556 device, i, j, n);
557 }
558 }
559 #elif defined(__hpux)
560 int i, j, n; /* Looping vars */
561 char device[255]; /* Device filename */
562
563
564 /*
565 * Standard parallel ports...
566 */
567
568 if (access("/dev/rlp", 0) == 0)
569 puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\"");
570
571 for (i = 0; i < 7; i ++)
572 for (j = 0; j < 7; j ++)
573 {
574 sprintf(device, "/dev/c%dt%dd0_lp", i, j);
575 if (access(device, 0) == 0)
576 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n",
577 device, i, j);
578 }
579
580 /*
581 * Central Data parallel ports...
582 */
583
584 for (i = 0; i < 9; i ++)
585 for (j = 0; j < 8; j ++)
586 for (n = 0; n < 32; n ++)
587 {
588 if (i == 8) /* EtherLite */
589 sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]);
590 else
591 sprintf(device, "/dev/lp%c%d%c", i + 'C', j,
592 funky_hex[n]);
593
594 if (access(device, 0) == 0)
595 {
596 if (i == 8)
597 printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n",
598 device, j, n);
599 else
600 printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n",
601 device, i, j, n);
602 }
603 }
604 #elif defined(__osf__)
605 int i; /* Looping var */
606 int fd; /* File descriptor */
607 char device[255]; /* Device filename */
608
609
610 for (i = 0; i < 3; i ++)
611 {
612 sprintf(device, "/dev/lp%d", i);
613 if ((fd = open(device, O_WRONLY)) >= 0)
614 {
615 close(fd);
616 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
617 }
618 }
619 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
620 int i; /* Looping var */
621 int fd; /* File descriptor */
622 char device[255]; /* Device filename */
623
624
625 for (i = 0; i < 3; i ++)
626 {
627 sprintf(device, "/dev/lpt%d", i);
628 if ((fd = open(device, O_WRONLY)) >= 0)
629 {
630 close(fd);
631 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (interrupt-driven)\"\n", device, i + 1);
632 }
633
634 sprintf(device, "/dev/lpa%d", i);
635 if ((fd = open(device, O_WRONLY)) >= 0)
636 {
637 close(fd);
638 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
639 }
640 }
641 #elif defined(_AIX)
642 int i; /* Looping var */
643 int fd; /* File descriptor */
644 char device[255]; /* Device filename */
645
646
647 for (i = 0; i < 8; i ++)
648 {
649 sprintf(device, "/dev/lp%d", i);
650 if ((fd = open(device, O_WRONLY)) >= 0)
651 {
652 close(fd);
653 printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
654 }
655 }
656 #endif
657 }
658
659
660 /*
661 * End of "$Id: parallel.c,v 1.41 2002/03/25 17:13:55 mike Exp $".
662 */