]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb.c
The rastertoepson filter would crash under certain cirsumstances
[thirdparty/cups.git] / backend / usb.c
1 /*
2 * "$Id: usb.c,v 1.50 2004/02/24 16:19:45 mike Exp $"
3 *
4 * USB port backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 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 USB port.
29 * list_devices() - List all USB 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 __linux
52 # include <sys/ioctl.h>
53 # include <linux/lp.h>
54 # define IOCNR_GET_DEVICE_ID 1
55
56 /*
57 * Get device_id string
58 */
59 # define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
60 #endif /* __linux */
61
62 #ifdef __sun
63 # ifdef __sparc
64 # include <sys/ecppio.h>
65 # else
66 # include <sys/ioccom.h>
67 # include <sys/ecppsys.h>
68 # endif /* __sparc */
69 #endif /* __sun */
70
71
72 /*
73 * Local functions...
74 */
75
76 void decode_device_id(int port, const char *device_id,
77 char *make_model, int mmsize,
78 char *uri, int urisize);
79 void list_devices(void);
80 int open_device(const char *uri);
81
82
83 /*
84 * 'main()' - Send a file to the specified USB port.
85 *
86 * Usage:
87 *
88 * printer-uri job-id user title copies options [file]
89 */
90
91 int /* O - Exit status */
92 main(int argc, /* I - Number of command-line arguments (6 or 7) */
93 char *argv[]) /* I - Command-line arguments */
94 {
95 int fp; /* Print file */
96 int copies; /* Number of copies to print */
97 int fd; /* Parallel device */
98 int wbytes; /* Number of bytes written */
99 size_t nbytes, /* Number of bytes read */
100 tbytes; /* Total number of bytes written */
101 char buffer[8192], /* Output buffer */
102 *bufptr; /* Pointer into buffer */
103 struct termios opts; /* Parallel port options */
104 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
105 struct sigaction action; /* Actions for POSIX signals */
106 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
107 #ifdef __linux
108 unsigned char status; /* Port status (off-line, out-of-paper, etc.) */
109 #endif /* __linux */
110
111
112 /*
113 * Make sure status messages are not buffered...
114 */
115
116 setbuf(stderr, NULL);
117
118 /*
119 * Ignore SIGPIPE signals...
120 */
121
122 #ifdef HAVE_SIGSET
123 sigset(SIGPIPE, SIG_IGN);
124 #elif defined(HAVE_SIGACTION)
125 memset(&action, 0, sizeof(action));
126 action.sa_handler = SIG_IGN;
127 sigaction(SIGPIPE, &action, NULL);
128 #else
129 signal(SIGPIPE, SIG_IGN);
130 #endif /* HAVE_SIGSET */
131
132 /*
133 * Check command-line...
134 */
135
136 if (argc == 1)
137 {
138 list_devices();
139 return (0);
140 }
141 else if (argc < 6 || argc > 7)
142 {
143 fputs("Usage: USB job-id user title copies options [file]\n", stderr);
144 return (1);
145 }
146
147 /*
148 * If we have 7 arguments, print the file named on the command-line.
149 * Otherwise, send stdin instead...
150 */
151
152 if (argc == 6)
153 {
154 fp = 0;
155 copies = 1;
156 }
157 else
158 {
159 /*
160 * Try to open the print file...
161 */
162
163 if ((fp = open(argv[6], O_RDONLY)) < 0)
164 {
165 perror("ERROR: unable to open print file");
166 return (1);
167 }
168
169 copies = atoi(argv[4]);
170 }
171
172 /*
173 * Open the USB port device...
174 */
175
176 do
177 {
178 if ((fd = open_device(argv[0])) == -1)
179 {
180 if (errno == EBUSY)
181 {
182 fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
183 sleep(30);
184 }
185 else if (errno == ENXIO || errno == EIO || errno == ENOENT)
186 {
187 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
188 sleep(30);
189 }
190 else
191 {
192 fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
193 argv[0], strerror(errno));
194 return (1);
195 }
196 }
197 }
198 while (fd < 0);
199
200 /*
201 * Set any options provided...
202 */
203
204 tcgetattr(fd, &opts);
205
206 opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
207
208 /**** No options supported yet ****/
209
210 tcsetattr(fd, TCSANOW, &opts);
211
212 /*
213 * Now that we are "connected" to the port, ignore SIGTERM so that we
214 * can finish out any page data the driver sends (e.g. to eject the
215 * current page... Only ignore SIGTERM if we are printing data from
216 * stdin (otherwise you can't cancel raw jobs...)
217 */
218
219 if (argc < 7)
220 {
221 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
222 sigset(SIGTERM, SIG_IGN);
223 #elif defined(HAVE_SIGACTION)
224 memset(&action, 0, sizeof(action));
225
226 sigemptyset(&action.sa_mask);
227 action.sa_handler = SIG_IGN;
228 sigaction(SIGTERM, &action, NULL);
229 #else
230 signal(SIGTERM, SIG_IGN);
231 #endif /* HAVE_SIGSET */
232 }
233
234 #if defined(__linux) && defined(LP_POUTPA)
235 /*
236 * Show the printer status before we send the file; normally, we'd
237 * do this while we write data to the printer, however at least some
238 * Linux kernels have buggy USB drivers which don't like to be
239 * queried while sending data to the printer...
240 *
241 * Also, we're using the 8255 constants instead of the ones that are
242 * supposed to be used, as it appears that the USB driver also doesn't
243 * follow standards...
244 */
245
246 if (ioctl(fd, LPGETSTATUS, &status) == 0)
247 {
248 fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
249
250 if (!(status & LP_POUTPA))
251 fputs("WARNING: Media tray empty!\n", stderr);
252 else if (!(status & LP_PERRORP))
253 fputs("WARNING: Printer fault!\n", stderr);
254 else if (!(status & LP_PSELECD))
255 fputs("WARNING: Printer off-line.\n", stderr);
256 }
257 #endif /* __linux && LP_POUTPA */
258
259 /*
260 * Finally, send the print file...
261 */
262
263 while (copies > 0)
264 {
265 copies --;
266
267 if (fp != 0)
268 {
269 fputs("PAGE: 1 1\n", stderr);
270 lseek(fp, 0, SEEK_SET);
271 }
272
273 tbytes = 0;
274 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
275 {
276 /*
277 * Write the print data to the printer...
278 */
279
280 tbytes += nbytes;
281 bufptr = buffer;
282
283 while (nbytes > 0)
284 {
285
286 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
287 if (errno == ENOTTY)
288 wbytes = write(fd, bufptr, nbytes);
289
290 if (wbytes < 0)
291 {
292 perror("ERROR: Unable to send print file to printer");
293 break;
294 }
295
296 nbytes -= wbytes;
297 bufptr += wbytes;
298 }
299
300 if (wbytes < 0)
301 break;
302
303 if (argc > 6)
304 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
305 (unsigned long)tbytes);
306 }
307 }
308
309 /*
310 * Close the socket connection and input file and return...
311 */
312
313 close(fd);
314 if (fp != 0)
315 close(fp);
316
317 fputs("INFO: Ready to print.\n", stderr);
318
319 return (0);
320 }
321
322
323 /*
324 * 'decode_device_id()' - Decode the IEEE-1284 device ID string.
325 */
326
327 void
328 decode_device_id(int port, /* I - Port number */
329 const char *device_id, /* I - 1284 device ID string */
330 char *make_model, /* O - Make/model */
331 int mmsize, /* I - Size of buffer */
332 char *uri, /* O - Device URI */
333 int urisize) /* I - Size of buffer */
334 {
335 char *attr, /* 1284 attribute */
336 *delim, /* 1284 delimiter */
337 *uriptr, /* Pointer into URI */
338 *mfg, /* Manufacturer string */
339 *mdl, /* Model string */
340 serial_number[1024]; /* Serial number string */
341
342
343 /*
344 * Look for the description field...
345 */
346
347 if ((attr = strstr(device_id, "DES:")) != NULL)
348 attr += 4;
349 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
350 attr += 12;
351
352 if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
353 mfg += 13;
354 else if ((mfg = strstr(device_id, "MFG:")) != NULL)
355 mfg += 4;
356
357 if ((mdl = strstr(device_id, "MODEL:")) != NULL)
358 mdl += 6;
359 else if ((mdl = strstr(device_id, "MDL:")) != NULL)
360 mdl += 4;
361
362 if (attr)
363 {
364 if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
365 {
366 strlcpy(make_model, "HP ", mmsize);
367 strlcpy(make_model + 3, attr + 16, mmsize - 3);
368 }
369 else
370 {
371 strlcpy(make_model, attr, mmsize);
372 }
373
374 if ((delim = strchr(make_model, ';')) != NULL)
375 *delim = '\0';
376 }
377 else if (mfg && mdl)
378 {
379 /*
380 * Build a make-model string from the manufacturer and model attributes...
381 */
382
383 strlcpy(make_model, mfg, mmsize);
384
385 if ((delim = strchr(make_model, ';')) != NULL)
386 *delim = '\0';
387
388 strlcat(make_model, " ", mmsize);
389 strlcat(make_model, mdl, mmsize);
390
391 if ((delim = strchr(make_model, ';')) != NULL)
392 *delim = '\0';
393 }
394 else
395 {
396 /*
397 * Use "Unknown" as the printer make and model...
398 */
399
400 strlcpy(make_model, "Unknown", mmsize);
401 }
402
403 /*
404 * Look for the serial number field...
405 */
406
407 if ((attr = strstr(device_id, "SERN:")) != NULL)
408 attr += 5;
409 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
410 attr += 13;
411 else if ((attr = strstr(device_id, ";SN:")) != NULL)
412 attr += 4;
413
414 if (mfg)
415 {
416 /*
417 * Make sure manufacturer is truncated at delimiter...
418 */
419
420 if ((delim = strchr(mfg, ';')) != NULL)
421 *delim = '\0';
422 }
423
424 if (mdl)
425 {
426 /*
427 * Make sure model is truncated at delimiter...
428 */
429
430 if ((delim = strchr(mdl, ';')) != NULL)
431 *delim = '\0';
432 }
433
434 if (attr)
435 {
436 strlcpy(serial_number, attr, sizeof(serial_number));
437
438 if ((delim = strchr(serial_number, ';')) != NULL)
439 *delim = '\0';
440 }
441 else
442 serial_number[0] = '\0';
443
444 /*
445 * Generate the device URI from the make_model and serial number strings.
446 */
447
448 strlcpy(uri, "usb://", urisize);
449 for (uriptr = uri + 6, delim = make_model;
450 *delim && uriptr < (uri + urisize - 1);
451 delim ++)
452 if (*delim == ' ')
453 {
454 delim ++;
455 *uriptr++ = '/';
456 break;
457 }
458 else
459 *uriptr++ = *delim;
460
461 for (; *delim && uriptr < (uri + urisize - 3); delim ++)
462 if (*delim == ' ')
463 {
464 *uriptr++ = '%';
465 *uriptr++ = '2';
466 *uriptr++ = '0';
467 }
468 else
469 *uriptr++ = *delim;
470
471 *uriptr = '\0';
472
473 if (serial_number[0])
474 {
475 /*
476 * Add the serial number to the URI...
477 */
478
479 strlcat(uri, "?serial=", urisize);
480 strlcat(uri, serial_number, urisize);
481 }
482 }
483
484
485 /*
486 * 'list_devices()' - List all USB devices.
487 */
488
489 void
490 list_devices(void)
491 {
492 #ifdef __linux
493 int i; /* Looping var */
494 int length; /* Length of device ID info */
495 int fd; /* File descriptor */
496 char format[255], /* Format for device filename */
497 device[255], /* Device filename */
498 device_id[1024], /* Device ID string */
499 device_uri[1024], /* Device URI string */
500 make_model[1024]; /* Make and model */
501
502
503 /*
504 * First figure out which USB printer filename to use...
505 */
506
507 if (access("/dev/usb/lp0", 0) == 0)
508 strcpy(format, "/dev/usb/lp%d");
509 else if (access("/dev/usb/usblp0", 0) == 0)
510 strcpy(format, "/dev/usb/usblp%d");
511 else
512 strcpy(format, "/dev/usblp%d");
513
514 /*
515 * Then open each USB device...
516 */
517
518 for (i = 0; i < 16; i ++)
519 {
520 sprintf(device, format, i);
521
522 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
523 {
524 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
525 {
526 length = (((unsigned)device_id[0] & 255) << 8) +
527 ((unsigned)device_id[1] & 255);
528
529 /*
530 * Check to see if the length is larger than our buffer; first
531 * assume that the vendor incorrectly implemented the 1284 spec,
532 * and then limit the length to the size of our buffer...
533 */
534
535 if (length > (sizeof(device_id) - 2))
536 length = (((unsigned)device_id[1] & 255) << 8) +
537 ((unsigned)device_id[0] & 255);
538
539 if (length > (sizeof(device_id) - 2))
540 length = sizeof(device_id) - 2;
541
542 memmove(device_id, device_id + 2, length);
543 device_id[length] = '\0';
544 }
545 else
546 device_id[0] = '\0';
547
548 close(fd);
549 }
550 else
551 device_id[0] = '\0';
552
553 if (device_id[0])
554 {
555 decode_device_id(i, device_id, make_model, sizeof(make_model),
556 device_uri, sizeof(device_uri));
557
558 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
559 make_model, i + 1);
560 }
561 else
562 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
563 }
564 #elif defined(__sgi)
565 #elif defined(__sun)
566 int i; /* Looping var */
567 int fd; /* File descriptor */
568 char device[255], /* Device filename */
569 device_id[1024], /* Device ID string */
570 device_uri[1024], /* Device URI string */
571 make_model[1024]; /* Make and model */
572 # ifdef ECPPIOC_GETDEVID
573 struct ecpp_device_id did; /* Device ID buffer */
574 # endif /* ECPPIOC_GETDEVID */
575
576
577 /*
578 * Open each USB device...
579 */
580
581 for (i = 0; i < 8; i ++)
582 {
583 sprintf(device, "/dev/usb/printer%d", i);
584
585 # ifndef ECPPIOC_GETDEVID
586 if (!access(device, 0))
587 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
588 # else
589 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
590 {
591 did.mode = ECPP_CENTRONICS;
592 did.len = sizeof(device_id);
593 did.rlen = 0;
594 did.addr = device_id;
595
596 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
597 {
598 if (did.rlen < (sizeof(device_id) - 1))
599 device_id[did.rlen] = '\0';
600 else
601 device_id[sizeof(device_id) - 1] = '\0';
602 }
603 else
604 device_id[0] = '\0';
605
606 close(fd);
607 }
608 else
609 device_id[0] = '\0';
610
611 if (device_id[0])
612 {
613 decode_device_id(i, device_id, make_model, sizeof(make_model),
614 device_uri, sizeof(device_uri));
615
616 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
617 make_model, i + 1);
618 }
619 else
620 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
621 # endif /* !ECPPIOC_GETDEVID */
622 }
623 #elif defined(__hpux)
624 #elif defined(__osf)
625 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
626 int i; /* Looping var */
627 char device[255]; /* Device filename */
628
629
630 for (i = 0; i < 8; i ++)
631 {
632 sprintf(device, "/dev/ulpt%d", i);
633 if (!access(device, 0))
634 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
635
636 sprintf(device, "/dev/unlpt%d", i);
637 if (!access(device, 0))
638 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
639 }
640 #endif
641 }
642
643
644 /*
645 * 'open_device()' - Open a USB device...
646 */
647
648 int /* O - File descriptor or -1 on error */
649 open_device(const char *uri) /* I - Device URI */
650 {
651 /*
652 * The generic implementation just treats the URI as a device filename...
653 * Specific operating systems may also support using the device serial
654 * number and/or make/model.
655 */
656
657 if (strncmp(uri, "usb:/dev/", 9) == 0)
658 return (open(uri + 4, O_RDWR | O_EXCL));
659 #ifdef __linux
660 else if (strncmp(uri, "usb://", 6) == 0)
661 {
662 /*
663 * For Linux, try looking up the device serial number or model...
664 */
665
666 int i; /* Looping var */
667 int length; /* Length of device ID info */
668 int fd; /* File descriptor */
669 char format[255], /* Format for device filename */
670 device[255], /* Device filename */
671 device_id[1024], /* Device ID string */
672 make_model[1024], /* Make and model */
673 device_uri[1024]; /* Device URI string */
674
675
676 /*
677 * First figure out which USB printer filename to use...
678 */
679
680 if (access("/dev/usb/lp0", 0) == 0)
681 strcpy(format, "/dev/usb/lp%d");
682 else if (access("/dev/usb/usblp0", 0) == 0)
683 strcpy(format, "/dev/usb/usblp%d");
684 else
685 strcpy(format, "/dev/usblp%d");
686
687 /*
688 * Then find the correct USB device...
689 */
690
691 for (i = 0; i < 16; i ++)
692 {
693 sprintf(device, format, i);
694
695 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
696 {
697 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
698 {
699 length = (((unsigned)device_id[0] & 255) << 8) +
700 ((unsigned)device_id[1] & 255);
701 memmove(device_id, device_id + 2, length);
702 device_id[length] = '\0';
703 }
704 else
705 device_id[0] = '\0';
706 }
707 else
708 device_id[0] = '\0';
709
710 if (device_id[0])
711 {
712 /*
713 * Got the device ID - is this the one?
714 */
715
716 decode_device_id(i, device_id, make_model, sizeof(make_model),
717 device_uri, sizeof(device_uri));
718
719 if (strcmp(uri, device_uri) == 0)
720 {
721 /*
722 * Yes, return this file descriptor...
723 */
724
725 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
726
727 return (fd);
728 }
729 }
730
731 /*
732 * This wasn't the one...
733 */
734
735 close(fd);
736 }
737
738 /*
739 * Couldn't find the printer, return "no such device or address"...
740 */
741
742 errno = ENODEV;
743
744 return (-1);
745 }
746 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
747 else if (strncmp(uri, "usb://", 6) == 0)
748 {
749 /*
750 * For Solaris, try looking up the device serial number or model...
751 */
752
753 int i; /* Looping var */
754 int fd; /* File descriptor */
755 char device[255], /* Device filename */
756 device_id[1024], /* Device ID string */
757 make_model[1024], /* Make and model */
758 device_uri[1024]; /* Device URI string */
759 struct ecpp_device_id did; /* Device ID buffer */
760
761
762 /*
763 * Find the correct USB device...
764 */
765
766 for (i = 0; i < 8; i ++)
767 {
768 sprintf(device, "/dev/usb/printer%d", i);
769
770 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
771 {
772 did.mode = ECPP_CENTRONICS;
773 did.len = sizeof(device_id);
774 did.rlen = 0;
775 did.addr = device_id;
776
777 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
778 {
779 if (did.rlen < (sizeof(device_id) - 1))
780 device_id[did.rlen] = '\0';
781 else
782 device_id[sizeof(device_id) - 1] = '\0';
783 }
784 else
785 device_id[0] = '\0';
786 }
787 else
788 device_id[0] = '\0';
789
790 if (device_id[0])
791 {
792 /*
793 * Got the device ID - is this the one?
794 */
795
796 decode_device_id(i, device_id, make_model, sizeof(make_model),
797 device_uri, sizeof(device_uri));
798
799 if (strcmp(uri, device_uri) == 0)
800 return (fd); /* Yes, return this file descriptor... */
801 }
802
803 /*
804 * This wasn't the one...
805 */
806
807 close(fd);
808 }
809
810 /*
811 * Couldn't find the printer, return "no such device or address"...
812 */
813
814 errno = ENODEV;
815
816 return (-1);
817 }
818 #endif /* __linux */
819 else
820 {
821 errno = ENODEV;
822 return (-1);
823 }
824 }
825
826
827 /*
828 * End of "$Id: usb.c,v 1.50 2004/02/24 16:19:45 mike Exp $".
829 */