]>
git.ipfire.org Git - thirdparty/cups.git/blob - backend/usb.c
2 * "$Id: usb.c,v 1.50 2004/02/24 16:19:45 mike Exp $"
4 * USB port backend for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * main() - Send a file to the specified USB port.
29 * list_devices() - List all USB devices.
33 * Include necessary headers.
36 #include <cups/cups.h>
40 #include <cups/string.h>
52 # include <sys/ioctl.h>
53 # include <linux/lp.h>
54 # define IOCNR_GET_DEVICE_ID 1
57 * Get device_id string
59 # define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
64 # include <sys/ecppio.h>
66 # include <sys/ioccom.h>
67 # include <sys/ecppsys.h>
76 void decode_device_id(int port
, const char *device_id
,
77 char *make_model
, int mmsize
,
78 char *uri
, int urisize
);
79 void list_devices(void);
80 int open_device(const char *uri
);
84 * 'main()' - Send a file to the specified USB port.
88 * printer-uri job-id user title copies options [file]
91 int /* O - Exit status */
92 main(int argc
, /* I - Number of command-line arguments (6 or 7) */
93 char *argv
[]) /* I - Command-line arguments */
95 int fp
; /* Print file */
96 int copies
; /* Number of copies to print */
97 int fd
; /* Parallel device */
98 int wbytes
; /* Number of bytes written */
99 size_t nbytes
, /* Number of bytes read */
100 tbytes
; /* Total number of bytes written */
101 char buffer
[8192], /* Output buffer */
102 *bufptr
; /* Pointer into buffer */
103 struct termios opts
; /* Parallel port options */
104 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
105 struct sigaction action
; /* Actions for POSIX signals */
106 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
108 unsigned char status
; /* Port status (off-line, out-of-paper, etc.) */
113 * Make sure status messages are not buffered...
116 setbuf(stderr
, NULL
);
119 * Ignore SIGPIPE signals...
123 sigset(SIGPIPE
, SIG_IGN
);
124 #elif defined(HAVE_SIGACTION)
125 memset(&action
, 0, sizeof(action
));
126 action
.sa_handler
= SIG_IGN
;
127 sigaction(SIGPIPE
, &action
, NULL
);
129 signal(SIGPIPE
, SIG_IGN
);
130 #endif /* HAVE_SIGSET */
133 * Check command-line...
141 else if (argc
< 6 || argc
> 7)
143 fputs("Usage: USB job-id user title copies options [file]\n", stderr
);
148 * If we have 7 arguments, print the file named on the command-line.
149 * Otherwise, send stdin instead...
160 * Try to open the print file...
163 if ((fp
= open(argv
[6], O_RDONLY
)) < 0)
165 perror("ERROR: unable to open print file");
169 copies
= atoi(argv
[4]);
173 * Open the USB port device...
178 if ((fd
= open_device(argv
[0])) == -1)
182 fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr
);
185 else if (errno
== ENXIO
|| errno
== EIO
|| errno
== ENOENT
)
187 fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr
);
192 fprintf(stderr
, "ERROR: Unable to open USB device \"%s\": %s\n",
193 argv
[0], strerror(errno
));
201 * Set any options provided...
204 tcgetattr(fd
, &opts
);
206 opts
.c_lflag
&= ~(ICANON
| ECHO
| ISIG
); /* Raw mode */
208 /**** No options supported yet ****/
210 tcsetattr(fd
, TCSANOW
, &opts
);
213 * Now that we are "connected" to the port, ignore SIGTERM so that we
214 * can finish out any page data the driver sends (e.g. to eject the
215 * current page... Only ignore SIGTERM if we are printing data from
216 * stdin (otherwise you can't cancel raw jobs...)
221 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
222 sigset(SIGTERM
, SIG_IGN
);
223 #elif defined(HAVE_SIGACTION)
224 memset(&action
, 0, sizeof(action
));
226 sigemptyset(&action
.sa_mask
);
227 action
.sa_handler
= SIG_IGN
;
228 sigaction(SIGTERM
, &action
, NULL
);
230 signal(SIGTERM
, SIG_IGN
);
231 #endif /* HAVE_SIGSET */
234 #if defined(__linux) && defined(LP_POUTPA)
236 * Show the printer status before we send the file; normally, we'd
237 * do this while we write data to the printer, however at least some
238 * Linux kernels have buggy USB drivers which don't like to be
239 * queried while sending data to the printer...
241 * Also, we're using the 8255 constants instead of the ones that are
242 * supposed to be used, as it appears that the USB driver also doesn't
243 * follow standards...
246 if (ioctl(fd
, LPGETSTATUS
, &status
) == 0)
248 fprintf(stderr
, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status
);
250 if (!(status
& LP_POUTPA
))
251 fputs("WARNING: Media tray empty!\n", stderr
);
252 else if (!(status
& LP_PERRORP
))
253 fputs("WARNING: Printer fault!\n", stderr
);
254 else if (!(status
& LP_PSELECD
))
255 fputs("WARNING: Printer off-line.\n", stderr
);
257 #endif /* __linux && LP_POUTPA */
260 * Finally, send the print file...
269 fputs("PAGE: 1 1\n", stderr
);
270 lseek(fp
, 0, SEEK_SET
);
274 while ((nbytes
= read(fp
, buffer
, sizeof(buffer
))) > 0)
277 * Write the print data to the printer...
286 if ((wbytes
= write(fd
, bufptr
, nbytes
)) < 0)
288 wbytes
= write(fd
, bufptr
, nbytes
);
292 perror("ERROR: Unable to send print file to printer");
304 fprintf(stderr
, "INFO: Sending print file, %lu bytes...\n",
305 (unsigned long)tbytes
);
310 * Close the socket connection and input file and return...
317 fputs("INFO: Ready to print.\n", stderr
);
324 * 'decode_device_id()' - Decode the IEEE-1284 device ID string.
328 decode_device_id(int port
, /* I - Port number */
329 const char *device_id
, /* I - 1284 device ID string */
330 char *make_model
, /* O - Make/model */
331 int mmsize
, /* I - Size of buffer */
332 char *uri
, /* O - Device URI */
333 int urisize
) /* I - Size of buffer */
335 char *attr
, /* 1284 attribute */
336 *delim
, /* 1284 delimiter */
337 *uriptr
, /* Pointer into URI */
338 *mfg
, /* Manufacturer string */
339 *mdl
, /* Model string */
340 serial_number
[1024]; /* Serial number string */
344 * Look for the description field...
347 if ((attr
= strstr(device_id
, "DES:")) != NULL
)
349 else if ((attr
= strstr(device_id
, "DESCRIPTION:")) != NULL
)
352 if ((mfg
= strstr(device_id
, "MANUFACTURER:")) != NULL
)
354 else if ((mfg
= strstr(device_id
, "MFG:")) != NULL
)
357 if ((mdl
= strstr(device_id
, "MODEL:")) != NULL
)
359 else if ((mdl
= strstr(device_id
, "MDL:")) != NULL
)
364 if (strncasecmp(attr
, "Hewlett-Packard ", 16) == 0)
366 strlcpy(make_model
, "HP ", mmsize
);
367 strlcpy(make_model
+ 3, attr
+ 16, mmsize
- 3);
371 strlcpy(make_model
, attr
, mmsize
);
374 if ((delim
= strchr(make_model
, ';')) != NULL
)
380 * Build a make-model string from the manufacturer and model attributes...
383 strlcpy(make_model
, mfg
, mmsize
);
385 if ((delim
= strchr(make_model
, ';')) != NULL
)
388 strlcat(make_model
, " ", mmsize
);
389 strlcat(make_model
, mdl
, mmsize
);
391 if ((delim
= strchr(make_model
, ';')) != NULL
)
397 * Use "Unknown" as the printer make and model...
400 strlcpy(make_model
, "Unknown", mmsize
);
404 * Look for the serial number field...
407 if ((attr
= strstr(device_id
, "SERN:")) != NULL
)
409 else if ((attr
= strstr(device_id
, "SERIALNUMBER:")) != NULL
)
411 else if ((attr
= strstr(device_id
, ";SN:")) != NULL
)
417 * Make sure manufacturer is truncated at delimiter...
420 if ((delim
= strchr(mfg
, ';')) != NULL
)
427 * Make sure model is truncated at delimiter...
430 if ((delim
= strchr(mdl
, ';')) != NULL
)
436 strlcpy(serial_number
, attr
, sizeof(serial_number
));
438 if ((delim
= strchr(serial_number
, ';')) != NULL
)
442 serial_number
[0] = '\0';
445 * Generate the device URI from the make_model and serial number strings.
448 strlcpy(uri
, "usb://", urisize
);
449 for (uriptr
= uri
+ 6, delim
= make_model
;
450 *delim
&& uriptr
< (uri
+ urisize
- 1);
461 for (; *delim
&& uriptr
< (uri
+ urisize
- 3); delim
++)
473 if (serial_number
[0])
476 * Add the serial number to the URI...
479 strlcat(uri
, "?serial=", urisize
);
480 strlcat(uri
, serial_number
, urisize
);
486 * 'list_devices()' - List all USB devices.
493 int i
; /* Looping var */
494 int length
; /* Length of device ID info */
495 int fd
; /* File descriptor */
496 char format
[255], /* Format for device filename */
497 device
[255], /* Device filename */
498 device_id
[1024], /* Device ID string */
499 device_uri
[1024], /* Device URI string */
500 make_model
[1024]; /* Make and model */
504 * First figure out which USB printer filename to use...
507 if (access("/dev/usb/lp0", 0) == 0)
508 strcpy(format
, "/dev/usb/lp%d");
509 else if (access("/dev/usb/usblp0", 0) == 0)
510 strcpy(format
, "/dev/usb/usblp%d");
512 strcpy(format
, "/dev/usblp%d");
515 * Then open each USB device...
518 for (i
= 0; i
< 16; i
++)
520 sprintf(device
, format
, i
);
522 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) >= 0)
524 if (ioctl(fd
, LPIOC_GET_DEVICE_ID(sizeof(device_id
)), device_id
) == 0)
526 length
= (((unsigned)device_id
[0] & 255) << 8) +
527 ((unsigned)device_id
[1] & 255);
530 * Check to see if the length is larger than our buffer; first
531 * assume that the vendor incorrectly implemented the 1284 spec,
532 * and then limit the length to the size of our buffer...
535 if (length
> (sizeof(device_id
) - 2))
536 length
= (((unsigned)device_id
[1] & 255) << 8) +
537 ((unsigned)device_id
[0] & 255);
539 if (length
> (sizeof(device_id
) - 2))
540 length
= sizeof(device_id
) - 2;
542 memmove(device_id
, device_id
+ 2, length
);
543 device_id
[length
] = '\0';
555 decode_device_id(i
, device_id
, make_model
, sizeof(make_model
),
556 device_uri
, sizeof(device_uri
));
558 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri
,
562 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device
, i
+ 1);
566 int i
; /* Looping var */
567 int fd
; /* File descriptor */
568 char device
[255], /* Device filename */
569 device_id
[1024], /* Device ID string */
570 device_uri
[1024], /* Device URI string */
571 make_model
[1024]; /* Make and model */
572 # ifdef ECPPIOC_GETDEVID
573 struct ecpp_device_id did
; /* Device ID buffer */
574 # endif /* ECPPIOC_GETDEVID */
578 * Open each USB device...
581 for (i
= 0; i
< 8; i
++)
583 sprintf(device
, "/dev/usb/printer%d", i
);
585 # ifndef ECPPIOC_GETDEVID
586 if (!access(device
, 0))
587 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device
, i
+ 1);
589 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) >= 0)
591 did
.mode
= ECPP_CENTRONICS
;
592 did
.len
= sizeof(device_id
);
594 did
.addr
= device_id
;
596 if (ioctl(fd
, ECPPIOC_GETDEVID
, &did
) == 0)
598 if (did
.rlen
< (sizeof(device_id
) - 1))
599 device_id
[did
.rlen
] = '\0';
601 device_id
[sizeof(device_id
) - 1] = '\0';
613 decode_device_id(i
, device_id
, make_model
, sizeof(make_model
),
614 device_uri
, sizeof(device_uri
));
616 printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri
,
620 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device
, i
+ 1);
621 # endif /* !ECPPIOC_GETDEVID */
623 #elif defined(__hpux)
625 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
626 int i
; /* Looping var */
627 char device
[255]; /* Device filename */
630 for (i
= 0; i
< 8; i
++)
632 sprintf(device
, "/dev/ulpt%d", i
);
633 if (!access(device
, 0))
634 printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device
, i
+ 1);
636 sprintf(device
, "/dev/unlpt%d", i
);
637 if (!access(device
, 0))
638 printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device
, i
+ 1);
645 * 'open_device()' - Open a USB device...
648 int /* O - File descriptor or -1 on error */
649 open_device(const char *uri
) /* I - Device URI */
652 * The generic implementation just treats the URI as a device filename...
653 * Specific operating systems may also support using the device serial
654 * number and/or make/model.
657 if (strncmp(uri
, "usb:/dev/", 9) == 0)
658 return (open(uri
+ 4, O_RDWR
| O_EXCL
));
660 else if (strncmp(uri
, "usb://", 6) == 0)
663 * For Linux, try looking up the device serial number or model...
666 int i
; /* Looping var */
667 int length
; /* Length of device ID info */
668 int fd
; /* File descriptor */
669 char format
[255], /* Format for device filename */
670 device
[255], /* Device filename */
671 device_id
[1024], /* Device ID string */
672 make_model
[1024], /* Make and model */
673 device_uri
[1024]; /* Device URI string */
677 * First figure out which USB printer filename to use...
680 if (access("/dev/usb/lp0", 0) == 0)
681 strcpy(format
, "/dev/usb/lp%d");
682 else if (access("/dev/usb/usblp0", 0) == 0)
683 strcpy(format
, "/dev/usb/usblp%d");
685 strcpy(format
, "/dev/usblp%d");
688 * Then find the correct USB device...
691 for (i
= 0; i
< 16; i
++)
693 sprintf(device
, format
, i
);
695 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) >= 0)
697 if (ioctl(fd
, LPIOC_GET_DEVICE_ID(sizeof(device_id
)), device_id
) == 0)
699 length
= (((unsigned)device_id
[0] & 255) << 8) +
700 ((unsigned)device_id
[1] & 255);
701 memmove(device_id
, device_id
+ 2, length
);
702 device_id
[length
] = '\0';
713 * Got the device ID - is this the one?
716 decode_device_id(i
, device_id
, make_model
, sizeof(make_model
),
717 device_uri
, sizeof(device_uri
));
719 if (strcmp(uri
, device_uri
) == 0)
722 * Yes, return this file descriptor...
725 fprintf(stderr
, "DEBUG: Printer using device file \"%s\"...\n", device
);
732 * This wasn't the one...
739 * Couldn't find the printer, return "no such device or address"...
746 #elif defined(__sun) && defined(ECPPIOC_GETDEVID)
747 else if (strncmp(uri
, "usb://", 6) == 0)
750 * For Solaris, try looking up the device serial number or model...
753 int i
; /* Looping var */
754 int fd
; /* File descriptor */
755 char device
[255], /* Device filename */
756 device_id
[1024], /* Device ID string */
757 make_model
[1024], /* Make and model */
758 device_uri
[1024]; /* Device URI string */
759 struct ecpp_device_id did
; /* Device ID buffer */
763 * Find the correct USB device...
766 for (i
= 0; i
< 8; i
++)
768 sprintf(device
, "/dev/usb/printer%d", i
);
770 if ((fd
= open(device
, O_RDWR
| O_EXCL
)) >= 0)
772 did
.mode
= ECPP_CENTRONICS
;
773 did
.len
= sizeof(device_id
);
775 did
.addr
= device_id
;
777 if (ioctl(fd
, ECPPIOC_GETDEVID
, &did
) == 0)
779 if (did
.rlen
< (sizeof(device_id
) - 1))
780 device_id
[did
.rlen
] = '\0';
782 device_id
[sizeof(device_id
) - 1] = '\0';
793 * Got the device ID - is this the one?
796 decode_device_id(i
, device_id
, make_model
, sizeof(make_model
),
797 device_uri
, sizeof(device_uri
));
799 if (strcmp(uri
, device_uri
) == 0)
800 return (fd
); /* Yes, return this file descriptor... */
804 * This wasn't the one...
811 * Couldn't find the printer, return "no such device or address"...
828 * End of "$Id: usb.c,v 1.50 2004/02/24 16:19:45 mike Exp $".