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