2013-06-27 23:02:34 -04:00
|
|
|
/*
|
|
|
|
* CUPS Backend common code
|
|
|
|
*
|
|
|
|
* (c) 2013 Solomon Peachy <pizza@shaftnet.org>
|
|
|
|
*
|
|
|
|
* The latest version of this program can be found at:
|
|
|
|
*
|
|
|
|
* http://git.shaftnet.org/git/gitweb.cgi?p=selphy_print.git
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 3 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* [http://www.gnu.org/licenses/gpl-3.0.html]
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <libusb-1.0/libusb.h>
|
2013-06-29 12:25:06 -04:00
|
|
|
#include <arpa/inet.h>
|
2013-06-27 23:02:34 -04:00
|
|
|
|
2013-07-17 23:39:31 -04:00
|
|
|
#define BACKEND_VERSION "0.6"
|
2013-06-30 13:01:17 -04:00
|
|
|
|
2013-06-27 23:02:34 -04:00
|
|
|
#define STR_LEN_MAX 64
|
|
|
|
#define DEBUG( ... ) fprintf(stderr, "DEBUG: " __VA_ARGS__ )
|
2013-06-28 07:50:24 -04:00
|
|
|
#define DEBUG2( ... ) fprintf(stderr, __VA_ARGS__ )
|
2013-06-27 23:02:34 -04:00
|
|
|
#define INFO( ... ) fprintf(stderr, "INFO: " __VA_ARGS__ )
|
|
|
|
#define ERROR( ... ) do { fprintf(stderr, "ERROR: " __VA_ARGS__ ); sleep(1); } while (0)
|
|
|
|
|
|
|
|
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
|
|
|
#define le32_to_cpu(__x) __x
|
|
|
|
#define le16_to_cpu(__x) __x
|
|
|
|
#define be16_to_cpu(__x) ntohs(__x)
|
|
|
|
#define be32_to_cpu(__x) ntohl(__x)
|
|
|
|
#else
|
|
|
|
#define le32_to_cpu(x) \
|
|
|
|
({ \
|
|
|
|
uint32_t __x = (x); \
|
|
|
|
((uint32_t)( \
|
|
|
|
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
|
|
|
|
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
|
|
|
|
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
|
|
|
|
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
|
|
|
|
})
|
|
|
|
#define le16_to_cpu(x) \
|
|
|
|
({ \
|
|
|
|
uint16_t __x = (x); \
|
|
|
|
((uint16_t)( \
|
|
|
|
(((uint16_t)(__x) & (uint16_t)0x00ff) << 8) | \
|
|
|
|
(((uint16_t)(__x) & (uint16_t)0xff00) >> 8) | \
|
|
|
|
})
|
|
|
|
#define be32_to_cpu(__x) __x
|
|
|
|
#define be16_to_cpu(__x) __x
|
|
|
|
#endif
|
|
|
|
|
2013-07-06 09:10:01 -04:00
|
|
|
#define cpu_to_le16 le16_to_cpu
|
|
|
|
#define cpu_to_le32 le32_to_cpu
|
|
|
|
#define cpu_to_be16 be16_to_cpu
|
|
|
|
#define cpu_to_be32 be32_to_cpu
|
|
|
|
|
2013-07-17 23:39:31 -04:00
|
|
|
/* To enumerate supported devices */
|
|
|
|
struct device_id {
|
|
|
|
uint16_t vid;
|
|
|
|
uint16_t pid;
|
|
|
|
int type;
|
|
|
|
char *manuf_str;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
P_ES1 = 0,
|
|
|
|
P_ES2_20,
|
|
|
|
P_ES3_30,
|
|
|
|
P_ES40_CP790,
|
|
|
|
P_CP_XXX,
|
|
|
|
P_CP10,
|
|
|
|
P_KODAK_6800,
|
|
|
|
P_KODAK_1400_805,
|
|
|
|
P_SHINKO_S2145,
|
|
|
|
P_SONY_UPDR150,
|
|
|
|
P_END,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define USB_VID_CANON 0x04a9
|
|
|
|
#define USB_PID_CANON_CP10 0x304A
|
|
|
|
#define USB_PID_CANON_CP100 0x3063
|
|
|
|
#define USB_PID_CANON_CP200 0x307C
|
|
|
|
#define USB_PID_CANON_CP220 0x30BD
|
|
|
|
#define USB_PID_CANON_CP300 0x307D
|
|
|
|
#define USB_PID_CANON_CP330 0x30BE
|
|
|
|
#define USB_PID_CANON_CP400 0x30F6
|
|
|
|
#define USB_PID_CANON_CP500 0x30F5
|
|
|
|
#define USB_PID_CANON_CP510 0x3128
|
|
|
|
#define USB_PID_CANON_CP520 520 // XXX 316f? 3172? (related to cp740/cp750)
|
|
|
|
#define USB_PID_CANON_CP530 0x31b1
|
|
|
|
#define USB_PID_CANON_CP600 0x310B
|
|
|
|
#define USB_PID_CANON_CP710 0x3127
|
|
|
|
#define USB_PID_CANON_CP720 0x3143
|
|
|
|
#define USB_PID_CANON_CP730 0x3142
|
|
|
|
#define USB_PID_CANON_CP740 0x3171
|
|
|
|
#define USB_PID_CANON_CP750 0x3170
|
|
|
|
#define USB_PID_CANON_CP760 0x31AB
|
|
|
|
#define USB_PID_CANON_CP770 0x31AA
|
|
|
|
#define USB_PID_CANON_CP780 0x31DD
|
|
|
|
#define USB_PID_CANON_CP790 790 // XXX 31ed? 31ef? (related to es40)
|
|
|
|
#define USB_PID_CANON_CP800 0x3214
|
|
|
|
#define USB_PID_CANON_CP810 0x3256
|
|
|
|
#define USB_PID_CANON_CP900 0x3255
|
|
|
|
#define USB_PID_CANON_ES1 0x3141
|
|
|
|
#define USB_PID_CANON_ES2 0x3185
|
|
|
|
#define USB_PID_CANON_ES20 0x3186
|
|
|
|
#define USB_PID_CANON_ES3 0x31AF
|
|
|
|
#define USB_PID_CANON_ES30 0x31B0
|
|
|
|
#define USB_PID_CANON_ES40 0x31EE
|
|
|
|
#define USB_VID_SONY 0x054C
|
|
|
|
#define USB_PID_SONY_UPDR150 0x01E8
|
|
|
|
#define USB_VID_KODAK 0x040A
|
|
|
|
#define USB_PID_KODAK_6800 0x4021
|
|
|
|
#define USB_PID_KODAK_1400 0x4022
|
|
|
|
#define USB_PID_KODAK_805 0x4034
|
|
|
|
#define USB_VID_SHINKO 0x10CE
|
|
|
|
#define USB_PID_SHINKO_S2145 0x000E
|
|
|
|
|
|
|
|
static struct device_id devices[] = {
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP10, P_CP10, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP100, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP200, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP220, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP300, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP330, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP400, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP500, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP510, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP520, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP530, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP600, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP710, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP720, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP730, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP740, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP750, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP760, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP770, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP780, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP790, P_ES40_CP790, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP800, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP810, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_CP900, P_CP_XXX, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES1, P_ES1, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES2, P_ES2_20, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES20, P_ES2_20, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES3, P_ES3_30, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES30, P_ES3_30, "Canon"},
|
|
|
|
{ USB_VID_CANON, USB_PID_CANON_ES40, P_ES40_CP790, "Canon"},
|
|
|
|
|
|
|
|
{ USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak"},
|
|
|
|
{ USB_VID_KODAK, USB_PID_KODAK_1400, P_KODAK_1400_805, "Kodak"},
|
|
|
|
{ USB_VID_KODAK, USB_PID_KODAK_805, P_KODAK_1400_805, "Kodak"},
|
|
|
|
|
|
|
|
{ USB_VID_SHINKO, USB_PID_SHINKO_S2145, P_SHINKO_S2145, ""},
|
|
|
|
{ USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, ""},
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Support Functions */
|
|
|
|
|
2013-06-27 23:02:34 -04:00
|
|
|
#define ID_BUF_SIZE 2048
|
|
|
|
static char *get_device_id(struct libusb_device_handle *dev)
|
|
|
|
{
|
2013-07-17 23:39:31 -04:00
|
|
|
int length;
|
2013-06-27 23:02:34 -04:00
|
|
|
int claimed = 0;
|
|
|
|
int iface = 0;
|
|
|
|
char *buf = malloc(ID_BUF_SIZE + 1);
|
|
|
|
|
|
|
|
claimed = libusb_kernel_driver_active(dev, iface);
|
|
|
|
if (claimed)
|
|
|
|
libusb_detach_kernel_driver(dev, iface);
|
|
|
|
|
|
|
|
libusb_claim_interface(dev, iface);
|
|
|
|
|
|
|
|
if (libusb_control_transfer(dev,
|
|
|
|
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_ENDPOINT_IN |
|
|
|
|
LIBUSB_RECIPIENT_INTERFACE,
|
|
|
|
0, 0,
|
|
|
|
(iface << 8),
|
|
|
|
(unsigned char *)buf, ID_BUF_SIZE, 5000) < 0)
|
|
|
|
{
|
|
|
|
*buf = '\0';
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* length is the first two bytes, MSB first */
|
|
|
|
length = (((unsigned)buf[0] & 255) << 8) |
|
|
|
|
((unsigned)buf[1] & 255);
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
if (length > ID_BUF_SIZE || length < 14)
|
|
|
|
length = (((unsigned)buf[1] & 255) << 8) |
|
|
|
|
((unsigned)buf[0] & 255);
|
|
|
|
|
|
|
|
if (length > ID_BUF_SIZE)
|
|
|
|
length = ID_BUF_SIZE;
|
|
|
|
|
|
|
|
if (length < 14) {
|
|
|
|
*buf = '\0';
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move, and terminate */
|
|
|
|
memmove(buf, buf + 2, length);
|
|
|
|
buf[length] = '\0';
|
|
|
|
|
|
|
|
done:
|
|
|
|
libusb_release_interface(dev, iface);
|
2013-07-17 23:40:48 -04:00
|
|
|
#if 0
|
2013-06-27 23:02:34 -04:00
|
|
|
if (claimed)
|
|
|
|
libusb_attach_kernel_driver(dev, iface);
|
2013-07-17 23:40:48 -04:00
|
|
|
#endif
|
2013-06-27 23:02:34 -04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2013-07-17 23:39:31 -04:00
|
|
|
|
2013-06-27 23:02:34 -04:00
|
|
|
static int send_data(struct libusb_device_handle *dev, uint8_t endp,
|
2013-06-30 12:05:32 -04:00
|
|
|
uint8_t *buf, int len)
|
2013-06-27 23:02:34 -04:00
|
|
|
{
|
|
|
|
int num;
|
|
|
|
|
2013-06-30 11:15:03 -04:00
|
|
|
while (len) {
|
|
|
|
int ret = libusb_bulk_transfer(dev, endp,
|
2013-07-06 10:12:19 -04:00
|
|
|
buf, (len > 65536) ? 65536: len,
|
|
|
|
&num, 5000);
|
2013-06-30 11:15:03 -04:00
|
|
|
if (ret < 0) {
|
|
|
|
ERROR("Failure to send data to printer (libusb error %d: (%d/%d to 0x%02x))\n", ret, num, len, endp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
len -= num;
|
|
|
|
buf += num;
|
2013-06-30 12:05:32 -04:00
|
|
|
// DEBUG("Sent %d (%d remaining) to 0x%x\n", num, len, endp);
|
2013-06-27 23:02:34 -04:00
|
|
|
}
|
2013-06-30 11:15:03 -04:00
|
|
|
|
2013-06-27 23:02:34 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int terminate = 0;
|
|
|
|
|
2013-06-30 11:15:03 -04:00
|
|
|
static void sigterm_handler(int signum) {
|
2013-06-27 23:02:34 -04:00
|
|
|
terminate = 1;
|
|
|
|
INFO("Job Cancelled");
|
|
|
|
}
|
2013-06-30 11:15:03 -04:00
|
|
|
|
2013-07-06 20:58:23 -04:00
|
|
|
static char *sanitize_string(char *str) {
|
|
|
|
int len = strlen(str);
|
|
|
|
|
|
|
|
while(len && (str[len-1] <= 0x20)) {
|
|
|
|
str[len-1] = 0;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2013-06-30 11:32:41 -04:00
|
|
|
static int print_scan_output(struct libusb_device *device,
|
|
|
|
struct libusb_device_descriptor *desc,
|
|
|
|
char *prefix, char *manuf2,
|
2013-07-17 22:43:49 -04:00
|
|
|
int found, int match,
|
2013-06-30 11:32:41 -04:00
|
|
|
int scan_only, char *match_serno)
|
2013-06-30 11:15:03 -04:00
|
|
|
{
|
2013-06-30 11:32:41 -04:00
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
|
|
|
|
unsigned char product[STR_LEN_MAX] = "";
|
|
|
|
unsigned char serial[STR_LEN_MAX] = "";
|
|
|
|
unsigned char manuf[STR_LEN_MAX] = "";
|
|
|
|
|
|
|
|
if (libusb_open(device, &dev)) {
|
|
|
|
ERROR("Could not open device %04x:%04x\n", desc->idVendor, desc->idProduct);
|
2013-06-30 12:05:32 -04:00
|
|
|
found = -1;
|
|
|
|
goto abort;
|
2013-06-30 11:32:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Query detailed info */
|
|
|
|
if (desc->iManufacturer) {
|
|
|
|
libusb_get_string_descriptor_ascii(dev, desc->iManufacturer, manuf, STR_LEN_MAX);
|
2013-07-06 20:58:23 -04:00
|
|
|
sanitize_string((char*)manuf);
|
2013-06-30 11:32:41 -04:00
|
|
|
}
|
|
|
|
if (desc->iProduct) {
|
|
|
|
libusb_get_string_descriptor_ascii(dev, desc->iProduct, product, STR_LEN_MAX);
|
2013-07-06 20:58:23 -04:00
|
|
|
sanitize_string((char*)product);
|
2013-06-30 11:15:03 -04:00
|
|
|
}
|
2013-06-30 11:32:41 -04:00
|
|
|
if (desc->iSerialNumber) {
|
|
|
|
libusb_get_string_descriptor_ascii(dev, desc->iSerialNumber, serial, STR_LEN_MAX);
|
2013-07-06 20:58:23 -04:00
|
|
|
sanitize_string((char*)serial);
|
2013-06-30 11:32:41 -04:00
|
|
|
}
|
|
|
|
|
2013-07-16 21:08:33 -04:00
|
|
|
if (!strlen((char*)serial)) {
|
|
|
|
uint8_t bus_num;
|
|
|
|
uint8_t port_num;
|
|
|
|
|
|
|
|
bus_num = libusb_get_bus_number(device);
|
|
|
|
port_num = libusb_get_port_number(device);
|
|
|
|
sprintf((char*)serial, "NONE_B%03d_D%03d", bus_num, port_num);
|
|
|
|
}
|
2013-06-30 11:32:41 -04:00
|
|
|
|
2013-07-17 22:43:49 -04:00
|
|
|
DEBUG("%sPID: %04X Manuf: '%s' Product: '%s' Serial: '%s'\n",
|
2013-06-30 12:05:32 -04:00
|
|
|
match ? "MATCH: " : "",
|
2013-07-06 21:05:00 -04:00
|
|
|
desc->idProduct, manuf, product, serial);
|
2013-06-30 11:15:03 -04:00
|
|
|
|
2013-07-17 22:43:49 -04:00
|
|
|
if (scan_only) {
|
2013-06-30 11:32:41 -04:00
|
|
|
/* URL-ify model. */
|
|
|
|
char buf[128]; // XXX ugly..
|
|
|
|
int j = 0, k = 0;
|
2013-07-06 20:58:23 -04:00
|
|
|
char *ieee_id = get_device_id(dev);
|
2013-06-30 11:32:41 -04:00
|
|
|
while (*(product + j + strlen(manuf2))) {
|
2013-07-06 20:58:23 -04:00
|
|
|
buf[k] = *(product + j + (strlen(manuf2) ? (strlen(manuf2) + 1) : 0));
|
2013-06-30 11:32:41 -04:00
|
|
|
if(buf[k] == ' ') {
|
|
|
|
buf[k++] = '%';
|
|
|
|
buf[k++] = '2';
|
|
|
|
buf[k] = '0';
|
|
|
|
}
|
|
|
|
k++;
|
|
|
|
j++;
|
|
|
|
}
|
2013-07-06 20:58:23 -04:00
|
|
|
buf[k] = 0;
|
2013-06-30 11:32:41 -04:00
|
|
|
|
|
|
|
fprintf(stdout, "direct %s%s/%s?serial=%s \"%s\" \"%s\" \"%s\" \"\"\n",
|
2013-07-06 20:58:23 -04:00
|
|
|
prefix, strlen(manuf2) ? manuf2 : (char*)manuf,
|
2013-06-30 11:32:41 -04:00
|
|
|
buf, serial, product, product,
|
|
|
|
ieee_id);
|
|
|
|
|
|
|
|
if (ieee_id)
|
|
|
|
free(ieee_id);
|
|
|
|
}
|
2013-06-30 11:15:03 -04:00
|
|
|
|
2013-06-30 11:32:41 -04:00
|
|
|
/* If a serial number was passed down, use it. */
|
|
|
|
if (found && match_serno &&
|
|
|
|
strcmp(match_serno, (char*)serial)) {
|
|
|
|
found = -1;
|
|
|
|
}
|
2013-06-30 11:15:03 -04:00
|
|
|
|
2013-06-30 11:32:41 -04:00
|
|
|
libusb_close(dev);
|
2013-06-30 12:05:32 -04:00
|
|
|
abort:
|
2013-06-30 11:32:41 -04:00
|
|
|
return found;
|
2013-06-30 11:15:03 -04:00
|
|
|
}
|
2013-07-17 23:39:31 -04:00
|
|
|
|
|
|
|
static int find_and_enumerate(struct libusb_context *ctx,
|
|
|
|
struct libusb_device ***list,
|
|
|
|
char *match_serno,
|
|
|
|
int printer_type,
|
|
|
|
int scan_only)
|
|
|
|
{
|
|
|
|
int num;
|
|
|
|
int i, j;
|
|
|
|
int found = -1;
|
|
|
|
|
|
|
|
/* Enumerate and find suitable device */
|
|
|
|
num = libusb_get_device_list(ctx, list);
|
|
|
|
|
|
|
|
for (i = 0 ; i < num ; i++) {
|
|
|
|
struct libusb_device_descriptor desc;
|
|
|
|
int match = 0;
|
|
|
|
libusb_get_device_descriptor((*list)[i], &desc);
|
|
|
|
|
|
|
|
for (j = 0 ; j < sizeof(devices)/sizeof(struct device_id) ; j++) {
|
|
|
|
if (desc.idVendor == devices[j].vid &&
|
|
|
|
desc.idProduct == devices[j].pid) {
|
|
|
|
match = 1;
|
|
|
|
if (printer_type == devices[j].type)
|
|
|
|
found = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
if (getenv("EXTRA_PID") && getenv("EXTRA_TYPE") && getenv("EXTRA_VID")) {
|
|
|
|
int pid = strtol(getenv("EXTRA_PID"), NULL, 16);
|
|
|
|
int vid = strtol(getenv("EXTRA_VID"), NULL, 16);
|
|
|
|
int type = atoi(getenv("EXTRA_TYPE"));
|
|
|
|
if (vid == desc.idVendor &&
|
|
|
|
pid == desc.idProduct) {
|
|
|
|
match = 1;
|
|
|
|
if (printer_type == type)
|
|
|
|
found = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!match)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
found = print_scan_output((*list)[i], &desc,
|
|
|
|
URI_PREFIX, devices[j].manuf_str,
|
|
|
|
found, (found == i),
|
|
|
|
scan_only, match_serno);
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|