X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=backend%2Fusb-unix.c;h=5efa30ff9bb04e59a7a8876234282b6aa61188bf;hp=e034a0a2c81eda7db6f4b191638dbe44dfb5e0a2;hb=f7deaa1a21758ec90bf23314af018481ea8aea7f;hpb=757d2cad8f3f75c420ad2e462b787cd9cf8a7a62 diff --git a/backend/usb-unix.c b/backend/usb-unix.c index e034a0a2c..5efa30ff9 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -1,11 +1,11 @@ /* - * "$Id: usb-unix.c 5241 2006-03-07 22:07:44Z mike $" + * "$Id: usb-unix.c 6293 2007-02-20 13:40:55Z mike $" * * USB port backend for the Common UNIX Printing System (CUPS). * * This file is included from "usb.c" when compiled on UNIX/Linux. * - * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -27,8 +27,10 @@ * * Contents: * - * main() - Send a file to the specified USB port. + * print_device() - Print a file to a USB device. * list_devices() - List all USB devices. + * open_device() - Open a USB device... + * side_cb() - Handle side-channel requests... */ /* @@ -43,7 +45,8 @@ * Local functions... */ -int open_device(const char *uri); +static int open_device(const char *uri, int *use_bc); +static void side_cb(int print_fd, int device_fd, int use_bc); /* @@ -55,29 +58,20 @@ print_device(const char *uri, /* I - Device URI */ const char *hostname, /* I - Hostname/manufacturer */ const char *resource, /* I - Resource/modelname */ const char *options, /* I - Device options/serial number */ - int fp, /* I - File descriptor to print */ - int copies) /* I - Copies to print */ + int print_fd, /* I - File descriptor to print */ + int copies, /* I - Copies to print */ + int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ { - int fd; /* USB device */ - int rbytes; /* Number of bytes read */ - int wbytes; /* Number of bytes written */ - size_t nbytes, /* Number of bytes read */ - tbytes; /* Total number of bytes written */ - char buffer[8192], /* Output buffer */ - *bufptr, /* Pointer into buffer */ - backbuf[1024]; /* Backchannel buffer */ + int use_bc; /* Use backchannel path? */ + int device_fd; /* USB device */ + size_t tbytes; /* Total number of bytes written */ struct termios opts; /* Parallel port options */ - fd_set input, /* Input set for select() */ - output; /* Output set for select() */ - int paperout; /* Paper out? */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ -#ifdef __linux - unsigned int status; /* Port status (off-line, out-of-paper, etc.) */ -#endif /* __linux */ + (void)argc; + (void)argv; + /* * Open the USB port device... */ @@ -86,7 +80,19 @@ print_device(const char *uri, /* I - Device URI */ do { - if ((fd = open_device(uri)) == -1) + /* + * Disable backchannel data when printing to Brother, Canon, or + * Minolta USB printers - apparently these printers will return + * the IEEE-1284 device ID over and over and over when they get + * a read request... + */ + + use_bc = strcasecmp(hostname, "Brother") && + strcasecmp(hostname, "Canon") && + strcasecmp(hostname, "Konica Minolta") && + strcasecmp(hostname, "Minolta"); + + if ((device_fd = open_device(uri, &use_bc)) == -1) { if (getenv("CLASS") != NULL) { @@ -114,7 +120,8 @@ print_device(const char *uri, /* I - Device URI */ fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr); sleep(30); } - else if (errno == ENXIO || errno == EIO || errno == ENOENT || errno == ENODEV) + else if (errno == ENXIO || errno == EIO || errno == ENOENT || + errno == ENODEV) { fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr); sleep(30); @@ -127,7 +134,7 @@ print_device(const char *uri, /* I - Device URI */ } } } - while (fd < 0); + while (device_fd < 0); fputs("STATE: -connecting-to-device\n", stderr); @@ -135,187 +142,44 @@ print_device(const char *uri, /* I - Device URI */ * Set any options provided... */ - tcgetattr(fd, &opts); + tcgetattr(device_fd, &opts); opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ /**** No options supported yet ****/ - tcsetattr(fd, TCSANOW, &opts); - - /* - * Check printer status... - */ - - paperout = 0; - -#if defined(__linux) && defined(LP_POUTPA) - /* - * Show the printer status before we send the file... - */ - - while (!ioctl(fd, LPGETSTATUS, &status)) - { - fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status); - - if (status & LP_POUTPA) - { - fputs("WARNING: Media tray empty!\n", stderr); - fputs("STATUS: +media-tray-empty-error\n", stderr); - - paperout = 1; - } - - if (!(status & LP_PERRORP)) - fputs("WARNING: Printer fault!\n", stderr); - else if (!(status & LP_PSELECD)) - fputs("WARNING: Printer off-line.\n", stderr); - else - break; - - sleep(5); - } -#endif /* __linux && LP_POUTPA */ - - /* - * Now that we are "connected" to the port, ignore SIGTERM so that we - * can finish out any page data the driver sends (e.g. to eject the - * current page... Only ignore SIGTERM if we are printing data from - * stdin (otherwise you can't cancel raw jobs...) - */ - - if (!fp) - { -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, SIG_IGN); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_IGN; - sigaction(SIGTERM, &action, NULL); -#else - signal(SIGTERM, SIG_IGN); -#endif /* HAVE_SIGSET */ - } + tcsetattr(device_fd, TCSANOW, &opts); /* * Finally, send the print file... */ - wbytes = 0; + tbytes = 0; - while (copies > 0) + while (copies > 0 && tbytes >= 0) { copies --; - if (fp != 0) + if (print_fd != 0) { fputs("PAGE: 1 1\n", stderr); - lseek(fp, 0, SEEK_SET); + lseek(print_fd, 0, SEEK_SET); } - tbytes = 0; - while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0) - { - /* - * Write the print data to the printer... - */ - - tbytes += nbytes; - bufptr = buffer; - - while (nbytes > 0) - { - /* - * See if we are ready to read or write... - */ - - do - { - FD_ZERO(&input); - FD_SET(fd, &input); - FD_ZERO(&output); - FD_SET(fd, &output); - } - while (select(fd + 1, &input, &output, NULL, NULL) < 0); + tbytes = backendRunLoop(print_fd, device_fd, use_bc, side_cb); - if (FD_ISSET(fd, &input)) - { - /* - * Read backchannel data... - */ - - if ((rbytes = read(fd, backbuf, sizeof(backbuf))) > 0) - { - fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", - rbytes); - cupsBackChannelWrite(backbuf, rbytes, 1.0); - } - } - - if (FD_ISSET(fd, &output)) - { - /* - * Write print data... - */ - - if ((wbytes = write(fd, bufptr, nbytes)) < 0) - if (errno == ENOTTY) - wbytes = write(fd, bufptr, nbytes); - - if (wbytes < 0) - { - /* - * Check for retryable errors... - */ - - if (errno == ENOSPC) - { - paperout = 1; - fputs("ERROR: Out of paper!\n", stderr); - fputs("STATUS: +media-tray-empty-error\n", stderr); - } - else if (errno != EAGAIN && errno != EINTR) - { - perror("ERROR: Unable to send print file to printer"); - break; - } - } - else - { - /* - * Update count and pointer... - */ - - if (paperout) - { - fputs("STATUS: -media-tray-empty-error\n", stderr); - paperout = 0; - } - - nbytes -= wbytes; - bufptr += wbytes; - } - } - } - - if (wbytes < 0) - break; - - if (fp) - fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", - (unsigned long)tbytes); - } + if (print_fd != 0 && tbytes >= 0) + fprintf(stderr, "INFO: Sent print file, " CUPS_LLFMT " bytes...\n", + CUPS_LLCAST tbytes); } /* * Close the USB port and return... */ - close(fd); + close(device_fd); - return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); + return (tbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); } @@ -327,44 +191,52 @@ void list_devices(void) { #ifdef __linux - int i; /* Looping var */ - int fd; /* File descriptor */ - char format[255], /* Format for device filename */ - device[255], /* Device filename */ - device_id[1024], /* Device ID string */ - device_uri[1024], /* Device URI string */ - make_model[1024]; /* Make and model */ - - - /* - * First figure out which USB printer filename to use... - */ - - if (!access("/dev/usblp0", 0)) - strcpy(format, "/dev/usblp%d"); - else if (!access("/dev/usb/usblp0", 0)) - strcpy(format, "/dev/usb/usblp%d"); - else - strcpy(format, "/dev/usb/lp%d"); + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255], /* Device filename */ + device_id[1024], /* Device ID string */ + device_uri[1024], /* Device URI string */ + make_model[1024]; /* Make and model */ /* - * Then open each USB device... + * Try to open each USB device... */ for (i = 0; i < 16; i ++) { - sprintf(device, format, i); + /* + * Linux has a long history of changing the standard filenames used + * for USB printer devices. We get the honor of trying them all... + */ - if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + sprintf(device, "/dev/usblp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0) { - if (!get_device_id(fd, device_id, sizeof(device_id), - make_model, sizeof(make_model), - "usb", device_uri, sizeof(device_uri))) - printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri, - make_model, make_model, i + 1, device_id); + if (errno != ENOENT) + continue; - close(fd); + sprintf(device, "/dev/usb/lp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0) + { + if (errno != ENOENT) + continue; + + sprintf(device, "/dev/usb/usblp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0) + continue; + } } + + if (!backendGetDeviceID(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri))) + printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri, + make_model, make_model, i + 1, device_id); + + close(fd); } #elif defined(__sgi) #elif defined(__sun) && defined(ECPPIOC_GETDEVID) @@ -374,7 +246,6 @@ list_devices(void) device_id[1024], /* Device ID string */ device_uri[1024], /* Device URI string */ make_model[1024]; /* Make and model */ - struct ecpp_device_id did; /* Device ID buffer */ /* @@ -385,11 +256,11 @@ list_devices(void) { sprintf(device, "/dev/usb/printer%d", i); - if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0) { - if (!get_device_id(fd, device_id, sizeof(device_id), - make_model, sizeof(make_model), - "usb", device_uri, sizeof(device_uri))) + if (!backendGetDeviceID(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri))) printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri, make_model, make_model, i + 1, device_id); @@ -421,9 +292,13 @@ list_devices(void) * 'open_device()' - Open a USB device... */ -int /* O - File descriptor or -1 on error */ -open_device(const char *uri) /* I - Device URI */ +static int /* O - File descriptor or -1 on error */ +open_device(const char *uri, /* I - Device URI */ + int *use_bc) /* O - Set to 0 for unidirectional */ { + int fd; /* File descriptor */ + + /* * The generic implementation just treats the URI as a device filename... * Specific operating systems may also support using the device serial @@ -432,7 +307,14 @@ open_device(const char *uri) /* I - Device URI */ if (!strncmp(uri, "usb:/dev/", 9)) #ifdef __linux - return (-1); /* Do not allow direct devices anymore */ + { + /* + * Do not allow direct devices anymore... + */ + + errno = ENODEV; + return (-1); + } else if (!strncmp(uri, "usb://", 6)) { /* @@ -441,40 +323,45 @@ open_device(const char *uri) /* I - Device URI */ int i; /* Looping var */ int busy; /* Are any ports busy? */ - int fd; /* File descriptor */ - char format[255], /* Format for device filename */ - device[255], /* Device filename */ + char device[255], /* Device filename */ device_id[1024], /* Device ID string */ make_model[1024], /* Make and model */ device_uri[1024]; /* Device URI string */ /* - * First figure out which USB printer filename to use... - */ - - if (!access("/dev/usblp0", 0)) - strcpy(format, "/dev/usblp%d"); - else if (!access("/dev/usb/usblp0", 0)) - strcpy(format, "/dev/usb/usblp%d"); - else - strcpy(format, "/dev/usb/lp%d"); - - /* - * Then find the correct USB device... + * Find the correct USB device... */ do { for (busy = 0, i = 0; i < 16; i ++) { - sprintf(device, format, i); + /* + * Linux has a long history of changing the standard filenames used + * for USB printer devices. We get the honor of trying them all... + */ + + sprintf(device, "/dev/usblp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) + { + sprintf(device, "/dev/usb/lp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) + { + sprintf(device, "/dev/usb/usblp%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) + continue; + } + } - if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + if (fd >= 0) { - get_device_id(fd, device_id, sizeof(device_id), - make_model, sizeof(make_model), - "usb", device_uri, sizeof(device_uri)); + backendGetDeviceID(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri)); } else { @@ -531,7 +418,14 @@ open_device(const char *uri) /* I - Device URI */ return (-1); } #elif defined(__sun) && defined(ECPPIOC_GETDEVID) - return (-1); /* Do not allow direct devices anymore */ + { + /* + * Do not allow direct devices anymore... + */ + + errno = ENODEV; + return (-1); + } else if (!strncmp(uri, "usb://", 6)) { /* @@ -540,12 +434,10 @@ open_device(const char *uri) /* I - Device URI */ int i; /* Looping var */ int busy; /* Are any ports busy? */ - int fd; /* File descriptor */ char device[255], /* Device filename */ device_id[1024], /* Device ID string */ make_model[1024], /* Make and model */ device_uri[1024]; /* Device URI string */ - struct ecpp_device_id did; /* Device ID buffer */ /* @@ -558,10 +450,10 @@ open_device(const char *uri) /* I - Device URI */ { sprintf(device, "/dev/usb/printer%d", i); - if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) - get_device_id(fd, device_id, sizeof(device_id), - make_model, sizeof(make_model), - "usb", device_uri, sizeof(device_uri)); + if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0) + backendGetDeviceID(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri)); else { /* @@ -576,7 +468,17 @@ open_device(const char *uri) /* I - Device URI */ } if (!strcmp(uri, device_uri)) - return (fd); /* Yes, return this file descriptor... */ + { + /* + * Yes, return this file descriptor... + */ + + fputs("DEBUG: Setting use_bc to 0!\n", stderr); + + *use_bc = 0; + + return (fd); + } /* * This wasn't the one... @@ -609,7 +511,15 @@ open_device(const char *uri) /* I - Device URI */ return (-1); } #else - return (open(uri + 4, O_RDWR | O_EXCL)); + { + if ((fd = open(uri + 4, O_RDWR | O_EXCL)) < 0) + { + fd = open(uri + 4, O_WRONLY | O_EXCL); + *use_bc = 0; + } + + return (fd); + } #endif /* __linux */ else { @@ -620,5 +530,70 @@ open_device(const char *uri) /* I - Device URI */ /* - * End of "$Id: usb-unix.c 5241 2006-03-07 22:07:44Z mike $". + * 'side_cb()' - Handle side-channel requests... + */ + +static void +side_cb(int print_fd, /* I - Print file */ + int device_fd, /* I - Device file */ + int use_bc) /* I - Using back-channel? */ +{ + cups_sc_command_t command; /* Request command */ + cups_sc_status_t status; /* Request/response status */ + char data[2048]; /* Request/response data */ + int datalen; /* Request/response data size */ + + + datalen = sizeof(data); + + if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) + { + fputs("WARNING: Failed to read side-channel request!\n", stderr); + return; + } + + switch (command) + { + case CUPS_SC_CMD_DRAIN_OUTPUT : + if (tcdrain(device_fd)) + status = CUPS_SC_STATUS_IO_ERROR; + else + status = CUPS_SC_STATUS_OK; + + datalen = 0; + break; + + case CUPS_SC_CMD_GET_BIDI : + data[0] = use_bc; + datalen = 1; + break; + + case CUPS_SC_CMD_GET_DEVICE_ID : + memset(data, 0, sizeof(data)); + + if (backendGetDeviceID(device_fd, data, sizeof(data) - 1, + NULL, 0, NULL, NULL, 0)) + { + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + datalen = 0; + } + else + { + status = CUPS_SC_STATUS_OK; + datalen = strlen(data); + } + break; + + default : + status = CUPS_SC_STATUS_NOT_IMPLEMENTED; + datalen = 0; + break; + } + + cupsSideChannelWrite(command, status, data, datalen, 1.0); +} + + +/* + * End of "$Id: usb-unix.c 6293 2007-02-20 13:40:55Z mike $". */