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