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