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