]> 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.26 2003/07/22 18:23:11 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 #ifdef __linux
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
237 if (ioctl(fd, LPGETSTATUS, &status) == 0)
238 {
239 fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
240
241 if (status & LP_NOPA)
242 fputs("WARNING: Media tray empty!\n", stderr);
243 else if (status & LP_ERR)
244 fputs("WARNING: Printer fault!\n", stderr);
245 else if (status & LP_OFFL)
246 fputs("WARNING: Printer off-line.\n", stderr);
247 }
248 #endif /* __linux */
249
250 /*
251 * Finally, send the print file...
252 */
253
254 while (copies > 0)
255 {
256 copies --;
257
258 if (fp != 0)
259 {
260 fputs("PAGE: 1 1\n", stderr);
261 lseek(fp, 0, SEEK_SET);
262 }
263
264 tbytes = 0;
265 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
266 {
267 /*
268 * Write the print data to the printer...
269 */
270
271 tbytes += nbytes;
272 bufptr = buffer;
273
274 while (nbytes > 0)
275 {
276
277 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
278 if (errno == ENOTTY)
279 wbytes = write(fd, bufptr, nbytes);
280
281 if (wbytes < 0)
282 {
283 perror("ERROR: Unable to send print file to printer");
284 break;
285 }
286
287 nbytes -= wbytes;
288 bufptr += wbytes;
289 }
290
291 if (argc > 6)
292 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
293 (unsigned long)tbytes);
294 }
295 }
296
297 /*
298 * Close the socket connection and input file and return...
299 */
300
301 close(fd);
302 if (fp != 0)
303 close(fp);
304
305 fputs("INFO: Ready to print.\n", stderr);
306
307 return (0);
308 }
309
310
311 /*
312 * 'decode_device_id()' - Decode the IEEE-1284 device ID string.
313 */
314
315 void
316 decode_device_id(int port, /* I - Port number */
317 const char *device_id, /* I - 1284 device ID string */
318 char *make_model, /* O - Make/model */
319 int mmsize, /* I - Size of buffer */
320 char *uri, /* O - Device URI */
321 int urisize) /* I - Size of buffer */
322 {
323 char *attr, /* 1284 attribute */
324 *delim, /* 1284 delimiter */
325 *uriptr, /* Pointer into URI */
326 *mfg, /* Manufacturer string */
327 *mdl, /* Model string */
328 serial_number[1024]; /* Serial number string */
329
330
331 /*
332 * Look for the description field...
333 */
334
335 if ((attr = strstr(device_id, "DES:")) != NULL)
336 attr += 4;
337 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
338 attr += 12;
339
340 if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
341 mfg += 13;
342 else if ((mfg = strstr(device_id, "MFG:")) != NULL)
343 mfg += 4;
344
345 if ((mdl = strstr(device_id, "MODEL:")) != NULL)
346 mdl += 6;
347 else if ((mdl = strstr(device_id, "MDL:")) != NULL)
348 mdl += 4;
349
350 if (attr)
351 {
352 if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
353 {
354 strlcpy(make_model, "HP ", mmsize);
355 strlcpy(make_model + 3, attr + 16, mmsize - 3);
356 }
357 else
358 {
359 strlcpy(make_model, attr, mmsize);
360 }
361
362 if ((delim = strchr(make_model, ';')) != NULL)
363 *delim = '\0';
364 }
365 else if (mfg && mdl)
366 {
367 /*
368 * Build a make-model string from the manufacturer and model attributes...
369 */
370
371 strlcpy(make_model, mfg, mmsize);
372
373 if ((delim = strchr(make_model, ';')) != NULL)
374 *delim = '\0';
375
376 strlcat(make_model, " ", mmsize);
377 strlcat(make_model, mdl, mmsize);
378
379 if ((delim = strchr(make_model, ';')) != NULL)
380 *delim = '\0';
381 }
382 else
383 {
384 /*
385 * Use "Unknown" as the printer make and model...
386 */
387
388 strlcpy(make_model, "Unknown", mmsize);
389 }
390
391 /*
392 * Look for the serial number field...
393 */
394
395 if ((attr = strstr(device_id, "SERN:")) != NULL)
396 attr += 5;
397 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
398 attr += 13;
399
400 if (attr)
401 {
402 strlcpy(serial_number, attr, sizeof(serial_number));
403
404 if ((delim = strchr(serial_number, ';')) != NULL)
405 *delim = '\0';
406 }
407 else
408 serial_number[0] = '\0';
409
410 /*
411 * Generate the device URI from the make_model and serial number strings.
412 */
413
414 strlcpy(uri, "usb://", urisize);
415 for (uriptr = uri + 6, delim = make_model;
416 *delim && uriptr < (uri + urisize - 1);
417 delim ++)
418 if (*delim == ' ')
419 {
420 delim ++;
421 *uriptr++ = '/';
422 break;
423 }
424 else
425 *uriptr++ = *delim;
426
427 for (; *delim && uriptr < (uri + urisize - 3); delim ++)
428 if (*delim == ' ')
429 {
430 *uriptr++ = '%';
431 *uriptr++ = '2';
432 *uriptr++ = '0';
433 }
434 else
435 *uriptr++ = *delim;
436
437 *uriptr = '\0';
438
439 if (serial_number[0])
440 {
441 /*
442 * Add the serial number to the URI...
443 */
444
445 strlcat(uri, "?serial=", urisize);
446 strlcat(uri, serial_number, urisize);
447 }
448 }
449
450
451 /*
452 * 'list_devices()' - List all USB devices.
453 */
454
455 void
456 list_devices(void)
457 {
458 #ifdef __linux
459 int i; /* Looping var */
460 int length; /* Length of device ID info */
461 int fd; /* File descriptor */
462 char format[255], /* Format for device filename */
463 device[255], /* Device filename */
464 device_id[1024], /* Device ID string */
465 device_uri[1024], /* Device URI string */
466 make_model[1024]; /* Make and model */
467
468
469 /*
470 * First figure out which USB printer filename to use...
471 */
472
473 if (access("/dev/usb/lp0", 0) == 0)
474 strcpy(format, "/dev/usb/lp%d");
475 else if (access("/dev/usb/usblp0", 0) == 0)
476 strcpy(format, "/dev/usb/usblp%d");
477 else
478 strcpy(format, "/dev/usblp%d");
479
480 /*
481 * Then open each USB device...
482 */
483
484 for (i = 0; i < 16; i ++)
485 {
486 sprintf(device, format, i);
487
488 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
489 {
490 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
491 {
492 length = (((unsigned)device_id[0] & 255) << 8) +
493 ((unsigned)device_id[1] & 255);
494
495 /*
496 * Check to see if the length is larger than our buffer; first
497 * assume that the vendor incorrectly implemented the 1284 spec,
498 * and then limit the length to the size of our buffer...
499 */
500
501 if (length > (sizeof(device_id) - 2))
502 length = (((unsigned)device_id[1] & 255) << 8) +
503 ((unsigned)device_id[0] & 255);
504
505 if (length > (sizeof(device_id) - 2))
506 length = sizeof(device_id) - 2;
507
508 memmove(device_id, device_id + 2, length);
509 device_id[length] = '\0';
510 }
511 else
512 device_id[0] = '\0';
513
514 close(fd);
515 }
516 else
517 device_id[0] = '\0';
518
519 if (device_id[0])
520 {
521 decode_device_id(i, device_id, make_model, sizeof(make_model),
522 device_uri, sizeof(device_uri));
523
524 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
525 make_model, i + 1);
526 }
527 else
528 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
529 }
530 #elif defined(__sgi)
531 #elif defined(__sun)
532 int i; /* Looping var */
533 int fd; /* File descriptor */
534 char device[255], /* Device filename */
535 device_id[1024], /* Device ID string */
536 device_uri[1024], /* Device URI string */
537 make_model[1024]; /* Make and model */
538 # ifdef ECPPIOC_GETDEVID
539 struct ecpp_device_id did; /* Device ID buffer */
540 # endif /* ECPPIOC_GETDEVID */
541
542
543 /*
544 * Open each USB device...
545 */
546
547 for (i = 0; i < 8; i ++)
548 {
549 sprintf(device, "/dev/usb/printer%d", i);
550
551 # ifndef ECPPIOC_GETDEVID
552 if (!access(device, 0))
553 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
554 # else
555 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
556 {
557 did.mode = ECPP_CENTRONICS;
558 did.len = sizeof(device_id);
559 did.rlen = 0;
560 did.addr = device_id;
561
562 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
563 {
564 if (did.rlen < (sizeof(device_id) - 1))
565 device_id[did.rlen] = '\0';
566 else
567 device_id[sizeof(device_id) - 1] = '\0';
568 }
569 else
570 device_id[0] = '\0';
571
572 close(fd);
573 }
574 else
575 device_id[0] = '\0';
576
577 if (device_id[0])
578 {
579 decode_device_id(i, device_id, make_model, sizeof(make_model),
580 device_uri, sizeof(device_uri));
581
582 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
583 make_model, i + 1);
584 }
585 else
586 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
587 # endif /* !ECPPIOC_GETDEVID */
588 }
589 #elif defined(__hpux)
590 #elif defined(__osf)
591 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
592 int i; /* Looping var */
593 char device[255]; /* Device filename */
594
595
596 for (i = 0; i < 8; i ++)
597 {
598 sprintf(device, "/dev/ulpt%d", i);
599 if (!access(device, 0))
600 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
601
602 sprintf(device, "/dev/unlpt%d", i);
603 if (!access(device, 0))
604 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
605 }
606 #endif
607 }
608
609
610 /*
611 * 'open_device()' - Open a USB device...
612 */
613
614 int /* O - File descriptor or -1 on error */
615 open_device(const char *uri) /* I - Device URI */
616 {
617 /*
618 * The generic implementation just treats the URI as a device filename...
619 * Specific operating systems may also support using the device serial
620 * number and/or make/model.
621 */
622
623 if (strncmp(uri, "usb:/dev/", 9) == 0)
624 return (open(uri + 4, O_RDWR | O_EXCL));
625 #ifdef __linux
626 else if (strncmp(uri, "usb://", 6) == 0)
627 {
628 /*
629 * For Linux, try looking up the device serial number or model...
630 */
631
632 int i; /* Looping var */
633 int length; /* Length of device ID info */
634 int fd; /* File descriptor */
635 char format[255], /* Format for device filename */
636 device[255], /* Device filename */
637 device_id[1024], /* Device ID string */
638 make_model[1024], /* Make and model */
639 device_uri[1024]; /* Device URI string */
640
641
642 /*
643 * First figure out which USB printer filename to use...
644 */
645
646 if (access("/dev/usb/lp0", 0) == 0)
647 strcpy(format, "/dev/usb/lp%d");
648 else if (access("/dev/usb/usblp0", 0) == 0)
649 strcpy(format, "/dev/usb/usblp%d");
650 else
651 strcpy(format, "/dev/usblp%d");
652
653 /*
654 * Then find the correct USB device...
655 */
656
657 for (i = 0; i < 16; i ++)
658 {
659 sprintf(device, format, i);
660
661 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
662 {
663 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
664 {
665 length = (((unsigned)device_id[0] & 255) << 8) +
666 ((unsigned)device_id[1] & 255);
667 memmove(device_id, device_id + 2, length);
668 device_id[length] = '\0';
669 }
670 else
671 device_id[0] = '\0';
672 }
673 else
674 device_id[0] = '\0';
675
676 if (device_id[0])
677 {
678 /*
679 * Got the device ID - is this the one?
680 */
681
682 decode_device_id(i, device_id, make_model, sizeof(make_model),
683 device_uri, sizeof(device_uri));
684
685 if (strcmp(uri, device_uri) == 0)
686 {
687 /*
688 * Yes, return this file descriptor...
689 */
690
691 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
692
693 return (fd);
694 }
695 }
696
697 /*
698 * This wasn't the one...
699 */
700
701 close(fd);
702 }
703
704 /*
705 * Couldn't find the printer, return "no such device or address"...
706 */
707
708 errno = ENODEV;
709
710 return (-1);
711 }
712 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
713 else if (strncmp(uri, "usb://", 6) == 0)
714 {
715 /*
716 * For Solaris, try looking up the device serial number or model...
717 */
718
719 int i; /* Looping var */
720 int fd; /* File descriptor */
721 char device[255], /* Device filename */
722 device_id[1024], /* Device ID string */
723 make_model[1024], /* Make and model */
724 device_uri[1024]; /* Device URI string */
725 struct ecpp_device_id did; /* Device ID buffer */
726
727
728 /*
729 * Find the correct USB device...
730 */
731
732 for (i = 0; i < 8; i ++)
733 {
734 sprintf(device, "/dev/usb/printer%d", i);
735
736 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
737 {
738 did.mode = ECPP_CENTRONICS;
739 did.len = sizeof(device_id);
740 did.rlen = 0;
741 did.addr = device_id;
742
743 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
744 {
745 if (did.rlen < (sizeof(device_id) - 1))
746 device_id[did.rlen] = '\0';
747 else
748 device_id[sizeof(device_id) - 1] = '\0';
749 }
750 else
751 device_id[0] = '\0';
752 }
753 else
754 device_id[0] = '\0';
755
756 if (device_id[0])
757 {
758 /*
759 * Got the device ID - is this the one?
760 */
761
762 decode_device_id(i, device_id, make_model, sizeof(make_model),
763 device_uri, sizeof(device_uri));
764
765 if (strcmp(uri, device_uri) == 0)
766 return (fd); /* Yes, return this file descriptor... */
767 }
768
769 /*
770 * This wasn't the one...
771 */
772
773 close(fd);
774 }
775
776 /*
777 * Couldn't find the printer, return "no such device or address"...
778 */
779
780 errno = ENODEV;
781
782 return (-1);
783 }
784 #endif /* __linux */
785 else
786 {
787 errno = ENODEV;
788 return (-1);
789 }
790 }
791
792
793 /*
794 * End of "$Id: usb.c,v 1.18.2.26 2003/07/22 18:23:11 mike Exp $".
795 */