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