]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb-unix.c
Fix compiles on unsupported platforms.
[thirdparty/cups.git] / backend / usb-unix.c
1 /*
2 * "$Id: usb-unix.c,v 1.3 2004/04/01 18:59:59 mike Exp $"
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-2004 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-3142 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 char 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 (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
143 if (fp)
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
187 while (copies > 0)
188 {
189 copies --;
190
191 if (fp != 0)
192 {
193 fputs("PAGE: 1 1\n", stderr);
194 lseek(fp, 0, SEEK_SET);
195 }
196
197 tbytes = 0;
198 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
199 {
200 /*
201 * Write the print data to the printer...
202 */
203
204 tbytes += nbytes;
205 bufptr = buffer;
206
207 while (nbytes > 0)
208 {
209
210 if ((wbytes = write(fd, bufptr, nbytes)) < 0)
211 if (errno == ENOTTY)
212 wbytes = write(fd, bufptr, nbytes);
213
214 if (wbytes < 0)
215 {
216 perror("ERROR: Unable to send print file to printer");
217 break;
218 }
219
220 nbytes -= wbytes;
221 bufptr += wbytes;
222 }
223
224 if (wbytes < 0)
225 break;
226
227 if (fp)
228 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
229 (unsigned long)tbytes);
230 }
231 }
232
233 /*
234 * Close the USB port and return...
235 */
236
237 close(fd);
238
239 return (0);
240 }
241
242
243 /*
244 * 'decode_device_id()' - Decode the IEEE-1284 device ID string.
245 */
246
247 void
248 decode_device_id(int port, /* I - Port number */
249 const char *device_id, /* I - 1284 device ID string */
250 char *make_model, /* O - Make/model */
251 int mmsize, /* I - Size of buffer */
252 char *uri, /* O - Device URI */
253 int urisize) /* I - Size of buffer */
254 {
255 char *attr, /* 1284 attribute */
256 *delim, /* 1284 delimiter */
257 *uriptr, /* Pointer into URI */
258 *mfg, /* Manufacturer string */
259 *mdl, /* Model string */
260 serial_number[1024]; /* Serial number string */
261
262
263 /*
264 * Look for the description field...
265 */
266
267 if ((attr = strstr(device_id, "DES:")) != NULL)
268 attr += 4;
269 else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
270 attr += 12;
271
272 if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
273 mfg += 13;
274 else if ((mfg = strstr(device_id, "MFG:")) != NULL)
275 mfg += 4;
276
277 if ((mdl = strstr(device_id, "MODEL:")) != NULL)
278 mdl += 6;
279 else if ((mdl = strstr(device_id, "MDL:")) != NULL)
280 mdl += 4;
281
282 if (attr)
283 {
284 if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
285 {
286 strlcpy(make_model, "HP ", mmsize);
287 strlcpy(make_model + 3, attr + 16, mmsize - 3);
288 }
289 else
290 {
291 strlcpy(make_model, attr, mmsize);
292 }
293
294 if ((delim = strchr(make_model, ';')) != NULL)
295 *delim = '\0';
296 }
297 else if (mfg && mdl)
298 {
299 /*
300 * Build a make-model string from the manufacturer and model attributes...
301 */
302
303 strlcpy(make_model, mfg, mmsize);
304
305 if ((delim = strchr(make_model, ';')) != NULL)
306 *delim = '\0';
307
308 strlcat(make_model, " ", mmsize);
309 strlcat(make_model, mdl, mmsize);
310
311 if ((delim = strchr(make_model, ';')) != NULL)
312 *delim = '\0';
313 }
314 else
315 {
316 /*
317 * Use "Unknown" as the printer make and model...
318 */
319
320 strlcpy(make_model, "Unknown", mmsize);
321 }
322
323 /*
324 * Look for the serial number field...
325 */
326
327 if ((attr = strstr(device_id, "SERN:")) != NULL)
328 attr += 5;
329 else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
330 attr += 13;
331 else if ((attr = strstr(device_id, ";SN:")) != NULL)
332 attr += 4;
333
334 if (mfg)
335 {
336 /*
337 * Make sure manufacturer is truncated at delimiter...
338 */
339
340 if ((delim = strchr(mfg, ';')) != NULL)
341 *delim = '\0';
342 }
343
344 if (mdl)
345 {
346 /*
347 * Make sure model is truncated at delimiter...
348 */
349
350 if ((delim = strchr(mdl, ';')) != NULL)
351 *delim = '\0';
352 }
353
354 if (attr)
355 {
356 strlcpy(serial_number, attr, sizeof(serial_number));
357
358 if ((delim = strchr(serial_number, ';')) != NULL)
359 *delim = '\0';
360 }
361 else
362 serial_number[0] = '\0';
363
364 /*
365 * Generate the device URI from the make_model and serial number strings.
366 */
367
368 strlcpy(uri, "usb://", urisize);
369 for (uriptr = uri + 6, delim = make_model;
370 *delim && uriptr < (uri + urisize - 1);
371 delim ++)
372 if (*delim == ' ')
373 {
374 delim ++;
375 *uriptr++ = '/';
376 break;
377 }
378 else
379 *uriptr++ = *delim;
380
381 for (; *delim && uriptr < (uri + urisize - 3); delim ++)
382 if (*delim == ' ')
383 {
384 *uriptr++ = '%';
385 *uriptr++ = '2';
386 *uriptr++ = '0';
387 }
388 else
389 *uriptr++ = *delim;
390
391 *uriptr = '\0';
392
393 if (serial_number[0])
394 {
395 /*
396 * Add the serial number to the URI...
397 */
398
399 strlcat(uri, "?serial=", urisize);
400 strlcat(uri, serial_number, urisize);
401 }
402 }
403
404
405 /*
406 * 'list_devices()' - List all USB devices.
407 */
408
409 void
410 list_devices(void)
411 {
412 #ifdef __linux
413 int i; /* Looping var */
414 int length; /* Length of device ID info */
415 int fd; /* File descriptor */
416 char format[255], /* Format for device filename */
417 device[255], /* Device filename */
418 device_id[1024], /* Device ID string */
419 device_uri[1024], /* Device URI string */
420 make_model[1024]; /* Make and model */
421
422
423 /*
424 * First figure out which USB printer filename to use...
425 */
426
427 if (access("/dev/usb/lp0", 0) == 0)
428 strcpy(format, "/dev/usb/lp%d");
429 else if (access("/dev/usb/usblp0", 0) == 0)
430 strcpy(format, "/dev/usb/usblp%d");
431 else
432 strcpy(format, "/dev/usblp%d");
433
434 /*
435 * Then open each USB device...
436 */
437
438 for (i = 0; i < 16; i ++)
439 {
440 sprintf(device, format, i);
441
442 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
443 {
444 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
445 {
446 length = (((unsigned)device_id[0] & 255) << 8) +
447 ((unsigned)device_id[1] & 255);
448
449 /*
450 * Check to see if the length is larger than our buffer; first
451 * assume that the vendor incorrectly implemented the 1284 spec,
452 * and then limit the length to the size of our buffer...
453 */
454
455 if (length > (sizeof(device_id) - 2))
456 length = (((unsigned)device_id[1] & 255) << 8) +
457 ((unsigned)device_id[0] & 255);
458
459 if (length > (sizeof(device_id) - 2))
460 length = sizeof(device_id) - 2;
461
462 memmove(device_id, device_id + 2, length);
463 device_id[length] = '\0';
464 }
465 else
466 device_id[0] = '\0';
467
468 close(fd);
469 }
470 else
471 device_id[0] = '\0';
472
473 if (device_id[0])
474 {
475 decode_device_id(i, device_id, make_model, sizeof(make_model),
476 device_uri, sizeof(device_uri));
477
478 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
479 make_model, i + 1);
480 }
481 else
482 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
483 }
484 #elif defined(__sgi)
485 #elif defined(__sun)
486 int i; /* Looping var */
487 int fd; /* File descriptor */
488 char device[255], /* Device filename */
489 device_id[1024], /* Device ID string */
490 device_uri[1024], /* Device URI string */
491 make_model[1024]; /* Make and model */
492 # ifdef ECPPIOC_GETDEVID
493 struct ecpp_device_id did; /* Device ID buffer */
494 # endif /* ECPPIOC_GETDEVID */
495
496
497 /*
498 * Open each USB device...
499 */
500
501 for (i = 0; i < 8; i ++)
502 {
503 sprintf(device, "/dev/usb/printer%d", i);
504
505 # ifndef ECPPIOC_GETDEVID
506 if (!access(device, 0))
507 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
508 # else
509 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
510 {
511 did.mode = ECPP_CENTRONICS;
512 did.len = sizeof(device_id);
513 did.rlen = 0;
514 did.addr = device_id;
515
516 if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
517 {
518 if (did.rlen < (sizeof(device_id) - 1))
519 device_id[did.rlen] = '\0';
520 else
521 device_id[sizeof(device_id) - 1] = '\0';
522 }
523 else
524 device_id[0] = '\0';
525
526 close(fd);
527 }
528 else
529 device_id[0] = '\0';
530
531 if (device_id[0])
532 {
533 decode_device_id(i, device_id, make_model, sizeof(make_model),
534 device_uri, sizeof(device_uri));
535
536 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
537 make_model, i + 1);
538 }
539 else
540 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
541 # endif /* !ECPPIOC_GETDEVID */
542 }
543 #elif defined(__hpux)
544 #elif defined(__osf)
545 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
546 int i; /* Looping var */
547 char device[255]; /* Device filename */
548
549
550 for (i = 0; i < 8; i ++)
551 {
552 sprintf(device, "/dev/ulpt%d", i);
553 if (!access(device, 0))
554 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
555
556 sprintf(device, "/dev/unlpt%d", i);
557 if (!access(device, 0))
558 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
559 }
560 #endif
561 }
562
563
564 /*
565 * 'open_device()' - Open a USB device...
566 */
567
568 int /* O - File descriptor or -1 on error */
569 open_device(const char *uri) /* I - Device URI */
570 {
571 /*
572 * The generic implementation just treats the URI as a device filename...
573 * Specific operating systems may also support using the device serial
574 * number and/or make/model.
575 */
576
577 if (strncmp(uri, "usb:/dev/", 9) == 0)
578 return (open(uri + 4, O_RDWR | O_EXCL));
579 #ifdef __linux
580 else if (strncmp(uri, "usb://", 6) == 0)
581 {
582 /*
583 * For Linux, try looking up the device serial number or model...
584 */
585
586 int i; /* Looping var */
587 int busy; /* Are any ports busy? */
588 int length; /* Length of device ID info */
589 int fd; /* File descriptor */
590 char format[255], /* Format for device filename */
591 device[255], /* Device filename */
592 device_id[1024], /* Device ID string */
593 make_model[1024], /* Make and model */
594 device_uri[1024]; /* Device URI string */
595
596
597 /*
598 * First figure out which USB printer filename to use...
599 */
600
601 if (access("/dev/usb/lp0", 0) == 0)
602 strcpy(format, "/dev/usb/lp%d");
603 else if (access("/dev/usb/usblp0", 0) == 0)
604 strcpy(format, "/dev/usb/usblp%d");
605 else
606 strcpy(format, "/dev/usblp%d");
607
608 /*
609 * Then find the correct USB device...
610 */
611
612 do
613 {
614 for (busy = 0, i = 0; i < 16; i ++)
615 {
616 sprintf(device, format, i);
617
618 if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
619 {
620 if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
621 {
622 length = (((unsigned)device_id[0] & 255) << 8) +
623 ((unsigned)device_id[1] & 255);
624 memmove(device_id, device_id + 2, length);
625 device_id[length] = '\0';
626 }
627 else
628 device_id[0] = '\0';
629 }
630 else
631 {
632 /*
633 * If the open failed because it was busy, flag it so we retry
634 * as needed...
635 */
636
637 if (errno == EBUSY)
638 busy = 1;
639
640 device_id[0] = '\0';
641 }
642
643 if (device_id[0])
644 {
645 /*
646 * Got the device ID - is this the one?
647 */
648
649 decode_device_id(i, device_id, make_model, sizeof(make_model),
650 device_uri, sizeof(device_uri));
651
652 if (strcmp(uri, device_uri) == 0)
653 {
654 /*
655 * Yes, return this file descriptor...
656 */
657
658 fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
659
660 return (fd);
661 }
662 }
663
664 /*
665 * This wasn't the one...
666 */
667
668 if (fd >= 0)
669 close(fd);
670 }
671
672 /*
673 * If we get here and at least one of the printer ports showed up
674 * as "busy", then sleep for a bit and retry...
675 */
676
677 if (busy)
678 {
679 fputs("INFO: USB printer is busy; will retry in 5 seconds...\n",
680 stderr);
681 sleep(5);
682 }
683 }
684 while (busy);
685
686 /*
687 * Couldn't find the printer, return "no such device or address"...
688 */
689
690 errno = ENODEV;
691
692 return (-1);
693 }
694 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
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 {
717 for (i = 0; i < 8; i ++)
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 }
794 #endif /* __linux */
795 else
796 {
797 errno = ENODEV;
798 return (-1);
799 }
800 }
801
802
803 /*
804 * End of "$Id: usb-unix.c,v 1.3 2004/04/01 18:59:59 mike Exp $".
805 */