+ char requested_uri[1024], /* Requested URI */
+ *requested_ptr, /* Pointer into requested URI */
+ detected_uri[1024], /* Detected URI */
+ *detected_ptr; /* Pointer into detected URI */
+
+
+ /*
+ * If we have an exact match, stop now...
+ */
+
+ if (!strcmp((char *)data, device_uri))
+ return (1);
+
+ /*
+ * Work on copies of the URIs...
+ */
+
+ strlcpy(requested_uri, (char *)data, sizeof(requested_uri));
+ strlcpy(detected_uri, device_uri, sizeof(detected_uri));
+
+ /*
+ * libusb-discovered URIs can have an "interface" specification and this
+ * never happens for usblp-discovered URIs, so remove the "interface"
+ * specification from the URI which we are checking currently. This way a
+ * queue for a usblp-discovered printer can now be accessed via libusb.
+ *
+ * Similarly, strip "?serial=NNN...NNN" as needed.
+ */
+
+ if ((requested_ptr = strstr(requested_uri, "?interface=")) == NULL)
+ requested_ptr = strstr(requested_uri, "&interface=");
+ if ((detected_ptr = strstr(detected_uri, "?interface=")) == NULL)
+ detected_ptr = strstr(detected_uri, "&interface=");
+
+ if (!requested_ptr && detected_ptr)
+ {
+ /*
+ * Strip "[?&]interface=nnn" from the detected printer.
+ */
+
+ *detected_ptr = '\0';
+ }
+ else if (requested_ptr && !detected_ptr)
+ {
+ /*
+ * Strip "[?&]interface=nnn" from the requested printer.
+ */
+
+ *requested_ptr = '\0';
+ }
+
+ if ((requested_ptr = strstr(requested_uri, "?serial=?")) != NULL)
+ {
+ /*
+ * Strip "?serial=?" from the requested printer. This is a special
+ * case, as "?serial=?" means no serial number and not the serial
+ * number '?'. This is not covered by the checks below...
+ */
+
+ *requested_ptr = '\0';
+ }
+
+ if ((requested_ptr = strstr(requested_uri, "?serial=")) == NULL &&
+ (detected_ptr = strstr(detected_uri, "?serial=")) != NULL)
+ {
+ /*
+ * Strip "?serial=nnn" from the detected printer.
+ */
+
+ *detected_ptr = '\0';
+ }
+ else if (requested_ptr && !detected_ptr)
+ {
+ /*
+ * Strip "?serial=nnn" from the requested printer.
+ */
+
+ *requested_ptr = '\0';
+ }
+
+ return (!strcmp(requested_uri, detected_uri));
+}
+
+
+/*
+ * 'read_thread()' - Thread to read the backchannel data on.
+ */
+
+static void *read_thread(void *reference)
+{
+ unsigned char readbuffer[512];
+ int rbytes;
+ int readstatus;
+ struct timeval now,
+ delay,
+ end,
+ timeleft;
+
+
+ (void)reference;
+
+ /*
+ * Read frequency: once every 250 milliseconds.
+ */
+
+ delay.tv_sec = 0;
+ delay.tv_usec = 250000;
+
+ do
+ {
+ /*
+ * Remember when we started so we can throttle the loop after the read
+ * call...
+ */
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Calculate what 250 milliSeconds are in absolute time...
+ */
+
+ timeradd(&now, &delay, &end);
+
+ rbytes = sizeof(readbuffer);
+ readstatus = libusb_bulk_transfer(g.printer->handle,
+ g.printer->read_endp,
+ readbuffer, rbytes,
+ &rbytes, 60000);
+ if (readstatus == LIBUSB_SUCCESS && rbytes > 0)
+ {
+ fprintf(stderr, "DEBUG: Read %d bytes of back-channel data...\n",
+ (int)rbytes);
+ cupsBackChannelWrite((const char *)readbuffer, (size_t)rbytes, 1.0);
+ }
+ else if (readstatus == LIBUSB_ERROR_TIMEOUT)
+ fputs("DEBUG: Got USB transaction timeout during read.\n", stderr);
+ else if (readstatus == LIBUSB_ERROR_PIPE)
+ fputs("DEBUG: Got USB pipe stalled during read.\n", stderr);
+ else if (readstatus == LIBUSB_ERROR_INTERRUPTED)
+ fputs("DEBUG: Got USB return aborted during read.\n", stderr);
+
+ /*
+ * Make sure this loop executes no more than once every 250 miliseconds...
+ */
+
+ if ((readstatus != LIBUSB_SUCCESS || rbytes == 0) &&
+ (g.wait_eof || !g.read_thread_stop))
+ {
+ gettimeofday(&now, NULL);
+ if (timercmp(&now, &end, <))
+ {
+ timersub(&end, &now, &timeleft);
+ usleep(1000000 * timeleft.tv_sec + timeleft.tv_usec);
+ }
+ }
+ } while (g.wait_eof || !g.read_thread_stop);
+
+ /*
+ * Let the main thread know that we have completed the read thread...
+ */
+
+ pthread_mutex_lock(&g.read_thread_mutex);
+ g.read_thread_done = 1;
+ pthread_cond_signal(&g.read_thread_cond);
+ pthread_mutex_unlock(&g.read_thread_mutex);
+
+ return (NULL);