summaryrefslogtreecommitdiff
path: root/src/cups
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2015-08-09 14:40:26 +0200
committerDidier Raboud <odyx@debian.org>2015-08-09 14:40:26 +0200
commit92976f71a4aa7f84cd8aadf013d2b03873dead7c (patch)
treecf693495783f07f67a0a2c8c12437fd6ed220593 /src/cups
parent58b4abe145a14a936e420a3ba5b7d0c6c56fa839 (diff)
Imported Upstream version 5.2.11~pre1
Diffstat (limited to 'src/cups')
-rw-r--r--src/cups/Makefile.am4
-rw-r--r--src/cups/Makefile.in37
-rw-r--r--src/cups/backend_common.c101
-rw-r--r--src/cups/backend_common.h23
-rw-r--r--src/cups/blacklist31
-rw-r--r--src/cups/citizencw01_print.c918
-rw-r--r--src/cups/cups-genppdupdate.in30
-rw-r--r--src/cups/dnpds40_print.c1092
-rw-r--r--src/cups/genppd.c6
-rw-r--r--src/cups/kodak1400_print.c57
-rw-r--r--src/cups/kodak605_print.c98
-rw-r--r--src/cups/kodak6800_print.c719
-rw-r--r--src/cups/mitsu70x_print.c638
-rw-r--r--src/cups/mitsu9550_print.c1013
-rw-r--r--src/cups/selphy_print.c107
-rw-r--r--src/cups/shinko_s2145_print.c512
-rw-r--r--src/cups/sony_updr150_print.c135
-rw-r--r--[-rwxr-xr-x]src/cups/test-ppds2
-rwxr-xr-xsrc/cups/test-rastertogutenprint.in38
19 files changed, 4484 insertions, 1077 deletions
diff --git a/src/cups/Makefile.am b/src/cups/Makefile.am
index ec2e01d..7bd6cd9 100644
--- a/src/cups/Makefile.am
+++ b/src/cups/Makefile.am
@@ -1,4 +1,4 @@
-## $Id: Makefile.am,v 1.148 2014/03/27 22:37:09 speachy Exp $
+## $Id: Makefile.am,v 1.150 2015/01/10 14:27:55 speachy Exp $
## Copyright (C) 2000 Roger Leigh
##
## This program is free software; you can redistribute it and/or modify
@@ -115,7 +115,7 @@ commandtoepson_SOURCES = commandtoepson.c
commandtoepson_LDADD = $(CUPS_LIBS)
if BUILD_LIBUSB_BACKENDS
-backend_gutenprint_SOURCES = selphy_print.c kodak1400_print.c kodak6800_print.c kodak605_print.c shinko_s2145_print.c sony_updr150_print.c dnpds40_print.c mitsu70x_print.c backend_common.c backend_common.h
+backend_gutenprint_SOURCES = selphy_print.c kodak1400_print.c kodak6800_print.c kodak605_print.c shinko_s2145_print.c sony_updr150_print.c dnpds40_print.c mitsu70x_print.c citizencw01_print.c mitsu9550_print.c backend_common.c backend_common.h
backend_gutenprint_LDADD = $(LIBUSB_LIBS)
backend_gutenprint_CPPFLAGS = $(LIBUSB_CFLAGS) -DURI_PREFIX=\"gutenprint$(GUTENPRINT_MAJOR_VERSION)$(GUTENPRINT_MINOR_VERSION)+usb\" -DLIBUSB_PRE_1_0_10
diff --git a/src/cups/Makefile.in b/src/cups/Makefile.in
index 25bfd1a..c5b156b 100644
--- a/src/cups/Makefile.in
+++ b/src/cups/Makefile.in
@@ -128,7 +128,8 @@ PROGRAMS = $(bin_PROGRAMS) $(cupsexec_backend_PROGRAMS) \
am__backend_gutenprint_SOURCES_DIST = selphy_print.c kodak1400_print.c \
kodak6800_print.c kodak605_print.c shinko_s2145_print.c \
sony_updr150_print.c dnpds40_print.c mitsu70x_print.c \
- backend_common.c backend_common.h
+ citizencw01_print.c mitsu9550_print.c backend_common.c \
+ backend_common.h
@BUILD_LIBUSB_BACKENDS_TRUE@am_backend_gutenprint_OBJECTS = backend_gutenprint-selphy_print.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-kodak1400_print.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-kodak6800_print.$(OBJEXT) \
@@ -137,6 +138,8 @@ am__backend_gutenprint_SOURCES_DIST = selphy_print.c kodak1400_print.c \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-sony_updr150_print.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-dnpds40_print.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-mitsu70x_print.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-citizencw01_print.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-mitsu9550_print.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_common.$(OBJEXT)
backend_gutenprint_OBJECTS = $(am_backend_gutenprint_OBJECTS)
am__DEPENDENCIES_1 =
@@ -716,7 +719,7 @@ commandtocanon_SOURCES = commandtocanon.c
commandtocanon_LDADD = $(CUPS_LIBS)
commandtoepson_SOURCES = commandtoepson.c
commandtoepson_LDADD = $(CUPS_LIBS)
-@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_SOURCES = selphy_print.c kodak1400_print.c kodak6800_print.c kodak605_print.c shinko_s2145_print.c sony_updr150_print.c dnpds40_print.c mitsu70x_print.c backend_common.c backend_common.h
+@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_SOURCES = selphy_print.c kodak1400_print.c kodak6800_print.c kodak605_print.c shinko_s2145_print.c sony_updr150_print.c dnpds40_print.c mitsu70x_print.c citizencw01_print.c mitsu9550_print.c backend_common.c backend_common.h
@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_LDADD = $(LIBUSB_LIBS)
@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_CPPFLAGS = $(LIBUSB_CFLAGS) -DURI_PREFIX=\"gutenprint$(GUTENPRINT_MAJOR_VERSION)$(GUTENPRINT_MINOR_VERSION)+usb\" -DLIBUSB_PRE_1_0_10
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_SOURCES = genppd.c i18n.c i18n.h
@@ -1106,11 +1109,13 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-citizencw01_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-dnpds40_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-kodak1400_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-kodak605_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-kodak6800_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-mitsu70x_print.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-mitsu9550_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-selphy_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-shinko_s2145_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-sony_updr150_print.Po@am__quote@
@@ -1257,6 +1262,34 @@ backend_gutenprint-mitsu70x_print.obj: mitsu70x_print.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backend_gutenprint-mitsu70x_print.obj `if test -f 'mitsu70x_print.c'; then $(CYGPATH_W) 'mitsu70x_print.c'; else $(CYGPATH_W) '$(srcdir)/mitsu70x_print.c'; fi`
+backend_gutenprint-citizencw01_print.o: citizencw01_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-citizencw01_print.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-citizencw01_print.Tpo -c -o backend_gutenprint-citizencw01_print.o `test -f 'citizencw01_print.c' || echo '$(srcdir)/'`citizencw01_print.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-citizencw01_print.Tpo $(DEPDIR)/backend_gutenprint-citizencw01_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='citizencw01_print.c' object='backend_gutenprint-citizencw01_print.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backend_gutenprint-citizencw01_print.o `test -f 'citizencw01_print.c' || echo '$(srcdir)/'`citizencw01_print.c
+
+backend_gutenprint-citizencw01_print.obj: citizencw01_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-citizencw01_print.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-citizencw01_print.Tpo -c -o backend_gutenprint-citizencw01_print.obj `if test -f 'citizencw01_print.c'; then $(CYGPATH_W) 'citizencw01_print.c'; else $(CYGPATH_W) '$(srcdir)/citizencw01_print.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-citizencw01_print.Tpo $(DEPDIR)/backend_gutenprint-citizencw01_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='citizencw01_print.c' object='backend_gutenprint-citizencw01_print.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backend_gutenprint-citizencw01_print.obj `if test -f 'citizencw01_print.c'; then $(CYGPATH_W) 'citizencw01_print.c'; else $(CYGPATH_W) '$(srcdir)/citizencw01_print.c'; fi`
+
+backend_gutenprint-mitsu9550_print.o: mitsu9550_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-mitsu9550_print.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-mitsu9550_print.Tpo -c -o backend_gutenprint-mitsu9550_print.o `test -f 'mitsu9550_print.c' || echo '$(srcdir)/'`mitsu9550_print.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-mitsu9550_print.Tpo $(DEPDIR)/backend_gutenprint-mitsu9550_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mitsu9550_print.c' object='backend_gutenprint-mitsu9550_print.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backend_gutenprint-mitsu9550_print.o `test -f 'mitsu9550_print.c' || echo '$(srcdir)/'`mitsu9550_print.c
+
+backend_gutenprint-mitsu9550_print.obj: mitsu9550_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-mitsu9550_print.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-mitsu9550_print.Tpo -c -o backend_gutenprint-mitsu9550_print.obj `if test -f 'mitsu9550_print.c'; then $(CYGPATH_W) 'mitsu9550_print.c'; else $(CYGPATH_W) '$(srcdir)/mitsu9550_print.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-mitsu9550_print.Tpo $(DEPDIR)/backend_gutenprint-mitsu9550_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mitsu9550_print.c' object='backend_gutenprint-mitsu9550_print.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backend_gutenprint-mitsu9550_print.obj `if test -f 'mitsu9550_print.c'; then $(CYGPATH_W) 'mitsu9550_print.c'; else $(CYGPATH_W) '$(srcdir)/mitsu9550_print.c'; fi`
+
backend_gutenprint-backend_common.o: backend_common.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_common.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_common.Tpo -c -o backend_gutenprint-backend_common.o `test -f 'backend_common.c' || echo '$(srcdir)/'`backend_common.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_common.Tpo $(DEPDIR)/backend_gutenprint-backend_common.Po
diff --git a/src/cups/backend_common.c b/src/cups/backend_common.c
index 73c6dba..0a2aaba 100644
--- a/src/cups/backend_common.c
+++ b/src/cups/backend_common.c
@@ -1,7 +1,7 @@
/*
* CUPS Backend common code
*
- * Copyright (c) 2007-2014 Solomon Peachy <pizza@shaftnet.org>
+ * Copyright (c) 2007-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -27,7 +27,7 @@
#include "backend_common.h"
-#define BACKEND_VERSION "0.48G"
+#define BACKEND_VERSION "0.54G"
#ifndef URI_PREFIX
#error "Must Define URI_PREFIX"
#endif
@@ -48,6 +48,11 @@ static char *get_device_id(struct libusb_device_handle *dev)
int iface = 0;
char *buf = malloc(ID_BUF_SIZE + 1);
+ if (!buf) {
+ ERROR("Memory allocation failure (%d bytes)\n", ID_BUF_SIZE+1);
+ return NULL;
+ }
+
if (libusb_kernel_driver_active(dev, iface))
libusb_detach_kernel_driver(dev, iface);
@@ -180,11 +185,23 @@ int read_data(struct libusb_device_handle *dev, uint8_t endp,
goto done;
}
- if (dyesub_debug > 1) {
- int i;
+ if (dyesub_debug) {
+ DEBUG("Received %d bytes from printer\n", *readlen);
+ }
+
+ if ((dyesub_debug > 1 && buflen < 4096) ||
+ dyesub_debug > 2) {
+ int i = *readlen;
+
DEBUG("<- ");
- for (i = 0 ; i < *readlen; i++) {
- DEBUG2("%02x ", *(buf+i));
+ while(i > 0) {
+ if ((*readlen-i) != 0 &&
+ (*readlen-i) % 16 == 0) {
+ DEBUG2("\n");
+ DEBUG(" ");
+ }
+ DEBUG2("%02x ", buf[*readlen-i]);
+ i--;
}
DEBUG2("\n");
}
@@ -208,11 +225,19 @@ int send_data(struct libusb_device_handle *dev, uint8_t endp,
buf, len2,
&num, 15000);
- if (dyesub_debug > 1) {
- int i;
+ if ((dyesub_debug > 1 && len < 4096) ||
+ dyesub_debug > 2) {
+ int i = num;
+
DEBUG("-> ");
- for (i = 0 ; i < num; i++) {
- DEBUG2("%02x ", *(buf+i));
+ while(i > 0) {
+ if ((num-i) != 0 &&
+ (num-i) % 16 == 0) {
+ DEBUG2("\n");
+ DEBUG(" ");
+ }
+ DEBUG2("%02x ", buf[num-i]);
+ i--;
}
DEBUG2("\n");
}
@@ -267,6 +292,11 @@ static char from_hex(char ch) {
static char *url_encode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
+ if (!buf) {
+ ERROR("Memory allocation failure (%d bytes)\n", (int) strlen(str)*3 + 1);
+ return NULL;
+ }
+
while (*pstr) {
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
*pbuf++ = *pstr;
@@ -281,6 +311,12 @@ static char *url_encode(char *str) {
}
static char *url_decode(char *str) {
char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf;
+
+ if (!buf) {
+ ERROR("Memory allocation failure (%d bytes)\n", (int) strlen(str) + 1);
+ return NULL;
+ }
+
while (*pstr) {
if (*pstr == '%') {
if (pstr[1] && pstr[2]) {
@@ -373,6 +409,11 @@ static int print_scan_output(struct libusb_device *device,
char *product2 = url_decode(product);
char *manuf3 = url_decode(manuf);
descr = malloc(256);
+ if (!descr) {
+ ERROR("Memory allocation failure (%d bytes)\n", 256);
+ return found;
+ }
+
sprintf(descr, "%s %s", manuf3, product2);
free(product2);
free(manuf3);
@@ -485,7 +526,9 @@ static struct dyesub_backend *backends[] = {
&shinkos2145_backend,
&updr150_backend,
&mitsu70x_backend,
+ &mitsu9550_backend,
&dnpds40_backend,
+ &cw01_backend,
NULL,
};
@@ -575,7 +618,7 @@ static struct dyesub_backend *find_backend(char *uri_prefix)
static void print_license_blurb(void)
{
const char *license = "\n\
-Copyright 2007-2014 Solomon Peachy <pizza AT shaftnet DOT org>\n\
+Copyright 2007-2015 Solomon Peachy <pizza AT shaftnet DOT org>\n\
\n\
This program is free software; you can redistribute it and/or modify it\n\
under the terms of the GNU General Public License as published by the Free\n\
@@ -590,7 +633,7 @@ for more details.\n\
You should have received a copy of the GNU General Public License\n\
along with this program; if not, write to the Free Software\n\
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\
-\n [http://www.gnu.org/licenses/gpl-3.0.html]\n\n";
+\n [http://www.gnu.org/licenses/gpl-2.0.html]\n\n";
fprintf(stderr, "%s", license);
}
@@ -645,7 +688,7 @@ static void print_help(char *argv0, struct dyesub_backend *backend)
i = libusb_init(&ctx);
if (i) {
ERROR("Failed to initialize libusb (%d)\n", i);
- exit(4); /* CUPS_BACKEND_STOP */
+ exit(CUPS_BACKEND_STOP);
}
find_and_enumerate(ctx, &list, backend, NULL, P_ANY, 1);
libusb_free_device_list(list, 1);
@@ -671,7 +714,7 @@ int main (int argc, char **argv)
int claimed;
int backend_cmd = 0;
- int ret = 0;
+ int ret = CUPS_BACKEND_OK;
int iface = 0;
int found = -1;
int copies = 1;
@@ -684,7 +727,7 @@ int main (int argc, char **argv)
DEBUG("Multi-Call Dye-sublimation CUPS Backend version %s\n",
BACKEND_VERSION);
- DEBUG("Copyright 2007-2014 Solomon Peachy\n");
+ DEBUG("Copyright 2007-2015 Solomon Peachy\n");
DEBUG("This free software comes with ABSOLUTELY NO WARRANTY! \n");
DEBUG("Licensed under the GNU GPL. Run with '-G' for more details.\n");
DEBUG("\n");
@@ -717,7 +760,7 @@ int main (int argc, char **argv)
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "B:dDGhP:S:T:V:")) >= 0) {
+ while ((i = getopt(argc, argv, "B:d:DGhP:S:T:V:")) >= 0) {
switch(i) {
case 'B':
backend = find_backend(optarg);
@@ -877,7 +920,7 @@ int main (int argc, char **argv)
if (fname && backend->early_parse) {
printer_type = backend->early_parse(backend_ctx, data_fd);
if (printer_type < 0) {
- ret = 5; /* CUPS_BACKEND_CANCEL */
+ ret = CUPS_BACKEND_CANCEL;
goto done;
}
}
@@ -886,7 +929,7 @@ int main (int argc, char **argv)
ret = libusb_init(&ctx);
if (ret) {
ERROR("Failed to initialize libusb (%d)\n", ret);
- ret = 4;
+ ret = CUPS_BACKEND_STOP;
goto done;
}
@@ -896,13 +939,14 @@ int main (int argc, char **argv)
#if 1
if (found == -1) {
ERROR("Printer open failure (No suitable printers found!)\n");
- ret = 4; /* CUPS_BACKEND_STOP */
+ ret = CUPS_BACKEND_HOLD;
goto done;
}
ret = libusb_open(list[found], &dev);
if (ret) {
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
+ ret = CUPS_BACKEND_STOP;
goto done;
}
@@ -910,20 +954,23 @@ int main (int argc, char **argv)
if (claimed) {
ret = libusb_detach_kernel_driver(dev, iface);
if (ret) {
- ERROR("Printer open failure (Could not detach printer from kernel)\n");
+ ERROR("Printer open failure (Could not detach printer from kernel) (%d)\n", ret);
+ ret = CUPS_BACKEND_STOP;
goto done_close;
}
}
ret = libusb_claim_interface(dev, iface);
if (ret) {
- ERROR("Printer open failure (Could not claim printer interface)\n");
+ ERROR("Printer open failure (Could not claim printer interface) (%d)\n", ret);
+ ret = CUPS_BACKEND_STOP;
goto done_close;
}
ret = libusb_get_active_config_descriptor(list[found], &config);
if (ret) {
- ERROR("Printer open failure (Could not fetch config descriptor)\n");
+ ERROR("Printer open failure (Could not fetch config descriptor) (%d)\n", ret);
+ ret = CUPS_BACKEND_STOP;
goto done_close;
}
@@ -951,14 +998,12 @@ int main (int argc, char **argv)
newpage:
/* Do early parsing if needed for subsequent pages */
- if (pages && backend->early_parse) {
- ret = backend->early_parse(backend_ctx, data_fd);
- if (ret < 0)
+ if (pages && backend->early_parse &&
+ backend->early_parse(backend_ctx, data_fd) < 0)
goto done_multiple;
- }
/* Read in data */
- if (backend->read_parse(backend_ctx, data_fd)) {
+ if ((ret = backend->read_parse(backend_ctx, data_fd))) {
if (pages)
goto done_multiple;
else
@@ -981,7 +1026,7 @@ done_multiple:
/* Done printing */
INFO("All printing done (%d pages * %d copies)\n", pages, copies);
- ret = 0;
+ ret = CUPS_BACKEND_OK;
done_claimed:
libusb_release_interface(dev, iface);
diff --git a/src/cups/backend_common.h b/src/cups/backend_common.h
index 99f8297..1a5c9f1 100644
--- a/src/cups/backend_common.h
+++ b/src/cups/backend_common.h
@@ -1,7 +1,7 @@
/*
* CUPS Backend common code
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -42,6 +42,9 @@
#define __BACKEND_COMMON_H
#define STR_LEN_MAX 64
+#define STATE( ... ) fprintf(stderr, "STATE: " __VA_ARGS__ )
+#define ATTR( ... ) fprintf(stderr, "ATTR: " __VA_ARGS__ )
+#define PAGE( ... ) fprintf(stderr, "PAGE: " __VA_ARGS__ )
#define DEBUG( ... ) fprintf(stderr, "DEBUG: " __VA_ARGS__ )
#define DEBUG2( ... ) fprintf(stderr, __VA_ARGS__ )
#define INFO( ... ) fprintf(stderr, "INFO: " __VA_ARGS__ )
@@ -98,10 +101,16 @@ enum {
P_KODAK_1400_805,
P_KODAK_605,
P_SHINKO_S2145,
+ P_SHINKO_S1245,
P_SONY_UPDR150,
+ P_SONY_UPCR10,
P_MITSU_D70X,
+ P_MITSU_9550,
P_DNP_DS40,
P_DNP_DS80,
+ P_CITIZEN_CW01,
+ P_DNP_DSRX1,
+ P_DNP_DS620,
P_END,
};
@@ -148,6 +157,18 @@ extern struct dyesub_backend kodak1400_backend;
extern struct dyesub_backend shinkos2145_backend;
extern struct dyesub_backend canonselphy_backend;
extern struct dyesub_backend mitsu70x_backend;
+extern struct dyesub_backend mitsu9550_backend;
extern struct dyesub_backend dnpds40_backend;
+extern struct dyesub_backend cw01_backend;
+
+/* CUPS compatibility */
+#define CUPS_BACKEND_OK 0 /* Sucess */
+#define CUPS_BACKEND_FAILED 1 /* Failed to print use CUPS policy */
+#define CUPS_BACKEND_AUTH_REQUIRED 2 /* Auth required */
+#define CUPS_BACKEND_HOLD 3 /* Hold this job only */
+#define CUPS_BACKEND_STOP 4 /* Stop the entire queue */
+#define CUPS_BACKEND_CANCEL 5 /* Cancel print job */
+#define CUPS_BACKEND_RETRY 6 /* Retry later */
+#define CUPS_BACKEND_RETRY_CURRENT 7 /* Retry immediately */
#endif /* __BACKEND_COMMON_H */
diff --git a/src/cups/blacklist b/src/cups/blacklist
index 204a8bc..420c485 100644
--- a/src/cups/blacklist
+++ b/src/cups/blacklist
@@ -111,23 +111,50 @@
# Kodak 605
0x040a 0x402e blacklist
-# Shinko CHC-S2145 (aka Sinfonia CS2)
+# Kodak 305
+0x040a 0x404f blacklist
+
+# Shinko CHC-S1245 (aka Sinfonia E1)
+0x10ce 0x0007 blacklist
+
+# Shinko CHC-S2145 (aka Sinfonia S2)
0x10ce 0x000e blacklist
+# Shinko CHC-S6145 (aka Sinfonia CS2)
+0x10ce 0x0019 blacklist
+
+# Shinko CHC-S6245 (aka Sinfonia CE1)
+0x10ce 0x001d blacklist
+
# Sony UP-DR150
0x054c 0x01e8 blacklist
+# Sony UP-DR200
+0x054c 0x035f blacklist
+
# Mitsubishi CP-D70/CP-D707
0x06d3 0x3b30 blacklist
# Mitsubishi CP-K60DW-S
0x06d3 0x3b31 blacklist
+# Mitsubishi CP-9550D/DW
+0x06d3 0x03a1 blacklist
+
+# Mitsubishi CP-9550DZ/DW-S
+0x06d3 0x03a5 blacklist
+
+# Citizen CW-01
+0x1343 0x0002 blacklist
+
# DNP DS40 + Citizen CX
0x1343 0x0003 blacklist
-# DNP DS80 + Citizen CX-W
+# DNP DS80 + Citizen CX-W + Mitsubishi CP3800
0x1343 0x0004 blacklist
# DNP DS-RX1 + Citizen CY
0x1343 0x0005 blacklist
+
+# DNP DS620
+0x1452 0x8b01 blacklist
diff --git a/src/cups/citizencw01_print.c b/src/cups/citizencw01_print.c
new file mode 100644
index 0000000..b99822c
--- /dev/null
+++ b/src/cups/citizencw01_print.c
@@ -0,0 +1,918 @@
+/*
+ * Citizen CW-01 Photo Printer CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2014-2015 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * The latest version of this program can be found at:
+ *
+ * http://git.shaftnet.org/cgit/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 2 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-2.0.html]
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "backend_common.h"
+
+#define USB_VID_CITIZEN 0x1343
+#define USB_PID_CITIZEN_CW01 0x0002 // Maybe others?
+//#define USB_PID_OLMEC_OP900 XXXX
+
+/* Private data stucture */
+struct cw01_spool_hdr {
+ uint8_t type; /* 0x00 -> 0x06 */
+ uint8_t res; /* vertical resolution; 0x00 == 334dpi, 0x01 == 600dpi */
+ uint8_t copies; /* number of prints */
+ uint8_t null0;
+ uint32_t plane_len; /* LE */
+ uint8_t null1[4];
+};
+#define DPI_334 0
+#define DPI_600 1
+
+#define TYPE_DSC 0
+#define TYPE_L 1
+#define TYPE_PC 2
+#define TYPE_2DSC 3
+#define TYPE_3L 4
+#define TYPE_A5 5
+#define TYPE_A6 6
+
+#define SPOOL_PLANE_HDR_LEN 1064
+#define PRINTER_PLANE_HDR_LEN 1088
+
+struct cw01_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ uint8_t *databuf;
+ struct cw01_spool_hdr hdr;
+};
+
+struct cw01_cmd {
+ uint8_t esc; /* Fixed at ascii ESC, aka 0x1B */
+ uint8_t p; /* Fixed at ascii 'P' aka 0x50 */
+ uint8_t arg1[6];
+ uint8_t arg2[16];
+ uint8_t arg3[8]; /* Decimal value of arg4's length, or empty */
+ uint8_t arg4[0]; /* Extra payload if arg3 is non-empty
+ Doesn't have to be sent in the same URB */
+
+ /* All unused elements are set to 0x20 (ie ascii space) */
+};
+
+#define min(__x, __y) ((__x) < (__y)) ? __x : __y
+
+static void cw01_build_cmd(struct cw01_cmd *cmd, char *arg1, char *arg2, uint32_t arg3_len)
+{
+ memset(cmd, 0x20, sizeof(*cmd));
+ cmd->esc = 0x1b;
+ cmd->p = 0x50;
+ memcpy(cmd->arg1, arg1, min(strlen(arg1), sizeof(cmd->arg1)));
+ memcpy(cmd->arg2, arg2, min(strlen(arg2), sizeof(cmd->arg2)));
+ if (arg3_len) {
+ char buf[9];
+ snprintf(buf, sizeof(buf), "%08u", arg3_len);
+ memcpy(cmd->arg3, buf, 8);
+ }
+
+}
+
+static void cw01_cleanup_string(char *start, int len)
+{
+ char *ptr = strchr(start, 0x0d);
+
+ if (ptr && (ptr - start < len)) {
+ *ptr = 0x00; /* If there is a <CR>, terminate there */
+ len = ptr - start;
+ } else {
+ start[--len] = 0x00; /* force null-termination */
+ }
+
+ /* Trim trailing spaces */
+ while (len && start[len-1] == ' ') {
+ start[--len] = 0;
+ }
+}
+
+static char *cw01_media_types(char *str)
+{
+ char tmp[4];
+ int i;
+
+ memcpy(tmp, str + 4, 3);
+ tmp[3] = 0;
+
+ i = atoi(tmp);
+
+ switch (i) {
+ case 100: return "UNK 100";
+ case 110: return "UNK 110";
+ case 200: return "?? 5x3.5 (L)";
+ case 210: return "?? 5x7 (2L)";
+ case 300: return "?? 6x4 (PC)";
+ case 400: return "?? 6x9 (A5W)";
+ default:
+ break;
+ }
+
+ return "Unknown type";
+}
+
+static char *cw01_statuses(char *str)
+{
+ char tmp[6];
+ int i;
+ memcpy(tmp, str, 5);
+ tmp[5] = 0;
+
+ i = atoi(tmp);
+
+ switch (i) {
+ case 0: return "Idle";
+ case 1: return "Printing";
+ case 500: return "Cooling Print Head";
+ case 510: return "Cooling Paper Motor";
+ case 1000: return "Cover Open";
+ case 1010: return "No Scrap Box";
+ case 1100: return "Paper End";
+ case 1200: return "Ribbon End";
+ case 1300: return "Paper Jam";
+ case 1400: return "Ribbon Error";
+ case 1500: return "Paper Definition Error";
+ case 1600: return "Data Error";
+ case 2000: return "Head Voltage Error";
+ case 2100: return "Head Position Error";
+ case 2200: return "Power Supply Fan Error";
+ case 2300: return "Cutter Error";
+ case 2400: return "Pinch Roller Error";
+ case 2500: return "Abnormal Head Temperature";
+ case 2600: return "Abnormal Media Temperature";
+ case 2610: return "Abnormal Paper Motor Temperature";
+ case 2700: return "Ribbon Tension Error";
+ case 2800: return "RF-ID Module Error";
+ case 3000: return "System Error";
+ default:
+ break;
+ }
+
+ return "Unkown Error";
+}
+
+static int cw01_do_cmd(struct cw01_ctx *ctx,
+ struct cw01_cmd *cmd,
+ uint8_t *data, int len)
+{
+ int ret;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*)cmd, sizeof(*cmd))))
+ return ret;
+
+ if (data && len)
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ data, len)))
+ return ret;
+
+ return CUPS_BACKEND_OK;
+}
+
+static uint8_t *cw01_resp_cmd(struct cw01_ctx *ctx,
+ struct cw01_cmd *cmd,
+ int *len)
+{
+ char tmp[9];
+ uint8_t *respbuf;
+
+ int ret, i, num = 0;
+
+ memset(tmp, 0, sizeof(tmp));
+
+ if ((ret = cw01_do_cmd(ctx, cmd, NULL, 0)))
+ return NULL;
+
+ /* Read in the response header */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*)tmp, 8, &num);
+ if (ret < 0)
+ return NULL;
+
+ if (num != 8) {
+ ERROR("Short read! (%d/%d)\n", num, 8);
+ return NULL;
+ }
+
+ i = atoi(tmp); /* Length of payload in bytes, possibly padded */
+ respbuf = malloc(i);
+ if (!respbuf) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+
+ /* Read in the actual response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ respbuf, i, &num);
+ if (ret < 0) {
+ free(respbuf);
+ return NULL;
+ }
+
+ if (num != i) {
+ ERROR("Short read! (%d/%d)\n", num, i);
+ free(respbuf);
+ return NULL;
+ }
+
+ *len = num;
+ return respbuf;
+}
+
+static int cw01_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
+{
+ struct cw01_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
+
+ struct cw01_ctx ctx = {
+ .dev = dev,
+ .endp_up = endp_up,
+ .endp_down = endp_down,
+ };
+
+ /* Get Serial Number */
+ cw01_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
+
+ resp = cw01_resp_cmd(&ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ strncpy(buf, (char*)resp, buf_len);
+ buf[buf_len-1] = 0;
+
+ free(resp);
+
+ return CUPS_BACKEND_OK;
+}
+
+static void *cw01_init(void)
+{
+ struct cw01_ctx *ctx = malloc(sizeof(struct cw01_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct cw01_ctx));
+
+ return ctx;
+}
+
+static void cw01_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct cw01_ctx *ctx = vctx;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+}
+
+static void cw01_teardown(void *vctx) {
+ struct cw01_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+ free(ctx);
+}
+
+static int cw01_read_parse(void *vctx, int data_fd) {
+ struct cw01_ctx *ctx = vctx;
+ int i, j, remain;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->databuf) {
+ free(ctx->databuf);
+ ctx->databuf = NULL;
+ }
+
+ i = read(data_fd, (uint8_t*) &ctx->hdr, sizeof(struct cw01_spool_hdr));
+
+ if (i < 0)
+ return i;
+ if (i == 0)
+ return CUPS_BACKEND_CANCEL;
+
+ if (i < (int)sizeof(struct cw01_spool_hdr))
+ return CUPS_BACKEND_CANCEL;
+
+ if (ctx->hdr.type > 0x06 || ctx->hdr.res > 0x01) {
+ ERROR("Unrecognized header data format!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+ ctx->hdr.plane_len = le32_to_cpu(ctx->hdr.plane_len);
+ remain = ctx->hdr.plane_len * 3;
+ ctx->databuf = malloc(remain);
+ if (!ctx->databuf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ j = 0;
+ while (remain) {
+ i = read(data_fd, ctx->databuf + j, remain);
+
+ if (i < 0)
+ return i;
+
+ remain -= i;
+ j += i;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int cw01_main_loop(void *vctx, int copies) {
+ struct cw01_ctx *ctx = vctx;
+ int ret;
+ struct cw01_cmd cmd;
+ uint8_t *resp = NULL;
+ int len = 0;
+ uint32_t tmp;
+ uint8_t *ptr;
+ char buf[9];
+ uint8_t plane_hdr[PRINTER_PLANE_HDR_LEN];
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+top:
+
+ if (resp) free(resp);
+
+ /* Query status */
+ cw01_build_cmd(&cmd, "STATUS", "", 0);
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+ cw01_cleanup_string((char*)resp, len);
+
+ /* If we're not idle */
+ if (strcmp("00000", (char*)resp)) {
+ if (!strcmp("00001", (char*)resp)) {
+ free(resp);
+ /* Query buffer state */
+ cw01_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+ cw01_cleanup_string((char*)resp, len);
+
+ /* Check to see if we have sufficient buffers */
+ // XXX audit these rules...?
+ if (!strcmp("FBP00", (char*)resp) ||
+ (ctx->hdr.res == DPI_600 && !strcmp("FBP01", (char*)resp))) {
+ INFO("Insufficient printer buffers, retrying...\n");
+ sleep(1);
+ goto top;
+ }
+ } else {
+ ERROR("Printer Status: %s\n", cw01_statuses((char*)resp));
+ free(resp);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ }
+
+ free(resp);
+ /* Get Vertical resolution */
+ cw01_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+#if 0
+ if (ctx->hdr.res == DPI_600 && strcmp("RV0334", *char*)resp) {
+ ERROR("600DPI prints not yet supported, need 600DPI CWD load");
+ return CUPS_BACKEND_CANCEL;
+ }
+#endif
+
+ free(resp);
+ resp = NULL;
+
+ /* Set print quantity */
+ cw01_build_cmd(&cmd, "CNTRL", "QTY", 8);
+ snprintf(buf, sizeof(buf), "%07d\r", copies);
+ ret = cw01_do_cmd(ctx, &cmd, (uint8_t*) buf, 8);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ /* Cutter control. ??? */
+ // cw01_build_cmd(&cmd, "CNTRL", "CUTTER", 8);
+ //snprintf(buf, sizeof(buf), "%08d", ???);
+ //ret = cw01_do_cmd(ctx, &cmd, (uint8_t*) buf, 8);
+ //if (ret)
+ // return CUPS_BACKEND_FAILED;
+
+ /* Start sending image data */
+ ptr = ctx->databuf;
+
+ /* Generate plane header (same for all planes) */
+ tmp = cpu_to_le32(ctx->hdr.plane_len) + 24;
+ memset(plane_hdr, 0, PRINTER_PLANE_HDR_LEN);
+ plane_hdr[0] = 0x42;
+ plane_hdr[1] = 0x4d;
+ memcpy(plane_hdr + 2, &tmp, sizeof(tmp));
+ plane_hdr[10] = 0x40;
+ plane_hdr[11] = 0x04;
+ memcpy(plane_hdr + 14, ptr, SPOOL_PLANE_HDR_LEN);
+
+ /******** Plane 1 */
+ cw01_build_cmd(&cmd, "IMAGE", "YPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
+ ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ /* Send plane data */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
+ return CUPS_BACKEND_FAILED;
+
+ ptr += ctx->hdr.plane_len;
+
+ /******** Plane 2 */
+ cw01_build_cmd(&cmd, "IMAGE", "MPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
+ ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ /* Send plane data */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
+ return CUPS_BACKEND_FAILED;
+
+ ptr += ctx->hdr.plane_len;
+
+ /******** Plane 3 */
+ cw01_build_cmd(&cmd, "IMAGE", "CPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
+ ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ /* Send plane data */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
+ return CUPS_BACKEND_FAILED;
+
+ ptr += ctx->hdr.plane_len;
+
+ /* Start print */
+ cw01_build_cmd(&cmd, "CNTRL", "START", 0);
+ ret = cw01_do_cmd(ctx, &cmd, NULL, 0);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ /* This printer handles copies internally */
+ copies = 1;
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ if (resp) free(resp);
+
+ return CUPS_BACKEND_OK;
+}
+
+static int cw01_get_info(struct cw01_ctx *ctx)
+{
+ struct cw01_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
+
+ /* Get Serial Number */
+ cw01_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Serial Number: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* Get Firmware Version */
+ cw01_build_cmd(&cmd, "INFO", "FVER", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Firmware Version: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* Get Sensor Info */
+ cw01_build_cmd(&cmd, "INFO", "SENSOR", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Sensor Info: '%s'\n", (char*)resp);
+ // XXX parse this out. Each token is 'XXX-###' delimited by '; '
+
+ free(resp);
+
+ /* Get Horizonal resolution */
+ cw01_build_cmd(&cmd, "INFO", "RESOLUTION_H", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Horizontal Resolution: '%s' dpi\n", (char*)resp + 3);
+
+ free(resp);
+
+ /* Get Vertical resolution */
+ cw01_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Vertical Resolution: '%s' dpi\n", (char*)resp + 3);
+
+ free(resp);
+
+ /* Get Media Color offset */
+ cw01_build_cmd(&cmd, "INFO", "MCOLOR", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Media Color Offset: '%02x%02x%02x%02x'\n", *(resp+2), *(resp+3),
+ *(resp+4), *(resp+5));
+
+ free(resp);
+
+ /* Get Media Lot */
+ cw01_build_cmd(&cmd, "INFO", "MLOT", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Media Lot Code: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n",
+ *(resp+2), *(resp+3), *(resp+4), *(resp+5), *(resp+6), *(resp+7),
+ *(resp+8), *(resp+9), *(resp+10), *(resp+11), *(resp+12), *(resp+13));
+
+ free(resp);
+
+ /* Get Media ID Set (?) */
+ cw01_build_cmd(&cmd, "MNT_RD", "MEDIA_ID_SET", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Media ID(?): '%s'\n", (char*)resp+4);
+
+ free(resp);
+
+ /* Get Color Control Data Version */
+ cw01_build_cmd(&cmd, "TBL_RD", "Version", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Color Data Version: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* Get Color Control Data Checksum */
+ cw01_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Color Data Checksum: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ return CUPS_BACKEND_OK;
+}
+
+static int cw01_get_status(struct cw01_ctx *ctx)
+{
+ struct cw01_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "STATUS", "", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Printer Status: %s => %s\n", (char*)resp, cw01_statuses((char*)resp));
+
+ free(resp);
+
+ /* Get remaining prints in this job */
+ cw01_build_cmd(&cmd, "INFO", "PQTY", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Prints Remaining in job: '%s'\n", (char*)resp + 4);
+
+ free(resp);
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Free Buffers: '%s'\n", (char*)resp + 3);
+
+ free(resp);
+
+ /* Get Media Info */
+ cw01_build_cmd(&cmd, "INFO", "MEDIA", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Media Type: '%s'\n", cw01_media_types((char*)resp));
+
+ free(resp);
+
+ /* Get Media remaining */
+ cw01_build_cmd(&cmd, "INFO", "MQTY", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Prints Remaining: '%s'\n", (char*)resp + 4);
+
+ free(resp);
+
+ return 0;
+}
+
+static int cw01_get_counters(struct cw01_ctx *ctx)
+{
+ struct cw01_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_LIFE", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("Lifetime Counter: '%s'\n", (char*)resp+2);
+
+ free(resp);
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_A", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("A Counter: '%s'\n", (char*)resp+2);
+
+ free(resp);
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_B", 0);
+
+ resp = cw01_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ cw01_cleanup_string((char*)resp, len);
+
+ INFO("B Counter: '%s'\n", (char*)resp+2);
+
+ free(resp);
+
+ return CUPS_BACKEND_OK;
+}
+
+static int cw01_clear_counter(struct cw01_ctx *ctx, char counter)
+{
+ struct cw01_cmd cmd;
+ char msg[4];
+ int ret;
+
+ /* Generate command */
+ cw01_build_cmd(&cmd, "MNT_WT", "COUNTER_CLEAR", 4);
+ msg[0] = 'C';
+ msg[1] = counter;
+ msg[2] = 0x0d; /* ie carriage return, ASCII '\r' */
+ msg[3] = 0x00;
+
+ if ((ret = cw01_do_cmd(ctx, &cmd, (uint8_t*)msg, 4)))
+ return ret;
+
+ return 0;
+}
+
+
+static void cw01_cmdline(void)
+{
+ DEBUG("\t\t[ -i ] # Query printer info\n");
+ DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -n ] # Query counters\n");
+ DEBUG("\t\t[ -N A|B|M ] # Clear counter A/B/M\n");
+}
+
+static int cw01_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct cw01_ctx *ctx = vctx;
+ int i, j = 0;
+
+ /* Reset arg parsing */
+ optind = 1;
+ opterr = 0;
+ while ((i = getopt(argc, argv, "inN:s")) >= 0) {
+ switch(i) {
+ case 'i':
+ if (ctx) {
+ j = cw01_get_info(ctx);
+ break;
+ }
+ return 1;
+ case 'n':
+ if (ctx) {
+ j = cw01_get_counters(ctx);
+ break;
+ }
+ return 1;
+ case 'N':
+ if (optarg[0] != 'A' &&
+ optarg[0] != 'B')
+ return CUPS_BACKEND_FAILED;
+ if (ctx) {
+ j = cw01_clear_counter(ctx, optarg[0]);
+ break;
+ }
+ return 1;
+ case 's':
+ if (ctx) {
+ j = cw01_get_status(ctx);
+ break;
+ }
+ return 1;
+ default:
+ break; /* Ignore completely */
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+/* Exported */
+struct dyesub_backend cw01_backend = {
+ .name = "Citizen CW-01",
+ .version = "0.10",
+ .uri_prefix = "citizencw01",
+ .cmdline_usage = cw01_cmdline,
+ .cmdline_arg = cw01_cmdline_arg,
+ .init = cw01_init,
+ .attach = cw01_attach,
+ .teardown = cw01_teardown,
+ .read_parse = cw01_read_parse,
+ .main_loop = cw01_main_loop,
+ .query_serno = cw01_query_serno,
+ .devices = {
+ { USB_VID_CITIZEN, USB_PID_CITIZEN_CW01, P_CITIZEN_CW01, ""},
+// { USB_VID_CITIZEN, USB_PID_OLMEC_OP900, P_CITIZEN_CW01, ""},
+ { 0, 0, 0, ""}
+ }
+};
+
+/*
+
+Basic spool file format:
+
+TT RR NN 00 XX XX XX XX 00 00 00 00 <- FILE header.
+
+ NN : copies (0x01 or more)
+ RR : resolution; 0 == 334 dpi, 1 == 600dpi
+ TT : type 0x02 == 4x6, 0x01 == 5x3.5
+ XX XX XX XX : plane length (LE)
+ plane length * 3 + 12 == file length.
+
+Followed by three planes, each with this header:
+
+28 00 00 00 00 08 00 00 RR RR 00 00 01 00 08 00
+00 00 00 00 00 00 00 00 5a 33 00 00 YY YY 00 00
+00 01 00 00 00 00 00 00
+
+ RR RR : rows in LE format
+ YY YY : 0x335a (334dpi) or 0x5c40 (600dpi)
+
+Followed by 1024 bytes of color tables:
+
+ ff ff ff 00 ... 00 00 00 00
+
+1024+40 = 1064 bytes of header per plane.
+
+Always have 2048 columns of data.
+
+followed by (2048 * rows) bytes of data.
+
+*/
diff --git a/src/cups/cups-genppdupdate.in b/src/cups/cups-genppdupdate.in
index 66d0a46..61b7206 100644
--- a/src/cups/cups-genppdupdate.in
+++ b/src/cups/cups-genppdupdate.in
@@ -1,5 +1,5 @@
#! @PERL@ -w
-# $Id: cups-genppdupdate.in,v 1.60 2012/02/14 23:11:41 tillkamppeter Exp $
+# $Id: cups-genppdupdate.in,v 1.61 2014/06/04 01:16:47 rlk Exp $
# Update CUPS PPDs for Gutenprint queues.
# Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org)
#
@@ -57,7 +57,8 @@ my $micro_version = "@GUTENPRINT_VERSION@";
my $use_static_ppd = "@BUILD_CUPS_PPDS@";
my $file_version = '"@VERSION@"$';
-my $ppd_dir = "@cups_conf_serverroot@/ppd"; # Location of in-use CUPS PPDs
+my $system_ppd_dir = "@cups_conf_serverroot@/ppd";# Location of in-use CUPS PPDs
+my $ppd_dir = $system_ppd_dir; # Location of in-use CUPS PPDs
my $ppd_root_dir = "@cups_conf_datadir@/model";
my $ppd_base_dir = "$ppd_root_dir/gutenprint/$version"; # Available PPDs
my $ppd_out_dir = ""; # By default output into source directory
@@ -181,7 +182,8 @@ if (!$quiet || $verbose) {
print STDOUT ", $skipped_ppd_count skipped";
}
print STDOUT ".";
- if (!defined $opt_o || $opt_o ne "") {
+ if ($ppd_out_dir eq $system_ppd_dir ||
+ ($ppd_dir eq $system_ppd_dir && $ppd_out_dir eq "")) {
print STDOUT " Restart cupsd for the changes to take effect.";
}
print STDOUT "\n";
@@ -590,6 +592,25 @@ sub update_ppd ($) {
$source_data =~ s/(\*StpLocale:\s*\")(.*)(\")/$1$orig_locale$3/;
}
+ # PageRegion, PageSize, Imageablearea, and PaperDimension need to match.
+ # ImageableArea and PaperDimension may be broken from cups-genppdupdate
+ # in 5.2.10 and earlier not updating them, but PageRegion and PageSize
+ # should match. Use PageSize as the default, but warn if PageSize
+ # and PageRegion don't match.
+
+ if ($defaults{"DefaultPageSize"} ne $defaults{"DefaultPageRegion"}) {
+ warn("Warning: DefaultPageSize $defaults{'DefaultPageSize'} and DefaultPageRegion $defaults{'DefaultPageRegion'} don't match. Using $defaults{'DefaultPageSize'} for both.\n");
+ $defaults{"DefaultPageRegion"} = $defaults{"DefaultPageSize"};
+ }
+ if ($defaults{"DefaultPageSize"} ne $defaults{"DefaultImageableArea"}) {
+ print STDERR "Correcting DefaultImageableArea from $defaults{'DefaultImageableArea'} to $defaults{'DefaultPageSize'}\n";
+ $defaults{"DefaultImageableArea"} = $defaults{"DefaultPageSize"};
+ }
+ if ($defaults{"DefaultPageSize"} ne $defaults{"DefaultPaperDimension"}) {
+ print STDERR "Correcting DefaultPaperDimension from $defaults{'DefaultPaperDimension'} to $defaults{'DefaultPageSize'}\n";
+ $defaults{"DefaultPaperDimension"} = $defaults{"DefaultPageSize"};
+ }
+
if ($debug & 4) {
print "Options (Old->New Default Type):\n";
foreach (sort keys %options) {
@@ -666,6 +687,7 @@ default_loop:
my $new_default = $new_defaults{$default_option};
if ((!defined($orig_method) || !defined($new_method)) ||
$orig_method ne $new_method) {
+ $source_data =~ s/^\*($default_option).*/*$1: $default_option_value/m;
next;
}
if (defined($new_default) &&
@@ -698,7 +720,7 @@ default_loop:
(defined $resolution_map{$dopt}) &&
($dopt = $resolution_map{$dopt}) eq $opt)) { # Valid option
# Set the option in the new PPD
- $source_data =~ s/^\*($default_option).*/*$1:$dopt/m;
+ $source_data =~ s/^\*($default_option).*/*$1: $dopt/m;
if ($verbose) {
print "$ppd_source_filename: Set *$default_option to $dopt\n";
}
diff --git a/src/cups/dnpds40_print.c b/src/cups/dnpds40_print.c
index f79df53..16e8ab1 100644
--- a/src/cups/dnpds40_print.c
+++ b/src/cups/dnpds40_print.c
@@ -1,11 +1,12 @@
/*
* DNP DS40/DS80 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
- * Marco Di Antonio and [ ilgruppodigitale.com ]
+ * Marco Di Antonio and [ ilgruppodigitale.com ]
+ * LiveLink Technology [ www.livelinktechnology.net ]
*
* The latest version of this program can be found at:
*
@@ -29,6 +30,10 @@
*
*/
+//#define MATTE_STATE
+//#define DNP_ONLY
+#define MATTE_GLOSSY_2BUF
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,17 +46,18 @@
#include "backend_common.h"
-#define USB_VID_DNP 0x1343
+#define USB_VID_CITIZEN 0x1343
#define USB_PID_DNP_DS40 0x0003 // Also Citizen CX
-#define USB_PID_DNP_DS80 0x0004 // Also Citizen CX-W
+#define USB_PID_DNP_DS80 0x0004 // Also Citizen CX-W, and Mitsubishi CP-3800DW
#define USB_PID_DNP_DSRX1 0x0005 // Also Citizen CY
-//#define USB_PID_CITIZEN_CW-01 XXXXX
-//#define USB_PID_CITIZEN_OP900 XXXXX
+#define USB_VID_DNP 0x1452
+#define USB_PID_DNP_DS620 0x8b01
+
+//#define USB_PID_DNP_DS80D XXXX
+
//#define USB_PID_CITIZEN_CW-02 XXXXX
//#define USB_PID_CITIZEN_OP900II XXXXX
-//#define USB_VID_MITSU 0x06D3
-//#define USB_PID_MITSU_CP3800DW XXXXX
/* Private data stucture */
struct dnpds40_ctx {
@@ -61,10 +67,33 @@ struct dnpds40_ctx {
int type;
+ char *serno;
+ char *version;
+
int buf_needed;
- uint32_t last_matte;
+ int last_matte;
+
+ int ver_major;
+ int ver_minor;
+ int media;
+
+ uint32_t multicut;
+ int matte;
+ int cutter;
+ int can_rewind;
+
+ int supports_6x9;
+ int supports_2x6;
+ int supports_3x5x2;
+ int supports_matte;
+ int supports_fullcut;
+ int supports_rewind;
+ int supports_standby;
+ int supports_6x4_5;
uint8_t *qty_offset;
+ uint8_t *buffctrl_offset;
+ uint8_t *multicut_offset;
uint8_t *databuf;
int datalen;
@@ -116,17 +145,9 @@ static void dnpds40_cleanup_string(char *start, int len)
}
}
-static char *dnpds40_media_types(char *str)
+static char *dnpds40_media_types(int media)
{
- char tmp[4];
- int i;
-
- memcpy(tmp, str + 4, 3);
- tmp[3] = 0;
-
- i = atoi(tmp);
-
- switch (i) {
+ switch (media) {
case 200: return "5x3.5 (L)";
case 210: return "5x7 (2L)";
case 300: return "6x4 (PC)";
@@ -141,20 +162,14 @@ static char *dnpds40_media_types(char *str)
return "Unknown type";
}
-static char *dnpds40_statuses(char *str)
+static char *dnpds40_statuses(int status)
{
- char tmp[6];
- int i;
- memcpy(tmp, str, 5);
- tmp[5] = 0;
-
- i = atoi(tmp);
-
- switch (i) {
+ switch (status) {
case 0: return "Idle";
case 1: return "Printing";
case 500: return "Cooling Print Head";
case 510: return "Cooling Paper Motor";
+ case 900: return "Standby Mode";
case 1000: return "Cover Open";
case 1010: return "No Scrap Box";
case 1100: return "Paper End";
@@ -196,7 +211,7 @@ static int dnpds40_do_cmd(struct dnpds40_ctx *ctx,
data, len)))
return ret;
- return 0;
+ return CUPS_BACKEND_OK;
}
static uint8_t * dnpds40_resp_cmd(struct dnpds40_ctx *ctx,
@@ -226,6 +241,10 @@ static uint8_t * dnpds40_resp_cmd(struct dnpds40_ctx *ctx,
i = atoi(tmp); /* Length of payload in bytes, possibly padded */
respbuf = malloc(i);
+ if (!respbuf) {
+ ERROR("Memory allocation failure (%d bytes)!\n", i);
+ return NULL;
+ }
/* Read in the actual response */
ret = read_data(ctx->dev, ctx->endp_up,
@@ -262,7 +281,7 @@ static int dnpds40_query_serno(struct libusb_device_handle *dev, uint8_t endp_up
resp = dnpds40_resp_cmd(&ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -271,23 +290,30 @@ static int dnpds40_query_serno(struct libusb_device_handle *dev, uint8_t endp_up
free(resp);
- return 0;
+ return CUPS_BACKEND_OK;
}
static void *dnpds40_init(void)
{
struct dnpds40_ctx *ctx = malloc(sizeof(struct dnpds40_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory allocation failure (%d bytes)!\n", (int)sizeof(struct dnpds40_ctx));
return NULL;
+ }
memset(ctx, 0, sizeof(struct dnpds40_ctx));
ctx->type = P_ANY;
+ ctx->last_matte = -1;
return ctx;
}
+#define FW_VER_CHECK(__major, __minor) \
+ ((ctx->ver_major > (__major)) || \
+ (ctx->ver_major == (__major) && ctx->ver_minor >= (__minor)))
+
static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct dnpds40_ctx *ctx = vctx;
struct libusb_device *device;
@@ -302,12 +328,115 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
- /* Map out device type */
- if (desc.idProduct == USB_PID_DNP_DS40)
+ {
+ /* Get Firmware Version */
+ struct dnpds40_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
+
+ dnpds40_build_cmd(&cmd, "INFO", "FVER", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (resp) {
+ char *ptr;
+ dnpds40_cleanup_string((char*)resp, len);
+ ctx->version = strdup((char*) resp);
+
+ /* Parse version */
+ ptr = strtok((char*)resp, " .");
+ ptr = strtok(NULL, ".");
+ ctx->ver_major = atoi(ptr);
+ ptr = strtok(NULL, ".");
+ ctx->ver_minor = atoi(ptr);
+ free(resp);
+ }
+
+ /* Get Serial Number */
+ dnpds40_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (resp) {
+ dnpds40_cleanup_string((char*)resp, len);
+ ctx->serno = (char*) resp;
+ /* Do NOT free resp! */
+ }
+
+ /* Query Media Info */
+ dnpds40_build_cmd(&cmd, "INFO", "MEDIA", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (resp) {
+ char tmp[4];
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ memcpy(tmp, resp + 4, 3);
+ tmp[3] = 0;
+
+ ctx->media = atoi(tmp);
+
+ /* Subtract out the "mark" type */
+ if (ctx->media & 1)
+ ctx->media--;
+
+ free(resp);
+ }
+ }
+
+#ifdef DNP_ONLY
+ /* Only allow DNP printers to work. Rebadged versions should not. */
+
+ { /* Validate USB Vendor String is "Dai Nippon Printing" */
+ char buf[256];
+ buf[0] = 0;
+ libusb_get_string_descriptor_ascii(dev, desc->iManufacturer, (unsigned char*)buf, STR_LEN_MAX);
+ sanitize_string(buf);
+ if (strncmp(buf, "Dai", 3))
+ return 0;
+ }
+#endif
+
+ /* Per-printer options */
+ switch (desc.idProduct) {
+ case USB_PID_DNP_DS40:
ctx->type = P_DNP_DS40;
- else
+ ctx->supports_6x9 = 1;
+ if (FW_VER_CHECK(1,30))
+ ctx->supports_matte = 1;
+ if (FW_VER_CHECK(1,40))
+ ctx->supports_2x6 = 1;
+ if (FW_VER_CHECK(1,50))
+ ctx->supports_3x5x2 = 1;
+ if (FW_VER_CHECK(1,51))
+ ctx->supports_fullcut = 1;
+ break;
+ case USB_PID_DNP_DS80:
ctx->type = P_DNP_DS80;
-
+ if (FW_VER_CHECK(1,30))
+ ctx->supports_matte = 1;
+ break;
+ case USB_PID_DNP_DSRX1:
+ ctx->type = P_DNP_DSRX1;
+ ctx->supports_matte = 1;
+ if (FW_VER_CHECK(1,10))
+ ctx->supports_2x6 = 1;
+ break;
+ case USB_PID_DNP_DS620:
+ ctx->type = P_DNP_DS620;
+ ctx->supports_matte = 1;
+ ctx->supports_2x6 = 1;
+ ctx->supports_fullcut = 1;
+ ctx->supports_rewind = 1; // XXX DS620 only, 620A does not.
+ ctx->supports_standby = 1;
+ if (FW_VER_CHECK(0,30))
+ ctx->supports_3x5x2 = 1;
+ if (FW_VER_CHECK(1,10))
+ ctx->supports_6x9 = ctx->supports_6x4_5 = 1;
+ break;
+ default:
+ ERROR("Unknown USB PID...\n");
+ return;
+ }
}
static void dnpds40_teardown(void *vctx) {
@@ -318,20 +447,24 @@ static void dnpds40_teardown(void *vctx) {
if (ctx->databuf)
free(ctx->databuf);
+ if (ctx->serno)
+ free(ctx->serno);
+ if (ctx->version)
+ free(ctx->version);
free(ctx);
}
-#define MAX_PRINTJOB_LEN (((2448*7536+1024+54))*3+1024) /* Worst-case */
+#define MAX_PRINTJOB_LEN (((2560*7536+1024+54))*3+1024) /* Worst-case */
static int dnpds40_read_parse(void *vctx, int data_fd) {
struct dnpds40_ctx *ctx = vctx;
int run = 1;
char buf[9] = { 0 };
- uint32_t matte = 0, multicut = 0, dpi = 0;
+ uint32_t matte, dpi, cutter;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->databuf) {
free(ctx->databuf);
@@ -351,9 +484,16 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
ctx->databuf = malloc(MAX_PRINTJOB_LEN);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 2;
+ return CUPS_BACKEND_CANCEL;
}
+ /* Clear everything out */
+ matte = 0;
+ dpi = 0;
+ cutter = 0;
+ ctx->multicut = 0;
+ ctx->buffctrl_offset = ctx->qty_offset = ctx->multicut_offset = 0;
+
while (run) {
int remain, i, j;
/* Read in command header */
@@ -364,12 +504,12 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
if (i == 0)
break;
if (i < (int) sizeof(struct dnpds40_cmd))
- return 1;
+ return CUPS_BACKEND_CANCEL;
if (ctx->databuf[ctx->datalen + 0] != 0x1b ||
ctx->databuf[ctx->datalen + 1] != 0x50) {
ERROR("Unrecognized header data format @%d!\n", ctx->datalen);
- return 1;
+ return CUPS_BACKEND_CANCEL;
}
/* Parse out length of data chunk, if any */
@@ -381,8 +521,10 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
while (remain > 0) {
i = read(data_fd, ctx->databuf + ctx->datalen + sizeof(struct dnpds40_cmd),
remain);
- if (i < 0)
+ if (i < 0) {
+ ERROR("Data Read Error: %d (%d/%d @%d)\n", i, remain, j, ctx->datalen);
return i;
+ }
if (i == 0)
return 1;
ctx->datalen += i;
@@ -394,45 +536,74 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
if(!memcmp("CNTRL QTY", ctx->databuf + ctx->datalen+2, 9)) {
ctx->qty_offset = ctx->databuf + ctx->datalen + 32;
}
- if(!memcmp("CNTRL OVERCOAT", ctx->databuf + ctx->datalen+2, 14)) {
+ if(!memcmp("CNTRL CUTTER", ctx->databuf + ctx->datalen+2, 12)) {
memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- matte = atoi(buf);
+ cutter = atoi(buf);
}
- if(!memcmp("CNTRL MULTICUT", ctx->databuf + ctx->datalen+2, 14)) {
+ if(!memcmp("CNTRL BUFFCNTRL", ctx->databuf + ctx->datalen+2, 15)) {
+ /* If the printer doesn't support matte, it doesn't
+ support buffcntrl. strip it from the stream */
+ if (ctx->supports_matte) {
+ ctx->buffctrl_offset = ctx->databuf + ctx->datalen + 32;
+ } else {
+ WARNING("Printer FW does not support BUFFCNTRL, please update\n");
+ continue;
+ }
+ }
+ if(!memcmp("CNTRL OVERCOAT", ctx->databuf + ctx->datalen+2, 14)) {
+ /* If the printer doesn't support matte, it doesn't
+ support buffcntrl. strip it from the stream */
+ if (ctx->supports_matte) {
+ memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
+ matte = atoi(buf);
+ } else {
+ WARNING("Printer FW does not support matte prints, please update\n");
+ continue;
+ }
+ }
+ if(!memcmp("IMAGE MULTICUT", ctx->databuf + ctx->datalen+2, 14)) {
+ ctx->multicut_offset = ctx->databuf + ctx->datalen + 32;
memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- multicut = atoi(buf);
+ ctx->multicut = atoi(buf);
}
- if(!memcmp("IMAGE YPLANE", ctx->databuf + ctx->datalen + 2, 12)) {
- uint32_t x_ppm;
- memcpy(&x_ppm, ctx->databuf + ctx->datalen + 32 + 42, sizeof(x_ppm));
- x_ppm = le32_to_cpu(x_ppm);
+ if(!memcmp("CNTRL FULL_CUTTER_SET", ctx->databuf + ctx->datalen+2, 21)) {
+ if (!ctx->supports_fullcut) {
+ WARNING("Printer FW does not support cutter control, please update!\n");
+ continue;
+ }
+ }
+ if(!memcmp("IMAGE YPLANE", ctx->databuf + ctx->datalen + 2, 12)) {
+ uint32_t y_ppm; /* Pixels Per Meter */
- ctx->buf_needed = 1;
- dpi = 300;
+ /* Validate vertical resolution */
+ memcpy(&y_ppm, ctx->databuf + ctx->datalen + 32 + 42, sizeof(y_ppm));
+ y_ppm = le32_to_cpu(y_ppm);
- if (x_ppm == 23615) { /* pixels per meter, aka 600dpi */
+ switch (y_ppm) {
+ case 11808:
+ dpi = 300;
+ break;
+ case 23615:
dpi = 600;
- if (ctx->type == P_DNP_DS80) { /* DS80/CX-W */
- if (matte && (multicut == 21 || // A4 length
- multicut == 20 || // 8x4*3
- multicut == 19 || // 8x8+8x4
- multicut == 15 || // 8x6*2
- multicut == 7)) // 8x12
- ctx->buf_needed = 2;
- } else { /* DS40/CX/CY/etc */
- if (multicut == 4 || // 6x8
- multicut == 5 || // 6x9
- multicut == 12) // 6x4*2
- ctx->buf_needed = 2;
- else if (matte && multicut == 3) // 5x7
- ctx->buf_needed = 2;
- }
+ break;
+ default:
+ ERROR("Unrecognized printjob resolution (%d ppm)\n", y_ppm);
+ return CUPS_BACKEND_CANCEL;
+ }
- /* If we are missing a multicut command,
- we can't parse this job so must assume
- worst case size needing both buffers! */
- if (!multicut)
- ctx->buf_needed = 2;
+ /* Validate horizontal size */
+ memcpy(&y_ppm, ctx->databuf + ctx->datalen + 32 + 18, sizeof(y_ppm));
+ y_ppm = le32_to_cpu(y_ppm);
+ if (ctx->type == P_DNP_DS80) {
+ if (y_ppm != 2560) {
+ ERROR("Incorrect horizontal resolution (%d), aborting!\n", y_ppm);
+ return CUPS_BACKEND_CANCEL;
+ }
+ } else {
+ if (y_ppm != 1920) {
+ ERROR("Incorrect horizontal resolution (%d), aborting!\n", y_ppm);
+ return CUPS_BACKEND_CANCEL;
+ }
}
}
@@ -444,20 +615,148 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
ctx->datalen += sizeof(struct dnpds40_cmd) + j;
}
- /* Special case: switching to matte or back needs both buffers */
- if (matte != ctx->last_matte)
- ctx->buf_needed = 2;
+ if (!ctx->datalen)
+ return CUPS_BACKEND_CANCEL;
+
+ /* Figure out the number of buffers we need. Most only need one. */
+ if (ctx->multicut) {
+ ctx->buf_needed = 1;
+
+ if (dpi == 600) {
+ if (ctx->type == P_DNP_DS620) {
+ if (ctx->multicut == 5 || // 6x9
+ ctx->multicut == 31) // 6x4.5*2
+ ctx->buf_needed = 2;
+ } else if (ctx->type == P_DNP_DS80) { /* DS80/CX-W */
+ if (matte && (ctx->multicut == 21 || // A4 length
+ ctx->multicut == 20 || // 8x4*3
+ ctx->multicut == 19 || // 8x8+8x4
+ ctx->multicut == 15 || // 8x6*2
+ ctx->multicut == 7)) // 8x12
+ ctx->buf_needed = 2;
+ } else { /* DS40/CX/RX1/CY/etc */
+ if (ctx->multicut == 4 || // 6x8
+ ctx->multicut == 5 || // 6x9
+ ctx->multicut == 12) // 6x4*2
+ ctx->buf_needed = 2;
+ else if (matte && ctx->multicut == 3) // 5x7
+ ctx->buf_needed = 2;
+ }
+ }
+ } else {
+ WARNING("Missing or illegal MULTICUT command, can't validate print job against loaded media!\n");
+ if (dpi == 300)
+ ctx->buf_needed = 1;
+ else
+ ctx->buf_needed = 2;
+ }
- DEBUG("dpi %u matte %u(%u) mcut %u bufs %d\n",
- dpi, matte, ctx->last_matte, multicut, ctx->buf_needed);
+ ctx->matte = (int)matte;
+ ctx->cutter = cutter;
+ ctx->can_rewind = 0;
- /* Track if our last print was matte */
- ctx->last_matte = matte;
+ DEBUG("dpi %u matte %u mcut %u cutter %d, bufs %d\n",
+ dpi, matte, ctx->multicut, cutter, ctx->buf_needed);
- if (!ctx->datalen)
- return 1;
+ /* Sanity-check printjob type vs loaded media */
+ if (ctx->multicut) {
+ switch(ctx->media) {
+ case 200: //"5x3.5 (L)"
+ if (ctx->multicut != 1) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ case 210: //"5x7 (2L)"
+ ctx->can_rewind = 1;
+ if (ctx->multicut != 1 && ctx->multicut != 3 &&
+ ctx->multicut != 22 && ctx->multicut != 29) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ case 300: //"6x4 (PC)"
+ if (ctx->multicut != 2) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ case 310: //"6x8 (A5)"
+ ctx->can_rewind = 1;
+ if (ctx->multicut != 2 && ctx->multicut != 4 &&
+ ctx->multicut != 27) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ case 400: //"6x9 (A5W)"
+ ctx->can_rewind = 1;
+ if (ctx->multicut != 2 && ctx->multicut != 4 &&
+ ctx->multicut != 5 && ctx->multicut != 27 &&
+ ctx->multicut != 30 && ctx->multicut != 31) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ case 500: //"8x10"
+ if (ctx->multicut < 6 || ctx->multicut == 7 ||
+ ctx->multicut == 15 || ctx->multicut >= 18 ) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ case 510: //"8x12"
+ if (ctx->multicut < 6 || ctx->multicut > 21) {
+ ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ break;
+ default:
+ ERROR("Unknown media (%d vs %d)!\n", ctx->media, ctx->multicut);
+ return CUPS_BACKEND_CANCEL;
+ }
+ }
- return 0;
+ /* Additional santity checks */
+ if ((ctx->multicut == 27 || ctx->multicut == 29) &&
+ ctx->type != P_DNP_DS620) {
+ ERROR("Printer does not support 6x6 or 5x5 prints, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ if ((ctx->multicut == 30 || ctx->multicut == 31) &&
+ !ctx->supports_6x4_5) {
+ ERROR("Printer does not support 6x4.5 prints, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ if (ctx->multicut == 5 && !ctx->supports_6x9) {
+ ERROR("Printer does not support 6x9 prints, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ if (ctx->multicut == 22 && !ctx->supports_3x5x2) {
+ ERROR("Printer does not support 3.5x5*2 prints, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ if (ctx->cutter == 120) {
+ if (ctx->multicut == 2 || ctx->multicut == 4) {
+ if (!ctx->supports_2x6) {
+ ERROR("Printer does not support 2x6 prints, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+ } else {
+ ERROR("Printer only supports 2-inch cuts on 4x6 or 8x6 jobs!");
+ return CUPS_BACKEND_CANCEL;
+ }
+ }
+
+ if (ctx->matte && !ctx->supports_matte) {
+ ERROR("Printer FW does not support matte operation, please update!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ return CUPS_BACKEND_OK;
}
static int dnpds40_main_loop(void *vctx, int copies) {
@@ -466,21 +765,126 @@ static int dnpds40_main_loop(void *vctx, int copies) {
struct dnpds40_cmd cmd;
uint8_t *resp = NULL;
int len = 0;
-
uint8_t *ptr;
char buf[9];
+ int status;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
+
+ /* Verify we have sufficient media for prints */
+ {
+ int i = 0;
+
+ /* See if we can rewind to save media */
+ if (ctx->can_rewind && ctx->supports_rewind &&
+ (ctx->multicut == 1 || ctx->multicut == 2)) {
+
+ /* Get Media remaining */
+ dnpds40_build_cmd(&cmd, "INFO", "RQTY", 0);
+
+ if (resp) free(resp);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- /* Parse job to figure out quantity offset. */
- if (copies > 1 && ctx->qty_offset) {
+ dnpds40_cleanup_string((char*)resp, len);
+ i = atoi((char*)resp);
+
+ /* If the count is odd, we can rewind. */
+ if (i & 1) {
+ snprintf(buf, sizeof(buf), "%08d", ctx->multicut + 400);
+ memcpy(ctx->multicut_offset, buf, 8);
+ }
+ }
+
+ /* If we didn't succeed with RQTY, try MQTY */
+ if (i == 0) {
+ dnpds40_build_cmd(&cmd, "INFO", "MQTY", 0);
+
+ if (resp) free(resp);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ i = atoi((char*)resp+4);
+
+ /* For some reason all but the DS620 report 50 too high */
+ if (ctx->type != P_DNP_DS620 && i > 0)
+ i -= 50;
+ }
+
+ if (i < 1) {
+ ERROR("Printer out of media, please correct!\n");
+ return CUPS_BACKEND_STOP;
+ }
+ if (i < copies) {
+ WARNING("Printer does not have sufficient remaining media to complete job..\n");
+ }
+ }
+
+ /* Update quantity offset with count */
+ if (copies > 1) {
snprintf(buf, sizeof(buf), "%07d\r", copies);
- memcpy(ctx->qty_offset, buf, 8);
+ if (ctx->qty_offset) {
+ memcpy(ctx->qty_offset, buf, 8);
+ } else {
+ dnpds40_build_cmd(&cmd, "CNTRL", "QTY", 8);
+ if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
+ return CUPS_BACKEND_FAILED;
+ }
+
+ copies = 1;
+ }
+
+ /* Enable job resumption on correctable errors */
+ if (ctx->supports_matte) {
+ snprintf(buf, sizeof(buf), "%08d", 1);
+ if (ctx->buffctrl_offset) {
+ memcpy(ctx->qty_offset, buf, 8);
+ } else {
+ dnpds40_build_cmd(&cmd, "CNTRL", "BUFFCNTRL", 8);
+ if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
+ return CUPS_BACKEND_FAILED;
+ }
+ }
+
+#ifdef MATTE_STATE
+ /* Check our current job's lamination vs previous job. */
+ {
+ /* Load last matte status from file */
+ char buf[64];
+ FILE *f;
+ snprintf(buf, sizeof(buf), "/tmp/%s-last", ctx->serno);
+ f = fopen(buf, "r");
+ if (f) {
+ fscanf(f, "%d", &ctx->last_matte);
+ fclose(f);
+ }
+ }
+#endif
+
+#ifdef MATTE_GLOSSY_2BUF
+ if (ctx->matte != ctx->last_matte)
+ ctx->buf_needed = 2; /* Switching needs both buffers */
+#endif
- // XXX should we set/reset BUFFCNTRL?
- // XXX should we verify we have sufficient media for prints?
+ ctx->last_matte = ctx->matte;
+#ifdef MATTE_STATE
+ {
+ /* Store last matte status into file */
+ char buf[64];
+ FILE *f;
+ snprintf(buf, sizeof(buf), "/tmp/%s-last", ctx->serno);
+ f = fopen(buf, "w");
+ if (f) {
+ fprintf(f, "%08d", ctx->last_matte);
+ fclose(f);
+ }
}
+#endif
top:
@@ -490,36 +894,63 @@ top:
dnpds40_build_cmd(&cmd, "STATUS", "", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
+ status = atoi((char*)resp);
+ free(resp);
- /* If we're not idle */
- if (strcmp("00000", (char*)resp)) {
- if (!strcmp("00001", (char*)resp)) {
- free(resp);
- /* Query buffer state */
- dnpds40_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
- dnpds40_cleanup_string((char*)resp, len);
-
- /* Check to see if we have sufficient buffers */
- if (!strcmp("FBP00", (char*)resp) ||
- (ctx->buf_needed == 1 && !strcmp("FBP01", (char*)resp))) {
- INFO("Insufficient printer buffers, retrying...\n");
- sleep(1);
- goto top;
- }
- } else if (!strcmp("00500", (char*)resp) ||
- !strcmp("00510", (char*)resp)) {
- INFO("Printer cooling, retrying...\n");
+ /* Figure out what's going on */
+ switch(status) {
+ case 0: /* Idle; we can continue! */
+ break;
+ case 1: /* Printing */
+ {
+ int bufs;
+
+ /* Query buffer state */
+ dnpds40_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+ /* Check to see if we have sufficient buffers */
+ bufs = atoi(((char*)resp)+3);
+ if (bufs < ctx->buf_needed) {
+ INFO("Insufficient printer buffers (%d vs %d), retrying...\n", bufs, ctx->buf_needed);
sleep(1);
goto top;
}
- free(resp);
- ERROR("Printer Status: %s\n", dnpds40_statuses((char*)resp));
- return 1;
+ break;
+ }
+ case 500: /* Cooling print head */
+ case 510: /* Cooling paper motor */
+ INFO("Printer cooling down...\n");
+ sleep(1);
+ goto top;
+ case 900:
+ INFO("Waking printer up from standby...\n");
+ // XXX do someting here?
+ break;
+ case 1000: /* Cover open */
+ case 1010: /* No Scrap Box */
+ case 1100: /* Paper End */
+ case 1200: /* Ribbon End */
+ case 1300: /* Paper Jam */
+ case 1400: /* Ribbon Error */
+ WARNING("Printer not ready: %s, please correct...\n", dnpds40_statuses(status));
+ sleep(1);
+ goto top;
+ case 1500: /* Paper definition error */
+ ERROR("Paper definition error, aborting job\n");
+ return CUPS_BACKEND_CANCEL;
+ case 1600: /* Data error */
+ ERROR("Data error, aborting job\n");
+ return CUPS_BACKEND_CANCEL;
+ default:
+ ERROR("Fatal Printer Error: %d => %s, halting queue!\n", status, dnpds40_statuses(status));
+ return CUPS_BACKEND_HOLD;
}
/* Send the stream over as individual data chunks */
@@ -534,14 +965,10 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
ptr, i)))
- return ret;
+ return CUPS_BACKEND_FAILED;
ptr += i;
}
-
- /* This printer handles copies internally */
- if (ctx->qty_offset)
- copies = 1;
/* Clean up */
if (terminate)
@@ -553,9 +980,7 @@ top:
goto top;
}
- if (resp) free(resp);
-
- return 0;
+ return CUPS_BACKEND_OK;
}
static int dnpds40_get_info(struct dnpds40_ctx *ctx)
@@ -564,56 +989,29 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
uint8_t *resp;
int len = 0;
- /* Get Serial Number */
- dnpds40_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
-
- dnpds40_cleanup_string((char*)resp, len);
-
- INFO("Serial Number: '%s'\n", (char*)resp);
-
- free(resp);
-
- /* Get Firmware Version */
- dnpds40_build_cmd(&cmd, "INFO", "FVER", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
+ /* Serial number already queried */
+ INFO("Serial Number: '%s'\n", ctx->serno);
- dnpds40_cleanup_string((char*)resp, len);
-
- INFO("Firmware Version: '%s'\n", (char*)resp);
-
- free(resp);
+ /* Firmware version already queried */
+ INFO("Firmware Version: '%s'\n", ctx->version);
/* Get Sensor Info */
dnpds40_build_cmd(&cmd, "INFO", "SENSOR", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
-
- INFO("Sensor Info: '%s'\n", (char*)resp);
- // XXX parse this out. Each token is 'XXX-###' delimited by '; '
-
- free(resp);
-
- /* Get Qty of prints made on this media? */
- dnpds40_build_cmd(&cmd, "INFO", "PQTY", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
-
- dnpds40_cleanup_string((char*)resp, len);
-
- INFO("Prints Performed(?): '%s'\n", (char*)resp + 4);
+ INFO("Sensor Info:\n");
+ {
+ char *tmp;
+ tmp = strtok((char*)resp, "; ");
+ do {
+ // XXX parse the components?
+ INFO(" %s\n", tmp);
+ } while ((tmp = strtok(NULL, "; ")) != NULL);
+ }
free(resp);
@@ -622,7 +1020,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -635,7 +1033,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -648,7 +1046,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -662,14 +1060,16 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
- INFO("Media Lot Code: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n",
- *(resp+2), *(resp+3), *(resp+4), *(resp+5), *(resp+6), *(resp+7),
- *(resp+8), *(resp+9), *(resp+10), *(resp+11), *(resp+12), *(resp+13));
-
+ INFO("Media Lot Code: '");
+ /* 16-byte data in a 20-byte response */
+ for (len = 0 ; len < 16 ; len++) {
+ DEBUG2("%c", *(resp+len+2));
+ }
+ DEBUG2("'\n");
free(resp);
/* Get Media ID Set (?) */
@@ -677,7 +1077,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -685,34 +1085,154 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
free(resp);
- /* Get Color Control Data Version */
- dnpds40_build_cmd(&cmd, "TBL_RD", "Version", 0);
+ if (ctx->type == P_DNP_DS620) {
+ /* Loop through control data versions and checksums */
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
+ /* 300 DPI */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Version", 0);
- dnpds40_cleanup_string((char*)resp, len);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- INFO("Color Data Version: '%s'\n", (char*)resp);
+ dnpds40_cleanup_string((char*)resp, len);
- free(resp);
+ INFO("300 DPI Color Data Version: '%s' ", (char*)resp);
- /* Get Color Control Data Checksum */
- dnpds40_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
+ free(resp);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Checksum", 0);
- dnpds40_cleanup_string((char*)resp, len);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- INFO("Color Data Checksum: '%s'\n", (char*)resp);
+ dnpds40_cleanup_string((char*)resp, len);
- free(resp);
+ INFO("Checksum: '%s'\n", (char*)resp);
+ free(resp);
- return 0;
+ /* 600 DPI */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD600_Version", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("600 DPI Color Data Version: '%s' ", (char*)resp);
+
+ free(resp);
+
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD600_Checksum", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Checksum: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* "Low Speed" */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Version", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Low Speed Color Data Version: '%s' ", (char*)resp);
+
+ free(resp);
+
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Checksum", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Checksum: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ } else {
+ /* Get Color Control Data Version */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "Version", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Color Data Version: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* Get Color Control Data Checksum */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Color Data Checksum: '%s'\n", (char*)resp);
+
+ free(resp);
+ }
+
+ if (ctx->type == P_DNP_DS620) {
+ /* Get Standby stuff */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "STANDBY_TIME", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Standby Transition time: '%s' minutes\n", (char*)resp);
+
+ free(resp);
+
+ /* Get Media End Keep */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "END_KEEP_MODE", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Media End kept across power cycles: '%s'\n", (char*)resp);
+
+ free(resp);
+
+ /* Get USB serial descriptor status */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "USB_ISERI_SET", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Report Serial Number in USB descriptor: '%s'\n", (char*)resp);
+
+ free(resp);
+ }
+
+ return CUPS_BACKEND_OK;
}
static int dnpds40_get_status(struct dnpds40_ctx *ctx)
@@ -726,78 +1246,93 @@ static int dnpds40_get_status(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
+ len = atoi((char*)resp);
- INFO("Printer Status: %s => %s\n", (char*)resp, dnpds40_statuses((char*)resp));
+ INFO("Printer Status: %d => %s\n", len, dnpds40_statuses(len));
free(resp);
- /* Generate command */
- dnpds40_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
+ /* Get remaining print quantity */
+ dnpds40_build_cmd(&cmd, "INFO", "PQTY", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
- INFO("Free Buffers: '%s'\n", (char*)resp + 3);
+ INFO("Prints remaining in job: '%s'\n", (char*)resp + 4);
free(resp);
- /* Get Media Info */
- dnpds40_build_cmd(&cmd, "INFO", "MEDIA", 0);
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
- INFO("Media Type: '%s'\n", dnpds40_media_types((char*)resp));
-
-#if 0
- switch (*(resp+3)) {
- case '1':
- INFO(" Stickier paper\n");
- break;
- case '0':
- INFO(" Standard paper\n");
- break;
- default:
- INFO(" Unknown paper(%c)\n", *(resp+4));
- break;
- }
- switch (*(resp+6)) {
- case '1':
- INFO(" With mark\n");
- break;
- case '0':
- INFO(" Without mark\n");
- break;
- default:
- INFO(" Unknown mark(%c)\n", *(resp+7));
- break;
- }
-#endif
+ INFO("Free Buffers: '%s'\n", (char*)resp + 3);
free(resp);
+ /* Report media */
+ INFO("Media Type: '%s'\n", dnpds40_media_types(ctx->media));
+
+ if (ctx->supports_rewind) {
+ /* Get Media remaining */
+ dnpds40_build_cmd(&cmd, "INFO", "MQTY_DEFAULT", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ len = atoi((char*)resp+4);
+
+ INFO("Prints Available on New Media: '%d'\n", len);
+
+ free(resp);
+ }
+
/* Get Media remaining */
dnpds40_build_cmd(&cmd, "INFO", "MQTY", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
- INFO("Prints Remaining: '%s'\n", (char*)resp + 4);
+ len = atoi((char*)resp+4);
+ if (ctx->type != P_DNP_DS620 && len > 0)
+ len -= 50;
+
+ INFO("Prints Remaining on Media: '%d'\n", len);
free(resp);
+ if (ctx->supports_rewind) {
+ /* Get Media remaining */
+ dnpds40_build_cmd(&cmd, "INFO", "RQTY", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("L/PC Prints Remaining on Media: '%s'\n", (char*)resp + 4);
+
+ free(resp);
+ }
+
return 0;
}
@@ -812,7 +1347,7 @@ static int dnpds40_get_counters(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -825,7 +1360,7 @@ static int dnpds40_get_counters(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -838,7 +1373,7 @@ static int dnpds40_get_counters(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -851,7 +1386,7 @@ static int dnpds40_get_counters(struct dnpds40_ctx *ctx)
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
- return -1;
+ return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
@@ -859,33 +1394,35 @@ static int dnpds40_get_counters(struct dnpds40_ctx *ctx)
free(resp);
- /* Generate command */
- dnpds40_build_cmd(&cmd, "MNT_RD", "COUNTER_M", 0);
+ if (ctx->supports_matte) {
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "COUNTER_M", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- dnpds40_cleanup_string((char*)resp, len);
+ dnpds40_cleanup_string((char*)resp, len);
- INFO("M Counter: '%s'\n", (char*)resp+2);
+ INFO("M Counter: '%s'\n", (char*)resp+2);
- free(resp);
+ free(resp);
- /* Generate command */
- dnpds40_build_cmd(&cmd, "MNT_RD", "COUNTER_MATTE", 0);
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "COUNTER_MATTE", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return -1;
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- dnpds40_cleanup_string((char*)resp, len);
+ dnpds40_cleanup_string((char*)resp, len);
- INFO("Matte Counter: '%s'\n", (char*)resp+4);
+ INFO("Matte Counter: '%s'\n", (char*)resp+4);
- free(resp);
+ free(resp);
+ }
- return 0;
+ return CUPS_BACKEND_OK;
}
static int dnpds40_clear_counter(struct dnpds40_ctx *ctx, char counter)
@@ -907,6 +1444,22 @@ static int dnpds40_clear_counter(struct dnpds40_ctx *ctx, char counter)
return 0;
}
+static int dnpds620_standby_mode(struct dnpds40_ctx *ctx, int delay)
+{
+ struct dnpds40_cmd cmd;
+ char msg[9];
+ int ret;
+
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "MNT_WT", "STANDBY_TIME", 8);
+ snprintf(msg, sizeof(msg), "%08d", delay);
+
+ if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)msg, 8)))
+ return ret;
+
+ return 0;
+}
+
static int dnpds40_set_counter_p(struct dnpds40_ctx *ctx, char *arg)
{
struct dnpds40_cmd cmd;
@@ -931,6 +1484,7 @@ static void dnpds40_cmdline(void)
DEBUG("\t\t[ -n ] # Query counters\n");
DEBUG("\t\t[ -N A|B|M ] # Clear counter A/B/M\n");
DEBUG("\t\t[ -p num ] # Set counter P\n");
+ DEBUG("\t\t[ -S num ] # Set standby time (1-99 minutes, 0 disables)\n");
}
@@ -942,7 +1496,7 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "inN:p:s")) >= 0) {
+ while ((i = getopt(argc, argv, "inN:p:sS:")) >= 0) {
switch(i) {
case 'i':
if (ctx) {
@@ -960,8 +1514,12 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
if (optarg[0] != 'A' &&
optarg[0] != 'B' &&
optarg[0] != 'M')
- return -1;
+ return CUPS_BACKEND_FAILED;
if (ctx) {
+ if (!ctx->supports_matte) {
+ ERROR("Printer FW does not support matte functions, please update!\n");
+ return CUPS_BACKEND_FAILED;
+ }
j = dnpds40_clear_counter(ctx, optarg[0]);
break;
}
@@ -978,6 +1536,21 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
break;
}
return 1;
+ case 'S':
+ if (ctx) {
+ int time = atoi(optarg);
+ if (!ctx->supports_standby) {
+ ERROR("Printer does not support standby\n");
+ j = -1;
+ break;
+ }
+ if (time < 0 || time > 99) {
+ ERROR("Value out of range (0-99)");
+ j = -1;
+ break;
+ }
+ j = dnpds620_standby_mode(ctx, time);
+ }
default:
break; /* Ignore completely */
}
@@ -990,8 +1563,8 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend dnpds40_backend = {
- .name = "DNP DS40/DS80/DSRX1",
- .version = "0.30",
+ .name = "DNP DS40/DS80/DSRX1/DS620",
+ .version = "0.51",
.uri_prefix = "dnpds40",
.cmdline_usage = dnpds40_cmdline,
.cmdline_arg = dnpds40_cmdline_arg,
@@ -1002,14 +1575,13 @@ struct dyesub_backend dnpds40_backend = {
.main_loop = dnpds40_main_loop,
.query_serno = dnpds40_query_serno,
.devices = {
- { USB_VID_DNP, USB_PID_DNP_DS40, P_DNP_DS40, ""},
- { USB_VID_DNP, USB_PID_DNP_DS80, P_DNP_DS80, ""},
- { USB_VID_DNP, USB_PID_DNP_DSRX1, P_DNP_DS40, ""},
+ { USB_VID_CITIZEN, USB_PID_DNP_DS40, P_DNP_DS40, ""},
+ { USB_VID_CITIZEN, USB_PID_DNP_DS80, P_DNP_DS80, ""},
+ { USB_VID_CITIZEN, USB_PID_DNP_DSRX1, P_DNP_DSRX1, ""},
+ { USB_VID_DNP, USB_PID_DNP_DS620, P_DNP_DS620, ""},
+// { USB_VID_DNP, USB_PID_DNP_DS80D, P_DNP_DS80, ""},
// { USB_VID_CITIZEN, USB_PID_CITIZEN_CW-02, P_DNP_DS40, ""},
// { USB_VID_CITIZEN, USB_PID_CITIZEN_OP900II, P_DNP_DS40, ""},
-// { USB_VID_CITIZEN, USB_PID_CITIZEN_CW-01, P_DNP_DS40, ""},
-// { USB_VID_CITIZEN, USB_PID_CITIZEN_OP900, P_DNP_DS40, ""},
-// { USB_VID_MITSU, USB_PID_MITSU_CP38000W, P_DNP_DS80, ""},
{ 0, 0, 0, ""}
}
};
diff --git a/src/cups/genppd.c b/src/cups/genppd.c
index 7b55c13..e868444 100644
--- a/src/cups/genppd.c
+++ b/src/cups/genppd.c
@@ -1,5 +1,5 @@
/*
- * "$Id: genppd.c,v 1.196 2014/02/13 02:30:27 rlk Exp $"
+ * "$Id: genppd.c,v 1.197 2015/06/25 01:48:02 speachy Exp $"
*
* PPD file generation program for the CUPS drivers.
*
@@ -564,9 +564,11 @@ main(int argc, /* I - Number of command-line arguments */
break;
}
}
+#ifdef HAVE_LIBZ
if (use_compression)
gpext = ".gz";
else
+#endif
gpext = "";
if (optind < argc) {
int n, numargs;
@@ -2706,5 +2708,5 @@ write_ppd(
/*
- * End of "$Id: genppd.c,v 1.196 2014/02/13 02:30:27 rlk Exp $".
+ * End of "$Id: genppd.c,v 1.197 2015/06/25 01:48:02 speachy Exp $".
*/
diff --git a/src/cups/kodak1400_print.c b/src/cups/kodak1400_print.c
index bc1d0d0..1921bb4 100644
--- a/src/cups/kodak1400_print.c
+++ b/src/cups/kodak1400_print.c
@@ -1,7 +1,7 @@
/*
* Kodak Professional 1400/805 CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -158,6 +158,11 @@ static int kodak1400_set_tonecurve(struct kodak1400_ctx *ctx, char *fname)
uint16_t *data = malloc(UPDATE_SIZE);
+ if (!data) {
+ ERROR("Memory Allocation Failure!\n");
+ return -1;
+ }
+
/* Read in file */
int tc_fd = open(fname, O_RDONLY);
if (tc_fd < 0) {
@@ -277,8 +282,10 @@ int kodak1400_cmdline_arg(void *vctx, int argc, char **argv)
static void *kodak1400_init(void)
{
struct kodak1400_ctx *ctx = malloc(sizeof(struct kodak1400_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
return NULL;
+ }
memset(ctx, 0, sizeof(struct kodak1400_ctx));
return ctx;
@@ -317,7 +324,7 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
int i, ret;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->plane_r) {
free(ctx->plane_r);
@@ -336,18 +343,18 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
if (ret < 0 || ret != sizeof(ctx->hdr)) {
if (ret == 0)
- return 1;
+ return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(ctx->hdr));
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
if (ctx->hdr.hdr[0] != 'P' ||
ctx->hdr.hdr[1] != 'G' ||
ctx->hdr.hdr[2] != 'H' ||
ctx->hdr.hdr[3] != 'D') {
ERROR("Unrecognized data format!\n");
- return 1;
+ return CUPS_BACKEND_CANCEL;
}
ctx->hdr.planesize = le32_to_cpu(ctx->hdr.planesize);
ctx->hdr.rows = le16_to_cpu(ctx->hdr.rows);
@@ -359,7 +366,7 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
ctx->plane_b = malloc(ctx->hdr.planesize);
if (!ctx->plane_r || !ctx->plane_g || !ctx->plane_b) {
ERROR("Memory allocation failure!\n");
- return 1;
+ return CUPS_BACKEND_FAILED;
}
for (i = 0 ; i < ctx->hdr.rows ; i++) {
int j;
@@ -381,7 +388,7 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
ret, remain, ctx->hdr.columns,
i, ctx->hdr.rows, j);
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
@@ -389,7 +396,7 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
}
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static uint8_t idle_data[READBACK_LEN] = { 0xe4, 0x72, 0x00, 0x00,
@@ -417,14 +424,14 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Read in the printer status */
ret = read_data(ctx->dev, ctx->endp_up,
rdbuf, READBACK_LEN, &num);
if (ret < 0)
- return ret;
+ return CUPS_BACKEND_FAILED;
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
memcpy(rdbuf2, rdbuf, READBACK_LEN);
} else if (state == last_state) {
@@ -436,7 +443,7 @@ top:
if (rdbuf[4] || rdbuf[5]) {
ERROR("Error code reported by printer (%02x/%02x), terminating print\n",
rdbuf[4], rdbuf[5]);
- return 1;
+ return CUPS_BACKEND_STOP; // HOLD/CANCEL/FAILED? XXXX parse error!
}
fflush(stderr);
@@ -451,7 +458,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Send page setup */
memset(cmdbuf, 0, CMDBUF_LEN);
@@ -465,7 +472,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Send lamination toggle? */
memset(cmdbuf, 0, CMDBUF_LEN);
@@ -475,7 +482,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Send matte toggle */
memset(cmdbuf, 0, CMDBUF_LEN);
@@ -485,7 +492,7 @@ top:
if (send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Send lamination strength */
memset(cmdbuf, 0, CMDBUF_LEN);
@@ -495,7 +502,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
/* Send unknown */
memset(cmdbuf, 0, CMDBUF_LEN);
@@ -505,14 +512,14 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_READY_Y;
break;
case S_PRINTER_READY_Y:
INFO("Sending YELLOW plane\n");
if ((ret = send_plane(ctx, 1, ctx->plane_b, cmdbuf)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_Y;
break;
case S_PRINTER_SENT_Y:
@@ -522,7 +529,7 @@ top:
case S_PRINTER_READY_M:
INFO("Sending MAGENTA plane\n");
if ((ret = send_plane(ctx, 2, ctx->plane_g, cmdbuf)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_M;
break;
case S_PRINTER_SENT_M:
@@ -532,7 +539,7 @@ top:
case S_PRINTER_READY_C:
INFO("Sending CYAN plane\n");
if ((ret = send_plane(ctx, 3, ctx->plane_r, cmdbuf)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_C;
break;
case S_PRINTER_SENT_C:
@@ -546,7 +553,7 @@ top:
case S_PRINTER_READY_L:
INFO("Laminating page\n");
if ((ret = send_plane(ctx, 4, NULL, cmdbuf)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_L;
break;
case S_PRINTER_SENT_L:
@@ -564,7 +571,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_FINISHED;
break;
@@ -586,7 +593,7 @@ top:
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
/* Exported */
@@ -596,7 +603,7 @@ top:
struct dyesub_backend kodak1400_backend = {
.name = "Kodak 1400/805",
- .version = "0.31",
+ .version = "0.33",
.uri_prefix = "kodak1400",
.cmdline_usage = kodak1400_cmdline,
.cmdline_arg = kodak1400_cmdline_arg,
diff --git a/src/cups/kodak605_print.c b/src/cups/kodak605_print.c
index 08df8f1..544eb72 100644
--- a/src/cups/kodak605_print.c
+++ b/src/cups/kodak605_print.c
@@ -1,7 +1,7 @@
/*
* Kodak 605 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -40,6 +40,20 @@
#define USB_VID_KODAK 0x040A
#define USB_PID_KODAK_605 0x402E
+/* Media structure */
+struct kodak605_medium {
+ uint8_t index;
+ uint16_t cols; /* LE */
+ uint16_t rows; /* LE */
+ uint8_t unk[5]; /* 01 00 00 00 00 */
+} __attribute__((packed));
+
+struct kodak605_media_list {
+ uint8_t unk[12]; /* 01 00 00 00 00 00 02 00 67 00 02 0b */
+ uint8_t count;
+ struct kodak605_medium entries[];
+} __attribute__((packed));
+
/* File header */
struct kodak605_hdr {
uint8_t hdr[4]; /* 01 40 0a 00 */
@@ -81,8 +95,10 @@ enum {
static void *kodak605_init(void)
{
struct kodak605_ctx *ctx = malloc(sizeof(struct kodak605_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
return NULL;
+ }
memset(ctx, 0, sizeof(struct kodak605_ctx));
return ctx;
@@ -122,7 +138,7 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
int ret;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_CANCEL;
if (ctx->databuf) {
free(ctx->databuf);
@@ -133,11 +149,11 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
if (ret < 0 || ret != sizeof(ctx->hdr)) {
if (ret == 0)
- return 1;
+ return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(ctx->hdr));
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
if (ctx->hdr.hdr[0] != 0x01 ||
@@ -145,14 +161,14 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
ctx->hdr.hdr[2] != 0x0a ||
ctx->hdr.hdr[3] != 0x00) {
ERROR("Unrecognized data format!\n");
- return(1);
+ return CUPS_BACKEND_CANCEL;
}
ctx->datalen = le16_to_cpu(ctx->hdr.rows) * le16_to_cpu(ctx->hdr.columns) * 3;
ctx->databuf = malloc(ctx->datalen);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 2;
+ return CUPS_BACKEND_FAILED;
}
{
@@ -164,14 +180,14 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, ctx->datalen);
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
} while (remain);
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static int kodak605_main_loop(void *vctx, int copies) {
@@ -186,15 +202,12 @@ static int kodak605_main_loop(void *vctx, int copies) {
int pending = 0;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
/* Printer handles generating copies.. */
-#if 1
- ctx->hdr.copies = copies;
+ if (ctx->hdr.copies < copies)
+ ctx->hdr.copies = copies;
copies = 1;
-#else
- ctx->hdr.copies = 1;
-#endif
top:
if (state != last_state) {
@@ -213,7 +226,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
- return ret;
+ return CUPS_BACKEND_FAILED;
skip_query:
/* Read in the printer status */
@@ -224,13 +237,13 @@ skip_query:
if (num < 10) {
ERROR("Short read! (%d/%d)\n", num, 10);
- return 4;
+ return CUPS_BACKEND_FAILED;
}
if (num != 10 && num != 76 && num != 113) {
ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n",
num, READBACK_LEN, ctx->endp_up);
- return ret;
+ return CUPS_BACKEND_FAILED;
}
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
@@ -275,7 +288,7 @@ skip_query:
INFO("Sending image header\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
(uint8_t*)&ctx->hdr, sizeof(ctx->hdr))))
- return ret;
+ return CUPS_BACKEND_FAILED;
pending = 1;
state = S_SENT_HDR;
break;
@@ -289,7 +302,7 @@ skip_query:
INFO("Sending image data\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->databuf, ctx->datalen)))
- return ret;
+ return CUPS_BACKEND_FAILED;
INFO("Image data sent\n");
sleep(1); /* An experiment */
@@ -324,7 +337,7 @@ skip_query:
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static int kodak605_get_status(struct kodak605_ctx *ctx)
@@ -362,12 +375,25 @@ static int kodak605_get_status(struct kodak605_ctx *ctx)
return 0;
}
+static void kodak605_dump_mediainfo(struct kodak605_media_list *media)
+{
+ int i;
+
+ DEBUG("Legal print sizes:\n");
+ for (i = 0 ; i < media->count ; i++) {
+ DEBUG("\t%d: %dx%d\n", i,
+ le16_to_cpu(media->entries[i].cols),
+ le16_to_cpu(media->entries[i].rows));
+ }
+ DEBUG("\n");
+}
+
static int kodak605_get_media(struct kodak605_ctx *ctx)
{
uint8_t cmdbuf[4];
uint8_t rdbuf[113];
- int ret, i, num = 0;
+ int ret, num = 0;
/* Send Media Query */
cmdbuf[0] = 0x02;
@@ -389,11 +415,7 @@ static int kodak605_get_media(struct kodak605_ctx *ctx)
return 4;
}
- DEBUG("media: ");
- for (i = 0 ; i < num ; i++) {
- DEBUG2("%02x ", rdbuf[i]);
- }
- DEBUG("\n");
+ kodak605_dump_mediainfo((struct kodak605_media_list *)rdbuf);
return 0;
}
@@ -521,7 +543,7 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend kodak605_backend = {
.name = "Kodak 605",
- .version = "0.18",
+ .version = "0.21",
.uri_prefix = "kodak605",
.cmdline_usage = kodak605_cmdline,
.cmdline_arg = kodak605_cmdline_arg,
@@ -561,23 +583,28 @@ struct dyesub_backend kodak605_backend = {
-> 01 00 00 00
<- [76 bytes -- status ]
--> 01 00 00 00
-<- [76 bytes -- status ]
+
01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00
00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 00
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 01 01 00 00 00 01 00 20 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 00 00 00 00 00
+-> 01 00 00 00
+<- [76 bytes -- status ]
+
01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00
00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 00
- 00 00 00 00 00 00 01 01 00 00 00 01 00 20 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 00 00 00 00 00
+
-> 02 00 00 00
<- [113 bytes -- supported media/sizes? Always seems to be identical ]
+ [ 13-byte header, plus 10 slots for 10-byte media definitions, see above ]
+
01 00 00 00 00 00 02 00 67 00 02 0b 04 01 34 07
d8 04 01 00 00 00 00 02 dc 05 34 08 01 00 00 00
00 03 34 07 82 09 01 00 00 00 00 04 34 07 ba 09
@@ -601,13 +628,6 @@ struct dyesub_backend kodak605_backend = {
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 01 00 00 00 00 00
- 01 00 00 00 00 00 01 00 42 00 31 00 00 00 31 00
- 00 00 14 00 00 00 77 00 00 00 31 00 00 00 5d 00
- 00 00 00 00 00 00 01 00 00 01 00 01 00 00 02 01
- 00 00 00 01 00 02 02 01 00 00 00 01 00 02 00 00
- 00 00 00 00 00 00 01 00 00 00 00 00
-
-
Write tone curve data:
-> 04 c0 0a 00 03 01 00 00 00 00 LL LL 00 00 [[ LL LL == 0x0600 in LE ]]
diff --git a/src/cups/kodak6800_print.c b/src/cups/kodak6800_print.c
index e7bb174..51093b8 100644
--- a/src/cups/kodak6800_print.c
+++ b/src/cups/kodak6800_print.c
@@ -1,7 +1,11 @@
/*
* Kodak 6800/6850 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * Development of this backend was sponsored by:
+ *
+ * LiveLink Technology [ www.livelinktechnology.net ]
*
* The latest version of this program can be found at:
*
@@ -43,15 +47,67 @@
/* File header */
struct kodak6800_hdr {
- uint8_t hdr[9];
+ uint8_t hdr[9]; /* Always 03 1b 43 48 43 0a 00 04 00 [6850]
+ 03 1b 43 48 43 0a 00 01 00 [6800] */
uint8_t copies;
uint16_t columns; /* BE */
uint16_t rows; /* BE */
- uint8_t media; /* 0x06 for 6x8, 0x00 for 6x4, 0x07 for 5x7 */
+ uint8_t size; /* 0x06 for 6x8, 0x00 for 6x4, 0x07 for 5x7 */
uint8_t laminate; /* 0x01 to laminate, 0x00 for not */
- uint8_t unk1; /* 0x00, 0x01 [may be print mode] */
+ uint8_t unk1; /* 0x00 or 0x01 (for 4x6 on 6x8 media) */
+} __attribute__((packed));
+
+struct kodak68x0_status_readback {
+ uint8_t hdr; /* Always 01 */
+ uint8_t sts1; /* Always 0x02 (idle) or 0x01 (busy) */
+ uint8_t sts2; /* 0x01 == ready, 0x02 == no media, 0x03 == not ready */
+ uint8_t errtype; /* 0x00 none, 0x80 "control" */
+ uint8_t null0[2];
+ uint8_t unkA; /* 0x00 or 0x01 or 0x10 */
+ uint8_t errcode; /* Error ## */
+ uint32_t ctr0; /* Total Prints (BE) */
+ uint32_t ctr1; /* Total Prints (BE) */
+ uint32_t ctr2; /* Increments by 1 for each print (6850), unk (6800). BE */
+ uint32_t ctr3; /* Increments by 2 for each print. BE */
+ uint8_t nullB[2];
+ uint8_t errtype2; /* 0x00 none, 0xd0 "control" */
+ uint8_t donor; /* Percentage, 0-100 */
+ uint8_t unkC[2]; /* Always 00 03 */
+ uint16_t main_fw; /* seen 652, 656, 670 (6850) and 232 (6800) */
+ uint8_t unkD[2]; /* Always 00 01 */
+ uint16_t dsp_fw; /* Seen 540, 541, 560 (6850) and 131 (6800) */
+ uint8_t unk1; /* Seen 0x00, 0x01, 0x03, 0x04 */
+ uint8_t null1[2];
+ uint8_t unk2; /* Seen 0x01, 0x00 */
+ uint8_t null2;
+ uint8_t unk3; /* Seen 0x01, 0x00 */
+ uint8_t null4;
+ uint8_t unk4; /* Seen 0x01, 0x00 */
+ uint8_t null5[7];
+} __attribute__((packed));
+
+struct kodak6800_printsize {
+ uint8_t hdr; /* Always 0x06 */
+ uint16_t width; /* BE */
+ uint16_t height; /* BE */
+ uint8_t hdr2; /* Always 0x01 */
+ uint8_t code; /* 00, 01, 02, 03, 04, 05 seen. An index? */
+ uint8_t code2; /* 00, 01 seen. Seems to be 1 only after a 4x6 printed. */
+ uint8_t null[2];
+} __attribute__((packed));
+
+#define MAX_MEDIA_LEN 128
+
+struct kodak68x0_media_readback {
+ uint8_t hdr; /* Always 0x01 */
+ uint8_t media; /* Always 0x00 (none), 0x0b or 0x03 */
+ uint8_t null[5];
+ uint8_t count; /* Always 0x04 (6800) or 0x06 (6850)? */
+ struct kodak6800_printsize sizes[];
} __attribute__((packed));
+#define KODAK68x0_MEDIA_6R 0x0b
+
#define CMDBUF_LEN 17
/* Private data stucture */
@@ -61,24 +117,154 @@ struct kodak6800_ctx {
uint8_t endp_down;
int type;
+ int media;
+
struct kodak6800_hdr hdr;
uint8_t *databuf;
int datalen;
};
+#define READBACK_LEN 68
-/* Program states */
-enum {
- S_IDLE = 0,
- S_6850_READY,
- S_6850_READY_WAIT,
- S_READY,
- S_STARTED,
- S_SENT_HDR,
- S_SENT_DATA,
- S_FINISHED,
-};
+char *kodak68x0_error_codes(uint8_t code1, uint8_t code2)
+{
+ if (code1 == 0x80 && code2 == 0xd0)
+ return "Control Error";
+
+ return "Unknown Type (please report!)";
+}
+
+static void kodak68x0_dump_mediainfo(struct kodak68x0_media_readback *media)
+{
+ int i;
+ if (media->media == KODAK68x0_MEDIA_6R) {
+ DEBUG("Media type: 6R (Kodak 197-4096 or equivalent)\n");
+ } else {
+ DEBUG("Media type %02x (unknown, please report!)\n", media->media);
+ }
+ DEBUG("Legal print sizes:\n");
+ for (i = 0 ; i < media->count ; i++) {
+ DEBUG("\t%d: %dx%d (%02x) %s\n", i,
+ be16_to_cpu(media->sizes[i].width),
+ be16_to_cpu(media->sizes[i].height),
+ media->sizes[i].code,
+ media->sizes[i].code2? "Disallowed" : "");
+ }
+ DEBUG("\n");
+}
+
+static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx, struct kodak68x0_media_readback *media)
+{
+ uint8_t req[16];
+ int ret, num;
+
+ memset(req, 0, sizeof(req));
+ memset(media, 0, sizeof(*media));
+
+ req[0] = 0x03;
+ req[1] = 0x1b;
+ req[2] = 0x43;
+ req[3] = 0x48;
+ req[4] = 0x43;
+ req[5] = 0x1a;
+
+ /* Send request */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ req, sizeof(req))))
+ return ret;
+
+ /* Get response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*)media, MAX_MEDIA_LEN, &num);
+
+ if (ret < 0)
+ return ret;
+ if (num < (int)sizeof(*media)) {
+ ERROR("Short read! (%d/%d)\n", num, (int) sizeof(*media));
+ return 4;
+ }
+
+
+ /* Validate proper response */
+ if (media->hdr != 0x01 ||
+ media->null[0] != 0x00) {
+ ERROR("Unexpected response from media query!\n");
+ return CUPS_BACKEND_STOP;
+ }
+
+ ctx->media = media->media;
+
+ return 0;
+}
+
+static void kodak68x0_dump_status(struct kodak6800_ctx *ctx, struct kodak68x0_status_readback *status)
+{
+ if (status->errtype || status->errtype2 || status->errcode) {
+ DEBUG("Error code : %s (%d/%d) # %d\n",
+ kodak68x0_error_codes(status->errtype, status->errtype2),
+ status->errtype, status->errtype2, status->errcode);
+ }
+ DEBUG("Total prints : %d\n", be32_to_cpu(status->ctr0));
+ DEBUG("Media prints : %d\n", be32_to_cpu(status->ctr2));
+ if (ctx->type == P_KODAK_6850) {
+ int max;
+ if (ctx->media == KODAK68x0_MEDIA_6R) {
+ max = 375;
+ } else {
+ max = 0;
+ }
+
+ if (max) {
+ DEBUG("Remaining prints : %d\n", max - be32_to_cpu(status->ctr2));
+ } else {
+ DEBUG("Remaining prints : Unknown media type\n");
+ }
+ }
+ DEBUG("Main FW version : %d\n", be16_to_cpu(status->main_fw));
+ DEBUG("DSP FW version : %d\n", be16_to_cpu(status->dsp_fw));
+ DEBUG("Donor : %d%%\n", status->donor);
+ DEBUG("\n");
+}
+
+static int kodak6800_get_status(struct kodak6800_ctx *ctx,
+ struct kodak68x0_status_readback *status)
+{
+ uint8_t req[16];
+ int ret, num;
+
+ memset(req, 0, sizeof(req));
+ memset(status, 0, sizeof(*status));
+
+ req[0] = 0x03;
+ req[1] = 0x1b;
+ req[2] = 0x43;
+ req[3] = 0x48;
+ req[4] = 0x43;
+ req[5] = 0x03;
+
+ /* Send request */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ req, sizeof(req))))
+ return ret;
+
+ /* Get response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*)status, sizeof(*status), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num < (int)sizeof(*status)) {
+ ERROR("Short read! (%d/%d)\n", num, (int) sizeof(*status));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (status->hdr != 0x01) {
+ ERROR("Unexpected response from status query!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ return 0;
+}
-#define READBACK_LEN 68
#define UPDATE_SIZE 1536
static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
@@ -93,6 +279,10 @@ static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
int i;
uint16_t *data = malloc(UPDATE_SIZE);
+ if (!data) {
+ ERROR("Memory Allocation Failure\n");
+ return -1;
+ }
INFO("Dump Tone Curve to '%s'\n", fname);
@@ -198,6 +388,11 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
uint16_t *data = malloc(UPDATE_SIZE);
uint8_t *ptr;
+ if (!data) {
+ ERROR("Memory Allocation Failure\n");
+ return -1;
+ }
+
INFO("Set Tone Curve from '%s'\n", fname);
/* Read in file */
@@ -285,10 +480,101 @@ done:
return ret;
}
+static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
+{
+ int ret;
+ int num;
+
+ uint8_t resp[33];
+ uint8_t req[16];
+
+ memset(req, 0, sizeof(req));
+ memset(resp, 0, sizeof(resp));
+
+ req[0] = 0x03;
+ req[1] = 0x1b;
+ req[2] = 0x43;
+ req[3] = 0x48;
+ req[4] = 0x43;
+ req[5] = 0x03;
+
+ /* Send request */
+ if ((ret = send_data(dev, endp_down,
+ req, sizeof(req))))
+ return ret;
+
+ /* Get response */
+ ret = read_data(dev, endp_up,
+ resp, sizeof(resp) - 1, &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != 32) {
+ ERROR("Short read! (%d/%d)\n", num, 32);
+ return 4;
+ }
+ strncpy(buf, (char*)resp+24, buf_len);
+ buf[buf_len-1] = 0;
+
+ return 0;
+}
+
+static int kodak6850_send_init(struct kodak6800_ctx *ctx)
+{
+ uint8_t cmdbuf[64];
+ uint8_t rdbuf[64];
+ int ret = 0, num = 0;
+
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmdbuf[0] = 0x03;
+ cmdbuf[1] = 0x1b;
+ cmdbuf[2] = 0x43;
+ cmdbuf[3] = 0x48;
+ cmdbuf[4] = 0x43;
+ cmdbuf[5] = 0x4c;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, CMDBUF_LEN -1)))
+ return CUPS_BACKEND_FAILED;
+
+ /* Read response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (num < 51) {
+ ERROR("Short read! (%d/%d)\n", num, 51);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (num != 51) {
+ ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n",
+ num, READBACK_LEN, ctx->endp_up);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (rdbuf[0] != 0x01 ||
+ rdbuf[2] != 0x43) {
+ ERROR("Unexpected response from printer init!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ // XXX I believe this the media position
+ // saying when we have a 4x6 left on an 8x6 blank
+ if (rdbuf[1] != 0x01 && rdbuf[1] != 0x00) {
+ ERROR("Unexpected status code (0x%02x)!\n", rdbuf[1]);
+ return CUPS_BACKEND_FAILED;
+ }
+ return ret;
+}
+
static void kodak6800_cmdline(void)
{
DEBUG("\t\t[ -c filename ] # Get tone curve\n");
DEBUG("\t\t[ -C filename ] # Set tone curve\n");
+ DEBUG("\t\t[ -m ] # Query media\n");
+ DEBUG("\t\t[ -s ] # Query status\n");
}
static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
@@ -299,7 +585,7 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "C:c:")) >= 0) {
+ while ((i = getopt(argc, argv, "C:c:ms")) >= 0) {
switch(i) {
case 'c':
if (ctx) {
@@ -313,6 +599,32 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
break;
}
return 1;
+ case 'm':
+ if (ctx) {
+ uint8_t mediabuf[MAX_MEDIA_LEN];
+ struct kodak68x0_media_readback *media = (struct kodak68x0_media_readback*)mediabuf;
+ j = kodak6800_get_mediainfo(ctx, media);
+ if (!j)
+ kodak68x0_dump_mediainfo(media);
+ break;
+ }
+ return 1;
+ case 's':
+ if (ctx) {
+ uint8_t mediabuf[MAX_MEDIA_LEN];
+ struct kodak68x0_media_readback *media = (struct kodak68x0_media_readback*)mediabuf;
+ struct kodak68x0_status_readback status;
+ j = kodak6800_get_mediainfo(ctx, media);
+ if (!j)
+ j = kodak6800_get_status(ctx, &status);
+ if (!j)
+ kodak68x0_dump_status(ctx, &status);
+
+ break;
+ }
+
+ return 1;
+
default:
break; /* Ignore completely */
}
@@ -327,11 +639,14 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
static void *kodak6800_init(void)
{
struct kodak6800_ctx *ctx = malloc(sizeof(struct kodak6800_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure\n");
return NULL;
+ }
memset(ctx, 0, sizeof(struct kodak6800_ctx));
ctx->type = P_ANY;
+ ctx->media = -1;
return ctx;
}
@@ -359,7 +674,6 @@ static void kodak6800_attach(void *vctx, struct libusb_device_handle *dev,
ctx->type = P_KODAK_6800;
}
-
static void kodak6800_teardown(void *vctx) {
struct kodak6800_ctx *ctx = vctx;
@@ -376,7 +690,7 @@ static int kodak6800_read_parse(void *vctx, int data_fd) {
int ret;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->databuf) {
free(ctx->databuf);
@@ -387,11 +701,11 @@ static int kodak6800_read_parse(void *vctx, int data_fd) {
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
if (ret < 0 || ret != sizeof(ctx->hdr)) {
if (ret == 0)
- return 1;
- ERROR("Read failed (%d/%d/%d)\n",
+ return CUPS_BACKEND_CANCEL;
+ ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(ctx->hdr));
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
if (ctx->hdr.hdr[0] != 0x03 ||
ctx->hdr.hdr[1] != 0x1b ||
@@ -399,14 +713,14 @@ static int kodak6800_read_parse(void *vctx, int data_fd) {
ctx->hdr.hdr[3] != 0x48 ||
ctx->hdr.hdr[4] != 0x43) {
ERROR("Unrecognized data format!\n");
- return(1);
+ return CUPS_BACKEND_CANCEL;
}
ctx->datalen = be16_to_cpu(ctx->hdr.rows) * be16_to_cpu(ctx->hdr.columns) * 3;
ctx->databuf = malloc(ctx->datalen);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 2;
+ return CUPS_BACKEND_FAILED;
}
{
@@ -418,207 +732,149 @@ static int kodak6800_read_parse(void *vctx, int data_fd) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, ctx->datalen);
perror("ERROR: Read failed");
- return ret;
+ return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
} while (remain);
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static int kodak6800_main_loop(void *vctx, int copies) {
struct kodak6800_ctx *ctx = vctx;
+ struct kodak68x0_status_readback status;
- uint8_t rdbuf[READBACK_LEN];
- uint8_t rdbuf2[READBACK_LEN];
uint8_t cmdbuf[CMDBUF_LEN];
- int last_state = -1, state = S_IDLE;
+ uint8_t mediabuf[MAX_MEDIA_LEN];
+ struct kodak68x0_media_readback *media = (struct kodak68x0_media_readback*)mediabuf;
+
int num, ret;
- int pending = 0;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
-top:
- if (state != last_state) {
- if (dyesub_debug)
- DEBUG("last_state %d new %d\n", last_state, state);
- }
-
- if (pending)
- goto skip_query;
-
- /* Send Status Query */
- memset(cmdbuf, 0, CMDBUF_LEN);
- cmdbuf[0] = 0x03;
- cmdbuf[1] = 0x1b;
- cmdbuf[2] = 0x43;
- cmdbuf[3] = 0x48;
- cmdbuf[4] = 0x43;
- cmdbuf[5] = 0x03;
+ /* Printer handles generating copies.. */
+ if (ctx->hdr.copies < copies)
+ ctx->hdr.copies = copies;
+ copies = 1;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN - 1)))
- return ret;
-
-skip_query:
- /* Read in the printer status */
- ret = read_data(ctx->dev, ctx->endp_up,
- rdbuf, READBACK_LEN, &num);
+ /* Query loaded media */
+ INFO("Querying loaded media\n");
+ ret = kodak6800_get_mediainfo(ctx, media);
if (ret < 0)
- return ret;
+ return CUPS_BACKEND_FAILED;
- if (num < 51) {
- ERROR("Short read! (%d/%d)\n", num, 51);
- return 4;
+ /* Appears to depend on media */
+ if (media->media != KODAK68x0_MEDIA_6R &&
+ media->media != 0x03) {
+ ERROR("Unrecognized media type %02x\n", media->media);
+ return CUPS_BACKEND_STOP;
}
- if (num != 51 && num != 58 && num != 68) {
- ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n",
- num, READBACK_LEN, ctx->endp_up);
- return ret;
+ /* Validate against supported media list */
+ for (num = 0 ; num < media->count; num++) {
+ if (media->sizes[num].height == ctx->hdr.rows &&
+ media->sizes[num].width == ctx->hdr.columns)
+ break;
}
-
- // XXX detect media type based on readback?
-
- if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- memcpy(rdbuf2, rdbuf, READBACK_LEN);
- } else if (state == last_state) {
- sleep(1);
+ if (num == media->count) {
+ ERROR("Print size unsupported by media!\n");
+ return CUPS_BACKEND_HOLD;
}
- last_state = state;
-
- fflush(stderr);
-
- pending = 0;
-
- switch (state) {
- case S_IDLE:
- INFO("Waiting for printer idle\n");
- if (rdbuf[0] != 0x01 ||
- rdbuf[1] != 0x02 ||
- rdbuf[2] != 0x01) {
- break;
- }
-
- INFO("Printing started; Sending init sequence\n");
- if (ctx->type == P_KODAK_6850)
- state = S_6850_READY;
- else
- state = S_READY;
- break;
- case S_6850_READY:
- INFO("Sending 6850 init sequence\n");
- memset(cmdbuf, 0, CMDBUF_LEN);
- cmdbuf[0] = 0x03;
- cmdbuf[1] = 0x1b;
- cmdbuf[2] = 0x43;
- cmdbuf[3] = 0x48;
- cmdbuf[4] = 0x43;
- cmdbuf[5] = 0x4c;
-
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN -1)))
- return ret;
- pending = 1;
- state = S_6850_READY_WAIT;
- break;
- case S_6850_READY_WAIT:
- if (rdbuf[0] != 0x01 ||
- rdbuf[2] != 0x43) {
- state = S_6850_READY;
- break;
- }
- state = S_READY;
- break;
- case S_READY:
- INFO("Sending attention sequence\n");
- /* Send reset/attention */
- memset(cmdbuf, 0, CMDBUF_LEN);
- cmdbuf[0] = 0x03;
- cmdbuf[1] = 0x1b;
- cmdbuf[2] = 0x43;
- cmdbuf[3] = 0x48;
- cmdbuf[4] = 0x43;
- cmdbuf[5] = 0x1a;
-
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN -1)))
- return ret;
- pending = 1;
- state = S_STARTED;
- break;
- case S_STARTED:
- if (rdbuf[0] != 0x01 ||
- rdbuf[2] != 0x00)
- break;
- /* Aappears to depend on media */
- if (rdbuf[1] != 0x0b &&
- rdbuf[1] != 0x03)
- break;
+top:
+ INFO("Waiting for printer idle\n");
- memcpy(cmdbuf, &ctx->hdr, CMDBUF_LEN);
+ while(1) {
+ if (kodak6800_get_status(ctx, &status))
+ return CUPS_BACKEND_FAILED;
- /* 6850 uses same spool format but different header gets sent */
- if (ctx->type == P_KODAK_6850) {
- if (ctx->hdr.media == 0x00)
- cmdbuf[7] = 0x04;
- else if (ctx->hdr.media == 0x06)
- cmdbuf[7] = 0x05;
+ if (status.errtype || status.errtype2 || status.errcode) {
+ ERROR("Printer error reported: %s (%d/%d) # %d\n",
+ kodak68x0_error_codes(status.errtype, status.errtype2),
+ status.errtype, status.errtype2, status.errcode);
+ return CUPS_BACKEND_FAILED;
}
- /* If we're printing a 4x6 on 8x6 media... */
- if (ctx->hdr.media == 0x00 &&
- rdbuf[11] == 0x09 &&
- rdbuf[12] == 0x82) {
- cmdbuf[14] = 0x06;
- cmdbuf[16] = 0x01;
+ if (status.sts1 == 0x01) {
+ // do nothing, this is expected.
+ sleep(1);
+ continue;
+ } else if (status.sts1 != 0x02) {
+ ERROR("Unknown status1 0x%02x\n", status.sts1);
+ return CUPS_BACKEND_FAILED;
}
- INFO("Sending image header\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN)))
- return ret;
- pending = 1;
- state = S_SENT_HDR;
- break;
- case S_SENT_HDR:
- INFO("Waiting for printer to accept data\n");
- if (rdbuf[0] != 0x01 ||
- rdbuf[1] != 0x02 ||
- rdbuf[2] != 0x01) {
+ if (status.sts2 == 0x02) {
+ ERROR("Printer is out of media!\n");
+ return CUPS_BACKEND_STOP;
+ } else if (status.sts2 == 0x03) {
+ ERROR("Printer is offline!\n");
+ return CUPS_BACKEND_STOP;
+ } else if (status.sts2 != 0x01) {
+ ERROR("Unknown status 0x%02x\n", status.sts2);
+ return CUPS_BACKEND_FAILED;
+ } else {
break;
}
+ }
- INFO("Sending image data\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ if (ctx->type == P_KODAK_6850) {
+ INFO("Sending 6850 init sequence\n");
+ ret = kodak6850_send_init(ctx);
+ if (ret)
return ret;
-
- INFO("Image data sent\n");
- state = S_SENT_DATA;
- break;
- case S_SENT_DATA:
- INFO("Waiting for printer to acknowledge completion\n");
- if (rdbuf[0] != 0x01 ||
- rdbuf[1] != 0x02 ||
- rdbuf[2] != 0x01) {
+ sleep(1);
+ }
+
+ /* Set up print job header */
+ memcpy(cmdbuf, &ctx->hdr, CMDBUF_LEN);
+
+ /* 6850 uses same spool format but different header gets sent */
+ if (ctx->type == P_KODAK_6850) {
+ if (ctx->hdr.size == 0x00)
+ cmdbuf[7] = 0x04;
+ else if (ctx->hdr.size == 0x06)
+ cmdbuf[7] = 0x05; /* XXX audit this! */
+ }
+
+ /* If we're printing a 4x6 on 8x6 media... */
+ if (ctx->hdr.size == 0x00 &&
+ be16_to_cpu(media->sizes[0].width) == 0x0982) {
+ cmdbuf[14] = 0x06;
+ cmdbuf[16] = 0x01;
+ }
+
+ INFO("Sending image header\n");
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, CMDBUF_LEN)))
+ return ret;
+ sleep(1);
+ INFO("Sending image data\n");
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ctx->databuf, ctx->datalen)))
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Waiting for printer to acknowledge completion\n");
+ sleep(1);
+ while(1) {
+ if (kodak6800_get_status(ctx, &status))
+ return CUPS_BACKEND_FAILED;
+
+ if (status.sts1 == 0x01) {
+ // do nothing, this is expected.
+ } else if (status.sts1 != 0x02) {
+ ERROR("Unknown status1 0x%02x\n", status.sts1);
+ return CUPS_BACKEND_FAILED;
+ } else {
break;
}
-
- state = S_FINISHED;
- break;
- default:
- break;
- };
-
- if (state != S_FINISHED)
- goto top;
-
+ sleep(1);
+ }
+
/* Clean up */
if (terminate)
copies = 1;
@@ -626,17 +882,16 @@ skip_query:
INFO("Print complete (%d copies remaining)\n", copies - 1);
if (copies && --copies) {
- state = S_IDLE;
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
/* Exported */
struct dyesub_backend kodak6800_backend = {
.name = "Kodak 6800/6850",
- .version = "0.32",
+ .version = "0.43",
.uri_prefix = "kodak6800",
.cmdline_usage = kodak6800_cmdline,
.cmdline_arg = kodak6800_cmdline_arg,
@@ -645,6 +900,7 @@ struct dyesub_backend kodak6800_backend = {
.teardown = kodak6800_teardown,
.read_parse = kodak6800_read_parse,
.main_loop = kodak6800_main_loop,
+ .query_serno = kodak6800_query_serno,
.devices = {
{ USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak"},
{ USB_VID_KODAK, USB_PID_KODAK_6850, P_KODAK_6850, "Kodak"},
@@ -662,18 +918,23 @@ struct dyesub_backend kodak6800_backend = {
Header:
03 1b 43 48 43 0a 00 01 00 Fixed header
- CC Number of copies
+ NN Number of copies (01-255)
WW WW Number of columns, big endian. (Fixed at 1844 on 6800)
HH HH Number of rows, big endian.
- DD 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850)
+ SS 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850)
LL Laminate, 0x00 (off) or 0x01 (on)
- 00
+ UU 0x01 for multi-cut, 0x00 otherwise.
+
+ Note: For 4x6 prints on 6x8 media, print size (SS) is set to 0x06 and the
+ final octet is set to 0x01.
************************************************************************
Kodak 6800 Printer Comms:
- [[file header]] 03 1b 43 48 43 0a 00 01 00 CC WW WW HH HH MT LL 00
+ [[file header]] 03 1b 43 48 43 0a 00 01 00 NN WW WW HH HH SS LL UU
+
+ (see above for details on fields)
-> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query]
<- [51 octets]
@@ -683,15 +944,16 @@ struct dyesub_backend kodak6800_backend = {
00 01 00 83 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00
--> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [get ready]
+-> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [media query]
<- [58 octets]
01 XX 00 00 00 00 00 04 06 WW WW MM MM 01 00 00 [MM MM == max printable size of media, 09 82 == 2434 for 6x8!]
00 00 06 WW WW 09 ba 01 02 00 00 00 06 WW WW HH [09 ba == 2940 == cut area?]
- HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == media type?; 0b/03]
+ HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == 0b or 03 == media type?]
00 00 00 00 00 00 00 00 00 00
--> 03 1b 43 48 43 0a 00 01 00 01 WW WW HH HH 06 01 [ image header, modified (trailing 0x01, '0x06' as media type) ]
+
+-> 03 1b 43 48 43 0a 00 01 00 01 WW WW HH HH 06 01 [ image header, modified, see above ]
01
<- [51 octets]
@@ -717,7 +979,7 @@ struct dyesub_backend kodak6800_backend = {
-> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [ status query ]
<- [51 octets, repeats]
- Other stuff seen:
+ Possible Serial number query:
-> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00
<- [32 octets]
@@ -782,7 +1044,11 @@ struct dyesub_backend kodak6800_backend = {
Kodak 6850 Printer Comms:
- [[file header]] 03 1b 43 48 43 0a 00 01 00 CC WW WW HH HH MT LL 00
+ [[file header]] 03 1b 43 48 43 0a 00 XX 00 CC WW WW HH HH SS LL UU
+
+ Note: 'XX' paper code is 0x04 for 4x6, 0x06 for 6x8 on the 6850!
+
+ (See above for details on all other fields)
-> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query]
<- [51 octets]
@@ -800,20 +1066,25 @@ struct dyesub_backend kodak6800_backend = {
00 01 02 1d 03 00 00 00 00 01 00 01 00 00 00 00
00 00 00
+ 01 00 43 48 43 4c 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 01 00 00 b7 d3 00 00 00 5c 00 03 02 8c
+ 00 01 02 1c 00 00 00 00 00 01 00 01 00 00 00 00
+ 00 00 00
+
-> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query]
<- [51 octets -- same as status query before ]
--> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [get ready]
+-> 03 1b 43 48 43 1a 00 00 00 00 00 00 00 00 00 00 [media query]
<- [68 octets]
01 XX 00 00 00 00 00 06 06 WW WW MM MM 01 00 00 [MM MM == max printable size of media, 09 82 == 2434 for 6x8!]
00 00 06 WW WW 09 ba 01 02 01 00 00 06 WW WW HH [09 ba == 2940 == cut area?]
- HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == media type? 03/0b ]
+ HH 01 01 00 00 00 06 WW WW MM MM 01 03 00 00 00 [XX == 0b or 03 == media type?]
06 WW WW 09 ba 01 05 01 00 00 06 WW WW HH HH 01
04 00 00 00
--> 03 1b 43 48 43 0a 00 04 00 01 07 34 04 d8 06 01 [ image header, modified ]
- 01 [ note we use '04' for 4x6, '05' for 6x8. last octet is always 0x01 when 4x6. ]
+-> 03 1b 43 48 43 0a 00 04 00 01 07 34 04 d8 06 01 [ image header, modified, see above ]
+ 01
<- [51 octets]
@@ -835,7 +1106,7 @@ struct dyesub_backend kodak6800_backend = {
00 01 02 1d 04 00 00 01 00 00 00 01 00 00 00 00
00 00 00
- Other stuff seen:
+ Possible Serial number query:
-> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00
00
@@ -907,12 +1178,42 @@ struct dyesub_backend kodak6800_backend = {
Also seen on the 6850:
-DEBUG: readback: 01 02 03 00 00 00 01 00 00 01 5f 6f 00 01 5f 6f 00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+DEBUG: readback:
+
+01 02 03 00 00 00 01 00 00 01 5f 6f 00 01 5f 6f
+00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90
+00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00
+
INIT/???
-DEBUG: readback: 01 02 03 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f 00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+DEBUG: readback:
+
+01 02 03 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f
+00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90
+00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00
+
??? 6x8c
-DEBUG: readback: 01 02 01 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f 00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90 00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+DEBUG: readback:
+
+01 02 01 00 00 00 00 00 00 01 5f 6f 00 01 5f 6f
+00 00 00 09 00 02 90 44 00 00 00 55 00 03 02 90
+00 01 02 1d 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00
+
+Seen on the 6850 with no media loaded:
+
+01 02 02 00 00 00 10 00 00 00 5d 1d 00 00 5d 1d
+00 00 00 00 00 00 b7 cc 00 00 00 00 00 03 02 8c
+00 01 02 1c 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00
+
+Seen on 6850 with 6R media (6x8) while offline:
+01 02 03 00 00 00 03 00 00 00 5d 1f 00 00 5d 1f
+00 00 00 01 00 00 b7 d3 00 00 00 5c 00 03 02 8c
+00 01 02 1c 00 00 00 00 00 01 00 01 00 00 00 00
+00 00 00
*/
diff --git a/src/cups/mitsu70x_print.c b/src/cups/mitsu70x_print.c
index 72f5f2e..2b9e56d 100644
--- a/src/cups/mitsu70x_print.c
+++ b/src/cups/mitsu70x_print.c
@@ -1,7 +1,7 @@
/*
* Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -40,6 +40,9 @@
#define USB_VID_MITSU 0x06D3
#define USB_PID_MITSU_D70X 0x3B30
#define USB_PID_MITSU_K60 0x3B31
+//#define USB_PID_MITSU_D80 XXXXXX
+#define USB_VID_KODAK 0x040a
+#define USB_PID_KODAK305 0x404f
/* Private data stucture */
struct mitsu70x_ctx {
@@ -49,6 +52,11 @@ struct mitsu70x_ctx {
uint8_t *databuf;
int datalen;
+
+ uint16_t rows;
+ uint16_t cols;
+
+ int k60;
};
/* Program states */
@@ -60,13 +68,72 @@ enum {
S_FINISHED,
};
+/* Printer data structures */
+struct mitsu70x_state {
+ uint32_t hdr;
+ uint8_t data[22];
+} __attribute__((packed));
+
+struct mitsu70x_status_deck {
+ uint16_t present; /* 0x80 for NOT present, 0x00 otherwise */
+ uint16_t unk[9];
+ uint16_t capacity; /* media capacity */
+ uint16_t remain; /* media remaining */
+ uint16_t unkb[2];
+ uint16_t prints; /* lifetime prints on deck? */
+ uint16_t unkc[1];
+ uint16_t blank[16]; /* All fields are 0x8000 */
+} __attribute__((packed));
+
+struct mitsu70x_status_ver {
+ char ver[6];
+ uint8_t unk[2]; /* checksum? */
+} __attribute__((packed));
+
+struct mitsu70x_status_resp {
+ uint8_t hdr[4];
+ uint8_t unk[36];
+ int16_t model[6]; /* LE, UTF-16 */
+ int16_t serno[6]; /* LE, UTF-16 */
+ struct mitsu70x_status_ver vers[7];
+ uint8_t null[8];
+ struct mitsu70x_status_deck lower;
+ struct mitsu70x_status_deck upper;
+} __attribute__((packed));
+
+struct mitsu70x_hdr {
+ uint32_t cmd;
+ uint8_t zero0[12];
+
+ uint16_t cols;
+ uint16_t rows;
+ uint16_t lamcols;
+ uint16_t lamrows;
+ uint8_t superfine;
+ uint8_t zero1[7];
+
+ uint8_t deck;
+ uint8_t zero2[7];
+ uint8_t zero3;
+ uint8_t laminate;
+ uint8_t zero4[6];
+
+ uint8_t multicut;
+ uint8_t zero5[15];
+
+ uint8_t zero6[448];
+} __attribute__((packed));
+
+#define CMDBUF_LEN 512
#define READBACK_LEN 256
static void *mitsu70x_init(void)
{
struct mitsu70x_ctx *ctx = malloc(sizeof(struct mitsu70x_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
return NULL;
+ }
memset(ctx, 0, sizeof(struct mitsu70x_ctx));
return ctx;
@@ -76,12 +143,24 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct mitsu70x_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
UNUSED(jobid);
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ if (desc.idProduct == USB_PID_MITSU_K60)
+ ctx->k60 = 1;
+
+ if (desc.idProduct == USB_PID_KODAK305)
+ ctx->k60 = 1;
+
}
@@ -96,34 +175,14 @@ static void mitsu70x_teardown(void *vctx) {
free(ctx);
}
-/* Max job size is 6x9+lamination, equalling ~38MB */
-#define MAX_PRINTJOB_LEN (1024*1024*40)
-
-struct mitsu70x_hdr {
- uint32_t cmd;
- uint8_t zero0[12];
- uint16_t cols;
- uint16_t rows;
- uint16_t lamcols;
- uint16_t lamrows;
- uint8_t superfine;
- uint8_t zero1[7];
- uint8_t deck;
- uint8_t zero2[7];
- uint8_t zero3;
- uint8_t laminate;
- uint8_t zero4[6];
- uint8_t zero5[512-48];
-};
-
static int mitsu70x_read_parse(void *vctx, int data_fd) {
struct mitsu70x_ctx *ctx = vctx;
uint8_t hdr[1024];
int i, remain;
- struct mitsu70x_hdr *mhdr = (struct mitsu70x_hdr*)(hdr + 512);
+ struct mitsu70x_hdr *mhdr = (struct mitsu70x_hdr*)(hdr + sizeof(struct mitsu70x_hdr));
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->databuf) {
free(ctx->databuf);
@@ -135,9 +194,9 @@ static int mitsu70x_read_parse(void *vctx, int data_fd) {
while (remain > 0) {
i = read(data_fd, hdr + sizeof(hdr) - remain, remain);
if (i == 0)
- return 1;
+ return CUPS_BACKEND_CANCEL;
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
remain -= i;
}
@@ -147,16 +206,19 @@ static int mitsu70x_read_parse(void *vctx, int data_fd) {
hdr[2] != 0x57 ||
hdr[3] != 0x55) {
ERROR("Unrecognized data format!\n");
- return(1);
+ return CUPS_BACKEND_CANCEL;
}
/* Work out printjob size */
- remain = be16_to_cpu(mhdr->rows) * be16_to_cpu(mhdr->cols) * 2;
+ ctx->cols = be16_to_cpu(mhdr->cols);
+ ctx->rows = be16_to_cpu(mhdr->rows);
+
+ remain = ctx->rows * ctx->cols * 2;
remain = (remain + 511) / 512 * 512; /* Round to nearest 512 bytes. */
remain *= 3; /* One for each plane */
if (mhdr->laminate) {
- i = be16_to_cpu(mhdr->lamrows) * be16_to_cpu(mhdr->lamcols) * 2;
+ i = be16_to_cpu(mhdr->lamcols) * be16_to_cpu(mhdr->lamrows) * 2;
i = (i + 511) / 512 * 512; /* Round to nearest 512 bytes. */
remain += i;
}
@@ -164,7 +226,7 @@ static int mitsu70x_read_parse(void *vctx, int data_fd) {
ctx->databuf = malloc(sizeof(hdr) + remain);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 2;
+ return CUPS_BACKEND_FAILED;
}
memcpy(ctx->databuf, &hdr, sizeof(hdr));
@@ -174,43 +236,69 @@ static int mitsu70x_read_parse(void *vctx, int data_fd) {
while(remain) {
i = read(data_fd, ctx->databuf + ctx->datalen, remain);
if (i == 0)
- return 1;
+ return CUPS_BACKEND_CANCEL;
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
ctx->datalen += i;
remain -= i;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
-#define CMDBUF_LEN 512
-#define READBACK_LEN 256
-
-static int mitsu70x_main_loop(void *vctx, int copies) {
- struct mitsu70x_ctx *ctx = vctx;
-
- uint8_t rdbuf[READBACK_LEN];
- uint8_t rdbuf2[READBACK_LEN];
+static int mitsu70x_do_pagesetup(struct mitsu70x_ctx *ctx)
+{
uint8_t cmdbuf[CMDBUF_LEN];
+ uint8_t rdbuf[READBACK_LEN];
- int last_state = -1, state = S_IDLE;
+ uint16_t tmp;
+
int num, ret;
- int pending = 0;
- if (!ctx)
- return 1;
-
-top:
- if (state != last_state) {
- if (dyesub_debug)
- DEBUG("last_state %d new %d\n", last_state, state);
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x56;
+ cmdbuf[2] = 0x33;
+ cmdbuf[3] = 0x00;
+ tmp = cpu_to_be16(ctx->cols);
+ memcpy(cmdbuf + 4, &tmp, 2);
+ tmp = cpu_to_be16(ctx->rows);
+ memcpy(cmdbuf + 6, &tmp, 2);
+ cmdbuf[8] = 0x00; // or 0x80??
+ cmdbuf[9] = 0x00;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, 10)))
+ return CUPS_BACKEND_FAILED;
+
+ /* Read in the printer status */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (num != 6) {
+ ERROR("Short Read! (%d/%d)\n", num, 26);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ /* Make sure response is sane */
+ if (rdbuf[0] != 0xe4 ||
+ rdbuf[1] != 0x56 ||
+ rdbuf[2] != 0x33) {
+ ERROR("Unknown response from printer\n");
+ return CUPS_BACKEND_FAILED;
}
+
+ return 0;
+}
- if (pending)
- goto skip_query;
+static int mitsu70x_get_state(struct mitsu70x_ctx *ctx, struct mitsu70x_state *resp)
+{
+ uint8_t cmdbuf[CMDBUF_LEN];
+ int num, ret;
- /* Send Status Query */
+ /* Send Printer Query */
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x56;
@@ -222,36 +310,73 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, 6)))
return ret;
- /* Send Status Query */
+
+ memset(resp, 0, sizeof(*resp));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) resp, sizeof(*resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(*resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
+ return 4;
+ }
+
+ return 0;
+}
+
+static int mitsu70x_get_status(struct mitsu70x_ctx *ctx, struct mitsu70x_status_resp *resp)
+{
+ uint8_t cmdbuf[CMDBUF_LEN];
+ int num, ret;
+
+ /* Send Printer Query */
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x56;
- cmdbuf[2] = 0x31;
+ cmdbuf[2] = 0x32;
cmdbuf[3] = 0x30;
-
-skip_query:
- /* Read in the printer status */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, 4)))
+ return ret;
+ memset(resp, 0, sizeof(*resp));
ret = read_data(ctx->dev, ctx->endp_up,
- rdbuf, READBACK_LEN, &num);
+ (uint8_t*) resp, sizeof(*resp), &num);
+
if (ret < 0)
return ret;
-
- if (num != 26) {
- ERROR("Short Read! (%d/%d)\n", num, 26);
+ if (num != sizeof(*resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
return 4;
}
- if (dyesub_debug) {
- unsigned int i;
- DEBUG("Printer Status Dump: ");
- for (i = 0 ; i < 26 ; i++) {
- DEBUG2("%02x ", rdbuf[i]);
- }
- DEBUG2("\n");
+ return 0;
+}
+
+static int mitsu70x_main_loop(void *vctx, int copies) {
+ struct mitsu70x_ctx *ctx = vctx;
+
+ struct mitsu70x_state rdbuf, rdbuf2;
+
+ int last_state = -1, state = S_IDLE;
+ int ret;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+top:
+ if (state != last_state) {
+ if (dyesub_debug)
+ DEBUG("last_state %d new %d\n", last_state, state);
}
- if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- memcpy(rdbuf2, rdbuf, READBACK_LEN);
+ ret = mitsu70x_get_state(ctx, &rdbuf);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ if (memcmp(&rdbuf, &rdbuf2, sizeof(rdbuf))) {
+ memcpy(&rdbuf2, &rdbuf, sizeof(rdbuf));
} else if (state == last_state) {
sleep(1);
}
@@ -259,39 +384,80 @@ skip_query:
fflush(stderr);
- pending = 0;
-
switch (state) {
case S_IDLE:
INFO("Waiting for printer idle\n");
- if (rdbuf[7] != 0x00 ||
- rdbuf[8] != 0x00 ||
- rdbuf[9] != 0x00) {
+#if 0 // XXX no idea if this works..
+ if (rdbuf.data[9] != 0x00) {
break;
}
-
+#endif
INFO("Sending attention sequence\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, 512)))
- return ret;
-
+ ctx->databuf, sizeof(struct mitsu70x_hdr))))
+ return CUPS_BACKEND_FAILED;
+
state = S_SENT_ATTN;
- case S_SENT_ATTN:
- INFO("Sending header sequence\n");
+ break;
+ case S_SENT_ATTN: {
+ struct mitsu70x_status_resp resp;
+ ret = mitsu70x_get_status(ctx, &resp);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf + 512, 512)))
- return ret;
+ /* Yes, do it twice.. */
+
+ ret = mitsu70x_get_status(ctx, &resp);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ // XXX check resp for sanity?
state = S_SENT_HDR;
break;
+ }
case S_SENT_HDR:
- INFO("Sending data\n");
+ INFO("Sending Page setup sequence\n");
+ if ((ret = mitsu70x_do_pagesetup(ctx)))
+ return ret;
+
+ INFO("Sending header sequence\n");
+
+ /* K60 may require fixups */
+ if (ctx->k60) {
+ struct mitsu70x_hdr *hdr = (struct mitsu70x_hdr*) (ctx->databuf + sizeof(struct mitsu70x_hdr));
+ /* K60 only has a lower deck */
+ hdr->deck = 1;
+
+ /* 4x6 prints on 6x8 media need multicut mode */
+ if (ctx->cols == 0x0748 &&
+ ctx->rows == 0x04c2)
+ hdr->multicut = 1;
+ }
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf + 1024, ctx->datalen - 1024)))
- return ret;
-
+ ctx->databuf + sizeof(struct mitsu70x_hdr),
+ sizeof(struct mitsu70x_hdr))))
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Sending data\n");
+
+ {
+ /* K60 and 305 need data sent in 256K chunks, but the first
+ chunk needs to subtract the length of the 512-byte header */
+ int chunk = 256*1024 - sizeof(struct mitsu70x_hdr);
+ int sent = 1024;
+ while (ctx->datalen > 0) {
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ctx->databuf + sent, chunk)))
+ return CUPS_BACKEND_FAILED;
+ sent += chunk;
+ chunk = ctx->datalen - sent;
+ if (chunk > 256*1024)
+ chunk = 256*1024;
+ }
+ }
+
state = S_SENT_DATA;
break;
case S_SENT_DATA:
@@ -317,80 +483,84 @@ skip_query:
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
-struct mitsu70x_status_deck {
- uint8_t unk[64];
- // unk[0] 0x80 for NOT PRESENT, 0x00 for present.
- // unk[7-8] 0x01ff or 0x0200? Changes; maybe status?
- // unk[22-23] prints remaining, 16-bit BE
+static void mitsu70x_dump_status(struct mitsu70x_status_resp *resp)
+{
+ unsigned int i;
+
+ INFO("Model : ");
+ for (i = 0 ; i < 6 ; i++) {
+ DEBUG2("%c", le16_to_cpu(resp->model[i]) & 0x7f);
+ }
+ DEBUG2("\n");
+ INFO("Serial Number : ");
+ for (i = 0 ; i < 6 ; i++) {
+ DEBUG2("%c", le16_to_cpu(resp->serno[i]) & 0x7f);
+ }
+ DEBUG2("\n");
+ for (i = 0 ; i < 7 ; i++) {
+ char buf[7];
+ if (resp->vers[i].ver[5] == '@') /* "DUMMY@" */
+ continue;
+ memcpy(buf, resp->vers[i].ver, 6);
+ buf[6] = 0;
+ INFO("Component #%d ID: %s (%02x%02x)\n",
+ i, buf, resp->vers[i].unk[0], resp->vers[i].unk[1]);
+ }
+ if (resp->upper.present) { /* IOW, Not present */
+ INFO("Prints remaining: %03d/%03d\n",
+ be16_to_cpu(resp->lower.remain),
+ be16_to_cpu(resp->lower.capacity));
+ } else {
+ INFO("Prints remaining: Lower: %03d/%03d\n"
+ " Upper: %03d/%03d\n",
+ be16_to_cpu(resp->lower.remain),
+ be16_to_cpu(resp->lower.capacity),
+ be16_to_cpu(resp->upper.remain),
+ be16_to_cpu(resp->upper.capacity));
+ }
+}
-};
+static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
+{
+ struct mitsu70x_status_resp resp;
+ int ret;
-struct mitsu70x_status_resp {
- uint8_t unk[128];
- struct mitsu70x_status_deck lower;
- struct mitsu70x_status_deck upper;
-};
+ ret = mitsu70x_get_status(ctx, &resp);
-static int mitsu70x_get_status(struct mitsu70x_ctx *ctx)
+ if (!ret)
+ mitsu70x_dump_status(&resp);
+
+ return ret;
+}
+
+static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
{
- uint8_t cmdbuf[CMDBUF_LEN];
+ int ret, i;
struct mitsu70x_status_resp resp;
- int num, ret;
-
- /* Send Printer Query */
- memset(cmdbuf, 0, CMDBUF_LEN);
- cmdbuf[0] = 0x1b;
- cmdbuf[1] = 0x56;
- cmdbuf[2] = 0x32;
- cmdbuf[3] = 0x30;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, 4)))
- return ret;
- memset(&resp, 0, sizeof(resp));
- ret = read_data(ctx->dev, ctx->endp_up,
- (uint8_t*) &resp, sizeof(resp), &num);
- if (ret < 0)
- return ret;
- if (num != sizeof(resp)) {
- ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(resp));
- return 4;
- }
+ struct mitsu70x_ctx ctx = {
+ .dev = dev,
+ .endp_up = endp_up,
+ .endp_down = endp_down,
+ };
- if (dyesub_debug) {
- unsigned int i;
+ ret = mitsu70x_get_status(&ctx, &resp);
- DEBUG("Status Dump:\n");
- for (i = 0 ; i < sizeof(resp.unk) ; i++) {
- DEBUG2("%02x ", resp.unk[i]);
- }
- DEBUG2("\n");
- DEBUG("Lower Deck:\n");
- for (i = 0 ; i < sizeof(resp.lower.unk) ; i++) {
- DEBUG2("%02x ", resp.lower.unk[i]);
- }
- DEBUG2("\n");
- DEBUG("Upper Deck:\n");
- for (i = 0 ; i < sizeof(resp.upper.unk) ; i++) {
- DEBUG2("%02x ", resp.upper.unk[i]);
- }
- DEBUG2("\n");
- }
- if (resp.upper.unk[0] & 0x80) { /* Not present */
- INFO("Prints remaining: %d\n",
- (resp.lower.unk[22] << 8) | resp.lower.unk[23]);
- } else {
- INFO("Prints remaining: Lower: %d Upper: %d\n",
- (resp.lower.unk[22] << 8) | resp.lower.unk[23],
- (resp.upper.unk[22] << 8) | resp.upper.unk[23]);
+ if (buf_len > 6) /* Will we ever have a buffer under 6 bytes? */
+ buf_len = 6;
+
+ for (i = 0 ; i < buf_len ; i++) {
+ *buf++ = le16_to_cpu(resp.serno[i]) & 0x7f;
}
-
- return 0;
+ *buf = 0; /* Null-terminate the returned string */
+
+ return ret;
}
+
static void mitsu70x_cmdline(void)
{
DEBUG("\t\t[ -s ] # Query status\n");
@@ -408,7 +578,7 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
switch(i) {
case 's':
if (ctx) {
- j = mitsu70x_get_status(ctx);
+ j = mitsu70x_query_status(ctx);
break;
}
return 1;
@@ -426,7 +596,7 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend mitsu70x_backend = {
.name = "Mitsubishi CP-D70/D707/K60",
- .version = "0.16",
+ .version = "0.31",
.uri_prefix = "mitsu70x",
.cmdline_usage = mitsu70x_cmdline,
.cmdline_arg = mitsu70x_cmdline_arg,
@@ -435,14 +605,17 @@ struct dyesub_backend mitsu70x_backend = {
.teardown = mitsu70x_teardown,
.read_parse = mitsu70x_read_parse,
.main_loop = mitsu70x_main_loop,
+ .query_serno = mitsu70x_query_serno,
.devices = {
{ USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, ""},
{ USB_VID_MITSU, USB_PID_MITSU_K60, P_MITSU_D70X, ""},
+// { USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D70X, ""},
+ { USB_VID_KODAK, USB_PID_KODAK305, P_MITSU_D70X, ""},
{ 0, 0, 0, ""}
}
};
-/* Mitsubish CP-D70x/CP-K60 data format
+/* Mitsubish CP-D70DW/CP-D707DW/CP-K60DW-S/CP-D80DW/Kodak 305 data format
Spool file consists of two headers followed by three image planes
and an optional lamination data plane. All blocks are rounded up to
@@ -455,60 +628,40 @@ struct dyesub_backend mitsu70x_backend = {
1b 45 57 55 00 00 00 00 00 00 00 00 00 00 00 00
(padded by NULLs to a 512-byte boundary)
- [[ D70x ]] Header 2: (Header)
+ Header 2: (Header)
- 1b 5a 54 01 00 00 00 00 00 00 00 00 00 00 00 00
+ 1b 5a 54 PP 00 00 00 00 00 00 00 00 00 00 00 00
XX XX YY YY QQ QQ ZZ ZZ SS 00 00 00 00 00 00 00
UU 00 00 00 00 00 00 00 00 TT 00 00 00 00 00 00
RR 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
(padded by NULLs to a 512-byte boundary)
+ PP == 0x01 on D70x/D80, 0x02 on K60/305
XX XX == columns
YY YY == rows
QQ QQ == lamination columns (equal to XX XX)
ZZ ZZ == lamination rows (YY YY + 12)
- SS == Print mode: 00 = Fine, 03 = SuperFine, 04 = UltraFine
+ SS == Print mode: 00 = Fine, 03 = SuperFine (D70x/D80 only), 04 = UltraFine
(Matte requires Superfine or Ultrafine)
- UU == 00 == Auto, 01 == Lower Deck, 02 == Upper Deck
- TT == 00 with no lamination, 02 with.
- RR == 00 (normal), 01 == (Double-cut 4x6), 05 == (double-cut 2x6)
+ UU == 00 = Auto, 01 = Lower Deck (required for K60/305), 02 = Upper Deck
+ TT == lamination: 00 glossy, 02 matte.
+ RR == 00 (normal), 01 = (Double-cut 4x6), 05 = (double-cut 2x6)
- [[ K60 ]] Header 2: (Header)
-
- 1b 5a 54 00 00 00 00 00 00 00 00 00 00 00 00 00
- XX XX YY YY QQ QQ ZZ ZZ SS 00 00 00 00 00 00 00
- UU 00 00 00 00 00 00 00 00 TT 00 00 00 00 00 00
- RR 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-
- (padded by NULLs to a 512-byte boundary)
-
- XX XX == columns
- YY YY == rows
- QQ QQ == lamination columns (equal to XX XX)
- ZZ ZZ == lamination rows (usually YY YY + 12)
- SS == Print mode: 00 = Fine, 04 = UltraFine
- (Matte requires Ultrafine)
- UU == 01 (Lower Deck)
- TT == 00 with no lamination, 02 with.
- RR == 00 (normal), 01 == (Double-cut 4x6), 05 == (double-cut 2x6)
-
Data planes:
16-bit data, rounded up to 512-byte block (XX * YY * 2 bytes)
- Lamination plane: (only present if QQ + ZZ are nonzero)
+ Lamination plane: (only present if QQ and ZZ are nonzero)
16-byte data, rounded up to 512-byte block (QQ * ZZ * 2 bytes)
- Lamination appears to be these bytes, repeated: 28 6a ab 58 6c 22
-
********************************************************************
- Command format: (D707)
+ Command format:
-> 1b 56 32 30
<- [256 byte payload]
- CP-D707DW:
+ PRINTER STATUS
e4 56 32 30 00 00 00 00 00 00 00 00 00 00 00 00 .V20............
00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 ................
@@ -519,39 +672,28 @@ struct dyesub_backend mitsu70x_backend = {
33 31 37 41 32 32 a3 82 44 55 4d 4d 59 40 00 00 317A22..DUMMY@..
44 55 4d 4d 59 40 00 00 00 00 00 00 00 00 00 00 DUMMY@..........
- LOWER DECK
+ LOWER DECK STATUS
- 00 00 00 00 00 00 02 04 3f 00 00 04 96 00 00 00
- ff 0f 01 00 00 c8 NN NN 00 00 00 00 05 28 75 80 NN NN: prints remaining
+ 00 00 00 00 00 00 02 04 3f 00 00 04 96 00 00 00 MM MM: media capacity
+ ff 0f 01 00 MM MM NN NN 00 00 00 00 05 28 75 80 NN NN: prints remaining
80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- UPPER DECK
+ alt (some sort of error state)
- 00 00 00 00 00 00 01 ee 3d 00 00 06 39 00 00 00
- ff 02 00 00 01 90 NN NN 00 00 00 00 06 67 78 00 NN NN: prints remaining
+ 00 00 00 0a 05 05 01 d5 38 00 00 00 14 00 00 00
+ ff ff ff ff ff ff ff ff ff ff 00 00 00 27 72 80
80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- CP-K60DW-S:
-
- e4 56 32 30 0f 00 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00 0a 80 00 00 00 00
- 02 00 00 00 5e 00 04 87 43 00 50 00 4b 00 36 00
- 30 00 44 00 30 00 32 00 33 00 32 00 30 00 36 00
- 33 31 36 4b 33 31 d6 7a 33 31 35 41 33 31 ae 37
- 33 31 39 41 37 31 6a 36 33 31 38 44 33 31 1e 4a
- 33 31 37 42 32 31 f4 19 44 55 4d 4d 59 40 00 00
- 44 55 4d 4d 59 40 00 00 00 00 00 00 00 00 00 00
-
- LOWER DECK (K60)
+ UPPER DECK STATUS (if present)
- 00 00 00 00 00 00 02 09 3f 00 00 00 05 00 00 01
- 61 8f 00 00 01 40 NN NN 00 00 00 00 00 16 81 80 NN NN: prints remaining
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
+ XX XX 00 00 00 00 01 ee 3d 00 00 06 39 00 00 00 MM MM: media capacity
+ ff 02 00 00 MM MM NN NN 00 00 00 00 06 67 78 00 NN NN: prints remaining
+ 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 XX XX: 0x80 00 if no deck
80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- UPPER DECK (K60 -- No upper deck present)
+ alt (no deck present)
80 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00
ff ff ff ff ff ff ff ff ff ff 00 00 00 00 80 00
@@ -563,20 +705,64 @@ struct dyesub_backend mitsu70x_backend = {
CP-D707DW:
- e4 56 31 30 00 00 00 XX YY ZZ 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00
+ e4 56 31 30 00 00 00 XX YY ZZ 00 00 TT 00 00 00
+ 00 00 00 00 WW 00 00 00 00 00
- XX/YY/ZZ are unkown. Observed values:
+ XX/YY/ZZ and WW/TT are unknown. Observed values:
- 00 00 00
- 40 80 a0
+ 00 00 00 00/00
+ 40 80 a0 80/0f
80 80 a0
+ 40 80 90
+ 40 80 00
- CP-K60DW-S: (only one readback observed so far)
+ also seen:
e4 56 31 30 00 00 00 00 00 00 00 00 0f 00 00 00
+ 00 0a 05 05 80 00 00 00 00 00
+
+ e4 56 31 30 00 00 00 40 80 90 10 00 0f 00 00 00
+ 00 0a 05 05 80 00 00 00 00 00
+
+ e4 56 31 30 00 00 00 00 40 80 00 00 00 ff 40 00
+ 00 00 00 00 80 00 00 00 00 00
+
+ print just submitted:
+
+ e4 56 31 30 00 00 00 00 40 20 00 00 00 8c 00 00
+ 00 00 00 00 80 00 00 00 00 00
+
+ prints running...
+
+ e4 56 31 30 00 00 00 00 40 20 00 00 00 cf 00 20
+ 00 00 00 00 80 00 00 00 00 00
+
+
+
+ CP-K60DW-S:
+
+ e4 56 31 30 00 00 00 XX YY 00 00 00 0f 00 00 00
00 00 00 00 80 00 00 00 00 00
+ XX/YY are unknown, observed values:
+
+ 40/80
+ 00/00
+
+ Sent to start a print
+
+ -> 1b 56 33 00 XX XX YY YY UU 00
+
+ XX XX == columns
+ YY YY == rows
+ UU == Unknown, seen 0x00 and 0x80
+
+ <- [ 6 byte payload ]
+
+ e4 56 33 00 00 00
+ e4 56 33 00 00 01
+ e5 56 33 ff 01 01 (which appeared to work)
+
** ** ** ** ** **
The windows drivers seem to send the id and status queries before
@@ -584,4 +770,34 @@ struct dyesub_backend mitsu70x_backend = {
appear to be any particular intelligence in the protocol, but it didn't
work when the raw dump was submitted as-is.
+ ** ** ** ** ** **
+
+Various deck status dumps:
+
+0080 00 00 00 00 00 00 01 d2 39 00 00 00 07 00 00 00 ........9.......
+0090 61 8f 00 00 01 40 01 36 00 00 00 00 00 17 79 80 a....@.6......y.
+
+0080 00 00 00 00 00 00 01 c6 39 00 00 00 08 00 00 00 ........9.......
+0090 61 8f 00 00 01 40 01 35 00 00 00 00 00 18 79 80 a....@.5......y.
+
+0080 00 00 00 00 00 00 02 19 50 00 00 00 19 00 00 01 ........P.......
+0090 6c 8f 00 00 01 40 01 22 00 00 00 00 00 27 83 80 l....@.".....'..
+
+0080 00 00 00 00 00 00 02 00 3e 00 00 04 96 00 00 00 ........>.......
+0090 ff 0f 01 00 00 c8 00 52 00 00 00 00 05 28 75 80 .......R.....(u.
+
+00c0 00 00 00 00 00 00 01 f3 3d 00 00 06 39 00 00 00 ........=...9...
+00d0 ff 02 00 00 01 90 00 c3 00 00 00 00 06 67 78 00 .............gx.
+
+0080 00 00 00 00 00 00 01 d0 38 00 00 03 70 00 00 00 ........8...p...
+0090 ff 02 00 00 01 90 00 1e 01 00 00 00 03 83 72 80 ..............r.
+
+0080 00 00 00 00 00 00 01 d6 39 00 00 00 20 00 00 00 ........9... ...
+0090 ff 02 00 00 01 90 01 7c 01 00 00 00 00 33 72 80 .......|.....3r.
+
+ 00 00 00 0a 05 05 01 d5 38 00 00 00 14 00 00 00
+ ff ff ff ff ff ff ff ff ff ff 00 00 00 27 72 80 ?? Error ??
+
+ 80 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00
+ ff ff ff ff ff ff ff ff ff ff 00 00 00 00 80 00 NO DECK PRESENT
*/
diff --git a/src/cups/mitsu9550_print.c b/src/cups/mitsu9550_print.c
new file mode 100644
index 0000000..7b83e6c
--- /dev/null
+++ b/src/cups/mitsu9550_print.c
@@ -0,0 +1,1013 @@
+/*
+ * Mitsubishi CP-9550DW[-S] Photo Printer CUPS backend
+ *
+ * (c) 2014-2015 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * The latest version of this program can be found at:
+ *
+ * http://git.shaftnet.org/cgit/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 2 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-2.0.html]
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "backend_common.h"
+
+#define USB_VID_MITSU 0x06D3
+#define USB_PID_MITSU_9550D 0x03A1
+#define USB_PID_MITSU_9550DS 0x03A5 // or DZ/DZS/DZU
+
+/* Private data stucture */
+struct mitsu9550_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ uint8_t *databuf;
+ int datalen;
+
+ int is_s_variant;
+
+ int fast_return;
+
+ uint16_t rows;
+ uint16_t cols;
+};
+
+/* Spool file structures */
+struct mitsu9550_hdr1 {
+ uint8_t cmd[4]; /* 1b 57 20 2e */
+ uint8_t unk[10];
+ uint16_t cols; /* BE */
+ uint16_t rows; /* BE */
+ uint8_t null[32];
+} __attribute__((packed));
+
+struct mitsu9550_hdr2 {
+ uint8_t cmd[4]; /* 1b 57 21 2e */
+ uint8_t unk[24];
+ uint16_t copies; /* BE, 1-580 */
+ uint8_t null[2];
+ uint8_t cut; /* 00 == normal, 83 == 2x6*2 */
+ uint8_t unkb[5];
+ uint8_t mode; /* 00 == normal, 80 == fine */
+ uint8_t unkc[11];
+} __attribute__((packed));
+
+struct mitsu9550_hdr3 {
+ uint8_t cmd[4]; /* 1b 57 22 2e */
+ uint8_t unk[7];
+ uint8_t mode2; /* 00 == normal, 01 == finedeep */
+ uint8_t unkb[38];
+} __attribute__((packed));
+
+struct mitsu9550_hdr4 {
+ uint8_t cmd[4]; /* 1b 57 26 2e */
+ uint8_t unk[46];
+} __attribute__((packed));
+
+struct mitsu9550_plane {
+ uint8_t cmd[4]; /* 1b 5a 54 00 */
+ uint8_t null[2];
+ uint16_t rem_rows; /* BE, normally 0 */
+ uint16_t columns; /* BE */
+ uint16_t rows; /* BE */
+} __attribute__((packed));
+
+struct mitsu9550_cmd {
+ uint8_t cmd[4];
+} __attribute__((packed));
+
+/* Printer data structures */
+struct mitsu9550_media {
+ uint8_t hdr[2]; /* 24 2e */
+ uint8_t unk[12];
+ uint8_t type;
+ uint8_t unka[13];
+ uint16_t max; /* BE, prints per media */
+ uint8_t unkb[2];
+ uint16_t remain; /* BE, prints remaining */
+ uint8_t unkc[14];
+} __attribute__((packed));
+
+struct mitsu9550_status {
+ uint8_t hdr[2]; /* 30 2e */
+ uint8_t null[4];
+ uint8_t sts1; // MM
+ uint8_t nullb[1];
+ uint16_t copies; // NN
+ uint8_t nullc[6];
+ uint8_t sts3; // QQ
+ uint8_t sts4; // RR
+ uint8_t sts5; // SS
+ uint8_t nulld[25];
+ uint8_t sts6; // TT
+ uint8_t sts7; // UU
+ uint8_t nulle[2];
+} __attribute__((packed));
+
+struct mitsu9550_status2 {
+ uint8_t hdr[2]; /* 21 2e */
+ uint8_t unk[40];
+ uint8_t remain; /* BE, media remaining */
+ uint8_t unkb[4];
+} __attribute__((packed));
+
+#define CMDBUF_LEN 64
+#define READBACK_LEN 128
+
+static void *mitsu9550_init(void)
+{
+ struct mitsu9550_ctx *ctx = malloc(sizeof(struct mitsu9550_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct mitsu9550_ctx));
+
+ /* Use Fast return by default in CUPS mode */
+ if (getenv("DEVICE_URI") || getenv("FAST_RETURN"))
+ ctx->fast_return = 1;
+
+ return ctx;
+}
+
+static void mitsu9550_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct mitsu9550_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ if (desc.idProduct == USB_PID_MITSU_9550DS)
+ ctx->is_s_variant = 1;
+}
+
+
+static void mitsu9550_teardown(void *vctx) {
+ struct mitsu9550_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+ free(ctx);
+}
+
+static int mitsu9550_read_parse(void *vctx, int data_fd) {
+ struct mitsu9550_ctx *ctx = vctx;
+ struct mitsu9550_hdr1 hdr;
+
+ int remain, i;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->databuf) {
+ free(ctx->databuf);
+ ctx->databuf = NULL;
+ }
+
+ /* Read in initial header */
+ remain = sizeof(hdr);
+ while (remain > 0) {
+ i = read(data_fd, ((uint8_t*)&hdr) + sizeof(hdr) - remain, remain);
+ if (i == 0)
+ return CUPS_BACKEND_CANCEL;
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ remain -= i;
+ }
+
+ /* Sanity check */
+ if (hdr.cmd[0] != 0x1b ||
+ hdr.cmd[1] != 0x57 ||
+ hdr.cmd[2] != 0x20 ||
+ hdr.cmd[3] != 0x2e) {
+ ERROR("Unrecognized data format!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Work out printjob size */
+ ctx->rows = be16_to_cpu(hdr.rows);
+ ctx->cols = be16_to_cpu(hdr.cols);
+
+ remain = ctx->rows * ctx->cols + sizeof(struct mitsu9550_plane);
+ remain *= 3;
+ remain += sizeof(struct mitsu9550_hdr2) + sizeof(struct mitsu9550_hdr3)+ sizeof(struct mitsu9550_hdr4) + sizeof(struct mitsu9550_cmd);
+
+ /* Allocate buffer */
+ ctx->databuf = malloc(remain + sizeof(struct mitsu9550_hdr1));
+ if (!ctx->databuf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ memcpy(ctx->databuf, &hdr, sizeof(struct mitsu9550_hdr1));
+ ctx->datalen = sizeof(struct mitsu9550_hdr1);
+
+ /* Read in the spool data */
+ while(remain) {
+ i = read(data_fd, ctx->databuf + ctx->datalen, remain);
+ if (i == 0)
+ return CUPS_BACKEND_CANCEL;
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ ctx->datalen += i;
+ remain -= i;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int status, int status2, int media)
+{
+ struct mitsu9550_cmd cmd;
+ int num, ret;
+
+ /* Send Printer Query */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x56;
+ if (status)
+ cmd.cmd[2] = 0x30;
+ else if (status2)
+ cmd.cmd[2] = 0x21;
+ else if (media)
+ cmd.cmd[2] = 0x24;
+ cmd.cmd[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return ret;
+ ret = read_data(ctx->dev, ctx->endp_up,
+ resp, sizeof(struct mitsu9550_status), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(struct mitsu9550_status)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(struct mitsu9550_status));
+ return 4;
+ }
+
+ return 0;
+}
+
+static int validate_media(int type, int cols, int rows) {
+ switch(type) {
+ case 0x01: /* 3.5x5 */
+ if (cols != 1812 || rows != 1240)
+ return 1;
+ break;
+ case 0x02: /* 4x6 */
+ case 0x03: /* PC ??? */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 || rows != 1184 ||
+ rows != 1240)
+ return 1;
+ break;
+ case 0x04: /* 5x7 */
+ if (cols != 1812)
+ return 1;
+ if (rows != 1240 || rows != 2452)
+ return 1;
+ break;
+ case 0x05: /* 6x9 */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 || rows != 2972 ||
+ rows != 2956 || rows != 3146)
+ return 1;
+ break;
+ case 0x06: /* V */
+ break;
+ default: /* Unknown */
+ break;
+ }
+ return 0;
+}
+
+static int mitsu9550_main_loop(void *vctx, int copies) {
+ struct mitsu9550_ctx *ctx = vctx;
+ struct mitsu9550_hdr2 *hdr2;
+ struct mitsu9550_cmd cmd;
+ uint8_t rdbuf[READBACK_LEN];
+
+ uint8_t *ptr;
+
+ int ret;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ /* This printer handles copies internally */
+ hdr2 = (struct mitsu9550_hdr2 *) (ctx->databuf + sizeof(struct mitsu9550_hdr1));
+ hdr2->copies = cpu_to_be16(copies);
+
+ ptr = ctx->databuf;
+
+top:
+ if (ctx->is_s_variant) {
+ int num;
+
+ /* Send "unknown 1" command */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x53;
+ cmd.cmd[2] = 0xc5;
+ cmd.cmd[3] = 0x9d;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+
+ /* Send "unknown 2" command */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x4b;
+ cmd.cmd[2] = 0x7f;
+ cmd.cmd[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+ // seen so far: eb 4b 7f 00 02 00 5e
+ }
+
+ /* Query statuses */
+ {
+ struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
+ //struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
+ struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Sanity-check media response */
+ if (media->remain == 0 || media->max == 0) {
+ ERROR("Printer out of media!\n");
+ return CUPS_BACKEND_HOLD;
+ }
+ if (validate_media(media->type, ctx->cols, ctx->rows)) {
+ ERROR("Incorrect media (%d) type for printjob (%dx%d)!\n", media->type, ctx->cols, ctx->rows);
+ return CUPS_BACKEND_HOLD;
+ }
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Make sure we're idle */
+ if (sts->sts5 != 0) { /* Printer ready for another job */
+ sleep(1);
+ goto top;
+ }
+ }
+
+ /* Now it's time for the actual print job! */
+
+ if (ctx->is_s_variant) {
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x44;
+ cmd.cmd[2] = 0;
+ cmd.cmd[3] = 0;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, 4)))
+ return CUPS_BACKEND_FAILED;
+ }
+
+ /* Query statuses */
+ {
+ struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
+// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
+ struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Sanity-check media response */
+ if (media->remain == 0 || media->max == 0) {
+ ERROR("Printer out of media!\n");
+ return CUPS_BACKEND_HOLD;
+ }
+ if (validate_media(media->type, ctx->cols, ctx->rows)) {
+ ERROR("Incorrect media (%d) type for printjob (%dx%d)!\n", media->type, ctx->cols, ctx->rows);
+ return CUPS_BACKEND_HOLD;
+ }
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Make sure we're idle */
+ if (sts->sts5 != 0) { /* Printer ready for another job */
+ sleep(1);
+ goto top;
+ }
+ }
+
+ /* Send printjob headers from spool data */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_hdr1))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_hdr1);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_hdr2))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_hdr2);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_hdr3))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_hdr3);
+ if (!ctx->is_s_variant) {
+ // XXX need to investigate what hdr4 is about
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_hdr4))))
+ return CUPS_BACKEND_FAILED;
+ }
+ ptr += sizeof(struct mitsu9550_hdr4);
+
+ if (ctx->is_s_variant) {
+ /* Send "start data" command */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x5a;
+ cmd.cmd[2] = 0x43;
+ cmd.cmd[3] = 0x00;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+ }
+ /* Send plane data */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_plane);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, ctx->rows * ctx->cols)))
+ return CUPS_BACKEND_FAILED;
+ ptr += ctx->rows * ctx->cols;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_plane);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, ctx->rows * ctx->cols)))
+ return CUPS_BACKEND_FAILED;
+ ptr += ctx->rows * ctx->cols;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_plane);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, ctx->rows * ctx->cols)))
+ return CUPS_BACKEND_FAILED;
+ ptr += ctx->rows * ctx->cols;
+
+
+ /* Query statuses */
+ {
+ struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
+// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
+ struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Sanity-check media response */
+ if (media->remain == 0 || media->max == 0) {
+ ERROR("Printer out of media!\n");
+ return CUPS_BACKEND_HOLD;
+ }
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Make sure we're ready to proceed */
+ if (sts->sts5 != 0) {
+ ERROR("Unexpected response (sts5 %02x)\n", sts->sts5);
+ return CUPS_BACKEND_FAILED;
+ }
+ if (!(sts->sts3 & 0xc0)) {
+ ERROR("Unexpected response (sts3 %02x)\n", sts->sts3);
+ return CUPS_BACKEND_FAILED;
+ }
+ }
+
+ if (ctx->is_s_variant) {
+ /* Send "end data" command */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x50;
+ cmd.cmd[2] = 0x47;
+ cmd.cmd[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+ } else {
+ /* Send "end data" command from spool file */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ptr, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(cmd);
+ }
+
+ /* Status loop, run until printer reports completion */
+ while(1) {
+ struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
+// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
+ struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* Sanity-check media response */
+ if (media->remain == 0 || media->max == 0) {
+ ERROR("Printer out of media!\n");
+ return CUPS_BACKEND_HOLD;
+ }
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ INFO("%03d copies remaining\n", be16_to_cpu(sts->copies));
+
+ if (!sts->sts1) /* If printer transitions to idle */
+ break;
+
+ if (ctx->fast_return && !be16_to_cpu(sts->copies)) { /* No remaining prints */
+ INFO("Fast return mode enabled.\n");
+ break;
+ }
+
+ if (ctx->fast_return && !sts->sts5) { /* Ready for another job */
+ INFO("Fast return mode enabled.\n");
+ break;
+ }
+
+ sleep(1);
+ }
+
+ /* This printer handles copies internally */
+ copies = 1;
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static char *mitsu9550_media_types(uint8_t type)
+{
+ switch (type) {
+ case 0x01:
+ return "3.5x5";
+ case 0x02:
+ return "4x6";
+ case 0x03:
+ return "PC";
+ case 0x04:
+ return "5x7";
+ case 0x05:
+ return "6x9";
+ case 0x06:
+ return "V";
+ default:
+ return "Unknown";
+ }
+ return NULL;
+}
+
+static void mitsu9550_dump_media(struct mitsu9550_media *resp)
+{
+ INFO("Media type : %02x (%s)\n",
+ resp->type, mitsu9550_media_types(resp->type));
+ INFO("Media remaining : %03d/%03d\n",
+ be16_to_cpu(resp->remain), be16_to_cpu(resp->max));
+}
+
+static void mitsu9550_dump_status(struct mitsu9550_status *resp)
+{
+ INFO("Printer status : %02x (%s)\n",
+ resp->sts1, resp->sts1 ? "Printing": "Idle");
+ INFO("Pages remaining : %03d\n",
+ be16_to_cpu(resp->copies));
+ INFO("Other status : %02x %02x %02x %02x %02x\n",
+ resp->sts3, resp->sts4, resp->sts5, resp->sts6, resp->sts7);
+
+}
+
+static int mitsu9550_query_media(struct mitsu9550_ctx *ctx)
+{
+ struct mitsu9550_media resp;
+ int ret;
+
+ ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 0, 0, 1);
+
+ if (!ret)
+ mitsu9550_dump_media(&resp);
+
+ return ret;
+}
+
+static int mitsu9550_query_status(struct mitsu9550_ctx *ctx)
+{
+ struct mitsu9550_status resp;
+ int ret;
+
+ ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 1, 0, 0);
+
+ if (!ret)
+ mitsu9550_dump_status(&resp);
+
+ return ret;
+}
+
+static int mitsu9550_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
+{
+ struct mitsu9550_cmd cmd;
+ uint8_t rdbuf[READBACK_LEN];
+ uint8_t *ptr;
+ int ret, num, i;
+
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x72;
+ cmd.cmd[2] = 0x6e;
+ cmd.cmd[3] = 0x00;
+
+ if ((ret = send_data(dev, endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return (ret < 0) ? ret : CUPS_BACKEND_FAILED;
+
+ ret = read_data(dev, endp_up,
+ rdbuf, READBACK_LEN, &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if ((unsigned int)num < sizeof(cmd) + 1) /* Short read */
+ return CUPS_BACKEND_FAILED;
+
+ if (rdbuf[0] != 0xe4 ||
+ rdbuf[1] != 0x72 ||
+ rdbuf[2] != 0x6e ||
+ rdbuf[3] != 0x00) /* Bad response */
+ return CUPS_BACKEND_FAILED;
+
+ /* If response is truncated, handle it */
+ num -= (sizeof(cmd) + 1);
+ if ((unsigned int) num != rdbuf[4])
+ WARNING("Short serno read! (%d vs %d)\r\n",
+ num, rdbuf[4]);
+
+ /* model and serial number are encoded as 16-bit unicode,
+ little endian, separated by spaces. */
+ i = num;
+ ptr = rdbuf + 5;
+ while (i > 0 && buf_len > 1) {
+ if (*ptr != 0x20)
+ *buf++ = *ptr;
+ buf_len--;
+ ptr += 2;
+ i -= 2;
+ }
+ *buf = 0; /* Null-terminate the returned string */
+
+ return ret;
+}
+
+static void mitsu9550_cmdline(void)
+{
+ DEBUG("\t\t[ -m ] # Query media\n");
+ DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -f ] # Enable fast return mode\n");
+}
+
+static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct mitsu9550_ctx *ctx = vctx;
+ int i, j = 0;
+
+ /* Reset arg parsing */
+ optind = 1;
+ opterr = 0;
+ while ((i = getopt(argc, argv, "mfs")) >= 0) {
+ switch(i) {
+ case 'm':
+ if (ctx) {
+ j = mitsu9550_query_media(ctx);
+ break;
+ }
+ return 1;
+ case 's':
+ if (ctx) {
+ j = mitsu9550_query_status(ctx);
+ break;
+ }
+ return 1;
+
+ case 'f':
+ if (ctx) {
+ ctx->fast_return = 1;
+ break;
+ }
+ return 1;
+ default:
+ break; /* Ignore completely */
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+/* Exported */
+struct dyesub_backend mitsu9550_backend = {
+ .name = "Mitsubishi CP-9550DW-S",
+ .version = "0.12",
+ .uri_prefix = "mitsu9550",
+ .cmdline_usage = mitsu9550_cmdline,
+ .cmdline_arg = mitsu9550_cmdline_arg,
+ .init = mitsu9550_init,
+ .attach = mitsu9550_attach,
+ .teardown = mitsu9550_teardown,
+ .read_parse = mitsu9550_read_parse,
+ .main_loop = mitsu9550_main_loop,
+ .query_serno = mitsu9550_query_serno,
+ .devices = {
+ { USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, ""},
+ { USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550, ""},
+ { 0, 0, 0, ""}
+ }
+};
+
+/* Mitsubish CP-9550D/DW spool data format
+
+ Spool file consists of four 50-byte headers, followed by three image
+ planes (BGR, each with a 12-byte header), and a 4-byte footer.
+
+ All multi-byte numbers are big endian.
+
+ ~~~ Printer Init: 4x 50-byte blocks:
+
+ 1b 57 20 2e 00 0a 10 00 00 00 00 00 00 00 07 14 :: 0714 = 1812 = X res
+ 04 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 04d8 = 1240 = Y res
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00
+
+ 1b 57 21 2e 00 80 00 22 08 03 00 00 00 00 00 00 :: ZZ = num copies (>= 0x01)
+ 00 00 00 00 00 00 00 00 00 00 00 00 ZZ ZZ 00 00 :: YY 00 = normal, 80 = Fine
+ XX 00 00 00 00 00 YY 00 00 00 00 00 00 00 00 00 :: XX 00 = normal, 83 = Cut 2x6
+ 00 01
+
+ 1b 57 22 2e 00 40 00 00 00 00 00 XX 00 00 00 00 :: 00 = normal, 01 = FineDeep
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00
+
+ 1b 57 26 2e 00 70 00 00 00 00 00 00 01 01 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00
+
+ ~~~~ Data follows: Data is 8-bit BGR.
+
+ 1b 5a 54 00 00 00 00 00 07 14 04 d8 :: 0714 == row len, 04d8 == rows
+ ^^ ^^ :: 0000 == remaining rows
+
+ Data follows immediately, no padding.
+
+ 1b 5a 54 00 00 00 00 00 07 14 04 d8 :: Another plane.
+
+ Data follows immediately, no padding.
+
+ 1b 5a 54 00 00 00 00 00 07 14 04 d8 :: Another plane.
+
+ Data follows immediately, no padding.
+
+ ~~~~ Footer:
+
+ 1b 50 46 00
+
+ ~~~~ QUESTIONS:
+
+ * Lamination control?
+ * Other multi-cut modes (on 6x9 media: 4x6*2, 4.4x6*2, 3x6*3, 2x6*4)
+
+ ***********************************************************************
+
+ * Mitsubishi ** CP-9550DW-S ** Communications Protocol:
+
+ [[ Unknown ]]
+
+ -> 1b 53 c5 9d
+
+ [[ Unknown ]]
+
+ -> 1b 4b 7f 00
+ <- eb 4b 8f 00 02 00 5e [[ '02' seems to be a length ]]
+
+ [[ Unknown ]]
+
+ -> 1b 53 00 00
+
+ Query Model & Serial number
+
+ -> 1b 72 6e 00
+ <- e4 82 6e 00 LL 39 00 35 00 35 00 30 00 5a 00 20
+ 00 41 00 32 00 30 00 30 00 36 00 37 00
+
+ 'LL' is length. Data is returned in 16-bit unicode, LE.
+ Contents are model ('9550Z'), then space, then serialnum ('A20067')
+
+ Media Query
+
+ -> 1b 56 24 00
+ <- 24 2e 00 00 00 00 00 00 00 00 00 00 00 00 TT 00 :: TT = Type
+ 00 00 00 00 00 00 00 00 00 00 00 00 MM MM 00 00 :: MM MM = Max prints
+ NN NN 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: NN NN = Remaining
+
+ Status Query
+
+ -> 1b 56 30 00
+ -> 30 2e 00 00 00 00 MM 00 NN NN 00 00 00 00 00 00 :: MM, NN
+ QQ RR SS 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ, RR, SS
+ 00 00 00 00 00 00 00 00 00 00 00 00 TT UU 00 00 :: TT, UU
+
+ Status Query B (not sure what to call this)
+
+ -> 1b 56 21 00
+ <- 21 2e 00 80 00 22 a8 0b 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 QQ 00 00 00 00 :: QQ == Prints in job?
+ 00 00 00 00 00 00 00 00 00 00 NN NN 0A 00 00 01 :: NN NN = Remaining media
+
+ [[ Unknown ]]
+
+ -> 1b 44
+
+ [[ Header 1 -- See above ]]
+
+ -> 1b 57 20 2e ....
+
+ [[ Header 2 -- See above ]]
+
+ -> 1b 57 21 2e ....
+
+ [[ Header 3 -- See above ]]
+
+ -> 1b 57 22 2e ....
+
+ [[ Unknown -- Start Data ? ]]
+
+ -> 1b 5a 43 00
+
+ [[ Plane header #1 (Blue) ]]
+
+ -> 1b 5a 54 00 00 00 00 00 XX XX YY YY :: XX XX == Columns, YY YY == Rows
+
+ Followed by image plane #1 (Blue), XXXX * YYYY bytes
+
+ [[ Plane header #2 (Green) ]]
+
+ -> 1b 5a 54 00 00 00 00 00 XX XX YY YY :: XX XX == Columns, YY YY == Rows
+
+ Followed by image plane #2 (Green), XXXX * YYYY bytes
+
+ [[ Plane header #3 (Red) ]]
+
+ -> 1b 5a 54 00 00 00 00 00 XX XX YY YY :: XX XX == Columns, YY YY == Rows
+
+ Followed by image plane #3 (Red), XXXX * YYYY bytes
+
+ [[ Unknown -- End Data aka START print? ]]
+
+ -> 1b 50 47 00
+
+ [[ At this point, loop status/status b/media queries until printer idle ]]
+
+ MM, NN, QQ RR SS, TT UU
+
+ <- 00 00 3e 00 00 8a 44 :: Idle.
+ 00 00 7e 00 00 8a 44 :: Plane data submitted, pre "end data" cmd
+ 00 00 7e 40 01 8a 44 :: "end data" sent
+ 30 01 7e 40 01 8a 44
+ 38 01 7e 40 01 8a 44
+ 59 01 7e 40 01 8a 44
+ 59 01 7e 40 00 8a 44
+ 4d 01 7e 40 00 8a 44
+ [...]
+ 43 01 7e 40 00 82 44
+ [...]
+ 50 01 7e 40 00 80 44
+ [...]
+ 31 01 7e 40 00 7d 44
+ [...]
+ 00 00 3e 00 00 80 44 :: Idle.
+
+ Also seen:
+
+ 00 00 3e 00 00 96 4b :: Idle
+ 00 00 be 00 00 96 4b :: Data submitted, pre "start"
+ 00 00 be 80 01 96 4b :: print start sent
+ 30 00 be 80 01 96 4c
+ [...]
+ 30 03 be 80 01 89 4b
+ 38 03 be 80 01 8a 4b
+ 59 03 be 80 01 8b 4b
+ [...]
+ 4d 03 be 80 01 89 4b
+ [...]
+ 43 03 be 80 01 89 4b
+ [...]
+ 50 03 be 80 01 82 4b
+ [...]
+ 31 03 be 80 01 80 4b
+ [...]
+
+ Working theory of interpreting the status flags:
+
+ MM :: 00 is idle, else mechanical printer state.
+ NN :: Remaining prints in job, or 0x00 0x00 when idle.
+ QQ :: ?? 0x3e + 0x40 or 0x80 (see below)
+ RR :: ?? 0x00 is idle, 0x40 or 0x80 is "printing"?
+ SS :: ?? 0x00 means "ready for another print" but 0x01 is "busy"
+ TT :: ?? seen values between 0x7c through 0x96)
+ UU :: ?? seen values between 0x44 and 0x4c
+
+ ***
+
+ Other printer commands seen:
+
+ [[ Set error policy ?? aka "header 4" ]]
+
+ -> 1b 57 26 2e 00 QQ 00 00 00 00 00 00 RR SS 00 00 :: QQ/RR 00 00 00 [9550S]
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 20 01 00 [9550S w/ ignore failures on]
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 70 01 01 [9550]
+ 00 00
+
+ */
diff --git a/src/cups/selphy_print.c b/src/cups/selphy_print.c
index 7247e51..2c9bab0 100644
--- a/src/cups/selphy_print.c
+++ b/src/cups/selphy_print.c
@@ -1,7 +1,7 @@
/*
* Canon SELPHY ES/CP series CUPS backend -- libusb-1.0 version
*
- * (c) 2007-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2007-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -426,6 +426,7 @@ enum {
S_PRINTER_M_SENT,
S_PRINTER_READY_C,
S_PRINTER_C_SENT,
+ S_PRINTER_CP900_FOOTER,
S_PRINTER_DONE,
S_FINISHED,
};
@@ -519,19 +520,28 @@ struct canonselphy_ctx {
uint8_t *footer;
uint8_t *buffer;
+
+ uint8_t cp900;
};
static void *canonselphy_init(void)
{
struct canonselphy_ctx *ctx = malloc(sizeof(struct canonselphy_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
return NULL;
+ }
memset(ctx, 0, sizeof(struct canonselphy_ctx));
/* Static initialization */
setup_paper_codes();
ctx->buffer = malloc(MAX_HEADER);
+ if (!ctx->buffer) {
+ ERROR("Memory Allocation Failure!\n");
+ free(ctx);
+ ctx = NULL;
+ }
return ctx;
}
@@ -540,6 +550,8 @@ static void canonselphy_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct canonselphy_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
UNUSED(jobid);
@@ -547,15 +559,14 @@ static void canonselphy_attach(void *vctx, struct libusb_device_handle *dev,
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
/* Special cases for some models */
if (ctx->printer->type == P_ES40_CP790) {
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
int i;
int printer_type;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
if (desc.idProduct == USB_PID_CANON_CP790)
printer_type = P_CP790;
@@ -568,6 +579,8 @@ static void canonselphy_attach(void *vctx, struct libusb_device_handle *dev,
break;
}
}
+ } else if (desc.idProduct == USB_PID_CANON_CP900) {
+ ctx->cp900 = 1;
}
}
@@ -610,7 +623,7 @@ static int canonselphy_early_parse(void *vctx, int data_fd)
ERROR("Read failed (%d/%d/%d)\n",
i, 0, MAX_HEADER);
perror("ERROR: Read failed");
- return i;
+ return -1;
}
printer_type = parse_printjob(ctx->buffer, &ctx->bw_mode, &ctx->plane_len);
@@ -642,7 +655,7 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
int i, remain;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->header) {
free(ctx->header);
@@ -674,7 +687,7 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
if (!ctx->plane_y || !ctx->plane_m || !ctx->plane_c || !ctx->header ||
(ctx->printer->foot_length && !ctx->footer)) {
ERROR("Memory allocation failure!\n");
- return 1;
+ return CUPS_BACKEND_FAILED;
}
/* Move over chunks already read in */
@@ -687,7 +700,7 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
while (remain > 0) {
i = read(data_fd, ctx->plane_y + (ctx->plane_len - remain), remain);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
remain -= i;
}
@@ -696,7 +709,7 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
while (remain > 0) {
i = read(data_fd, ctx->plane_m + (ctx->plane_len - remain), remain);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
remain -= i;
}
@@ -705,7 +718,7 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
while (remain > 0) {
i = read(data_fd, ctx->plane_c + (ctx->plane_len - remain), remain);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
remain -= i;
}
@@ -715,12 +728,12 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
while (remain > 0) {
i = read(data_fd, ctx->footer + (ctx->printer->foot_length - remain), remain);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
remain -= i;
}
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static int canonselphy_main_loop(void *vctx, int copies) {
@@ -735,7 +748,7 @@ static int canonselphy_main_loop(void *vctx, int copies) {
rdbuf, READBACK_LEN, &num);
if (ret < 0)
- return ret;
+ return CUPS_BACKEND_FAILED;
top:
@@ -748,11 +761,11 @@ top:
ret = read_data(ctx->dev, ctx->endp_up,
rdbuf, READBACK_LEN, &num);
if (ret < 0)
- return ret;
+ return CUPS_BACKEND_FAILED;
if (num != READBACK_LEN) {
ERROR("Short read! (%d/%d)\n", num, READBACK_LEN);
- return 4;
+ return CUPS_BACKEND_FAILED;
}
/* Error detection */
@@ -760,8 +773,8 @@ top:
if (ctx->printer->clear_error_len)
/* Try to clear error state */
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->printer->clear_error, ctx->printer->clear_error_len)))
- return ret;
- return 4;
+ return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_HOLD;
}
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
@@ -787,20 +800,20 @@ top:
if (pc & 0xf0) {
ERROR("Incorrect paper tray loaded, aborting job!\n");
- return 3;
+ return CUPS_BACKEND_HOLD;
} else {
ERROR("No paper tray loaded, aborting!\n");
- return 4;
+ return CUPS_BACKEND_STOP;
}
}
if ((pc & 0xf) != (ctx->paper_code & 0xf)) {
if (pc & 0x0f) {
ERROR("Incorrect ribbon loaded, aborting job!\n");
- return 3;
+ return CUPS_BACKEND_HOLD;
} else {
ERROR("No ribbon loaded, aborting job!\n");
- return 4;
+ return CUPS_BACKEND_STOP;
}
}
} else {
@@ -809,7 +822,7 @@ top:
ERROR("Incorrect media/ribbon loaded (%02x vs %02x), aborting job!\n",
ctx->paper_code,
rdbuf[ctx->printer->paper_code_offset]);
- return 3; /* Hold this job, don't stop queue */
+ return CUPS_BACKEND_HOLD; /* Hold this job, don't stop queue */
}
}
} else if (ctx->printer->type == P_CP790) {
@@ -818,17 +831,17 @@ top:
if (ribbon == 0xf) {
ERROR("No ribbon loaded, aborting!\n");
- return 4;
+ return CUPS_BACKEND_STOP;
} else if (ribbon != ctx->paper_code) {
ERROR("Incorrect ribbon loaded, aborting job!\n");
- return 3;
+ return CUPS_BACKEND_HOLD;
}
if (paper == 0xf) {
ERROR("No paper tray loaded, aborting!\n");
- return 4;
+ return CUPS_BACKEND_STOP;
} else if (paper != ctx->paper_code) {
ERROR("Incorrect paper loaded, aborting job!\n");
- return 3;
+ return CUPS_BACKEND_HOLD;
}
}
@@ -838,7 +851,7 @@ top:
INFO("Printing started; Sending init sequence\n");
/* Send printer init */
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->header, ctx->printer->init_length)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_INIT_SENT;
break;
@@ -854,7 +867,7 @@ top:
INFO("Sending YELLOW plane\n");
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_y, ctx->plane_len)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_Y_SENT;
break;
@@ -870,7 +883,7 @@ top:
INFO("Sending MAGENTA plane\n");
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_m, ctx->plane_len)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_M_SENT;
break;
@@ -883,21 +896,35 @@ top:
INFO("Sending CYAN plane\n");
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_c, ctx->plane_len)))
- return ret;
+ return CUPS_BACKEND_FAILED;
state = S_PRINTER_C_SENT;
break;
case S_PRINTER_C_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->done_c_readback, READBACK_LEN)) {
- state = S_PRINTER_DONE;
+ if (ctx->cp900)
+ state = S_PRINTER_CP900_FOOTER;
+ else
+ state = S_PRINTER_DONE;
}
break;
+ case S_PRINTER_CP900_FOOTER: {
+ uint32_t empty = 0;
+
+ INFO("Sending CP900 Footer\n");
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*)&empty, sizeof(empty))))
+ return CUPS_BACKEND_FAILED;
+
+ state = S_PRINTER_DONE;
+ break;
+ }
case S_PRINTER_DONE:
if (ctx->printer->foot_length) {
INFO("Cleaning up\n");
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->footer, ctx->printer->foot_length)))
- return ret;
+ return CUPS_BACKEND_FAILED;
}
state = S_FINISHED;
/* Intentional Fallthrough */
@@ -919,12 +946,12 @@ top:
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
struct dyesub_backend canonselphy_backend = {
.name = "Canon SELPHY CP/ES",
- .version = "0.82.2G",
+ .version = "0.87",
.uri_prefix = "canonselphy",
.init = canonselphy_init,
.attach = canonselphy_attach,
@@ -1284,6 +1311,8 @@ struct dyesub_backend canonselphy_backend = {
adding a 50x50mm sticker and 22x17.3mm ministickers, though I think the
driver treats all of those as 'C' sizes for printing purposes.
+ Printer does *not* apparently require use of a spooler!
+
32-byte header:
0f 00 00 40 00 00 00 00 00 00 00 00 00 00 01 00
@@ -1305,8 +1334,8 @@ struct dyesub_backend canonselphy_backend = {
05 (L)
02 (C)
- P == 7008800 == 2336256 * 3 + 32 (4.884% larger than CP)
- L == 5087264 == 1695744 * 3 + 32 (5.878% larger than CP)
- C == 2180384 == 726784 * 3 + 32 (3.991% larger than CP)
+ P == 7008800 == 2336256 * 3 + 32 (1872*1248)
+ L == 5087264 == 1695744 * 3 + 32 (1536*1104)
+ C == 2180384 == 726784 * 3 + 32 (1088*668)
*/
diff --git a/src/cups/shinko_s2145_print.c b/src/cups/shinko_s2145_print.c
index 68c3e31..5196528 100644
--- a/src/cups/shinko_s2145_print.c
+++ b/src/cups/shinko_s2145_print.c
@@ -1,7 +1,7 @@
/*
* Shinko/Sinfonia CHC-S2145 CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@@ -52,18 +52,18 @@ enum {
/* Structure of printjob header. All fields are LITTLE ENDIAN */
struct s2145_printjob_hdr {
uint32_t len1; /* Fixed at 0x10 */
- uint32_t model; /* Fixed at '2145' (decimal) */
- uint32_t unk2;
- uint32_t unk3;
+ uint32_t model; /* Equal to the printer model (eg '2145' or '1245' decimal) */
+ uint32_t med_type; /* 6145 only, media type */
+ uint32_t unk3; /* Fixed at 0x01 */
uint32_t len2; /* Fixed at 0x64 */
uint32_t unk5;
uint32_t media;
uint32_t unk6;
- uint32_t method;
- uint32_t mode;
- uint32_t unk7;
+ uint32_t method; /* Method for 2145, 0x00 for 6245, multicut for 6145 */
+ uint32_t mode; /* Mode for 2145, 0x00 for 6245, quality for 6145 */
+ uint32_t oc_mode; /* 6145/6245 only, Matte/Glossy/None */
uint32_t unk8;
uint32_t unk9;
@@ -99,6 +99,8 @@ struct shinkos2145_ctx {
struct s2145_printjob_hdr hdr;
+ uint32_t model;
+
uint8_t *databuf;
int datalen;
};
@@ -359,245 +361,199 @@ struct s2145_status_hdr {
#define ERROR_PRINTER 0x11
#define ERROR_BUFFER_FULL 0x21
-
-/*
-
- I have a list of 72 different errors that are displayed on the printer,
- but it appears the list is incomplete, and there's no mapping between
- category and major code numbers. Also, not all of the individual errors
- have minor codes listed (particularly the "consumables")
-
- These are the observed error codes to date (via stored error log dumps):
-
- 01/16 [ controller/parameter? ]
- 05/15 [ jam/reloading? ]
- 05/4e [ jam/unknown ]
- 05/4f [ jam/unknown? ]
- 05/61 [ jam/cantload? ]
- 05/62 [ jam/cantload? ]
- 05/64 [ jam/unknown? ]
- 06/01 [ "cover open" ]
- 06/0a [ consumables ? ]
- 06/0b [ consumables ? ]
-
- Errors logged on printer A:
-
- 0x01/0x16 @ 77845
- 0x06/0x0b @ 77822, 70053
- 0x05/0x64 @ 76034
- 0x05/0x61 @ 76034, 75420
- 0x05/0x62 @ 76034
- 0x05/0x4e @ 69824, 69820, 69781
-
- Errors logged on printer B:
-
- 0x06/0x0b @ 33270
- 0x05/0x4e @ 32952, 27672
- 0x05/0x4f @ 32935, 31834
- 0x05/0x61 @ 30856, 27982
- 0x01/0x16 @ 29132
- 0x05/0x64 @ 27982
- 0x05/0x62 @ 27982
-
- Errors logged on printer C:
-
- 0x06/0x0a @ 78014, 77948, 77943, 77938 x2, 77937, 77936, 77933, 77919
- 0x05/0x15 @ 77938
-
-
- */
static char *error_codes(uint8_t major, uint8_t minor)
{
switch(major) {
- case 0x06:
- switch (minor) {
- case 0x01:
- return "Front Cover Open";
- default:
- return "Unknown";
- }
-#if 0
- case 9: /* "Controller Error" */
+ case 0x01: /* "Controller Error" */
switch(minor) {
case 0x01:
- return "Controller: 01 EEPROM";
+ return "Controller: EEPROM Write Timeout";
case 0x02:
- return "Controller: 02 EEPROM";
+ return "Controller: EEPROM Verify";
case 0x04:
- return "Controller: 04 DSP";
+ return "Controller: DSP Inactive";
case 0x05:
- return "Controller: 05 DSP";
+ return "Controller: DSP Application Inactive";
case 0x06:
- return "Controller: 06 Main FW";
+ return "Controller: Main FW Data";
case 0x07:
- return "Controller: 07 Main FW";
+ return "Controller: Main FW Write";
case 0x08:
- return "Controller: 08 DSP FW";
+ return "Controller: DSP FW Data";
case 0x09:
- return "Controller: 09 DSP FW";
+ return "Controller: DSP FW Write";
case 0x0A:
- return "Controller: 0A ASIC";
+ return "Controller: 0A ASIC??";
case 0x0B:
- return "Controller: 0B FPGA";
+ return "Controller: 0B FPGA??";
case 0x0D:
- return "Controller: 0D Tone Curve";
+ return "Controller: Tone Curve Write";
case 0x16:
- return "Controller: 16 Parameter Table";
+ return "Controller: Invalid Parameter Table";
case 0x17:
- return "Controller: 17 Parameter Table";
+ return "Controller: Parameter Table Data";
case 0x18:
- return "Controller: 18 Parameter Table";
+ return "Controller: Parameter Table Write";
case 0x29:
- return "Controller: 29 DSP Comms";
+ return "Controller: DSP Communication";
case 0x2A:
- return "Controller: 2A DSP Comms";
+ return "Controller: DSP DMA Failure";
default:
return "Controller: Unknown";
}
- case 8: /* XXXX "Mechanical Error" */
+ case 0x02: /* "Mechanical Error" */
switch (minor) {
case 0x01:
- return "Mechanical: 01 Thermal Head";
+ return "Mechanical: Thermal Head (Upper Up)";
case 0x02:
- return "Mechanical: 02 Thermal Head";
+ return "Mechanical: Thermal Head (Head Up)";
case 0x03:
- return "Mechanical: 03 Thermal Head";
+ return "Mechanical: Thermal Head (Head Down)";
case 0x04:
- return "Mechanical: 04 Pinch Roller";
+ return "Mechanical: Pinch Roller (Initialize)";
case 0x05:
- return "Mechanical: 05 Pinch Roller";
+ return "Mechanical: Pinch Roller (Mode1)";
case 0x06:
- return "Mechanical: 06 Pinch Roller";
+ return "Mechanical: Pinch Roller (Mode2)";
case 0x07:
- return "Mechanical: 07 Pinch Roller";
+ return "Mechanical: Pinch Roller (Mode3)";
case 0x08:
- return "Mechanical: 08 Pinch Roller";
+ return "Mechanical: Pinch Roller (Mode4)";
case 0x09:
- return "Mechanical: 09 Cutter";
+ return "Mechanical: Cutter (Right)";
case 0x0A:
- return "Mechanical: 0A Cutter";
+ return "Mechanical: Cutter (Left)";
+ case 0x0B:
+ return "Mechanical: Thermal Head (Head Down Recovery)";
default:
return "Mechanical: Unknown";
}
- case 2: /* XXXX "Sensor Error" */
+ case 0x03: /* "Sensor Error" */
switch (minor) {
case 0x01:
- return "Sensor: 01 Thermal Head";
+ return "Sensor: Thermal Head";
case 0x02:
- return "Sensor: 02 Pinch Roller";
+ return "Sensor: Pinch Roller";
case 0x03:
- return "Sensor: 03 Cutter L";
+ return "Sensor: Cutter Left";
case 0x04:
- return "Sensor: 04 Cutter R";
+ return "Sensor: Cutter Right";
case 0x05:
- return "Sensor: 05 Cutter M";
+ return "Sensor: Cutter Unknown";
+ case 0x08:
+ return "Sensor: Ribbon Encoder (Supply)";
+ case 0x09:
+ return "Sensor: Ribbon Encoder (Takeup)";
+ case 0x13:
+ return "Sensor: Thermal Head";
default:
return "Sensor: Unknown";
}
- case 3: /* XXXX "Temperature Sensor Error" */
+ case 0x04: /* "Temperature Sensor Error" */
switch (minor) {
case 0x01:
- return "Temp Sensor: 01 Thermal Head High";
+ return "Temp Sensor: Thermal Head High";
case 0x02:
- return "Temp Sensor: 02 Thermal Head Low";
+ return "Temp Sensor: Thermal Head Low";
case 0x03:
- return "Temp Sensor: 03 Environment High";
+ return "Temp Sensor: Environment High";
case 0x04:
- return "Temp Sensor: 04 Environment Low";
+ return "Temp Sensor: Environment Low";
case 0x05:
- return "Temp Sensor: 05 Warmup Timed Out";
+ return "Temp Sensor: Warmup Timed Out";
default:
return "Temp Sensor: Unknown";
}
-
- case 4: /* XXXX "Front Cover Open" */
- switch (minor) {
-// case 0x01:
-// return "Front Cover: 01 Cover Open";
- case 0x02:
- return "Front Cover: 02 Cover Open Error";
- default:
- return "Front Cover: Unknown";
- }
- case 5: /* XXX "Paper Jam" */
+ case 0x5: /* "Paper Jam" */
switch (minor) {
case 0x01:
- return "Paper Jam: 01 Loading";
+ return "Paper Jam: Loading Leading Edge Off";
case 0x02:
- return "Paper Jam: 02 Loading";
+ return "Paper Jam: Loading Print Position On";
case 0x03:
- return "Paper Jam: 03 Loading";
+ return "Paper Jam: Loading Print Position Off";
case 0x04:
- return "Paper Jam: 04 Loading";
+ return "Paper Jam: Loading Print Position On";
case 0x05:
- return "Paper Jam: 05 Loading";
+ return "Paper Jam: Loading Leading Edge On";
case 0x11:
- return "Paper Jam: 11 Reloading";
+ return "Paper Jam: Initializing Print Position Off";
case 0x12:
- return "Paper Jam: 12 Reloading";
+ return "Paper Jam: Initializing Print Position On";
case 0x13:
- return "Paper Jam: 13 Reloading";
+ return "Paper Jam: Initializing Leading Edge On";
case 0x14:
- return "Paper Jam: 14 Reloading";
+ return "Paper Jam: Initializing Print Position On";
case 0x15:
- return "Paper Jam: 15 Reloading";
+ return "Paper Jam: Initializing Print Position Off";
case 0x16:
- return "Paper Jam: 16 Reloading";
+ return "Paper Jam: Initializing Print Position On";
case 0x21:
- return "Paper Jam: 21 Takeup";
+ return "Paper Jam: Initializing Print Position On";
case 0x22:
- return "Paper Jam: 22 Takeup";
+ return "Paper Jam: Rewinding Print Position On";
+ case 0x40:
+ return "Paper Jam: Pre-Printing Print Position Off";
case 0x41:
- return "Paper Jam: 41 Printing";
+ return "Paper Jam: Pre-Printing Print Position Off";
case 0x42:
- return "Paper Jam: 42 Printing";
+ return "Paper Jam: Printing Leading Edge Off";
case 0x43:
- return "Paper Jam: 43 Printing";
+ return "Paper Jam: After Returning Lead Edge Off";
case 0x44:
- return "Paper Jam: 44 Printing";
+ return "Paper Jam: After Printing Print Position Off";
case 0x45:
- return "Paper Jam: 45 Printing";
+ return "Paper Jam: After Printing Print Position On";
case 0x46:
- return "Paper Jam: 46 Printing";
+ return "Paper Jam: After Printing Print Position On";
case 0x47:
- return "Paper Jam: 47 Printing";
+ return "Paper Jam: After Printing Print Position Off";
case 0x49:
- return "Paper Jam: 49 Printing";
+ return "Paper Jam: Printing Lost Ribbon Mark";
case 0x4A:
- return "Paper Jam: 4A Ribbon Cut";
+ return "Paper Jam: Printing Ribbon Cut";
+ case 0x4D:
+ return "Paper Jam: Printing Lost M Mark";
+ case 0x4E:
+ return "Paper Jam: Printing Lost C Mark";
+ case 0x4F:
+ return "Paper Jam: Printing Lost OP Mark";
case 0x61:
- return "Paper Jam: 61 Can't Load";
+ return "Paper Jam: Initializing Lead Edge On";
case 0x62:
- return "Paper Jam: 62 Can't Load";
+ return "Paper Jam: Initizlizing Print Position On";
+ case 0x64:
+ return "Paper Jam: Initizlizing Paper Size On";
default:
return "Paper Jam: Unknown";
}
- case 6: /* XXXX "Consumables" */
+ case 0x06: /* User Error */
switch (minor) {
- case 0x01: // XXX
- return "Consumables: XX No Ribbon+Paper";
- case 0x02: // XXX
- return "Consumables: XX No Ribbon";
- case 0x03: // XXX
- return "Consumables: XX Ribbon Empty";
- case 0x04: // XXX
- return "Consumables: XX Ribbon Mismatch";
- case 0x05: // XXX
- return "Consumables: XX 01 Ribbon Incorrect";
- case 0x06: // XXX
- return "Consumables: XX 02 Ribbon Incorrect";
- case 0x07: // XXX
- return "Consumables: XX 03 Ribbon Incorrect";
- case 0x08: // XXX
- return "Consumables: XX No Paper";
- case 0x09: // XXX
- return "Consumables: XX Paper Empty";
- case 0x0A: // XXX
- return "Consumables: XX Paper Mismatch";
+ case 0x01:
+ return "Front Cover Open";
+ case 0x02:
+ return "Incorrect Ribbon";
+ case 0x03:
+ return "No Ribbon";
+ case 0x04:
+ return "Mismatched Ribbon";
+ case 0x05:
+ return "Mismatched Paper";
+ case 0x06:
+ return "Paper Empty";
+ case 0x08:
+ return "No Paper";
+ case 0x09:
+ return "Take Out Paper";
+ case 0x0A:
+ return "Cover Open Error";
+ case 0x0B:
+ return "Thermal Head Damaged";
+ case 0x0C:
+ return "Thermal Head Recovery";
default:
- return "Consumables: Unknown";
+ return "Unknown";
}
-#endif
default:
return "Unknown";
}
@@ -1202,6 +1158,10 @@ static int get_tonecurve(struct shinkos2145_ctx *ctx, int type, char *fname)
resp->total_size = le16_to_cpu(resp->total_size);
data = malloc(resp->total_size * 2);
+ if (!data) {
+ ERROR("Memory allocation failure! (%d bytes)\n",
+ resp->total_size * 2);
+ }
i = 0;
while (i < resp->total_size) {
@@ -1252,6 +1212,11 @@ static int set_tonecurve(struct shinkos2145_ctx *ctx, int target, char *fname)
uint16_t *data = malloc(UPDATE_SIZE);
+ if (!data) {
+ ERROR("Memory allocation failure! (%d bytes)\n",
+ UPDATE_SIZE);
+ }
+
/* Read in file */
int tc_fd = open(fname, O_RDONLY);
if (tc_fd < 0) {
@@ -1445,8 +1410,12 @@ int shinkos2145_cmdline_arg(void *vctx, int argc, char **argv)
static void *shinkos2145_init(void)
{
struct shinkos2145_ctx *ctx = malloc(sizeof(struct shinkos2145_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory allocation failure! (%d bytes)\n",
+ (int)sizeof(struct shinkos2145_ctx));
+
return NULL;
+ }
memset(ctx, 0, sizeof(struct shinkos2145_ctx));
/* Use Fast return by default in CUPS mode */
@@ -1482,24 +1451,18 @@ static void shinkos2145_teardown(void *vctx) {
free(ctx);
}
-static int shinkos2145_read_parse(void *vctx, int data_fd) {
+static int shinkos2145_early_parse(void *vctx, int data_fd) {
struct shinkos2145_ctx *ctx = vctx;
- int ret;
- uint8_t tmpbuf[4];
+ int printer_type, ret;
if (!ctx)
- return 1;
-
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
- }
+ return -1;
/* Read in then validate header */
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
if (ret < 0 || ret != sizeof(ctx->hdr)) {
if (ret == 0)
- return 1;
+ return -1; /* deliberate */
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(ctx->hdr));
perror("ERROR: Read failed");
@@ -1507,18 +1470,50 @@ static int shinkos2145_read_parse(void *vctx, int data_fd) {
}
if (le32_to_cpu(ctx->hdr.len1) != 0x10 ||
- le32_to_cpu(ctx->hdr.model) != 2145 ||
le32_to_cpu(ctx->hdr.len2) != 0x64 ||
le32_to_cpu(ctx->hdr.dpi) != 300) {
ERROR("Unrecognized header data format!\n");
- return 1;
+ return -1;
+ }
+
+ ctx->model = le32_to_cpu(ctx->hdr.model);
+
+ switch(ctx->model) {
+ case 2145:
+ printer_type = P_SHINKO_S2145;
+ break;
+ case 6145:
+ case 6245:
+ default:
+ ERROR("Unrecognized printer (%d)!\n", le32_to_cpu(ctx->hdr.model));
+
+ return -1;
+ }
+
+ INFO("File intended for an S%d printer\n", ctx->model);
+
+ return printer_type;
+}
+
+static int shinkos2145_read_parse(void *vctx, int data_fd) {
+ struct shinkos2145_ctx *ctx = vctx;
+ int ret;
+ uint8_t tmpbuf[4];
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->databuf) {
+ free(ctx->databuf);
+ ctx->databuf = NULL;
}
+
ctx->datalen = le32_to_cpu(ctx->hdr.rows) * le32_to_cpu(ctx->hdr.columns) * 3;
ctx->databuf = malloc(ctx->datalen);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 1;
+ return CUPS_BACKEND_FAILED;
}
{
@@ -1550,10 +1545,10 @@ static int shinkos2145_read_parse(void *vctx, int data_fd) {
tmpbuf[2] != 0x02 ||
tmpbuf[3] != 0x01) {
ERROR("Unrecognized footer data format!\n");
- return 1;
+ return CUPS_BACKEND_FAILED;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
static int shinkos2145_main_loop(void *vctx, int copies) {
@@ -1563,11 +1558,40 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
uint8_t cmdbuf[CMDBUF_LEN];
uint8_t rdbuf2[READBACK_LEN];
- int last_state = -1, state = S_IDLE;
+ int i, last_state = -1, state = S_IDLE;
struct s2145_cmd_hdr *cmd = (struct s2145_cmd_hdr *) cmdbuf;;
struct s2145_print_cmd *print = (struct s2145_print_cmd *) cmdbuf;
struct s2145_status_resp *sts = (struct s2145_status_resp *) rdbuf;
+ struct s2145_mediainfo_resp *media = (struct s2145_mediainfo_resp *) rdbuf;
+
+ /* Send Media Query */
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmd->cmd = cpu_to_le16(S2145_CMD_MEDIAINFO);
+ cmd->len = cpu_to_le16(0);
+
+ if ((ret = s2145_do_cmd(ctx,
+ cmdbuf, sizeof(*cmd),
+ sizeof(*media),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (le16_to_cpu(media->hdr.payload_len) != (sizeof(struct s2145_mediainfo_resp) - sizeof(struct s2145_status_hdr)))
+ return CUPS_BACKEND_FAILED;
+
+ /* Validate print sizes */
+ for (i = 0; i < media->count ; i++) {
+ /* Look for matching media */
+ if (le16_to_cpu(media->items[i].columns) == cpu_to_le16(le32_to_cpu(ctx->hdr.columns)) &&
+ le16_to_cpu(media->items[i].rows) == cpu_to_le16(le32_to_cpu(ctx->hdr.rows)))
+ break;
+ }
+ if (i == media->count) {
+ ERROR("Incorrect media loaded for print!\n");
+ return CUPS_BACKEND_HOLD;
+ }
top:
if (state != last_state) {
@@ -1585,7 +1609,7 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
sizeof(struct s2145_status_hdr),
&num)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd));
- return ret;
+ return CUPS_BACKEND_FAILED;
}
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
@@ -1593,13 +1617,13 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
INFO("Printer Status: 0x%02x (%s)\n",
sts->hdr.status, status_str(sts->hdr.status));
- if (sts->hdr.error == ERROR_PRINTER) {
- ERROR("Printer Reported Error: 0x%02x.0x%02x (%s)\n",
- sts->hdr.printer_major, sts->hdr.printer_minor,
- error_codes(sts->hdr.printer_major, sts->hdr.printer_minor));
- }
+ if (sts->hdr.result != RESULT_SUCCESS)
+ goto printer_error;
+ if (sts->hdr.error == ERROR_PRINTER)
+ goto printer_error;
} else if (state == last_state) {
sleep(1);
+ goto top;
}
last_state = state;
@@ -1608,12 +1632,6 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
switch (state) {
case S_IDLE:
INFO("Waiting for printer idle\n");
- /* Basic error handling */
- if (sts->hdr.result != RESULT_SUCCESS)
- goto printer_error;
- if (sts->hdr.error != ERROR_NONE)
- goto printer_error;
-
/* If either bank is free, continue */
if (sts->bank1_status == BANK_STATUS_FREE ||
sts->bank2_status == BANK_STATUS_FREE)
@@ -1626,13 +1644,20 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
memset(cmdbuf, 0, CMDBUF_LEN);
print->hdr.cmd = cpu_to_le16(S2145_CMD_PRINTJOB);
print->hdr.len = cpu_to_le16(sizeof (*print) - sizeof(*cmd));
- print->id = ctx->jobid;
- print->count = cpu_to_le16(copies);
- print->columns = cpu_to_le16(le32_to_cpu(ctx->hdr.columns));
- print->rows = cpu_to_le16(le32_to_cpu(ctx->hdr.rows));
- print->media = le32_to_cpu(ctx->hdr.media);
- print->mode = le32_to_cpu(ctx->hdr.mode);
- print->method = le32_to_cpu(ctx->hdr.method);
+
+ if (ctx->model == 2145) {
+ print->id = ctx->jobid;
+ print->count = cpu_to_le16(copies);
+ print->columns = cpu_to_le16(le32_to_cpu(ctx->hdr.columns));
+ print->rows = cpu_to_le16(le32_to_cpu(ctx->hdr.rows));
+ print->media = le32_to_cpu(ctx->hdr.media);
+ print->mode = le32_to_cpu(ctx->hdr.mode);
+ print->method = le32_to_cpu(ctx->hdr.method);
+ } else {
+ // s6145, s6245 use different fields
+ ERROR("Don't know how to initiate print on non-2145 models!\n");
+ return CUPS_BACKEND_FAILED;
+ }
if ((ret = s2145_do_cmd(ctx,
cmdbuf, sizeof(*print),
@@ -1653,22 +1678,20 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
INFO("Sending image data to printer\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->databuf, ctx->datalen)))
- return ret;
+ return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
sleep(1);
state = S_PRINTER_SENT_DATA;
break;
case S_PRINTER_SENT_DATA:
- if (sts->hdr.result != RESULT_SUCCESS)
- goto printer_error;
if (ctx->fast_return) {
INFO("Fast return mode enabled.\n");
state = S_FINISHED;
- }
- else if (sts->hdr.status == STATUS_READY ||
- sts->hdr.status == STATUS_FINISHED)
+ } else if (sts->hdr.status == STATUS_READY ||
+ sts->hdr.status == STATUS_FINISHED) {
state = S_FINISHED;
+ }
break;
default:
break;
@@ -1691,7 +1714,7 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
printer_error:
ERROR("Printer reported error: %#x (%s) status: %#x (%s) -> %#x.%#x (%s)\n",
@@ -1701,7 +1724,7 @@ printer_error:
status_str(sts->hdr.status),
sts->hdr.printer_major, sts->hdr.printer_minor,
error_codes(sts->hdr.printer_major, sts->hdr.printer_minor));
- return 1; /* CUPS_BACKEND_FAILED */
+ return CUPS_BACKEND_FAILED;
}
static int shinkos2145_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
@@ -1735,27 +1758,35 @@ static int shinkos2145_query_serno(struct libusb_device_handle *dev, uint8_t end
strncpy(buf, (char*)resp->data, buf_len);
buf[buf_len-1] = 0; /* ensure it's null terminated */
- return 0;
+ return CUPS_BACKEND_OK;
}
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S2145 0x000E
+#define USB_PID_SHINKO_S6145 0x0019
+#define USB_PID_SHINKO_S6245 0x001D
+//#define USB_VID_CIAAT xxxxxx
+//#define USB_PID_CIAAT_BRAVA21 xxxxx
struct dyesub_backend shinkos2145_backend = {
- .name = "Shinko/Sinfonia CHC-S2145 (S2)",
- .version = "0.31",
+ .name = "Shinko/Sinfonia CHC-S2145",
+ .version = "0.40",
.uri_prefix = "shinkos2145",
.cmdline_usage = shinkos2145_cmdline,
.cmdline_arg = shinkos2145_cmdline_arg,
.init = shinkos2145_init,
.attach = shinkos2145_attach,
.teardown = shinkos2145_teardown,
+ .early_parse = shinkos2145_early_parse,
.read_parse = shinkos2145_read_parse,
.main_loop = shinkos2145_main_loop,
.query_serno = shinkos2145_query_serno,
.devices = {
{ USB_VID_SHINKO, USB_PID_SHINKO_S2145, P_SHINKO_S2145, ""},
+// { USB_VID_SHINKO, USB_PID_SHINKO_S6145, P_SHINKO_S2145, ""},
+// { USB_VID_SHINKO, USB_PID_SHINKO_S6245, P_SHINKO_S2145, ""},
+// { USB_VID_CIAAT, USB_PID_CIAAT_BRAVA21, P_SHINKO_S2145, ""},
{ 0, 0, 0, ""}
}
};
@@ -1767,8 +1798,8 @@ struct dyesub_backend shinkos2145_backend = {
4-byte Little Endian words.
10 00 00 00 MM MM 00 00 00 00 00 00 01 00 00 00 MM == Model (ie 2145d)
- 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == Media Type
- MM 00 00 00 PP 00 00 00 00 00 00 00 00 00 00 00 PP = Print Mode, MM = Print Method
+ 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == Media/Print Size
+ MM 00 00 00 PP 00 00 00 00 00 00 00 00 00 00 00 MM = Print Method (aka cut control), PP = Print Mode
00 00 00 00 WW WW 00 00 HH HH 00 00 XX 00 00 00 XX == Copies
00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI, ie 300.
@@ -1779,4 +1810,67 @@ struct dyesub_backend shinkos2145_backend = {
04 03 02 01 [[ footer ]]
+ * CHC-S6245 data format
+
+ Spool file consists of an 116-byte header, followed by RGB-packed data,
+ followed by a 4-byte footer. Header appears to consist of a series of
+ 4-byte Little Endian words.
+
+ 10 00 00 00 MM MM 00 00 01 00 00 00 01 00 00 00 MM == Model (ie 6245d)
+ 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == 0x20 8x4, 0x21 8x5, 0x22 8x6, 0x23 8x8, 0x10 8x10, 0x11 8x12
+ 00 00 00 00 00 00 00 00 XX 00 00 00 00 00 00 00 XX == 0x03 matte, 0x02 glossy, 0x01 no coat
+ 00 00 00 00 WW WW 00 00 HH HH 00 00 NN 00 00 00 WW/HH Width, Height (LE), NN == Copies
+ 00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
+ 00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI (300)
+ 00 00 00 00 ce ff ff ff 00 00 00 00 00 00 00 00
+ 00 00 00 00
+
+ [[Packed RGB payload of WW*HH*3 bytes]]
+
+ 04 03 02 01 [[ footer ]]
+
+ * CHC-S6145 data format
+
+ Spool file consists of an 116-byte header, followed by RGB-packed data,
+ followed by a 4-byte footer. Header appears to consist of a series of
+ 4-byte Little Endian words.
+
+ 10 00 00 00 MM MM 00 00 HH 00 00 00 01 00 00 00 MM == Model (ie 6145d), HH == 0x02 (5" media), 0x03 (6" media)
+ 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == 0x08 5x5, 0x03 5x7, 0x07 2x6, 0x00 4x6, 0x06 6x6/6x6+6x2/6x8
+ UU 00 00 00 ZZ 00 00 00 XX 00 00 00 00 00 00 00 XX == 0x00 default, 0x02 glossy, 0x03 matte, ZZ == 0x00 default, 0x01 == std qual; UU == 0x00 normal, 0x04 2x6*2, 0x05 6x6+2x6
+ 00 00 00 00 WW WW 00 00 HH HH 00 00 NN 00 00 00 WW/HH Width, Height (LE), NN == Copies
+ 00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
+ 00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI (300)
+ 00 00 00 00 ce ff ff ff 00 00 00 00 00 00 00 00
+ 00 00 00 00
+
+ [[Packed RGB payload of WW*HH*3 bytes]]
+
+ 04 03 02 01 [[ footer ]]
+
+ * CIAAT Brava 21 data format
+
+ This printer is supposed to be a variant of the S6145, but uses a
+ different spool format -- but seems to use the same command language.
+
+ 01 40 12 00 01 NN 00 YY YY XX XX TT 00 00 00 00 00 00 01 MM QQ 00
+
+ NN == copies
+ YY YY == Columns (LE)
+ XX XX == Rows (LE)
+ MM == Overcoat (02 = glossy, 03 = matte, 01 = none)
+ QQ == Multicut (00 = normal, 01 = none, 02 = 2*4x6,
+ 04 = 2*2x6, 80 = 4x6-notrim)
+ TT == Type (00 = 4x6, 03 = 5x7, 06 = 8x6, 07 = 2x6)
+
+ 1844*2434 8x6
+ 1844*2492 4x6*2
+ 1548*2140 5x7
+ 1844*1240 4x6 (and 2x6*2)
+ 1844*1210 4x6-notrim (WTF?)
+ 1844*634 2x6
+
+
+ [[ Followed by XX*YY*3 bytes of image data, RGB ]]
+
*/
diff --git a/src/cups/sony_updr150_print.c b/src/cups/sony_updr150_print.c
index 15347b0..5df9742 100644
--- a/src/cups/sony_updr150_print.c
+++ b/src/cups/sony_updr150_print.c
@@ -1,7 +1,7 @@
/*
* Sony UP-DR150 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2014 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -37,6 +37,12 @@
#include "backend_common.h"
+/* Exported */
+#define USB_VID_SONY 0x054C
+#define USB_PID_SONY_UPDR150 0x01E8
+#define USB_PID_SONY_UPDR200 0x035F
+#define USB_PID_SONY_UPCR10 1234
+
/* Private data stucture */
struct updr150_ctx {
struct libusb_device_handle *dev;
@@ -45,13 +51,18 @@ struct updr150_ctx {
uint8_t *databuf;
int datalen;
+
+ uint32_t copies_offset;
+ uint8_t type;
};
static void* updr150_init(void)
{
struct updr150_ctx *ctx = malloc(sizeof(struct updr150_ctx));
- if (!ctx)
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!");
return NULL;
+ }
memset(ctx, 0, sizeof(struct updr150_ctx));
return ctx;
}
@@ -60,12 +71,24 @@ static void updr150_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct updr150_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
UNUSED(jobid);
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+ if (desc.idProduct == USB_PID_SONY_UPDR150 ||
+ desc.idProduct == USB_PID_SONY_UPDR200)
+ ctx->type = P_SONY_UPDR150;
+ else
+ ctx->type = P_SONY_UPCR10; // XXX
+
+ ctx->copies_offset = 0;
}
static void updr150_teardown(void *vctx) {
@@ -85,7 +108,7 @@ static int updr150_read_parse(void *vctx, int data_fd) {
int len, run = 1;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
if (ctx->databuf) {
free(ctx->databuf);
@@ -96,7 +119,7 @@ static int updr150_read_parse(void *vctx, int data_fd) {
ctx->databuf = malloc(MAX_PRINTJOB_LEN);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
- return 2;
+ return CUPS_BACKEND_FAILED;
}
while(run) {
@@ -104,7 +127,7 @@ static int updr150_read_parse(void *vctx, int data_fd) {
int keep = 0;
i = read(data_fd, ctx->databuf + ctx->datalen, 4);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
if (i == 0)
break;
@@ -113,16 +136,18 @@ static int updr150_read_parse(void *vctx, int data_fd) {
/* Filter out chunks we don't send to the printer */
switch (len) {
+ case 0xffffff60:
case 0xffffff6a:
- case 0xfffffffc:
- case 0xfffffffb:
- case 0xfffffff4:
+ case 0xffffffeb:
+ case 0xffffffec:
case 0xffffffed:
- case 0xfffffff9:
+ case 0xfffffff4:
case 0xfffffff8:
- case 0xffffffec:
- case 0xffffffeb:
+ case 0xfffffff9:
case 0xfffffffa:
+ case 0xfffffffb:
+ case 0xfffffffc:
+ case 0xffffffff:
if(dyesub_debug)
DEBUG("Block ID '%08x' (len %d)\n", len, 0);
len = 0;
@@ -131,7 +156,15 @@ static int updr150_read_parse(void *vctx, int data_fd) {
if(dyesub_debug)
DEBUG("Block ID '%08x' (len %d)\n", len, 0);
len = 0;
- run = 0;
+ if (ctx->type == P_SONY_UPDR150)
+ run = 0;
+ break;
+ case 0xfffffff7:
+ if(dyesub_debug)
+ DEBUG("Block ID '%08x' (len %d)\n", len, 0);
+ len = 0;
+ if (ctx->type == P_SONY_UPCR10)
+ run = 0;
break;
case 0xffffffef:
case 0xfffffff5:
@@ -142,7 +175,7 @@ static int updr150_read_parse(void *vctx, int data_fd) {
default:
if (len & 0xff000000) {
ERROR("Unknown block ID '%08x', aborting!\n", len);
- return 1;
+ return CUPS_BACKEND_CANCEL;
} else {
/* Only keep these chunks */
if(dyesub_debug)
@@ -158,18 +191,27 @@ static int updr150_read_parse(void *vctx, int data_fd) {
while(len > 0) {
i = read(data_fd, ctx->databuf + ctx->datalen, len);
if (i < 0)
- return i;
+ return CUPS_BACKEND_CANCEL;
if (i == 0)
break;
+
+ if (ctx->databuf[ctx->datalen] == 0x1b &&
+ ctx->databuf[ctx->datalen + 1] == 0xee) {
+ if (ctx->type == P_SONY_UPCR10)
+ ctx->copies_offset = ctx->datalen + 8;
+ else
+ ctx->copies_offset = ctx->datalen + 12;
+ }
+
if (keep)
ctx->datalen += i;
len -= i;
}
}
if (!ctx->datalen)
- return 1;
+ return CUPS_BACKEND_CANCEL;
- return 0;
+ return CUPS_BACKEND_OK;
}
static int updr150_main_loop(void *vctx, int copies) {
@@ -177,7 +219,13 @@ static int updr150_main_loop(void *vctx, int copies) {
int i = 0, ret;
if (!ctx)
- return 1;
+ return CUPS_BACKEND_FAILED;
+
+ /* Some models specify copies in the print job */
+ if (ctx->copies_offset) {
+ ctx->databuf[ctx->copies_offset] = copies;
+ copies = 1;
+ }
top:
while (i < ctx->datalen) {
@@ -187,11 +235,9 @@ top:
i += sizeof(uint32_t);
- if (dyesub_debug)
- DEBUG("Sending %u bytes to printer @ %i\n", len, i);
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->databuf + i, len)))
- return ret;
+ return CUPS_BACKEND_FAILED;
i += len;
}
@@ -206,17 +252,12 @@ top:
goto top;
}
- return 0;
+ return CUPS_BACKEND_OK;
}
-/* Exported */
-#define USB_VID_SONY 0x054C
-#define USB_PID_SONY_UPDR150 0x01E8
-#define USB_PID_SONY_UPDR200 0x035F
-
struct dyesub_backend updr150_backend = {
- .name = "Sony UP-DR150/UP-DR200",
- .version = "0.13",
+ .name = "Sony UP-DR150/UP-DR200/UP-CR10",
+ .version = "0.17",
.uri_prefix = "sonyupdr150",
.init = updr150_init,
.attach = updr150_attach,
@@ -226,6 +267,7 @@ struct dyesub_backend updr150_backend = {
.devices = {
{ USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, ""},
{ USB_VID_SONY, USB_PID_SONY_UPDR200, P_SONY_UPDR150, ""},
+ { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, ""},
{ 0, 0, 0, ""}
}
};
@@ -236,10 +278,11 @@ struct dyesub_backend updr150_backend = {
arguments. The purpose of the commands is unknown, but they presumably
instruct the driver to perform certain things.
- If you treat these 4 bytes as a 32-bit little-endian number, if the most significant
- four bits are bits are non-zero, the value is is to be interpreted as a driver
- command. If the most significant bits are zero, the value signifies that the following
- N bytes of data should be sent to the printer as-is.
+ If you treat these 4 bytes as a 32-bit little-endian number, if the
+ most significant four bits are bits are non-zero, the value is is to
+ be interpreted as a driver command. If the most significant bits are
+ zero, the value signifies that the following N bytes of data should be
+ sent to the printer as-is.
Known driver "commands":
@@ -313,4 +356,32 @@ struct dyesub_backend updr150_backend = {
[[fin]]
+ **************
+
+ Sony UP-CL10 / DNP SL-10 spool format:
+
+60 ff ff ff
+f8 ff ff ff
+fd ff ff ff 14 00 00 00 1b 15 00 00 00 0d 00 00 00 00 00 07 00 00 00 00 WW WW HH HH
+fb ff ff ff
+f4 ff ff ff 0b 00 00 00 1b ea 00 00 00 00 SH SH SH SH 00 SL SL SL SL
+
+ [[ Data, rows * cols * 3 bytes ]]
+
+f3 ff ff ff 0f 00 00 00 1b e5 00 00 00 08 00 00 00 00 00 00 00 00 00
+ 12 00 00 00 1b e1 00 00 00 0b 00 00 80 00 00 00 00 00 WW WW HH HH
+fa ff ff ff 09 00 00 00 1b ee 00 00 00 02 00 00 NN
+ 07 00 00 00 1b 0a 00 00 00 00 00
+f9 ff ff ff
+fc ff ff ff 07 00 00 00 1b 17 00 00 00 00 00
+f7 ff ff ff
+
+ WW WW == Columns, Big Endian
+ HH HH == Rows, Big Endian
+ SL SL SL SL == Plane size, Little Endian (Rows * Cols * 3)
+ SH SH SH SH == Plane size, Big Endian (Rows * Cols * 3)
+ NN == Copies
+
+
+
*/
diff --git a/src/cups/test-ppds b/src/cups/test-ppds
index fb0c0fd..7dd004b 100755..100644
--- a/src/cups/test-ppds
+++ b/src/cups/test-ppds
@@ -14,7 +14,7 @@ cupstestppdopts='-I profiles -W sizes'
ppd_count=`find ppd \( -name '*.ppd.gz' -o -name '*.ppd' \) -print | wc -l`
-failures="`find ppd -name '*.ppd*' -print | xargs cupstestppd $cupstestppdopts |grep 'FAIL$' | awk -F: '{print $1}'`"
+failures="`find ppd -name '*.ppd*' -print | sort | xargs cupstestppd $cupstestppdopts |grep 'FAIL$' | awk -F: '{print $1}'`"
if [ -z "$failures" ] ; then
echo "All $ppd_count PPD files pass"
diff --git a/src/cups/test-rastertogutenprint.in b/src/cups/test-rastertogutenprint.in
index 533063d..373f127 100755
--- a/src/cups/test-rastertogutenprint.in
+++ b/src/cups/test-rastertogutenprint.in
@@ -27,6 +27,7 @@ make_ppds=1
md5dir=''
outdir=''
cupsargs=''
+postscript=''
npages=3
usage() {
@@ -48,6 +49,7 @@ set_args() {
-o|--option) shift; cupsargs="$cupsargs $1" ;;
-m|--md5dir) shift; md5dir="$1" ;;
-p|--pages) shift; npages="$1" ;;
+ -P|--postscript) shift; postscript=1 ;;
--) shift; args="$@"; return ;;
*) return ;;
esac
@@ -64,15 +66,18 @@ if [ -n "$md5dir" -a ! -d "$md5dir" ] ; then
mkdir -p "$md5dir"
fi
-version="@GUTENPRINT_MAJOR_VERSION@.@GUTENPRINT_MINOR_VERSION@";
-cupsdir="@cups_conf_serverbin@/filter"
+version="5.2";
+cupsdir="/usr/lib/cups/filter"
if [ -x "$cupsdir/pstoraster" -o -x "$cupsdir/gstoraster" -o -x "$cupsdir/cgpdftoraster" ] ; then
- pages="page-ranges=24-`expr 24 + $npages - 1` "
+ pages="24-`expr 24 + $npages - 1`"
+ if [ -n "$postscript" ] ; then
+ pages="page-ranges=$pages"
+ fi
else
pages=''
fi
-if [ ! -x "$cupsdir/cgpdftoraster" -a ! -x "$cupsdir/pdftops" ] ; then
+if [ ! -x "$cupsdir/cgpdftoraster" -a ! -x "$cupsdir/pdftops" -a ! -x "$cupsdir/gstoraster" ] ; then
echo 'CUPS does not appear to be installed, skipping test'
exit 0
fi
@@ -84,17 +89,28 @@ cleanup() {
exit 1
}
-pdftops="`type -p pdftops`"
-
-if [ ! -n "$pdftops" -o ! -x "$pdftops" ] ; then
- pdftops="`whence pdftops`"
+pdfjam="`which pdfjam`"
+if [ -z "$pdfjam" ] ; then
+ postscript=1
fi
-if [ -n "$pdftops" -a ! -x "$cupsdir/cgpdftoraster" ] ; then
+if [ -n "$postscript" ] ; then
+ pdftops="`type -p pdftops`"
+
+ if [ ! -n "$pdftops" -o ! -x "$pdftops" ] ; then
+ pdftops="`whence pdftops`"
+ fi
+
+ if [ -n "$pdftops" -a ! -x "$cupsdir/cgpdftoraster" ] ; then
+ tfile=`mktemp`
+ trap cleanup 1 2 3 6 14 15 30
+ "$pdftops" -f 24 -l `expr 24 + $npages - 1` "$sdir/../../doc/gutenprint-users-manual.pdf" $tfile
+ fi
+else
tfile=`mktemp`
trap cleanup 1 2 3 6 14 15 30
- $pdftops -f 24 -l `expr 24 + $npages - 1` "$sdir/../../doc/gutenprint-users-manual.pdf" $tfile
-fi
+ "$pdfjam" -q "$sdir/../../doc/gutenprint-users-manual.pdf" "$pages" -o $tfile
+fi
if [ -z "$verbose" ] ; then
STP_SUPPRESS_MESSAGES=1