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