]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/usb-unix.c
Update copyright notices, addresses, etc.
[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 {
286 if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
287 {
288 strlcpy(make_model, "HP ", mmsize);
289 strlcpy(make_model + 3, attr + 16, mmsize - 3);
290 }
291 else
292 {
293 strlcpy(make_model, attr, mmsize);
294 }
295
296 if ((delim = strchr(make_model, ';')) != NULL)
297 *delim = '\0';
298 }
299 else if (mfg && mdl)
300 {
301 /*
302 * Build a make-model string from the manufacturer and model attributes...
303 */
304
305 strlcpy(make_model, mfg, mmsize);
306
307 if ((delim = strchr(make_model, ';')) != NULL)
308 *delim = '\0';
309
310 strlcat(make_model, " ", mmsize);
311 strlcat(make_model, mdl, mmsize);
312
313 if ((delim = strchr(make_model, ';')) != NULL)
314 *delim = '\0';
315 }
316 else
317 {
318 /*
319 * Use "Unknown" as the printer make and model...
320 */
321
322 strlcpy(make_model, "Unknown", mmsize);
323 }
324
325 /*
326 * Look for the serial number field...
327 */
328
329 if ((attr = strstr(device_id, "SERN:")) != NULL)
330 attr += 5;
331 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
332 attr += 13;
333 else if ((attr = strstr(device_id, ";SN:")) != NULL)
334 attr += 4;
335
336 if (mfg)
337 {
338 /*
339 * Make sure manufacturer is truncated at delimiter...
340 */
341
342 if ((delim = strchr(mfg, ';')) != NULL)
343 *delim = '\0';
344 }
345
346 if (mdl)
347 {
348 /*
349 * Make sure model is truncated at delimiter...
350 */
351
352 if ((delim = strchr(mdl, ';')) != NULL)
353 *delim = '\0';
354 }
355
356 if (attr)
357 {
358 strlcpy(serial_number, attr, sizeof(serial_number));
359
360 if ((delim = strchr(serial_number, ';')) != NULL)
361 *delim = '\0';
362 }
363 else
364 serial_number[0] = '\0';
365
366 /*
367 * Generate the device URI from the make_model and serial number strings.
368 */
369
370 strlcpy(uri, "usb://", urisize);
371 for (uriptr = uri + 6, delim = make_model;
372 *delim && uriptr < (uri + urisize - 1);
373 delim ++)
374 if (*delim == ' ')
375 {
376 delim ++;
377 *uriptr++ = '/';
378 break;
379 }
380 else
381 *uriptr++ = *delim;
382
383 for (; *delim && uriptr < (uri + urisize - 3); delim ++)
384 if (*delim == ' ')
385 {
386 *uriptr++ = '%';
387 *uriptr++ = '2';
388 *uriptr++ = '0';
389 }
390 else
391 *uriptr++ = *delim;
392
393 *uriptr = '\0';
394
395 if (serial_number[0])
396 {
397 /*
398 * Add the serial number to the URI...
399 */
400
401 strlcat(uri, "?serial=", urisize);
402 strlcat(uri, serial_number, urisize);
403 }
404}
405
406
407/*
408 * 'list_devices()' - List all USB devices.
409 */
410
411void
412list_devices(void)
413{
414#ifdef __linux
415 int i; /* Looping var */
416 int length; /* Length of device ID info */
417 int fd; /* File descriptor */
418 char format[255], /* Format for device filename */
419 device[255], /* Device filename */
420 device_id[1024], /* Device ID string */
421 device_uri[1024], /* Device URI string */
422 make_model[1024]; /* Make and model */
423
424
425 /*
426 * First figure out which USB printer filename to use...
427 */
428
6f96d00f 429 if (access("/dev/usblp0", 0) == 0)
430 strcpy(format, "/dev/usblp%d");
8e3807e7 431 else if (access("/dev/usb/usblp0", 0) == 0)
432 strcpy(format, "/dev/usb/usblp%d");
433 else
6f96d00f 434 strcpy(format, "/dev/usb/lp%d");
8e3807e7 435
436 /*
437 * Then open each USB device...
438 */
439
440 for (i = 0; i < 16; i ++)
441 {
442 sprintf(device, format, i);
443
444 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
445 {
446 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
447 {
448 length = (((unsigned)device_id[0] & 255) << 8) +
449 ((unsigned)device_id[1] & 255);
450
451 /*
452 * Check to see if the length is larger than our buffer; first
453 * assume that the vendor incorrectly implemented the 1284 spec,
454 * and then limit the length to the size of our buffer...
455 */
456
457 if (length > (sizeof(device_id) - 2))
458 length = (((unsigned)device_id[1] & 255) << 8) +
459 ((unsigned)device_id[0] & 255);
460
461 if (length > (sizeof(device_id) - 2))
462 length = sizeof(device_id) - 2;
463
464 memmove(device_id, device_id + 2, length);
465 device_id[length] = '\0';
466 }
467 else
468 device_id[0] = '\0';
469
470 close(fd);
471 }
472 else
473 device_id[0] = '\0';
474
475 if (device_id[0])
476 {
477 decode_device_id(i, device_id, make_model, sizeof(make_model),
478 device_uri, sizeof(device_uri));
479
480 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
481 make_model, i + 1);
482 }
483 else
484 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
485 }
486#elif defined(__sgi)
487#elif defined(__sun)
488 int i; /* Looping var */
489 int fd; /* File descriptor */
490 char device[255], /* Device filename */
491 device_id[1024], /* Device ID string */
492 device_uri[1024], /* Device URI string */
493 make_model[1024]; /* Make and model */
494# ifdef ECPPIOC_GETDEVID
495 struct ecpp_device_id did; /* Device ID buffer */
496# endif /* ECPPIOC_GETDEVID */
497
498
499 /*
500 * Open each USB device...
501 */
502
503 for (i = 0; i < 8; i ++)
504 {
505 sprintf(device, "/dev/usb/printer%d", i);
506
507# ifndef ECPPIOC_GETDEVID
508 if (!access(device, 0))
509 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
510# else
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 }
541 else
542 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
543# endif /* !ECPPIOC_GETDEVID */
544 }
545#elif defined(__hpux)
546#elif defined(__osf)
547#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
548 int i; /* Looping var */
549 char device[255]; /* Device filename */
550
551
552 for (i = 0; i < 8; i ++)
553 {
554 sprintf(device, "/dev/ulpt%d", i);
555 if (!access(device, 0))
556 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
557
558 sprintf(device, "/dev/unlpt%d", i);
559 if (!access(device, 0))
560 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
561 }
562#endif
563}
564
565
566/*
567 * 'open_device()' - Open a USB device...
568 */
569
570int /* O - File descriptor or -1 on error */
571open_device(const char *uri) /* I - Device URI */
572{
573 /*
574 * The generic implementation just treats the URI as a device filename...
575 * Specific operating systems may also support using the device serial
576 * number and/or make/model.
577 */
578
579 if (strncmp(uri, "usb:/dev/", 9) == 0)
580 return (open(uri + 4, O_RDWR | O_EXCL));
581#ifdef __linux
582 else if (strncmp(uri, "usb://", 6) == 0)
583 {
584 /*
585 * For Linux, try looking up the device serial number or model...
586 */
587
588 int i; /* Looping var */
589 int busy; /* Are any ports busy? */
590 int length; /* Length of device ID info */
591 int fd; /* File descriptor */
592 char format[255], /* Format for device filename */
593 device[255], /* Device filename */
594 device_id[1024], /* Device ID string */
595 make_model[1024], /* Make and model */
596 device_uri[1024]; /* Device URI string */
597
598
599 /*
600 * First figure out which USB printer filename to use...
601 */
602
6f96d00f 603 if (access("/dev/usblp0", 0) == 0)
604 strcpy(format, "/dev/usblp%d");
8e3807e7 605 else if (access("/dev/usb/usblp0", 0) == 0)
606 strcpy(format, "/dev/usb/usblp%d");
607 else
6f96d00f 608 strcpy(format, "/dev/usb/lp%d");
8e3807e7 609
610 /*
611 * Then find the correct USB device...
612 */
613
614 do
615 {
616 for (busy = 0, i = 0; i < 16; i ++)
617 {
618 sprintf(device, format, i);
619
620 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
621 {
622 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
623 {
624 length = (((unsigned)device_id[0] & 255) << 8) +
625 ((unsigned)device_id[1] & 255);
626 memmove(device_id, device_id + 2, length);
627 device_id[length] = '\0';
628 }
629 else
630 device_id[0] = '\0';
631 }
632 else
633 {
634 /*
635 * If the open failed because it was busy, flag it so we retry
636 * as needed...
637 */
638
639 if (errno == EBUSY)
640 busy = 1;
641
642 device_id[0] = '\0';
643 }
644
645 if (device_id[0])
646 {
647 /*
648 * Got the device ID - is this the one?
649 */
650
651 decode_device_id(i, device_id, make_model, sizeof(make_model),
652 device_uri, sizeof(device_uri));
653
654 if (strcmp(uri, device_uri) == 0)
655 {
656 /*
657 * Yes, return this file descriptor...
658 */
659
660 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
661
662 return (fd);
663 }
664 }
665
666 /*
667 * This wasn't the one...
668 */
669
670 if (fd >= 0)
671 close(fd);
672 }
673
674 /*
675 * If we get here and at least one of the printer ports showed up
676 * as "busy", then sleep for a bit and retry...
677 */
678
679 if (busy)
680 {
681 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
682 stderr);
683 sleep(5);
684 }
685 }
686 while (busy);
687
688 /*
689 * Couldn't find the printer, return "no such device or address"...
690 */
691
692 errno = ENODEV;
693
694 return (-1);
695 }
696#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
697 else if (strncmp(uri, "usb://", 6) == 0)
698 {
699 /*
700 * For Solaris, try looking up the device serial number or model...
701 */
702
703 int i; /* Looping var */
704 int busy; /* Are any ports busy? */
705 int fd; /* File descriptor */
706 char device[255], /* Device filename */
707 device_id[1024], /* Device ID string */
708 make_model[1024], /* Make and model */
709 device_uri[1024]; /* Device URI string */
710 struct ecpp_device_id did; /* Device ID buffer */
711
712
713 /*
714 * Find the correct USB device...
715 */
716
717 do
718 {
63412dfd 719 for (i = 0, busy = 0; i < 8; i ++)
8e3807e7 720 {
721 sprintf(device, "/dev/usb/printer%d", i);
722
723 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
724 {
725 did.mode = ECPP_CENTRONICS;
726 did.len = sizeof(device_id);
727 did.rlen = 0;
728 did.addr = device_id;
729
730 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
731 {
732 if (did.rlen < (sizeof(device_id) - 1))
733 device_id[did.rlen] = '\0';
734 else
735 device_id[sizeof(device_id) - 1] = '\0';
736 }
737 else
738 device_id[0] = '\0';
739 }
740 else
741 {
742 /*
743 * If the open failed because it was busy, flag it so we retry
744 * as needed...
745 */
746
747 if (errno == EBUSY)
748 busy = 1;
749
750 device_id[0] = '\0';
751 }
752
753 if (device_id[0])
754 {
755 /*
756 * Got the device ID - is this the one?
757 */
758
759 decode_device_id(i, device_id, make_model, sizeof(make_model),
760 device_uri, sizeof(device_uri));
761
762 if (strcmp(uri, device_uri) == 0)
763 return (fd); /* Yes, return this file descriptor... */
764 }
765
766 /*
767 * This wasn't the one...
768 */
769
770 if (fd >= 0)
771 close(fd);
772 }
773
774 /*
775 * If we get here and at least one of the printer ports showed up
776 * as "busy", then sleep for a bit and retry...
777 */
778
779 if (busy)
780 {
781 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
782 stderr);
783 sleep(5);
784 }
785 }
786 while (busy);
787
788 /*
789 * Couldn't find the printer, return "no such device or address"...
790 */
791
792 errno = ENODEV;
793
794 return (-1);
795 }
796#endif /* __linux */
797 else
798 {
799 errno = ENODEV;
800 return (-1);
801 }
802}
803
804
805/*
c9d3f842 806 * End of "$Id$".
8e3807e7 807 */