rpms/cups/devel cups-libusb.patch,NONE,1.1
fedora-cvs-commits at redhat.com
fedora-cvs-commits at redhat.com
Thu May 11 17:16:30 UTC 2006
Author: twaugh
Update of /cvs/dist/rpms/cups/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv5280
Added Files:
cups-libusb.patch
Log Message:
Work-in-progress libusb patch.
cups-libusb.patch:
Makefile | 2
usb-unix.c | 585 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 586 insertions(+), 1 deletion(-)
--- NEW FILE cups-libusb.patch ---
--- cups-1.2.0/backend/Makefile.libusb 2006-05-11 17:10:21.000000000 +0100
+++ cups-1.2.0/backend/Makefile 2006-05-11 17:10:47.000000000 +0100
@@ -198,7 +198,7 @@
usb: usb.o ../cups/$(LIBCUPS)
echo Linking $@...
- $(CC) $(LDFLAGS) -o usb usb.o $(BACKLIBS) $(LIBS)
+ $(CC) $(LDFLAGS) -o usb usb.o $(BACKLIBS) $(LIBS) -lusb
usb.o: usb.c usb-darwin.c usb-unix.c ieee1284.c
--- cups-1.2.0/backend/usb-unix.c.libusb 2006-05-11 14:45:36.000000000 +0100
+++ cups-1.2.0/backend/usb-unix.c 2006-05-11 18:14:08.000000000 +0100
@@ -37,7 +37,17 @@
#include "ieee1284.c"
#include <sys/select.h>
+#include <usb.h>
+#define LIBUSB_TIMEOUT 5000 /* 5 sec */
+
+
+/*
+ * Local globals...
+ */
+
+static int use_libusb = 0;
+static int have_read_usb_conf = 0;
/*
* Local functions...
@@ -45,6 +55,71 @@
int open_device(const char *uri);
+/*
+ * 'read_usb_conf()' - Read the usb.conf file.
+ */
+
+static void
+read_usb_conf(void)
+{
+ cups_file_t *fp; /* File pointer */
+ char filename[1024], /* Filename */
+ line[1024], /* Line from file */
+ *value; /* Value on line */
+ int linenum; /* Line number */
+ const char *cups_serverroot; /* CUPS_SERVERROOT env var */
+
+ if (have_read_usb_conf)
+ return;
+
+ if ((cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
+ cups_serverroot = CUPS_SERVERROOT;
+
+ snprintf(filename, sizeof(filename), "%s/usb.conf", cups_serverroot);
+
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ /*
+ * Read the snmp.conf file...
+ */
+
+ linenum = 0;
+
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!value)
+ fprintf(stderr, "ERROR: Missing value on line %d of %s!\n", linenum,
+ filename);
+ else if (!strcasecmp(line, "Libusb"))
+ use_libusb = (!strcasecmp(value, "on") ||
+ !strcasecmp(value, "yes") ||
+ !strcasecmp(value, "true"));
+ else
+ fprintf(stderr, "ERROR: Unknown directive %s on line %d of %s!\n",
+ line, linenum, filename);
+ }
+
+ cupsFileClose(fp);
+ }
+
+ have_read_usb_conf = 1;
+}
+
+/*
+ * 'print_device_usb()' - Print a file using libusb.
+ */
+static int /* O - Exit status */
+print_device_libusb(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 argc, /* I - Number of command-line arguments (6 or 7) */
+ char *argv[])/* I - Command-line arguments */
+{
+ return CUPS_BACKEND_FAILED;
+}
/*
* 'print_device()' - Print a file to a USB device.
@@ -82,6 +157,11 @@
(void)argc;
(void)argv;
+ read_usb_conf ();
+ if (use_libusb)
+ return print_device_libusb (uri, hostname, resource, options, fp, copies,
+ argc, argv);
+
/*
* Open the USB port device...
*/
@@ -322,6 +402,504 @@
return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
}
+static int
+get_device_id_libusb(struct usb_device *dev,
+ usb_dev_handle *devhdl,
+ int conf,
+ int interface,
+ int alt_set,
+ char *device_id,
+ int device_id_size,
+ char *make_model,
+ int make_model_size,
+ const char *scheme,
+ char *uri,
+ int uri_size)
+{
+ struct usb_interface_descriptor *pi;
+ int ret;
+ int length;
+
+ pi = &dev->config[conf].interface[interface].altsetting[alt_set];
+ ret = usb_control_msg(devhdl,
+ (USB_TYPE_CLASS | USB_ENDPOINT_IN |
+ USB_RECIP_INTERFACE),
+ 0, 0,
+ interface << 8 | pi->bAlternateSetting,
+ device_id, device_id_size - 1, LIBUSB_TIMEOUT);
+ if (ret < 0)
+ return ret;
+
+ ////
+ // Copied from ieee1284.c's get_device_id(). That function needs
+ // splitting out into two parts.
+ ////
+
+ *device_id = '\0';
+ *make_model = '\0';
+
+ /*
+ * Extract the length of the device ID string from the first two
+ * bytes. The 1284 spec says the length is stored MSB first...
+ */
+ length = (((unsigned)device_id[0] & 255) << 8) +
+ ((unsigned)device_id[1] & 255);
+
+ /*
+ * Check to see if the length is larger than our buffer; first
+ * assume that the vendor incorrectly implemented the 1284 spec,
+ * and then limit the length to the size of our buffer...
+ */
+
+ if (length > (device_id_size - 2))
+ length = (((unsigned)device_id[1] & 255) << 8) +
+ ((unsigned)device_id[0] & 255);
+
+ if (length > (device_id_size - 2))
+ length = device_id_size - 2;
+
+ /*
+ * Copy the device ID text to the beginning of the buffer and
+ * nul-terminate.
+ */
+
+ memmove(device_id, device_id + 2, length);
+ device_id[length] = '\0';
+
+ if (!*device_id)
+ return (-1);
+
+ /*
+ * Get the make and model...
+ */
+
+ get_make_model(device_id, make_model, make_model_size);
+
+ /*
+ * Then generate a device URI...
+ */
+
+ if (scheme && uri && uri_size > 32)
+ {
+ char *attr, /* 1284 attribute */
+ *delim, /* 1284 delimiter */
+ *uriptr, /* Pointer into URI */
+ manufacturer[256], /* Manufacturer string */
+ serial_number[1024]; /* Serial number string */
+ int manulen; /* Length of manufacturer string */
+
+ /*
+ * Look for the serial number field...
+ */
+
+ if ((attr = strstr(device_id, "SERN:")) != NULL)
+ attr += 5;
+ else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
+ attr += 13;
+ else if ((attr = strstr(device_id, ";SN:")) != NULL)
+ attr += 4;
+
+ if (attr)
+ {
+ strlcpy(serial_number, attr, sizeof(serial_number));
+
+ if ((delim = strchr(serial_number, ';')) != NULL)
+ *delim = '\0';
+ }
+ else
+ serial_number[0] = '\0';
+
+ /*
+ * Generate the device URI from the manufacturer, make_model, and
+ * serial number strings.
+ */
+
+ snprintf(uri, uri_size, "%s://", scheme);
+
+ if ((attr = strstr(device_id, "MANUFACTURER:")) != NULL)
+ attr += 13;
+ else if ((attr = strstr(device_id, "Manufacturer:")) != NULL)
+ attr += 13;
+ else if ((attr = strstr(device_id, "MFG:")) != NULL)
+ attr += 4;
+
+ if (attr)
+ {
+ strlcpy(manufacturer, attr, sizeof(manufacturer));
+
+ if ((delim = strchr(manufacturer, ';')) != NULL)
+ *delim = '\0';
+
+ if (!strcasecmp(manufacturer, "Hewlett-Packard"))
+ strcpy(manufacturer, "HP");
+ }
+ else
+ {
+ strlcpy(manufacturer, make_model, sizeof(manufacturer));
+
+ if ((delim = strchr(manufacturer, ' ')) != NULL)
+ *delim = '\0';
+ }
+
+ manulen = strlen(manufacturer);
+
+ for (uriptr = uri + strlen(uri), delim = manufacturer;
+ *delim && uriptr < (uri + uri_size - 3);
+ delim ++)
+ if (*delim == ' ')
+ {
+ *uriptr++ = '%';
+ *uriptr++ = '2';
+ *uriptr++ = '0';
+ }
+ else
+ *uriptr++ = *delim;
+
+ *uriptr++ = '/';
+
+ if (!strncasecmp(make_model, manufacturer, manulen))
+ {
+ delim = make_model + manulen;
+
+ while (isspace(*delim & 255))
+ delim ++;
+ }
+ else
+ delim = make_model;
+
+ for (; *delim && uriptr < (uri + uri_size - 3); delim ++)
+ if (*delim == ' ')
+ {
+ *uriptr++ = '%';
+ *uriptr++ = '2';
+ *uriptr++ = '0';
+ }
+ else
+ *uriptr++ = *delim;
+
+ if (serial_number[0])
+ {
+ /*
+ * Add the serial number to the URI...
+ */
+
+ strlcpy(uriptr, "?serial=", uri_size - (uriptr - uri));
+ strlcat(uriptr, serial_number, uri_size - (uriptr - uri));
+ }
+ else
+ *uriptr = '\0';
+ }
+
+ return (0);
+}
+
+static usb_dev_handle *
+open_device_bydev(struct usb_device *dev,
+ int conf,
+ int interface,
+ int alt_set)
+{
+ usb_dev_handle *devhdl;
+ struct usb_interface_descriptor *pi;
+
+ devhdl = usb_open(dev);
+ if (!devhdl)
+ {
+ fprintf(stderr,"DEBUG: Cannot open device %d:%d\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return NULL;
+ }
+
+ pi = &dev->config[conf].interface[interface].altsetting[alt_set];
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ fprintf (stderr, "DEBUG: detaching kernel driver\n");
+ usb_detach_kernel_driver_np(devhdl, pi->bInterfaceNumber);
+#endif
+
+ // This can sometimes fail (e.g. HP PSC devices). Ignore failures?
+ usb_set_configuration(devhdl, dev->config[conf].bConfigurationValue);
+
+ /* we always claim interface 0 even if the printer is not there,
+ we use it for control */
+ if (pi->bInterfaceNumber != 0)
+ {
+ while (usb_claim_interface (devhdl,pi->bInterfaceNumber) < 0)
+ {
+ if (errno == EBUSY)
+ {
+ fprintf(stderr,
+ "INFO: USB printer is busy; will retry in 5 seconds...\n");
+ sleep(5);
+
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ usb_detach_kernel_driver_np(devhdl, pi->bInterfaceNumber);
+#endif
+ continue;
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Cannot claim interface %d device %d:%d\n",
+ interface, dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ return NULL;
+ }
+ }
+ }
+
+ while (usb_claim_interface (devhdl, 0) < 0)
+ {
+ if (errno == EBUSY)
+ {
+ fprintf(stderr,
+ "INFO: USB printer is busy; will retry in 5 seconds...\n");
+ sleep(5);
+
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ usb_detach_kernel_driver_np(devhdl, pi->bInterfaceNumber);
+#endif
+ continue;
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Cannot claim interface %d device %d:%d\n",
+ interface, dev->descriptor.idVendor, dev->descriptor.idProduct);
+ usb_close(devhdl);
+ return NULL;
+ }
+ }
+
+ while (usb_set_altinterface(devhdl, pi->bAlternateSetting) < 0 )
+ {
+ if (errno == EBUSY)
+ {
+ fprintf(stderr,
+ "INFO: USB printer is busy; will retry in 5 seconds...\n");
+ sleep(5);
+
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ usb_detach_kernel_driver_np(devhdl, pi->bInterfaceNumber);
+#endif
+ continue;
+ }
+ else
+ {
+ fprintf(stderr, "DEBUG: Cannot set alternate setting %d device %d:%d\n",
+ alt_set, dev->descriptor.idVendor, dev->descriptor.idProduct);
+ usb_close(devhdl);
+ return NULL;
+ }
+ }
+
+ return devhdl;
+}
+
+static int
+print_detected_device (struct usb_device *dev,
+ int conf,
+ int interface,
+ int alt_set,
+ int ep,
+ const void * arg)
+{
+ usb_dev_handle *devhdl;
+ char device_id[1024], /* Device ID string */
+ device_uri[1024], /* Device URI string */
+ make_model[1024]; /* Make and model */
+
+ devhdl = open_device_bydev(dev, conf, interface, alt_set);
+ if (!devhdl)
+ return -1;
+
+ if (get_device_id_libusb(dev, devhdl, conf, interface,
+ alt_set,
+ device_id, sizeof(device_id),
+ make_model, sizeof(make_model),
+ "usb", device_uri, sizeof(device_uri)) < 0)
+ {
+ fprintf(stderr, "DEBUG: Cannot get DeviceID string device %d:%d\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ printf("direct usb:%s%s \"Unknown\" \"USB Printer #%s%s\"\n",
+ dev->bus->dirname, dev->filename, dev->bus->dirname, dev->filename);
+ }
+ else
+ printf("direct %s \"%s\" \"%s USB %s\" \"%s\"\n", device_uri,
+ make_model, make_model, dev->filename, device_id);
+
+ usb_close(devhdl);
+ return -1;
+}
+
+/* this is a helper function which call a callback for every printer on the bus.
+ * usefull for seaching a device or listing all devices
+ * callback declaration
+ int cb(struct usb_device * dev, int conf, int interface, int alt_set, int ep, void * arg)
+ * arg is the "arg" argument supplied to find_device.
+ *
+ * when the callback return 0, the search is stopped and the function end
+ * return 0 when printer found( and argument are populated ), -1 otherwise
+ */
+struct protocol_available {
+ int epread;
+ int epwrite;
+ int alt_set;
+};
+
+static int
+find_device(struct usb_device **pdev,
+ int *pconf,
+ int *pinterface,
+ int *palt_set,
+ int *pep,
+ int (*cb)(struct usb_device *, int, int, int, int, const void *),
+ const void * arg)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ for (bus = usb_get_busses (); bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ int conf = 0;
+ int alt_set = 0;
+ int interface = 0;
+ int protocol = 0;
+ int found = 0;
+ int ep = 0;
+ /* temporary struct to stock every protocol supported by printer so
+ * we can choose the best one */
+ struct protocol_available dev_proto[3] =
+ {
+ {-1,-1,-1},{-1,-1,-1},{-1,-1,-1}
+ };
+
+ if (!dev->config)
+ continue;
+
+ if (dev->descriptor.idVendor == 0 || dev->descriptor.idProduct == 0)
+ /* root hub */
+ continue;
+
+ for(conf = 0;
+ conf < dev->descriptor.bNumConfigurations && !found;
+ conf++)
+ {
+ for (interface = 0;
+ interface < dev->config[conf].bNumInterfaces && !found;
+ interface++)
+ {
+ for (alt_set = 0;
+ alt_set < dev->config[conf].interface[interface].num_altsetting;
+ alt_set++)
+ {
+ struct usb_interface_descriptor *pi;
+ pi = &dev->config[conf].interface[interface].altsetting[alt_set];
+ if (pi->bInterfaceClass != USB_CLASS_PRINTER ||
+ pi->bInterfaceSubClass != 1)
+ continue;
+
+ protocol = pi->bInterfaceProtocol;
+ if (protocol < 1 || protocol > 3)
+ continue;
+
+ dev_proto[protocol-1].alt_set = alt_set;
+ /* look for bulk write and read endpoint */
+ for (ep = 0;
+ ep < pi->bNumEndpoints;
+ ep++)
+ {
+ struct usb_endpoint_descriptor *epd = &pi->endpoint[ep];
+ if ((epd->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+ != USB_ENDPOINT_TYPE_BULK)
+ continue;
+
+ if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK))
+ {
+ if (dev_proto[protocol-1].epwrite == -1)
+ dev_proto[protocol-1].epwrite = ep;
+ }
+ else
+ {
+ if (dev_proto[protocol-1].epread == -1)
+ dev_proto[protocol-1].epread = ep;
+ }
+ }
+ }
+
+ /* check if 7/1/2 is ok */
+ if (dev_proto[1].epread != -1 && dev_proto[1].epwrite != -1)
+ {
+ alt_set = dev_proto[1].alt_set;
+ ep = dev_proto[1].epwrite;
+ found = 1;
+ continue;
+ }
+
+ /* check if 7/1/1 is ok */
+ if (dev_proto[0].epwrite != -1)
+ {
+ alt_set = dev_proto[0].alt_set;
+ ep = dev_proto[0].epwrite;
+ found = 1;
+ continue;
+ }
+
+ /* check if 7/1/3 is ok */
+ if (dev_proto[2].epwrite != -1 && dev_proto[2].epread != -1)
+ {
+ alt_set = dev_proto[2].alt_set;
+ ep = dev_proto[2].epwrite;
+ found = 1;
+ continue;
+ }
+ }
+ }
+
+ if (found)
+ {
+ if (!cb(dev, conf - 1, interface - 1, alt_set, ep, arg))
+ {
+ if (pdev)
+ *pdev = dev;
+ if (pconf)
+ *pconf = conf - 1;
+ if (pinterface)
+ *pinterface = interface - 1;
+ if (palt_set)
+ *palt_set = alt_set;
+ if (pep)
+ *pep = ep;
+ return 0;
+ }
+ }
+ }
+ }
+
+ if (pdev)
+ *pdev = NULL;
+ if (pconf)
+ *pconf = 0;
+ if (pinterface)
+ *pinterface = 0;
+ if (palt_set)
+ *palt_set = 0;
+ if (pep)
+ *pep = 0;
+
+ return -1;
+}
+
+/*
+ * 'list_devices_libusb()' - List devices using libusb.
+ */
+static void
+list_devices_libusb(void)
+{
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ find_device(NULL, NULL, NULL, NULL, NULL, print_detected_device, NULL);
+}
/*
* 'list_devices()' - List all USB devices.
@@ -330,6 +908,13 @@
void
list_devices(void)
{
+ read_usb_conf ();
+ if (use_libusb)
+ {
+ list_devices_libusb ();
+ return;
+ }
+
#ifdef __linux
int i; /* Looping var */
int fd; /* File descriptor */
More information about the fedora-cvs-commits
mailing list