summaryrefslogtreecommitdiff
path: root/src/cups
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2015-10-19 10:40:17 +0200
committerDidier Raboud <odyx@debian.org>2015-10-19 10:40:17 +0200
commit82a5e2a21f1cc4ea142514a1a045a63158f10256 (patch)
tree43bb3f0d058d6f632c273f1073708f2017b6d1bb /src/cups
parent92976f71a4aa7f84cd8aadf013d2b03873dead7c (diff)
Imported Upstream version 5.2.11~pre2
Diffstat (limited to 'src/cups')
-rw-r--r--src/cups/Makefile.am4
-rw-r--r--src/cups/Makefile.in40
-rw-r--r--src/cups/backend_common.c433
-rw-r--r--src/cups/backend_common.h69
-rw-r--r--src/cups/blacklist3
-rw-r--r--src/cups/citizencw01_print.c65
-rw-r--r--src/cups/dnpds40_print.c541
-rw-r--r--src/cups/genppd.c69
-rw-r--r--src/cups/kodak1400_print.c30
-rw-r--r--src/cups/kodak605_print.c548
-rw-r--r--src/cups/kodak6800_print.c1186
-rw-r--r--src/cups/mitsu70x_print.c38
-rw-r--r--src/cups/mitsu9550_print.c88
-rw-r--r--src/cups/selphy_print.c92
-rw-r--r--src/cups/shinko_s1245_print.c1621
-rw-r--r--src/cups/shinko_s2145_print.c344
-rw-r--r--src/cups/shinko_s6245_print.c1863
-rw-r--r--src/cups/sony_updr150_print.c36
-rwxr-xr-x[-rw-r--r--]src/cups/test-ppds2
-rwxr-xr-xsrc/cups/test-rastertogutenprint.in31
20 files changed, 5362 insertions, 1741 deletions
diff --git a/src/cups/Makefile.am b/src/cups/Makefile.am
index 7bd6cd9..d4789ad 100644
--- a/src/cups/Makefile.am
+++ b/src/cups/Makefile.am
@@ -1,4 +1,4 @@
-## $Id: Makefile.am,v 1.150 2015/01/10 14:27:55 speachy Exp $
+## $Id: Makefile.am,v 1.151 2015/10/05 13:55:40 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 citizencw01_print.c mitsu9550_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 shinko_s1245_print.c shinko_s6245_print.c
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 c5b156b..2074e88 100644
--- a/src/cups/Makefile.in
+++ b/src/cups/Makefile.in
@@ -129,7 +129,7 @@ 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 \
citizencw01_print.c mitsu9550_print.c backend_common.c \
- backend_common.h
+ backend_common.h shinko_s1245_print.c shinko_s6245_print.c
@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) \
@@ -140,7 +140,9 @@ am__backend_gutenprint_SOURCES_DIST = selphy_print.c kodak1400_print.c \
@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)
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_common.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-shinko_s1245_print.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-shinko_s6245_print.$(OBJEXT)
backend_gutenprint_OBJECTS = $(am_backend_gutenprint_OBJECTS)
am__DEPENDENCIES_1 =
@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_DEPENDENCIES = \
@@ -508,6 +510,8 @@ ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ENABLE_SHARED = @ENABLE_SHARED@
+ENABLE_STATIC = @ENABLE_STATIC@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
FIND = @FIND@
@@ -719,7 +723,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 citizencw01_print.c mitsu9550_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 shinko_s1245_print.c shinko_s6245_print.c
@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
@@ -1117,7 +1121,9 @@ distclean-compile:
@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_s1245_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-shinko_s6245_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-sony_updr150_print.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandtocanon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandtoepson.Po@am__quote@
@@ -1304,6 +1310,34 @@ backend_gutenprint-backend_common.obj: backend_common.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-backend_common.obj `if test -f 'backend_common.c'; then $(CYGPATH_W) 'backend_common.c'; else $(CYGPATH_W) '$(srcdir)/backend_common.c'; fi`
+backend_gutenprint-shinko_s1245_print.o: shinko_s1245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-shinko_s1245_print.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Tpo -c -o backend_gutenprint-shinko_s1245_print.o `test -f 'shinko_s1245_print.c' || echo '$(srcdir)/'`shinko_s1245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Tpo $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shinko_s1245_print.c' object='backend_gutenprint-shinko_s1245_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-shinko_s1245_print.o `test -f 'shinko_s1245_print.c' || echo '$(srcdir)/'`shinko_s1245_print.c
+
+backend_gutenprint-shinko_s1245_print.obj: shinko_s1245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-shinko_s1245_print.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Tpo -c -o backend_gutenprint-shinko_s1245_print.obj `if test -f 'shinko_s1245_print.c'; then $(CYGPATH_W) 'shinko_s1245_print.c'; else $(CYGPATH_W) '$(srcdir)/shinko_s1245_print.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Tpo $(DEPDIR)/backend_gutenprint-shinko_s1245_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shinko_s1245_print.c' object='backend_gutenprint-shinko_s1245_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-shinko_s1245_print.obj `if test -f 'shinko_s1245_print.c'; then $(CYGPATH_W) 'shinko_s1245_print.c'; else $(CYGPATH_W) '$(srcdir)/shinko_s1245_print.c'; fi`
+
+backend_gutenprint-shinko_s6245_print.o: shinko_s6245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-shinko_s6245_print.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Tpo -c -o backend_gutenprint-shinko_s6245_print.o `test -f 'shinko_s6245_print.c' || echo '$(srcdir)/'`shinko_s6245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Tpo $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shinko_s6245_print.c' object='backend_gutenprint-shinko_s6245_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-shinko_s6245_print.o `test -f 'shinko_s6245_print.c' || echo '$(srcdir)/'`shinko_s6245_print.c
+
+backend_gutenprint-shinko_s6245_print.obj: shinko_s6245_print.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-shinko_s6245_print.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Tpo -c -o backend_gutenprint-shinko_s6245_print.obj `if test -f 'shinko_s6245_print.c'; then $(CYGPATH_W) 'shinko_s6245_print.c'; else $(CYGPATH_W) '$(srcdir)/shinko_s6245_print.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Tpo $(DEPDIR)/backend_gutenprint-shinko_s6245_print.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='shinko_s6245_print.c' object='backend_gutenprint-shinko_s6245_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-shinko_s6245_print.obj `if test -f 'shinko_s6245_print.c'; then $(CYGPATH_W) 'shinko_s6245_print.c'; else $(CYGPATH_W) '$(srcdir)/shinko_s6245_print.c'; fi`
+
cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.o: genppd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -MT cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.o -MD -MP -MF $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Tpo -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.o `test -f 'genppd.c' || echo '$(srcdir)/'`genppd.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Tpo $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
diff --git a/src/cups/backend_common.c b/src/cups/backend_common.c
index 0a2aaba..02aa923 100644
--- a/src/cups/backend_common.c
+++ b/src/cups/backend_common.c
@@ -27,19 +27,41 @@
#include "backend_common.h"
-#define BACKEND_VERSION "0.54G"
+#define BACKEND_VERSION "0.62G"
#ifndef URI_PREFIX
#error "Must Define URI_PREFIX"
#endif
-/* Global variables */
+#define NUM_CLAIM_ATTEMPTS 10
+
+/* Global Variables */
int dyesub_debug = 0;
+int terminate = 0;
+int fast_return = 0;
int extra_vid = -1;
int extra_pid = -1;
int extra_type = -1;
+int copies = 1;
char *use_serno = NULL;
+int current_page = 0;
/* Support Functions */
+static int backend_claim_interface(struct libusb_device_handle *dev, int iface)
+{
+ int attempts = NUM_CLAIM_ATTEMPTS;
+ int ret;
+ do {
+ ret = libusb_claim_interface(dev, iface);
+ if (!ret)
+ break;
+ sleep(1);
+ } while (--attempts > 0);
+
+ if (ret)
+ ERROR("Printer open failure (Could not claim printer interface after %d attempts) (%d)\n", NUM_CLAIM_ATTEMPTS, ret);
+
+ return ret;
+}
#define ID_BUF_SIZE 2048
static char *get_device_id(struct libusb_device_handle *dev)
@@ -56,7 +78,8 @@ static char *get_device_id(struct libusb_device_handle *dev)
if (libusb_kernel_driver_active(dev, iface))
libusb_detach_kernel_driver(dev, iface);
- libusb_claim_interface(dev, iface);
+ if (backend_claim_interface(dev, iface))
+ return NULL;
if (libusb_control_transfer(dev,
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_ENDPOINT_IN |
@@ -97,7 +120,6 @@ done:
}
/* Used with the IEEE1284 deviceid string parsing */
-
struct deviceid_dict {
char *key;
char *val;
@@ -112,6 +134,9 @@ static int parse1284_data(const char *device_id, struct deviceid_dict* dict)
char val[256];
int num = 0;
+ if (!device_id)
+ return 0;
+
//[whitespace]key[whitespace]:[whitespace]value[whitespace];
while (*device_id && num < MAX_DICT) {
/* Skip leading spaces */
@@ -165,7 +190,6 @@ static char *dict_find(const char *key, int dlen, struct deviceid_dict* dict)
}
/* I/O functions */
-
int read_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int buflen, int *readlen)
{
@@ -254,8 +278,6 @@ int send_data(struct libusb_device_handle *dev, uint8_t endp,
}
/* More stuff */
-int terminate = 0;
-
static void sigterm_handler(int signum) {
UNUSED(signum);
@@ -339,7 +361,7 @@ static char *url_decode(char *str) {
static int print_scan_output(struct libusb_device *device,
struct libusb_device_descriptor *desc,
char *prefix, char *manuf2,
- int found, int match,
+ int found,
int scan_only, char *match_serno,
struct dyesub_backend *backend)
{
@@ -411,7 +433,11 @@ static int print_scan_output(struct libusb_device *device,
descr = malloc(256);
if (!descr) {
ERROR("Memory allocation failure (%d bytes)\n", 256);
- return found;
+ if (manuf3)
+ free(manuf3);
+ if (product2)
+ free(product2);
+ return -1;
}
sprintf(descr, "%s %s", manuf3, product2);
@@ -434,17 +460,16 @@ static int print_scan_output(struct libusb_device *device,
serial = url_encode(buf);
} else if (backend->query_serno) { /* Get from backend hook */
int iface = 0;
+
struct libusb_config_descriptor *config;
if (libusb_kernel_driver_active(dev, iface))
libusb_detach_kernel_driver(dev, iface);
- /* If we fail to claim the printer, it's already in use
- so we should just skip over it... */
- buf[0] = 0;
- if (!libusb_claim_interface(dev, iface)) {
+ /* Try to claim the printer, and handle transient failures */
+ if (!backend_claim_interface(dev, iface)) {
int i;
- uint8_t endp_up, endp_down;
+ uint8_t endp_up = 0, endp_down = 0;
libusb_get_active_config_descriptor(device, &config);
for (i = 0 ; i < config->interface[0].altsetting[0].bNumEndpoints ; i++) {
if ((config->interface[0].altsetting[0].endpoint[i].bmAttributes & 3) == LIBUSB_TRANSFER_TYPE_BULK) {
@@ -455,6 +480,7 @@ static int print_scan_output(struct libusb_device *device,
}
}
+ buf[0] = 0;
/* Ignore result since a failure isn't critical here */
backend->query_serno(dev, endp_up, endp_down, buf, STR_LEN_MAX);
libusb_release_interface(dev, iface);
@@ -471,8 +497,7 @@ static int print_scan_output(struct libusb_device *device,
}
if (dyesub_debug)
- DEBUG("%sVID: %04X PID: %04X Manuf: '%s' Product: '%s' Serial: '%s'\n",
- match ? "MATCH: " : "",
+ DEBUG("VID: %04X PID: %04X Manuf: '%s' Product: '%s' Serial: '%s'\n",
desc->idVendor, desc->idProduct, manuf, product, serial);
if (scan_only) {
@@ -518,12 +543,29 @@ abort:
return found;
}
+extern struct dyesub_backend updr150_backend;
+extern struct dyesub_backend kodak6800_backend;
+extern struct dyesub_backend kodak605_backend;
+extern struct dyesub_backend kodak1400_backend;
+extern struct dyesub_backend shinkos1245_backend;
+extern struct dyesub_backend shinkos2145_backend;
+extern struct dyesub_backend shinkos6145_backend;
+extern struct dyesub_backend shinkos6245_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;
+
static struct dyesub_backend *backends[] = {
&canonselphy_backend,
&kodak6800_backend,
&kodak605_backend,
&kodak1400_backend,
+ &shinkos1245_backend,
&shinkos2145_backend,
+// &shinkos6145_backend,
+ &shinkos6245_backend,
&updr150_backend,
&mitsu70x_backend,
&mitsu9550_backend,
@@ -536,11 +578,10 @@ static int find_and_enumerate(struct libusb_context *ctx,
struct libusb_device ***list,
struct dyesub_backend *backend,
char *match_serno,
- int printer_type,
int scan_only)
{
int num;
- int i, j, k;
+ int i, j = 0, k;
int found = -1;
/* Enumerate and find suitable device */
@@ -548,45 +589,36 @@ static int find_and_enumerate(struct libusb_context *ctx,
for (i = 0 ; i < num ; i++) {
struct libusb_device_descriptor desc;
- int match = 0;
libusb_get_device_descriptor((*list)[i], &desc);
for (k = 0 ; backends[k] ; k++) {
if (backend && backend != backends[k])
continue;
for (j = 0 ; backends[k]->devices[j].vid ; j++) {
+ if (extra_pid != -1 &&
+ extra_vid != -1 &&
+ extra_type != -1) {
+ if (backends[k]->devices[j].type == extra_type &&
+ extra_vid == desc.idVendor &&
+ extra_pid == desc.idProduct) {
+ found = i;
+ goto match;
+ }
+ }
if (desc.idVendor == backends[k]->devices[j].vid &&
desc.idProduct == backends[k]->devices[j].pid) {
- match = 1;
- if (printer_type == P_ANY ||
- printer_type == backends[k]->devices[j].type)
- found = i;
+ found = i;
goto match;
}
}
}
- match:
- if (!match) {
- if (extra_pid != -1 &&
- extra_vid != -1 &&
- extra_type != -1) {
- if (extra_vid == desc.idVendor &&
- extra_pid == desc.idProduct) {
- match = 1;
- if (printer_type == P_ANY ||
- printer_type == extra_type)
- found = i;
- }
- }
- }
-
- if (!match)
- continue;
+ continue;
+ match:
found = print_scan_output((*list)[i], &desc,
URI_PREFIX, backends[k]->devices[j].manuf_str,
- found, (found == i),
+ found,
scan_only, match_serno,
backends[k]);
@@ -615,7 +647,7 @@ static struct dyesub_backend *find_backend(char *uri_prefix)
return NULL;
}
-static void print_license_blurb(void)
+void print_license_blurb(void)
{
const char *license = "\n\
Copyright 2007-2015 Solomon Peachy <pizza AT shaftnet DOT org>\n\
@@ -638,7 +670,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\
fprintf(stderr, "%s", license);
}
-static void print_help(char *argv0, struct dyesub_backend *backend)
+void print_help(char *argv0, struct dyesub_backend *backend)
{
struct libusb_context *ctx = NULL;
struct libusb_device **list = NULL;
@@ -655,21 +687,24 @@ static void print_help(char *argv0, struct dyesub_backend *backend)
if (!backend) {
int i;
+ DEBUG("Environment variables:\n");
+ DEBUG(" DYESUB_DEBUG EXTRA_PID EXTRA_VID EXTRA_TYPE BACKEND SERIAL\n");
DEBUG("CUPS Usage:\n");
DEBUG("\tDEVICE_URI=someuri %s job user title num-copies options [ filename ]\n", URI_PREFIX);
DEBUG("\n");
DEBUG("Standalone Usage:\n");
DEBUG("\t%s\n", URI_PREFIX);
- DEBUG(" [ -D ] [ -G ]\n");
- DEBUG(" [ -S serialnum ] [ -B backendname ] \n");
+ DEBUG(" [ -D ] [ -G ] [ -f ]\n");
+ DEBUG(" [ -S serialnum ] \n");
DEBUG(" [ -V extra_vid ] [ -P extra_pid ] [ -T extra_type ] \n");
DEBUG(" [ backend_specific_args ] \n");
- DEBUG(" [ -d copies ] [ - | infile ] \n");
+ DEBUG(" [ -d copies ] \n");
+ DEBUG(" [ - | infile ] \n");
for (i = 0; ; i++) {
backend = backends[i];
if (!backend)
break;
- DEBUG(" -B %s\t# %s version %s\n",
+ DEBUG(" BACKEND=%s\t# %s version %s\n",
backend->uri_prefix, backend->name, backend->version);
if (backend->cmdline_usage)
backend->cmdline_usage();
@@ -685,12 +720,13 @@ static void print_help(char *argv0, struct dyesub_backend *backend)
DEBUG("\t[ -d copies ] [ infile | - ]\n");
}
+ /* Probe for printers */
i = libusb_init(&ctx);
if (i) {
ERROR("Failed to initialize libusb (%d)\n", i);
exit(CUPS_BACKEND_STOP);
}
- find_and_enumerate(ctx, &list, backend, NULL, P_ANY, 1);
+ find_and_enumerate(ctx, &list, backend, NULL, 1);
libusb_free_device_list(list, 1);
libusb_exit(ctx);
}
@@ -712,18 +748,14 @@ int main (int argc, char **argv)
int i;
int claimed;
- int backend_cmd = 0;
int ret = CUPS_BACKEND_OK;
int iface = 0;
int found = -1;
- int copies = 1;
int jobid = 0;
- int pages = 0;
char *uri;
char *fname = NULL;
- int printer_type = P_ANY;
DEBUG("Multi-Call Dye-sublimation CUPS Backend version %s\n",
BACKEND_VERSION);
@@ -734,7 +766,7 @@ int main (int argc, char **argv)
/* First pass at cmdline parsing */
if (getenv("DYESUB_DEBUG"))
- dyesub_debug++;
+ dyesub_debug = atoi(getenv("DYESUB_DEBUG"));
if (getenv("EXTRA_PID"))
extra_pid = strtol(getenv("EXTRA_PID"), NULL, 16);
if (getenv("EXTRA_VID"))
@@ -743,114 +775,26 @@ int main (int argc, char **argv)
extra_type = atoi(getenv("EXTRA_TYPE"));
if (getenv("BACKEND"))
backend = find_backend(getenv("BACKEND"));
- use_serno = getenv("DEVICE");
- uri = getenv("DEVICE_URI"); /* For CUPS */
-
- /* Try to ensure we have a sane backend for standalone mode.
- CUPS mode uses 'uri' later on. */
- if (!backend) {
- char *ptr = strrchr(argv[0], '/');
- if (ptr)
- ptr++;
- else
- ptr = argv[0];
- backend = find_backend(ptr);
- }
-
- /* Reset arg parsing */
- optind = 1;
- opterr = 0;
- while ((i = getopt(argc, argv, "B:d:DGhP:S:T:V:")) >= 0) {
- switch(i) {
- case 'B':
- backend = find_backend(optarg);
- if (!backend) {
- fprintf(stderr, "ERROR: Unknown backend '%s'\n", optarg);
- }
- break;
- case 'd':
- copies = atoi(optarg);
- break;
- case 'D':
- dyesub_debug++;
- break;
- case 'G':
- print_license_blurb();
- exit(0);
- case 'h':
- print_help(argv[0], backend);
- exit(0);
- break;
- case 'P':
- extra_pid = strtol(optarg, NULL, 16);
- break;
- case 'S':
- use_serno = optarg;
- break;
- case 'T':
- extra_type = atoi(optarg);
- break;
- case 'V':
- extra_pid = strtol(optarg, NULL, 16);
- break;
- case '?':
- default: {
- /* Check to see if it is claimed by the backend */
- if (backend && backend->cmdline_arg) {
- int keep = optind;
- backend_cmd += backend->cmdline_arg(NULL, argc, argv);
- optind = keep;
- }
- break;
- }
- }
- }
+ if (getenv("FAST_RETURN"))
+ fast_return++;
+ use_serno = getenv("SERIAL");
+ uri = getenv("DEVICE_URI"); /* CUPS backend mode? */
-#ifndef LIBUSB_PRE_1_0_10
- if (dyesub_debug) {
- const struct libusb_version *ver;
- ver = libusb_get_version();
- DEBUG(" ** running with libusb %d.%d.%d%s (%d)\n",
- ver->major, ver->minor, ver->micro, (ver->rc? ver->rc : ""), ver->nano );
- }
-#endif
-
- /* Make sure a filename was specified */
- if (!backend_cmd && (optind == argc || !argv[optind])) {
- print_help(argv[0], backend);
- exit(0);
- }
-
- /* Are we running as a CUPS backend? */
if (uri) {
- int base = optind; // XXX aka 1.
- fname = argv[base + 5];
+ /* CUPS backend mode */
+ int base = optind; /* ie 1 */
+ if (argc < 6) {
+ ERROR("Insufficient arguments\n");
+ exit(1);
+ }
if (argv[base])
jobid = atoi(argv[base]);
if (argv[base + 3])
copies = atoi(argv[base + 3]);
- if (fname) { /* IOW, is it specified? */
- data_fd = open(fname, O_RDONLY);
- if (data_fd < 0) {
- perror("ERROR:Can't open input file");
- exit(1);
- }
- } else {
+ if (argc > 6)
+ fname = argv[base + 5];
+ else
fname = "-";
- }
-
- /* Ensure we're using BLOCKING I/O */
- i = fcntl(data_fd, F_GETFL, 0);
- if (i < 0) {
- perror("ERROR:Can't open input");
- exit(1);
- }
- i &= ~O_NONBLOCK;
- i = fcntl(data_fd, F_SETFL, 0);
- if (i < 0) {
- perror("ERROR:Can't open input");
- exit(1);
- }
/* Figure out backend based on URI */
{
@@ -884,46 +828,34 @@ int main (int argc, char **argv)
if (ptr)
*ptr = 0;
}
- } else {
- srand(getpid());
- jobid = rand();
- /* Grab the filename */
- fname = argv[optind];
+ /* Always enable fast return in CUPS mode */
+ fast_return++;
+ } else {
+ /* Standalone mode */
- if (!fname && !backend_cmd) {
- perror("ERROR:No input file");
- exit(1);
- }
- if (fname) {
- /* Open Input File */
- if (strcmp("-", fname)) {
- data_fd = open(fname, O_RDONLY);
- if (data_fd < 0) {
- perror("ERROR:Can't open input file");
- exit(1);
- }
- }
+ /* Try to guess backend from executable name */
+ if (!backend) {
+ char *ptr = strrchr(argv[0], '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr = argv[0];
+ backend = find_backend(ptr);
}
+
+ srand(getpid());
+ jobid = rand();
}
- /* Ignore SIGPIPE */
- signal(SIGPIPE, SIG_IGN);
- signal(SIGTERM, sigterm_handler);
-
- /* Initialize backend */
- DEBUG("Initializing '%s' backend (version %s)\n",
- backend->name, backend->version);
- backend_ctx = backend->init();
-
- /* Parse printjob if necessary */
- if (fname && backend->early_parse) {
- printer_type = backend->early_parse(backend_ctx, data_fd);
- if (printer_type < 0) {
- ret = CUPS_BACKEND_CANCEL;
- goto done;
- }
+#ifndef LIBUSB_PRE_1_0_10
+ if (dyesub_debug) {
+ const struct libusb_version *ver;
+ ver = libusb_get_version();
+ DEBUG(" ** running with libusb %d.%d.%d%s (%d)\n",
+ ver->major, ver->minor, ver->micro, (ver->rc? ver->rc : ""), ver->nano );
}
+#endif
/* Libusb setup */
ret = libusb_init(&ctx);
@@ -933,16 +865,30 @@ int main (int argc, char **argv)
goto done;
}
+ /* If we don't have a valid backend, print help and terminate */
+ if (!backend) {
+ print_help(argv[0], NULL); // probes all devices
+ exit(1);
+ }
+
+ /* If we're in standalone mode, print help only if no args */
+ if (!uri) {
+ if (argc < 2) {
+ print_help(argv[0], backend); // probes all devices
+ exit(1);
+ }
+ }
+
/* Enumerate devices */
- found = find_and_enumerate(ctx, &list, backend, use_serno, printer_type, 0);
+ found = find_and_enumerate(ctx, &list, backend, use_serno, 0);
-#if 1
if (found == -1) {
- ERROR("Printer open failure (No suitable printers found!)\n");
+ ERROR("Printer open failure (No matching printers found!)\n");
ret = CUPS_BACKEND_HOLD;
goto done;
}
+ /* Open an appropriate device */
ret = libusb_open(list[found], &dev);
if (ret) {
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
@@ -960,9 +906,8 @@ int main (int argc, char **argv)
}
}
- ret = libusb_claim_interface(dev, iface);
+ ret = backend_claim_interface(dev, iface);
if (ret) {
- ERROR("Printer open failure (Could not claim printer interface) (%d)\n", ret);
ret = CUPS_BACKEND_STOP;
goto done_close;
}
@@ -982,35 +927,69 @@ int main (int argc, char **argv)
endp_down = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
}
}
-#endif
+
+ /* Initialize backend */
+ DEBUG("Initializing '%s' backend (version %s)\n",
+ backend->name, backend->version);
+ backend_ctx = backend->init();
+
/* Attach backend to device */
backend->attach(backend_ctx, dev, endp_up, endp_down, jobid);
- if (backend_cmd && !uri) {
- if (backend->cmdline_arg(backend_ctx, argc, argv))
- goto done_claimed;
- if (!fname)
+ if (!uri) {
+ if (backend->cmdline_arg(backend_ctx, argc, argv) < 0)
goto done_claimed;
+
+ /* Grab the filename */
+ fname = argv[optind]; // XXX do this a smarter way?
}
+ if (!fname) {
+ if (uri)
+ fprintf(stderr, "ERROR: No input file specified\n");
+ goto done_claimed;
+ }
+
+ /* Open file if not STDIN */
+ if (strcmp("-", fname)) {
+ data_fd = open(fname, O_RDONLY);
+ if (data_fd < 0) {
+ perror("ERROR:Can't open input file");
+ exit(1);
+ }
+ }
+
+ /* Ensure we're using BLOCKING I/O */
+ i = fcntl(data_fd, F_GETFL, 0);
+ if (i < 0) {
+ perror("ERROR:Can't open input");
+ exit(1);
+ }
+ i &= ~O_NONBLOCK;
+ i = fcntl(data_fd, F_SETFL, i);
+ if (i < 0) {
+ perror("ERROR:Can't open input");
+ exit(1);
+ }
+
+ /* Ignore SIGPIPE */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+
/* Time for the main processing loop */
INFO("Printing started (%d copies)\n", copies);
newpage:
- /* Do early parsing if needed for subsequent pages */
- if (pages && backend->early_parse &&
- backend->early_parse(backend_ctx, data_fd) < 0)
- goto done_multiple;
/* Read in data */
if ((ret = backend->read_parse(backend_ctx, data_fd))) {
- if (pages)
+ if (current_page)
goto done_multiple;
else
goto done_claimed;
}
- INFO("Printing page %d\n", ++pages);
+ INFO("Printing page %d\n", ++current_page);
ret = backend->main_loop(backend_ctx, copies);
if (ret)
@@ -1025,7 +1004,7 @@ done_multiple:
close(data_fd);
/* Done printing */
- INFO("All printing done (%d pages * %d copies)\n", pages, copies);
+ INFO("All printing done (%d pages * %d copies)\n", current_page, copies);
ret = CUPS_BACKEND_OK;
done_claimed:
@@ -1050,3 +1029,47 @@ done:
return ret;
}
+int lookup_printer_type(struct dyesub_backend *backend, uint16_t idVendor, uint16_t idProduct)
+{
+ int i;
+ int type = -1;
+
+ for (i = 0 ; backend->devices[i].vid ; i++) {
+ if (extra_pid != -1 &&
+ extra_vid != -1 &&
+ extra_type != -1) {
+ if (backend->devices[i].type == extra_type &&
+ extra_vid == idVendor &&
+ extra_pid == idProduct) {
+ return extra_type;
+ }
+ }
+ if (idVendor == backend->devices[i].vid &&
+ idProduct == backend->devices[i].pid) {
+ return backend->devices[i].type;
+ }
+ }
+
+ return type;
+}
+
+uint16_t uint16_to_packed_bcd(uint16_t val)
+{
+ uint16_t bcd;
+ uint16_t i;
+
+ /* Handle from 0-9999 */
+ i = val % 10;
+ bcd = i;
+ val /= 10;
+ i = val % 10;
+ bcd |= (i << 4);
+ val /= 10;
+ i = val % 10;
+ bcd |= (i << 8);
+ val /= 10;
+ i = val % 10;
+ bcd |= (i << 12);
+
+ return bcd;
+}
diff --git a/src/cups/backend_common.h b/src/cups/backend_common.h
index 1a5c9f1..9b32071 100644
--- a/src/cups/backend_common.h
+++ b/src/cups/backend_common.h
@@ -91,7 +91,6 @@ enum {
P_ES1,
P_ES2_20,
P_ES3_30,
- P_ES40_CP790,
P_ES40,
P_CP790,
P_CP_XXX,
@@ -102,12 +101,17 @@ enum {
P_KODAK_605,
P_SHINKO_S2145,
P_SHINKO_S1245,
+ P_SHINKO_S6245,
+ P_SHINKO_S6145,
P_SONY_UPDR150,
P_SONY_UPCR10,
P_MITSU_D70X,
+ P_MITSU_K60,
P_MITSU_9550,
+ P_MITSU_9550S,
P_DNP_DS40,
P_DNP_DS80,
+ P_DNP_DS80D,
P_CITIZEN_CW01,
P_DNP_DSRX1,
P_DNP_DS620,
@@ -132,7 +136,6 @@ struct dyesub_backend {
uint8_t endp_up, uint8_t endp_down, uint8_t jobid);
void (*teardown)(void *ctx);
int (*cmdline_arg)(void *ctx, int argc, char **argv);
- int (*early_parse)(void *ctx, int data_fd);
int (*read_parse)(void *ctx, int data_fd);
int (*main_loop)(void *ctx, int copies);
int (*query_serno)(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len);
@@ -144,22 +147,27 @@ int send_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int len);
int read_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int buflen, int *readlen);
+int lookup_printer_type(struct dyesub_backend *backend, uint16_t idVendor, uint16_t idProduct);
-/* Exported data */
+void print_license_blurb(void);
+void print_help(char *argv0, struct dyesub_backend *backend);
+
+uint16_t uint16_to_packed_bcd(uint16_t val);
+
+/* Global data */
extern int terminate;
extern int dyesub_debug;
-
-/* External data */
-extern struct dyesub_backend updr150_backend;
-extern struct dyesub_backend kodak6800_backend;
-extern struct dyesub_backend kodak605_backend;
-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;
+extern int fast_return;
+extern int extra_vid;
+extern int extra_pid;
+extern int extra_type;
+extern int copies;
+extern char *use_serno;
+extern int current_page;
+
+#if defined(BACKEND)
+extern struct dyesub_backend BACKEND;
+#endif
/* CUPS compatibility */
#define CUPS_BACKEND_OK 0 /* Sucess */
@@ -171,4 +179,35 @@ extern struct dyesub_backend cw01_backend;
#define CUPS_BACKEND_RETRY 6 /* Retry later */
#define CUPS_BACKEND_RETRY_CURRENT 7 /* Retry immediately */
+/* Argument processing */
+#define GETOPT_LIST_GLOBAL "d:DfGhP:S:T:V:"
+#define GETOPT_PROCESS_GLOBAL \
+ case 'd': \
+ copies = atoi(optarg); \
+ break; \
+ case 'D': \
+ dyesub_debug++; \
+ break; \
+ case 'f': \
+ fast_return++; \
+ break; \
+ case 'G': \
+ print_license_blurb(); \
+ exit(0); \
+ case 'h': \
+ print_help(argv[0], &BACKEND); \
+ exit(0); \
+ case 'P': \
+ extra_pid = strtol(optarg, NULL, 16); \
+ break; \
+ case 'S': \
+ use_serno = optarg; \
+ break; \
+ case 'T': \
+ extra_type = atoi(optarg); \
+ break; \
+ case 'V': \
+ extra_pid = strtol(optarg, NULL, 16); \
+ break;
+
#endif /* __BACKEND_COMMON_H */
diff --git a/src/cups/blacklist b/src/cups/blacklist
index 420c485..b137624 100644
--- a/src/cups/blacklist
+++ b/src/cups/blacklist
@@ -132,6 +132,9 @@
# Sony UP-DR200
0x054c 0x035f blacklist
+# Sony UP-CR10L
+0x054c 0x0226 blacklist
+
# Mitsubishi CP-D70/CP-D707
0x06d3 0x3b30 blacklist
diff --git a/src/cups/citizencw01_print.c b/src/cups/citizencw01_print.c
index b99822c..37313b5 100644
--- a/src/cups/citizencw01_print.c
+++ b/src/cups/citizencw01_print.c
@@ -35,6 +35,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND cw01_backend
+
#include "backend_common.h"
#define USB_VID_CITIZEN 0x1343
@@ -68,6 +70,7 @@ struct cw01_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
uint8_t *databuf;
struct cw01_spool_hdr hdr;
@@ -296,12 +299,20 @@ 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;
+ 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);
+
+ ctx->type = lookup_printer_type(&cw01_backend,
+ desc.idVendor, desc.idProduct);
}
static void cw01_teardown(void *vctx) {
@@ -434,7 +445,8 @@ top:
free(resp);
resp = NULL;
- /* Set print quantity */
+ /* Set print quantity */ // XXX check against remaining print count
+
cw01_build_cmd(&cmd, "CNTRL", "QTY", 8);
snprintf(buf, sizeof(buf), "%07d\r", copies);
ret = cw01_do_cmd(ctx, &cmd, (uint8_t*) buf, 8);
@@ -498,7 +510,7 @@ top:
ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
return CUPS_BACKEND_FAILED;
- ptr += ctx->hdr.plane_len;
+ /* ptr += ctx->hdr.plane_len; */
/* Start print */
cw01_build_cmd(&cmd, "CNTRL", "START", 0);
@@ -506,18 +518,7 @@ top:
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;
- }
+ INFO("Print complete\n");
if (resp) free(resp);
@@ -822,38 +823,30 @@ static int cw01_cmdline_arg(void *vctx, int argc, char **argv)
struct cw01_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "inN:s")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "inN:s")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'i':
- if (ctx) {
- j = cw01_get_info(ctx);
- break;
- }
- return 1;
+ j = cw01_get_info(ctx);
+ break;
case 'n':
- if (ctx) {
- j = cw01_get_counters(ctx);
- break;
- }
- return 1;
+ j = cw01_get_counters(ctx);
+ break;
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;
+ j = cw01_clear_counter(ctx, optarg[0]);
+ break;
case 's':
- if (ctx) {
- j = cw01_get_status(ctx);
- break;
- }
- return 1;
+ j = cw01_get_status(ctx);
+ break;
default:
break; /* Ignore completely */
}
@@ -867,7 +860,7 @@ static int cw01_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend cw01_backend = {
.name = "Citizen CW-01",
- .version = "0.10",
+ .version = "0.12",
.uri_prefix = "citizencw01",
.cmdline_usage = cw01_cmdline,
.cmdline_arg = cw01_cmdline_arg,
diff --git a/src/cups/dnpds40_print.c b/src/cups/dnpds40_print.c
index 16e8ab1..47ff498 100644
--- a/src/cups/dnpds40_print.c
+++ b/src/cups/dnpds40_print.c
@@ -44,6 +44,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND dnpds40_backend
+
#include "backend_common.h"
#define USB_VID_CITIZEN 0x1343
@@ -82,6 +84,7 @@ struct dnpds40_ctx {
int cutter;
int can_rewind;
+ int manual_copies;
int supports_6x9;
int supports_2x6;
int supports_3x5x2;
@@ -90,6 +93,8 @@ struct dnpds40_ctx {
int supports_rewind;
int supports_standby;
int supports_6x4_5;
+ int supports_mqty_default;
+ int supports_iserial;
uint8_t *qty_offset;
uint8_t *buffctrl_offset;
@@ -328,6 +333,9 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
+ ctx->type = lookup_printer_type(&dnpds40_backend,
+ desc.idVendor, desc.idProduct);
+
{
/* Get Firmware Version */
struct dnpds40_cmd cmd;
@@ -343,7 +351,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->version = strdup((char*) resp);
/* Parse version */
- ptr = strtok((char*)resp, " .");
+ /* ptr = */ strtok((char*)resp, " .");
ptr = strtok(NULL, ".");
ctx->ver_major = atoi(ptr);
ptr = strtok(NULL, ".");
@@ -397,9 +405,8 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
#endif
/* Per-printer options */
- switch (desc.idProduct) {
- case USB_PID_DNP_DS40:
- ctx->type = P_DNP_DS40;
+ switch (ctx->type) {
+ case P_DNP_DS40:
ctx->supports_6x9 = 1;
if (FW_VER_CHECK(1,30))
ctx->supports_matte = 1;
@@ -410,31 +417,31 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
if (FW_VER_CHECK(1,51))
ctx->supports_fullcut = 1;
break;
- case USB_PID_DNP_DS80:
- ctx->type = P_DNP_DS80;
+ case P_DNP_DS80:
if (FW_VER_CHECK(1,30))
ctx->supports_matte = 1;
break;
- case USB_PID_DNP_DSRX1:
- ctx->type = P_DNP_DSRX1;
+ case P_DNP_DSRX1:
ctx->supports_matte = 1;
+ ctx->supports_mqty_default = 1; // 1.10 does. Maybe older too?
if (FW_VER_CHECK(1,10))
ctx->supports_2x6 = 1;
break;
- case USB_PID_DNP_DS620:
- ctx->type = P_DNP_DS620;
+ case 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_mqty_default = 1;
+ ctx->supports_rewind = 1;
ctx->supports_standby = 1;
+ ctx->supports_iserial = 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");
+ ERROR("Unknown vid/pid %04x/%04x (%d)\n", desc.idVendor, desc.idProduct, ctx->type);
return;
}
}
@@ -491,6 +498,7 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
matte = 0;
dpi = 0;
cutter = 0;
+ ctx->manual_copies = 0;
ctx->multicut = 0;
ctx->buffctrl_offset = ctx->qty_offset = ctx->multicut_offset = 0;
@@ -603,7 +611,7 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
if (y_ppm != 1920) {
ERROR("Incorrect horizontal resolution (%d), aborting!\n", y_ppm);
return CUPS_BACKEND_CANCEL;
- }
+ }
}
}
@@ -616,8 +624,8 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
}
if (!ctx->datalen)
- return CUPS_BACKEND_CANCEL;
-
+ return CUPS_BACKEND_CANCEL;
+
/* Figure out the number of buffers we need. Most only need one. */
if (ctx->multicut) {
ctx->buf_needed = 1;
@@ -668,12 +676,14 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
}
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;
}
+ /* Only 3.5x5 on 7x5 media can be rewound */
+ if (ctx->multicut == 1)
+ ctx->can_rewind = 1;
break;
case 300: //"6x4 (PC)"
if (ctx->multicut != 2) {
@@ -682,21 +692,27 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
}
break;
case 310: //"6x8 (A5)"
- ctx->can_rewind = 1;
if (ctx->multicut != 2 && ctx->multicut != 4 &&
- ctx->multicut != 27) {
+ ctx->multicut != 12 &&
+ ctx->multicut != 27 && ctx->multicut != 30) {
ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
return CUPS_BACKEND_CANCEL;
}
+ /* Only 6x4 on 6x8 media can be rewound */
+ if (ctx->multicut == 2)
+ ctx->can_rewind = 1;
break;
case 400: //"6x9 (A5W)"
- ctx->can_rewind = 1;
if (ctx->multicut != 2 && ctx->multicut != 4 &&
- ctx->multicut != 5 && ctx->multicut != 27 &&
+ ctx->multicut != 5 && ctx->multicut != 12 &&
+ 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;
}
+ /* Only 6x4 or 6x4.5 on 6x9 media can be rewound */
+ if (ctx->multicut == 2 || ctx->multicut == 30)
+ ctx->can_rewind = 1;
break;
case 500: //"8x10"
if (ctx->multicut < 6 || ctx->multicut == 7 ||
@@ -749,6 +765,11 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
ERROR("Printer only supports 2-inch cuts on 4x6 or 8x6 jobs!");
return CUPS_BACKEND_CANCEL;
}
+
+ /* Work around firmware bug on DS40 where if we run out
+ of media, we can't resume the job without losing the
+ cutter setting. XXX add version test? */
+ ctx->manual_copies = 1;
}
if (ctx->matte && !ctx->supports_matte) {
@@ -768,65 +789,15 @@ static int dnpds40_main_loop(void *vctx, int copies) {
uint8_t *ptr;
char buf[9];
int status;
+ int buf_needed;
if (!ctx)
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;
-
- 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) {
+ // XXX this breaks if ctx->manual_copies is set, but the job
+ // has a CNTRL QTY != 1
+ if (!ctx->manual_copies && copies > 1) {
snprintf(buf, sizeof(buf), "%07d\r", copies);
if (ctx->qty_offset) {
memcpy(ctx->qty_offset, buf, 8);
@@ -843,7 +814,7 @@ static int dnpds40_main_loop(void *vctx, int copies) {
if (ctx->supports_matte) {
snprintf(buf, sizeof(buf), "%08d", 1);
if (ctx->buffctrl_offset) {
- memcpy(ctx->qty_offset, buf, 8);
+ memcpy(ctx->buffctrl_offset, buf, 8);
} else {
dnpds40_build_cmd(&cmd, "CNTRL", "BUFFCNTRL", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
@@ -866,9 +837,11 @@ static int dnpds40_main_loop(void *vctx, int copies) {
}
#endif
+ buf_needed = ctx->buf_needed;
+
#ifdef MATTE_GLOSSY_2BUF
if (ctx->matte != ctx->last_matte)
- ctx->buf_needed = 2; /* Switching needs both buffers */
+ buf_needed = 2; /* Switching needs both buffers */
#endif
ctx->last_matte = ctx->matte;
@@ -888,25 +861,23 @@ static int dnpds40_main_loop(void *vctx, int copies) {
top:
- if (resp) free(resp);
-
/* Query status */
dnpds40_build_cmd(&cmd, "STATUS", "", 0);
+ if (resp) free(resp);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
status = atoi((char*)resp);
- free(resp);
/* Figure out what's going on */
switch(status) {
case 0: /* Idle; we can continue! */
- break;
case 1: /* Printing */
{
int bufs;
+ if (resp) free(resp);
/* Query buffer state */
dnpds40_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
@@ -917,8 +888,8 @@ top:
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);
+ if (bufs < buf_needed) {
+ INFO("Insufficient printer buffers (%d vs %d), retrying...\n", bufs, buf_needed);
sleep(1);
goto top;
}
@@ -952,7 +923,56 @@ top:
ERROR("Fatal Printer Error: %d => %s, halting queue!\n", status, dnpds40_statuses(status));
return CUPS_BACKEND_HOLD;
}
-
+
+ /* 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) {
+ /* Tell the printer we want to rewind, if possible. */
+ snprintf(buf, sizeof(buf), "%08d", ctx->multicut + 400);
+ memcpy(ctx->multicut_offset, buf, 8);
+
+ /* 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;
+
+ dnpds40_cleanup_string((char*)resp, len);
+ i = atoi((char*)resp+4);
+ }
+
+ /* 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");
+ }
+ }
+
/* Send the stream over as individual data chunks */
ptr = ctx->databuf;
@@ -962,7 +982,6 @@ top:
memcpy(buf, ptr + 24, 8);
i = atoi(buf) + 32;
-
if ((ret = send_data(ctx->dev, ctx->endp_down,
ptr, i)))
return CUPS_BACKEND_FAILED;
@@ -973,27 +992,26 @@ top:
/* Clean up */
if (terminate)
copies = 1;
-
+
INFO("Print complete (%d copies remaining)\n", copies - 1);
if (copies && --copies) {
+#ifdef MATTE_GLOSSY_2BUF
+ /* No need to wait on buffers due to matte switching */
+ buf_needed = ctx->buf_needed;
+#endif
goto top;
}
return CUPS_BACKEND_OK;
}
-static int dnpds40_get_info(struct dnpds40_ctx *ctx)
+static int dnpds40_get_sensors(struct dnpds40_ctx *ctx)
{
struct dnpds40_cmd cmd;
uint8_t *resp;
int len = 0;
-
- /* Serial number already queried */
- INFO("Serial Number: '%s'\n", ctx->serno);
-
- /* Firmware version already queried */
- INFO("Firmware Version: '%s'\n", ctx->version);
+ char *tok;
/* Get Sensor Info */
dnpds40_build_cmd(&cmd, "INFO", "SENSOR", 0);
@@ -1003,33 +1021,72 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
return CUPS_BACKEND_FAILED;
dnpds40_cleanup_string((char*)resp, len);
- 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);
+ tok = strtok((char*)resp, "; -");
+ do {
+ char *val = strtok(NULL, "; -");
+
+ if (!strcmp("HDT", tok)) {
+ INFO("Head Temperature : %s\n", val);
+ } else if (!strcmp("MDT", tok)) {
+ INFO("Media Temperature : %s\n", val);
+ } else if (!strcmp("PMK", tok)) {
+ INFO("Paper Mark : %s\n", val);
+ } else if (!strcmp("RML", tok)) {
+ INFO("Ribbon Mark Left : %s\n", val);
+ } else if (!strcmp("RMC", tok)) {
+ INFO("Ribbon Mark Right : %s\n", val);
+ } else if (!strcmp("RMR", tok)) {
+ INFO("Ribbon Mark Center : %s\n", val);
+ } else if (!strcmp("PSZ", tok)) {
+ INFO("Paper Size : %s\n", val);
+ } else if (!strcmp("PNT", tok)) {
+ INFO("Paper Notch : %s\n", val);
+ } else if (!strcmp("PJM", tok)) {
+ INFO("Paper Jam : %s\n", val);
+ } else if (!strcmp("PED", tok)) {
+ INFO("Paper End : %s\n", val);
+ } else if (!strcmp("PET", tok)) {
+ INFO("Paper Empty : %s\n", val);
+ } else if (!strcmp("HDV", tok)) {
+ INFO("Head Voltage : %s\n", val);
+ } else if (!strcmp("HMD", tok)) {
+ INFO("Humidity : %s\n", val);
+ } else if (!strcmp("RP1", tok)) {
+ INFO("Roll Paper End 1 : %s\n", val);
+ } else if (!strcmp("RP2", tok)) {
+ INFO("Roll Paper End 2 : %s\n", val);
+ } else if (!strcmp("GSR", tok)) {
+ INFO("Color Sensor Red : %s\n", val);
+ } else if (!strcmp("GSG", tok)) {
+ INFO("Color Sensor Green : %s\n", val);
+ } else if (!strcmp("GSB", tok)) {
+ INFO("Color Sensor Blue : %s\n", val);
+ } else {
+ INFO("Unknown Sensor: '%s' '%s'\n",
+ tok, val);
+ }
+ } while ((tok = strtok(NULL, "; -")) != NULL);
- /* Get Horizonal resolution */
- dnpds40_build_cmd(&cmd, "INFO", "RESOLUTION_H", 0);
+ free(resp);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_OK;
+}
- dnpds40_cleanup_string((char*)resp, len);
+static int dnpds40_get_info(struct dnpds40_ctx *ctx)
+{
+ struct dnpds40_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
- INFO("Horizontal Resolution: '%s' dpi\n", (char*)resp + 3);
+ /* Serial number already queried */
+ INFO("Serial Number: '%s'\n", ctx->serno);
- free(resp);
+ /* Firmware version already queried */
+ INFO("Firmware Version: '%s'\n", ctx->version);
- /* Get Vertical resolution */
- dnpds40_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
+ /* Get Media Color offset */
+ dnpds40_build_cmd(&cmd, "INFO", "MCOLOR", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
@@ -1037,12 +1094,13 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
dnpds40_cleanup_string((char*)resp, len);
- INFO("Vertical Resolution: '%s' dpi\n", (char*)resp + 3);
+ INFO("Media Color Offset: '%02x%02x%02x%02x'\n", *(resp+2), *(resp+3),
+ *(resp+4), *(resp+5));
free(resp);
- /* Get Media Color offset */
- dnpds40_build_cmd(&cmd, "INFO", "MCOLOR", 0);
+ /* Get Media Class */
+ dnpds40_build_cmd(&cmd, "INFO", "MEDIA_CLASS", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
@@ -1050,8 +1108,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
dnpds40_cleanup_string((char*)resp, len);
- INFO("Media Color Offset: '%02x%02x%02x%02x'\n", *(resp+2), *(resp+3),
- *(resp+4), *(resp+5));
+ INFO("Media Class: '%s'\n", (char*)resp);
free(resp);
@@ -1085,87 +1142,74 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
free(resp);
- if (ctx->type == P_DNP_DS620) {
- /* Loop through control data versions and checksums */
-
- /* 300 DPI */
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Version", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- dnpds40_cleanup_string((char*)resp, len);
-
- INFO("300 DPI Color Data Version: '%s' ", (char*)resp);
-
- free(resp);
+ /* Get Ribbon ID code (?) */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "RIBBON_ID_CODE", 0);
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Checksum", 0);
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
- 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("Ribbon ID(?): '%s'\n", (char*)resp+4);
- INFO("Checksum: '%s'\n", (char*)resp);
+ free(resp);
- free(resp);
+ /* Figure out control data and checksums */
- /* 600 DPI */
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD600_Version", 0);
+ /* 300 DPI */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Version", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
+ 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("600 DPI Color Data Version: '%s' ", (char*)resp);
+ INFO("300 DPI Color Data Version: '%s' ", (char*)resp);
- free(resp);
+ free(resp);
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD600_Checksum", 0);
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD300_Checksum", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
+ 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("Checksum: '%s'\n", (char*)resp);
+ DEBUG2("Checksum: '%s'\n", (char*)resp);
- free(resp);
+ free(resp);
- /* "Low Speed" */
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Version", 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;
+ 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("Low Speed Color Data Version: '%s' ", (char*)resp);
+ INFO("600 DPI Color Data Version: '%s' ", (char*)resp);
- free(resp);
+ free(resp);
- dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Checksum", 0);
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD600_Checksum", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
+ 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("Checksum: '%s'\n", (char*)resp);
+ DEBUG2("Checksum: '%s'\n", (char*)resp);
- free(resp);
+ free(resp);
- } else {
- /* Get Color Control Data Version */
- dnpds40_build_cmd(&cmd, "TBL_RD", "Version", 0);
+ if (ctx->type == P_DNP_DS620) {
+ /* "Low Speed" */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Version", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
@@ -1173,12 +1217,11 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
dnpds40_cleanup_string((char*)resp, len);
- INFO("Color Data Version: '%s'\n", (char*)resp);
+ INFO("Low Speed Color Data Version: '%s' ", (char*)resp);
free(resp);
- /* Get Color Control Data Checksum */
- dnpds40_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
+ dnpds40_build_cmd(&cmd, "TBL_RD", "CWD610_Checksum", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
if (!resp)
@@ -1186,7 +1229,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
dnpds40_cleanup_string((char*)resp, len);
- INFO("Color Data Checksum: '%s'\n", (char*)resp);
+ DEBUG2("Checksum: '%s'\n", (char*)resp);
free(resp);
}
@@ -1217,7 +1260,9 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
INFO("Media End kept across power cycles: '%s'\n", (char*)resp);
free(resp);
+ }
+ if (ctx->supports_iserial) {
/* Get USB serial descriptor status */
dnpds40_build_cmd(&cmd, "MNT_RD", "USB_ISERI_SET", 0);
@@ -1284,7 +1329,7 @@ static int dnpds40_get_status(struct dnpds40_ctx *ctx)
/* Report media */
INFO("Media Type: '%s'\n", dnpds40_media_types(ctx->media));
- if (ctx->supports_rewind) {
+ if (ctx->supports_mqty_default) {
/* Get Media remaining */
dnpds40_build_cmd(&cmd, "INFO", "MQTY_DEFAULT", 0);
@@ -1460,6 +1505,38 @@ static int dnpds620_standby_mode(struct dnpds40_ctx *ctx, int delay)
return 0;
}
+static int dnpds620_media_keep_mode(struct dnpds40_ctx *ctx, int delay)
+{
+ struct dnpds40_cmd cmd;
+ char msg[9];
+ int ret;
+
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "MNT_WT", "END_KEEP_MODE", 4);
+ snprintf(msg, sizeof(msg), "%02d\r", delay);
+
+ if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)msg, 4)))
+ return ret;
+
+ return 0;
+}
+
+static int dnpds620_iserial_mode(struct dnpds40_ctx *ctx, int enable)
+{
+ struct dnpds40_cmd cmd;
+ char msg[9];
+ int ret;
+
+ /* Generate command */
+ dnpds40_build_cmd(&cmd, "MNT_WT", "USB_ISERI_SET", 4);
+ snprintf(msg, sizeof(msg), "%02d\r", enable);
+
+ 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;
@@ -1480,12 +1557,14 @@ static int dnpds40_set_counter_p(struct dnpds40_ctx *ctx, char *arg)
static void dnpds40_cmdline(void)
{
DEBUG("\t\t[ -i ] # Query printer info\n");
+ DEBUG("\t\t[ -I ] # Query sensor 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");
DEBUG("\t\t[ -p num ] # Set counter P\n");
- DEBUG("\t\t[ -S num ] # Set standby time (1-99 minutes, 0 disables)\n");
-
+ DEBUG("\t\t[ -k num ] # Set standby time (1-99 minutes, 0 disables)\n");
+ DEBUG("\t\t[ -K num ] # Keep Media Status Across Power Cycles (1 on, 0 off)\n");
+ DEBUG("\t\t[ -x num ] # Set USB iSerialNumber Reporting (1 on, 0 off)\n");
}
static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
@@ -1493,64 +1572,86 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
struct dnpds40_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "inN:p:sS:")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "iInN:p:sK:k:")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'i':
- if (ctx) {
- j = dnpds40_get_info(ctx);
- break;
- }
- return 1;
+ j = dnpds40_get_info(ctx);
+ break;
+ case 'I':
+ j = dnpds40_get_sensors(ctx);
+ break;
case 'n':
- if (ctx) {
- j = dnpds40_get_counters(ctx);
- break;
- }
- return 1;
+ j = dnpds40_get_counters(ctx);
+ break;
case 'N':
if (optarg[0] != 'A' &&
optarg[0] != 'B' &&
optarg[0] != 'M')
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;
+ if (!ctx->supports_matte) {
+ ERROR("Printer FW does not support matte functions, please update!\n");
+ return CUPS_BACKEND_FAILED;
}
- return 1;
+ j = dnpds40_clear_counter(ctx, optarg[0]);
+ break;
case 'p':
- if (ctx) {
- j = dnpds40_set_counter_p(ctx, optarg);
+ j = dnpds40_set_counter_p(ctx, optarg);
+ break;
+ case 's':
+ j = dnpds40_get_status(ctx);
+ break;
+ case 'k': {
+ int time = atoi(optarg);
+ if (!ctx->supports_standby) {
+ ERROR("Printer does not support standby\n");
+ j = -1;
break;
}
- return 1;
- case 's':
- if (ctx) {
- j = dnpds40_get_status(ctx);
+ if (time < 0 || time > 99) {
+ ERROR("Value out of range (0-99)");
+ j = -1;
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);
+ j = dnpds620_standby_mode(ctx, time);
+ break;
+ }
+ case 'K': {
+ int keep = atoi(optarg);
+ if (!ctx->supports_standby) {
+ ERROR("Printer does not support media keep mode\n");
+ j = -1;
+ break;
+ }
+ if (keep < 0 || keep > 1) {
+ ERROR("Value out of range (0-1)");
+ j = -1;
+ break;
}
+ j = dnpds620_media_keep_mode(ctx, keep);
+ break;
+ }
+ case 'x': {
+ int enable = atoi(optarg);
+ if (!ctx->supports_iserial) {
+ ERROR("Printer does not support USB iSerialNumber reporting\n");
+ j = -1;
+ break;
+ }
+ if (enable < 0 || enable > 1) {
+ ERROR("Value out of range (0-1)");
+ j = -1;
+ break;
+ }
+ j = dnpds620_iserial_mode(ctx, enable);
+ break;
+ }
default:
break; /* Ignore completely */
}
@@ -1564,7 +1665,7 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend dnpds40_backend = {
.name = "DNP DS40/DS80/DSRX1/DS620",
- .version = "0.51",
+ .version = "0.61",
.uri_prefix = "dnpds40",
.cmdline_usage = dnpds40_cmdline,
.cmdline_arg = dnpds40_cmdline_arg,
diff --git a/src/cups/genppd.c b/src/cups/genppd.c
index e868444..8633611 100644
--- a/src/cups/genppd.c
+++ b/src/cups/genppd.c
@@ -1,5 +1,5 @@
/*
- * "$Id: genppd.c,v 1.197 2015/06/25 01:48:02 speachy Exp $"
+ * "$Id: genppd.c,v 1.204 2015/09/13 14:37:16 speachy Exp $"
*
* PPD file generation program for the CUPS drivers.
*
@@ -579,8 +579,6 @@ main(int argc, /* I - Number of command-line arguments */
models[n] = argv[optind+n];
}
models[numargs] = (char*)NULL;
-
- n=0;
}
/*
@@ -1144,12 +1142,13 @@ print_ppd_header(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
}
static void
-print_ppd_header_3(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
- const char *family, const char *long_name,
- const char *manufacturer, const char *device_id,
- const char *ppd_location,
- const char *language, const stp_string_list_t *po,
- char **all_langs)
+print_ppd_header_3(gpFile fp, ppd_type_t ppd_type, int model,
+ const char *driver,
+ const char *family, const char *long_name,
+ const char *manufacturer, const char *device_id,
+ const char *ppd_location,
+ const char *language, const stp_string_list_t *po,
+ char **all_langs)
{
int i;
gpputs(fp, "*FileSystem: False\n");
@@ -1157,7 +1156,7 @@ print_ppd_header_3(gpFile fp, ppd_type_t ppd_type, int model, const char *driver
gpputs(fp, "*TTRasterizer: Type42\n");
gpputs(fp, "*cupsVersion: 1.2\n");
- gpputs(fp, "*cupsManualCopies: True\n");
+
gpprintf(fp, "*cupsFilter: \"application/vnd.cups-raster 100 rastertogutenprint.%s\"\n", GUTENPRINT_RELEASE_VERSION);
if (strcasecmp(manufacturer, "EPSON") == 0)
gpputs(fp, "*cupsFilter: \"application/vnd.cups-command 33 commandtoepson\"\n");
@@ -1946,6 +1945,7 @@ write_ppd(
const char *manufacturer; /* Manufacturer of printer */
const char *device_id; /* IEEE1284 device ID */
const stp_vars_t *printvars; /* Printer option names */
+ int nativecopies = 0; /* Printer natively generates copies */
stp_parameter_t desc;
stp_parameter_list_t param_list;
const stp_param_string_t *opt;
@@ -2004,9 +2004,21 @@ write_ppd(
}
stp_parameter_description_destroy(&desc);
- print_ppd_header_3(fp, ppd_type, model, driver, family, long_name,
- manufacturer, device_id, ppd_location, language, po,
- all_langs);
+ stp_describe_parameter(v, "NativeCopies", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_BOOLEAN)
+ nativecopies = stp_get_boolean_parameter(v, "NativeCopies");
+
+ stp_parameter_description_destroy(&desc);
+
+ if (nativecopies)
+ gpputs(fp, "*cupsManualCopies: False\n");
+ else
+ gpputs(fp, "*cupsManualCopies: True\n");
+
+ print_ppd_header_3(fp, ppd_type, model,
+ driver, family, long_name,
+ manufacturer, device_id, ppd_location, language, po,
+ all_langs);
/* Macintosh color management */
@@ -2426,6 +2438,33 @@ write_ppd(
}
stp_parameter_description_destroy(&desc);
+ /* Constraints */
+ stp_describe_parameter(v, "PPDUIConstraints", &desc);
+ if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
+ {
+ num_opts = stp_string_list_count(desc.bounds.str);
+ if (num_opts > 0)
+ {
+ gpputs(fp, "*% ===== Constraints ===== \n");
+ for (i = 0; i < num_opts; i++)
+ {
+ char *opt1, *opt2;
+ opt = stp_string_list_param(desc.bounds.str, i);
+ opt1 = stp_strdup(opt->text);
+ opt2 = strrchr(opt1, '*');
+ if (opt2)
+ {
+ opt2[-1] = 0;
+ gpprintf(fp, "*%s: %s %s\n", opt->name, opt1, opt2);
+ gpprintf(fp, "*%s: %s %s\n", opt->name, opt2, opt1);
+ }
+ stp_free(opt1);
+ }
+ gpputs(fp, "\n");
+ }
+ }
+ stp_parameter_description_destroy(&desc);
+
if (!language)
{
/*
@@ -2554,7 +2593,7 @@ write_ppd(
}
}
stp_parameter_description_destroy(&desc);
-
+
/*
* Quality settings
*/
@@ -2708,5 +2747,5 @@ write_ppd(
/*
- * End of "$Id: genppd.c,v 1.197 2015/06/25 01:48:02 speachy Exp $".
+ * End of "$Id: genppd.c,v 1.204 2015/09/13 14:37:16 speachy Exp $".
*/
diff --git a/src/cups/kodak1400_print.c b/src/cups/kodak1400_print.c
index 1921bb4..c8e257c 100644
--- a/src/cups/kodak1400_print.c
+++ b/src/cups/kodak1400_print.c
@@ -35,6 +35,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND kodak1400_backend
+
#include "backend_common.h"
/* Program states */
@@ -77,6 +79,7 @@ struct kodak1400_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
struct kodak1400_hdr hdr;
uint8_t *plane_r;
@@ -258,17 +261,18 @@ int kodak1400_cmdline_arg(void *vctx, int argc, char **argv)
struct kodak1400_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "C:")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'C':
- if (ctx) {
- j = kodak1400_set_tonecurve(ctx, optarg);
- break;
- }
- return 1;
+ j = kodak1400_set_tonecurve(ctx, optarg);
+ break;
default:
break; /* Ignore completely */
}
@@ -295,14 +299,21 @@ static void kodak1400_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct kodak1400_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);
+
+ ctx->type = lookup_printer_type(&kodak1400_backend,
+ desc.idVendor, desc.idProduct);
+}
static void kodak1400_teardown(void *vctx) {
struct kodak1400_ctx *ctx = vctx;
@@ -603,7 +614,7 @@ top:
struct dyesub_backend kodak1400_backend = {
.name = "Kodak 1400/805",
- .version = "0.33",
+ .version = "0.34",
.uri_prefix = "kodak1400",
.cmdline_usage = kodak1400_cmdline,
.cmdline_arg = kodak1400_cmdline_arg,
@@ -739,7 +750,8 @@ struct dyesub_backend kodak1400_backend = {
Other readback codes seen:
- e4 72 00 00 10 00 50 59 -- ???
+ e4 72 00 00 40 00 50 59 -- ?? paper jam?
+ e4 72 00 00 10 00 50 59 -- media red blink, error red blink, [media mismatch]]
e4 72 00 00 10 01 50 59 -- ???
e4 72 00 00 00 04 50 59 -- media red blink, error red [media too small for image ?]
e4 72 00 00 02 00 50 59 -- media off, error red. [out of paper]
diff --git a/src/cups/kodak605_print.c b/src/cups/kodak605_print.c
index 544eb72..ad2e6bf 100644
--- a/src/cups/kodak605_print.c
+++ b/src/cups/kodak605_print.c
@@ -35,38 +35,116 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND kodak605_backend
+
#include "backend_common.h"
#define USB_VID_KODAK 0x040A
#define USB_PID_KODAK_605 0x402E
+/* Command Header */
+struct kodak605_cmd {
+ uint16_t cmd; /* LE */
+ uint16_t len; /* LE, not counting this header */
+} __attribute__((packed));
+
+struct kodak605_sts_hdr {
+ uint8_t result; /* RESULT_* */
+ uint8_t unk_1[5]; /* 00 00 00 00 00 */
+ uint8_t sts_1; /* 01/02 */
+ uint8_t sts_2; /* 00/61->6b ?? temperature? */
+ uint16_t length; /* LE, not counting this header */
+} __attribute__((packed));
+
+#define RESULT_SUCCESS 0x01
+#define RESULT_FAIL 0x02
+
/* 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 */
+ uint8_t type; /* MEDIA_TYPE_* */
+ uint8_t unk[4]; /* 00 00 00 00 */
} __attribute__((packed));
+#define MEDIA_TYPE_UNKNOWN 0x00
+#define MEDIA_TYPE_PAPER 0x01
+
struct kodak605_media_list {
- uint8_t unk[12]; /* 01 00 00 00 00 00 02 00 67 00 02 0b */
+ struct kodak605_sts_hdr hdr;
+ uint8_t unk; /* always seen 02 */
+ uint8_t type; /* KODAK_MEDIA_* */
uint8_t count;
struct kodak605_medium entries[];
} __attribute__((packed));
+#define KODAK_MEDIA_6R 0x0b
+#define KODAK_MEDIA_NONE 0x00
+
+#define MAX_MEDIA_LEN 128
+
+/* Status response */
+struct kodak605_status {
+ struct kodak605_sts_hdr hdr;
+/*@10*/ uint32_t ctr_life; /* Lifetime Prints */
+ uint32_t ctr_maint; /* Prints since last maintainence */
+ uint32_t ctr_media; /* Prints on current media */
+ uint32_t ctr_cut; /* Cutter Actuations */
+ uint32_t ctr_head; /* Prints on current head */
+/*@30*/ uint8_t donor; /* Donor Percentage remaining */
+/*@31*/ uint8_t null_1[7]; /* 00 00 00 00 00 00 00 */
+/*@38*/ uint8_t b1_id; /* 00/01/02 */
+ uint16_t b1_remain;
+ uint16_t b1_complete;
+ uint16_t b1_total;
+/*@45*/ uint8_t b1_sts; /* See BANK_STATUS_* */
+ uint8_t b2_id; /* 00/01/02 */
+ uint16_t b2_remain;
+ uint16_t b2_complete;
+ uint16_t b2_total;
+/*@53*/ uint8_t b2_sts; /* see BANK_STATUS_* */
+/*@54*/ uint8_t id; /* current job id ( 00/01/02 seen ) */
+/*@55*/ uint16_t remain; /* in current job */
+/*@57*/ uint16_t complete; /* in current job */
+/*@59*/ uint16_t total; /* in current job */
+/*@61*/ uint8_t null_2[9]; /* 00 00 00 00 00 00 00 00 00 */
+/*@70*/ uint8_t unk_12[6]; /* 01 00 00 00 00 00 */
+} __attribute__((packed));
+
/* File header */
struct kodak605_hdr {
uint8_t hdr[4]; /* 01 40 0a 00 */
- uint8_t unk1; /* 01 or 02 */
- uint8_t copies; /* 01 or more */
- uint8_t unk2; /* always 00 */
- uint16_t columns; /* BE always 0x0734 */
- uint16_t rows; /* BE */
+ uint8_t jobid;
+ uint16_t copies; /* LE, 0x0001 or more */
+ uint16_t columns; /* LE, always 0x0734 */
+ uint16_t rows; /* LE */
uint8_t media; /* 0x03 for 6x8, 0x01 for 6x4 */
uint8_t laminate; /* 0x02 to laminate, 0x01 for not */
- uint8_t unk3; /* 0x00, 0x01 [may be print mode] */
+ uint8_t mode; /* Print mode -- 0x00, 0x01 seen */
} __attribute__((packed));
+#define BANK_STATUS_FREE 0x00
+#define BANK_STATUS_XFER 0x01
+#define BANK_STATUS_FULL 0x02
+#define BANK_STATUS_PRINTING 0x12
+
+static char *bank_statuses(uint8_t v)
+{
+ switch (v) {
+ case BANK_STATUS_FREE:
+ return "Free";
+ case BANK_STATUS_XFER:
+ return "Xfer";
+ case BANK_STATUS_FULL:
+ return "Full";
+ case BANK_STATUS_PRINTING:
+ return "Printing";
+ default:
+ return "Unknown";
+ }
+}
+
#define CMDBUF_LEN 4
/* Private data stucture */
@@ -74,23 +152,50 @@ struct kodak605_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
+ uint8_t jobid;
struct kodak605_hdr hdr;
+
+ struct kodak605_media_list *media;
+
uint8_t *databuf;
int datalen;
};
-/* Program states */
-enum {
- S_IDLE = 0,
- S_READY,
- S_STARTED,
- S_SENT_HDR,
- S_SENT_DATA,
- S_FINISHED,
-};
+static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_list *media)
+{
+ uint8_t cmdbuf[4];
+
+ int ret, num = 0;
+
+ /* Send Media Query */
+ cmdbuf[0] = 0x02;
+ cmdbuf[1] = 0x00;
+ cmdbuf[2] = 0x00;
+ cmdbuf[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
-#define READBACK_LEN 120
+ /* Read in the printer status */
+ 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 CUPS_BACKEND_FAILED;
+ }
+
+ if (media->hdr.result != RESULT_SUCCESS) {
+ ERROR("Unexpected response from media query (%x)!\n", media->hdr.result);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ return 0;
+}
static void *kodak605_init(void)
{
@@ -101,6 +206,10 @@ static void *kodak605_init(void)
}
memset(ctx, 0, sizeof(struct kodak605_ctx));
+ ctx->media = malloc(MAX_MEDIA_LEN);
+
+ ctx->type = P_ANY;
+
return ctx;
}
@@ -111,15 +220,23 @@ static void kodak605_attach(void *vctx, struct libusb_device_handle *dev,
struct libusb_device *device;
struct libusb_device_descriptor desc;
- UNUSED(jobid);
-
- ctx->dev = dev;
+ ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
+ ctx->type = lookup_printer_type(&kodak605_backend,
+ desc.idVendor, desc.idProduct);
+
+ /* Make sure jobid is sane */
+ ctx->jobid = (jobid & 0x7f) + 1;
+
+ /* Query media info */
+ if (kodak605_get_media(ctx, ctx->media)) {
+ ERROR("Can't query media\n");
+ }
}
static void kodak605_teardown(void *vctx) {
@@ -190,236 +307,176 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
return CUPS_BACKEND_OK;
}
-static int kodak605_main_loop(void *vctx, int copies) {
- struct kodak605_ctx *ctx = vctx;
-
- uint8_t rdbuf[READBACK_LEN];
- uint8_t rdbuf2[READBACK_LEN];
- uint8_t cmdbuf[CMDBUF_LEN];
-
- int last_state = -1, state = S_IDLE;
- int num, ret;
- int pending = 0;
-
- if (!ctx)
- return CUPS_BACKEND_FAILED;
-
- /* Printer handles generating copies.. */
- if (ctx->hdr.copies < copies)
- ctx->hdr.copies = copies;
- copies = 1;
-
-top:
- if (state != last_state) {
- if (dyesub_debug)
- DEBUG("last_state %d new %d\n", last_state, state);
- }
+static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status *sts)
+{
+ uint8_t cmdbuf[4];
- if (pending)
- goto skip_query;
+ int ret, num = 0;
/* Send Status Query */
cmdbuf[0] = 0x01;
cmdbuf[1] = 0x00;
cmdbuf[2] = 0x00;
cmdbuf[3] = 0x00;
-
if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN)))
- return CUPS_BACKEND_FAILED;
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
-skip_query:
/* Read in the printer status */
ret = read_data(ctx->dev, ctx->endp_up,
- rdbuf, READBACK_LEN, &num);
+ (uint8_t*) sts, sizeof(*sts), &num);
if (ret < 0)
return ret;
- if (num < 10) {
- ERROR("Short read! (%d/%d)\n", num, 10);
+ if (num < (int)sizeof(*sts)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*sts));
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);
+ if (sts->hdr.result != RESULT_SUCCESS) {
+ ERROR("Unexpected response from status query (%x)!\n", sts->hdr.result);
return CUPS_BACKEND_FAILED;
}
- if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- memcpy(rdbuf2, rdbuf, READBACK_LEN);
- } else if (state == last_state) {
- sleep(1);
- }
- last_state = state;
+ return 0;
+}
+
+static int kodak605_main_loop(void *vctx, int copies) {
+ struct kodak605_ctx *ctx = vctx;
- fflush(stderr);
+ struct kodak605_status sts;
- pending = 0;
+ int num, ret;
- switch (state) {
- case S_IDLE:
- INFO("Waiting for printer idle\n");
-#if 0
- if (rdbuf[0] != 0x01 ||
- rdbuf[1] != 0x02 ||
- rdbuf[2] != 0x01) {
- break;
- }
-#endif
- // XXX detect media type based on readback!
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
- INFO("Printing started; Sending init sequence\n");
- state = S_STARTED;
+ /* Printer handles generating copies.. */
+ if (le16_to_cpu(ctx->hdr.copies) < copies)
+ ctx->hdr.copies = cpu_to_le16(copies);
- break;
- case S_STARTED:
-#if 0
- if (rdbuf[0] != 0x01 ||
- rdbuf[2] != 0x00)
+ /* Validate against supported media list */
+ for (num = 0 ; num < ctx->media->count; num++) {
+ if (ctx->media->entries[num].rows == ctx->hdr.rows &&
+ ctx->media->entries[num].cols == ctx->hdr.columns)
break;
+ }
+ if (num == ctx->media->count) {
+ ERROR("Print size unsupported by media!\n");
+ return CUPS_BACKEND_HOLD;
+ }
- /* Aappears to depend on media */
- if (rdbuf[1] != 0x0b &&
- rdbuf[1] != 0x03)
- break;
-#endif
+ /* Use specified jobid */
+ ctx->hdr.jobid = ctx->jobid;
- INFO("Sending image header\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*)&ctx->hdr, sizeof(ctx->hdr))))
- return CUPS_BACKEND_FAILED;
- pending = 1;
- state = S_SENT_HDR;
- break;
- case S_SENT_HDR:
- INFO("Waiting for printer to accept data\n");
- if (rdbuf[0] != 0x01 ||
- rdbuf[6] == 0x00 ||
- num != 10) {
- break;
- }
- INFO("Sending image data\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ INFO("Waiting for printer idle\n");
+
+ while(1) {
+ if ((ret = kodak605_get_status(ctx, &sts)))
return CUPS_BACKEND_FAILED;
- INFO("Image data sent\n");
- sleep(1); /* An experiment */
- state = S_SENT_DATA;
- break;
- case S_SENT_DATA:
- INFO("Waiting for printer to acknowledge completion\n");
-#if 0
- if (rdbuf[0] != 0x01 ||
- rdbuf[1] != 0x02 ||
- rdbuf[2] != 0x01) {
+ // XXX check for errors
+
+ /* Wait for a free buffer */
+ if (sts.b1_sts == BANK_STATUS_FREE ||
+ sts.b2_sts == BANK_STATUS_FREE) {
break;
}
-#endif
- state = S_FINISHED;
- break;
- default:
- break;
- };
- if (state != S_FINISHED)
- goto top;
+ sleep(1);
+ }
- /* Clean up */
- if (terminate)
- copies = 1;
+ {
+ INFO("Sending image header\n");
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*)&ctx->hdr, sizeof(ctx->hdr))))
+ return CUPS_BACKEND_FAILED;
- INFO("Print complete (%d copies remaining)\n", copies - 1);
+ struct kodak605_sts_hdr resp;
+ if ((ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &resp, sizeof(resp), &num)))
+ return CUPS_BACKEND_FAILED;
- if (copies && --copies) {
- state = S_IDLE;
- goto top;
+ if (resp.result != RESULT_SUCCESS) {
+ ERROR("Unexpected response from print command (%x)!\n", resp.result);
+ return CUPS_BACKEND_FAILED;
+ }
+ // XXX what about resp.sts1 or resp.sts2?
}
+ sleep(1);
- return CUPS_BACKEND_OK;
-}
+ INFO("Sending image data\n");
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ctx->databuf, ctx->datalen)))
+ return CUPS_BACKEND_FAILED;
-static int kodak605_get_status(struct kodak605_ctx *ctx)
-{
- uint8_t cmdbuf[4];
- uint8_t rdbuf[76];
+ INFO("Image data sent\n");
- int ret, i, num = 0;
+ INFO("Waiting for printer to acknowledge completion\n");
+ do {
+ sleep(1);
+ if ((ret = kodak605_get_status(ctx, &sts)))
+ return CUPS_BACKEND_FAILED;
- /* Send Status Query */
- cmdbuf[0] = 0x01;
- cmdbuf[1] = 0x00;
- cmdbuf[2] = 0x00;
- cmdbuf[3] = 0x00;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, sizeof(cmdbuf))))
- return ret;
+ // XXX check for errors ?
- /* Read in the printer status */
- ret = read_data(ctx->dev, ctx->endp_up,
- rdbuf, READBACK_LEN, &num);
- if (ret < 0)
- return ret;
+ /* Wait for completion */
+ if (sts.b1_id == ctx->jobid && sts.b1_complete == sts.b1_total)
+ break;
+ if (sts.b2_id == ctx->jobid && sts.b2_complete == sts.b2_total)
+ break;
- if (num < (int)sizeof(rdbuf)) {
- ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(rdbuf));
- return 4;
- }
+ if (fast_return) {
+ INFO("Fast return mode enabled.\n");
+ break;
+ }
+ } while(1);
- DEBUG("status: ");
- for (i = 0 ; i < num ; i++) {
- DEBUG2("%02x ", rdbuf[i]);
- }
+ INFO("Print complete\n");
- return 0;
+ return CUPS_BACKEND_OK;
+}
+
+static void kodak605_dump_status(struct kodak605_status *sts)
+{
+ INFO("Bank 1: %s Job %03u @ %03u/%03u\n",
+ bank_statuses(sts->b1_sts), sts->b1_id,
+ le16_to_cpu(sts->b1_complete), le16_to_cpu(sts->b1_complete));
+ INFO("Bank 2: %s Job %03u @ %03u/%03u\n",
+ bank_statuses(sts->b2_sts), sts->b2_id,
+ le16_to_cpu(sts->b2_complete), le16_to_cpu(sts->b2_complete));
+
+ INFO("Lifetime prints : %d\n", be32_to_cpu(sts->ctr_life));
+ INFO("Cutter actuations : %d\n", be32_to_cpu(sts->ctr_cut));
+ INFO("Head prints : %d\n", be32_to_cpu(sts->ctr_head));
+ INFO("Media prints : %d\n", be32_to_cpu(sts->ctr_media));
+ INFO("Donor : %d%%\n", sts->donor);
}
static void kodak605_dump_mediainfo(struct kodak605_media_list *media)
{
int i;
+ if (media->type == KODAK_MEDIA_NONE) {
+ DEBUG("No Media Loaded\n");
+ return;
+ }
+
+ if (media->type == KODAK_MEDIA_6R) {
+ DEBUG("Media type: 6R (Kodak 197-4096 or equivalent)\n");
+ } else {
+ DEBUG("Media type %02x (unknown, please report!)\n", media->type);
+ }
+
DEBUG("Legal print sizes:\n");
for (i = 0 ; i < media->count ; i++) {
- DEBUG("\t%d: %dx%d\n", 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, num = 0;
-
- /* Send Media Query */
- cmdbuf[0] = 0x02;
- cmdbuf[1] = 0x00;
- cmdbuf[2] = 0x00;
- cmdbuf[3] = 0x00;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, sizeof(cmdbuf))))
- return ret;
-
- /* Read in the printer status */
- ret = read_data(ctx->dev, ctx->endp_up,
- rdbuf, READBACK_LEN, &num);
- if (ret < 0)
- return ret;
-
- if (num < (int)sizeof(rdbuf)) {
- ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(rdbuf));
- return 4;
- }
-
- kodak605_dump_mediainfo((struct kodak605_media_list *)rdbuf);
-
- return 0;
-}
-
#define UPDATE_SIZE 1536
static int kodak605_set_tonecurve(struct kodak605_ctx *ctx, char *fname)
{
@@ -507,29 +564,29 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
struct kodak605_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "C:ms")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:ms")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'C':
- if (ctx) {
- j = kodak605_set_tonecurve(ctx, optarg);
- break;
- }
- return 1;
+ j = kodak605_set_tonecurve(ctx, optarg);
+ break;
case 'm':
- if (ctx) {
- j = kodak605_get_media(ctx);
- break;
- }
- return 1;
- case 's':
- if (ctx) {
- j = kodak605_get_status(ctx);
- break;
- }
- return 1;
+ kodak605_dump_mediainfo(ctx->media);
+ break;
+ case 's': {
+ struct kodak605_status sts;
+
+ j = kodak605_get_status(ctx, &sts);
+ if (!j)
+ kodak605_dump_status(&sts);
+ break;
+ }
default:
break; /* Ignore completely */
}
@@ -543,7 +600,7 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend kodak605_backend = {
.name = "Kodak 605",
- .version = "0.21",
+ .version = "0.24",
.uri_prefix = "kodak605",
.cmdline_usage = kodak605_cmdline,
.cmdline_arg = kodak605_cmdline_arg,
@@ -563,76 +620,23 @@ struct dyesub_backend kodak605_backend = {
Spool file consists of 14-byte header followed by plane-interleaved BGR data.
Native printer resolution is 1844 pixels per row, and 1240 or 2434 rows.
+ All fields are LITTLE ENDIAN unless otherwise specified
+
Header:
01 40 0a 00 Fixed header
- XX Unknown, always 01 in file, but 02 seen in sniffs sometimes
- CC Number of copies (1-255)
- 00 Always 0x00
- WW WW Number of columns, little endian. (Fixed at 1844)
- HH HH Number of rows, little endian. (1240 or 2434)
+ XX Job ID
+ CC CC Number of copies (1-???)
+ WW WW Number of columns (Fixed at 1844)
+ HH HH Number of rows (1240 or 2434)
DD 0x01 (4x6) 0x03 (8x6)
LL Laminate, 0x01 (off) or 0x02 (on)
- 00
+ 00 Print Mode (???)
************************************************************************
- Kodak 605 Printer Comms:
-
- [[file header]] 01 40 0a 00 01 CC 00 WW WW HH HH MT LL 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 01 00 00 00 00 00
-
--> 01 00 00 00
-<- [76 bytes -- status ]
+ Note: Kodak 605 is actually a Shinko CHC-S1545-5A
- 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 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
- 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 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 40 0a 00 01 01 00 34 07 d8 04 01 02 00 [[ unmodified header ]]
-<- 01 00 00 00 00 00 XX 00 00 00 [[ Seen 0x01 and 0x02 ]
--> image data!
--> image data!
-
--> 01 00 00 00
-<- [76 bytes -- status ?? ]
-
- 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 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
-
- Write tone curve data:
-
--> 04 c0 0a 00 03 01 00 00 00 00 LL LL 00 00 [[ LL LL == 0x0600 in LE ]]
-<- 01 00 00 00 00 00 XX 00 00 00 [[ Seen 0x01 and 0x02 ]
-
--> [[ 1536 bytes of LE tone curve data ]]
+ ************************************************************************
*/
diff --git a/src/cups/kodak6800_print.c b/src/cups/kodak6800_print.c
index 51093b8..1e77850 100644
--- a/src/cups/kodak6800_print.c
+++ b/src/cups/kodak6800_print.c
@@ -39,6 +39,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND kodak6800_backend
+
#include "backend_common.h"
#define USB_VID_KODAK 0x040A
@@ -47,50 +49,155 @@
/* File header */
struct kodak6800_hdr {
- 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;
+ uint8_t hdr[7]; /* Always 03 1b 43 48 43 0a 00 */
+ uint8_t jobid; /* Non-zero */
+ uint16_t copies; /* BE, in BCD format (1-9999) */
uint16_t columns; /* BE */
uint16_t rows; /* BE */
- uint8_t size; /* 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 or 0x01 (for 4x6 on 6x8 media) */
+ uint8_t mode; /* 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 status; /* STATUS_* */
+ uint8_t status1; /* STATUS1_* */
+ uint32_t status2; /* STATUS2_* */
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 */
+ uint32_t lifetime; /* Lifetime Prints (BE) */
+ uint32_t maint; /* Maint Prints (BE) */
+ uint32_t media; /* Media Prints (6850), Unknown (6800) (BE) */
+ uint32_t cutter; /* Cutter Actuations (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];
+ uint8_t errtype; /* seen 0x00 or 0xd0 */
+ uint8_t donor; /* Percentage, 0-100 */
+ uint16_t main_boot; /* Always 003 */
+ uint16_t main_fw; /* seen 652, 656, 670, 671 (6850) and 232 (6800) */
+ uint16_t dsp_boot; /* Always 001 */
+ uint16_t dsp_fw; /* Seen 540, 541, 560 (6850) and 131 (6800) */
+ uint8_t b1_jobid;
+ uint8_t b2_jobid;
+ uint16_t b1_remain; /* Remaining prints in job */
+ uint16_t b1_complete; /* Completed prints in job */
+ uint16_t b1_total; /* Total prints in job */
+ uint16_t b2_remain; /* Remaining prints in job */
+ uint16_t b2_complete; /* Completed prints in job */
+ uint16_t b2_total; /* Total prints in job */
+ uint8_t curve_status; /* Always seems to be 0x00 */
} __attribute__((packed));
+enum {
+ CMD_CODE_OK = 1,
+ CMD_CODE_BAD = 2,
+};
+
+enum {
+ STATUS_PRINTING = 1,
+ STATUS_IDLE = 2,
+};
+
+enum {
+ STATE_STATUS1_STANDBY = 1,
+ STATE_STATUS1_ERROR = 2,
+ STATE_STATUS1_WAIT = 3,
+};
+
+#define STATE_STANDBY_STATUS2 0x0
+
+enum {
+ WAIT_STATUS2_INIT = 0,
+ WAIT_STATUS2_RIBBON = 1,
+ WAIT_STATUS2_THERMAL = 2,
+ WAIT_STATUS2_OPERATING = 3,
+ WAIT_STATUS2_BUSY = 4,
+};
+
+#define ERROR_STATUS2_CTRL_CIRCUIT (1<<31)
+#define ERROR_STATUS2_MECHANISM_CTRL (1<<30)
+#define ERROR_STATUS2_SENSOR (1<<13)
+#define ERROR_STATUS2_COVER_OPEN (1<<12)
+#define ERROR_STATUS2_TEMP_SENSOR (1<<9)
+#define ERROR_STATUS2_PAPER_JAM (1<<8)
+#define ERROR_STATUS2_PAPER_EMPTY (1<<6)
+#define ERROR_STATUS2_RIBBON_ERR (1<<4)
+
+enum {
+ CTRL_CIR_ERROR_EEPROM1 = 0x01,
+ CTRL_CIR_ERROR_EEPROM2 = 0x02,
+ CTRL_CIR_ERROR_DSP = 0x04,
+ CTRL_CIR_ERROR_CRC_MAIN = 0x06,
+ CTRL_CIR_ERROR_DL_MAIN = 0x07,
+ CTRL_CIR_ERROR_CRC_DSP = 0x08,
+ CTRL_CIR_ERROR_DL_DSP = 0x09,
+ CTRL_CIR_ERROR_ASIC = 0x0a,
+ CTRL_CIR_ERROR_DRAM = 0x0b,
+ CTRL_CIR_ERROR_DSPCOMM = 0x29,
+};
+
+enum {
+ MECH_ERROR_HEAD_UP = 0x01,
+ MECH_ERROR_HEAD_DOWN = 0x02,
+ MECH_ERROR_MAIN_PINCH_UP = 0x03,
+ MECH_ERROR_MAIN_PINCH_DOWN = 0x04,
+ MECH_ERROR_SUB_PINCH_UP = 0x05,
+ MECH_ERROR_SUB_PINCH_DOWN = 0x06,
+ MECH_ERROR_FEEDIN_PINCH_UP = 0x07,
+ MECH_ERROR_FEEDIN_PINCH_DOWN = 0x08,
+ MECH_ERROR_FEEDOUT_PINCH_UP = 0x09,
+ MECH_ERROR_FEEDOUT_PINCH_DOWN = 0x0a,
+ MECH_ERROR_CUTTER_LR = 0x0b,
+ MECH_ERROR_CUTTER_RL = 0x0c,
+};
+
+enum {
+ SENSOR_ERROR_CUTTER = 0x05,
+ SENSOR_ERROR_HEAD_DOWN = 0x09,
+ SENSOR_ERROR_HEAD_UP = 0x0a,
+ SENSOR_ERROR_MAIN_PINCH_DOWN = 0x0b,
+ SENSOR_ERROR_MAIN_PINCH_UP = 0x0c,
+ SENSOR_ERROR_FEED_PINCH_DOWN = 0x0d,
+ SENSOR_ERROR_FEED_PINCH_UP = 0x0e,
+ SENSOR_ERROR_EXIT_PINCH_DOWN = 0x0f,
+ SENSOR_ERROR_EXIT_PINCH_UP = 0x10,
+ SENSOR_ERROR_LEFT_CUTTER = 0x11,
+ SENSOR_ERROR_RIGHT_CUTTER = 0x12,
+ SENSOR_ERROR_CENTER_CUTTER = 0x13,
+ SENSOR_ERROR_UPPER_CUTTER = 0x14,
+ SENSOR_ERROR_PAPER_FEED_COVER = 0x15,
+};
+
+enum {
+ TEMP_SENSOR_ERROR_HEAD_HIGH = 0x01,
+ TEMP_SENSOR_ERROR_HEAD_LOW = 0x02,
+ TEMP_SENSOR_ERROR_ENV_HIGH = 0x03,
+ TEMP_SENSOR_ERROR_ENV_LOW = 0x04,
+};
+
+enum {
+ COVER_OPEN_ERROR_UPPER = 0x01,
+ COVER_OPEN_ERROR_LOWER = 0x02,
+};
+
+enum {
+ PAPER_EMPTY_ERROR = 0x00,
+};
+
+enum {
+ RIBBON_ERROR = 0x00,
+};
+
+enum {
+ CURVE_TABLE_STATUS_INITIAL = 0x00,
+ CURVE_TABLE_STATUS_USERSET = 0x01,
+ CURVE_TABLE_STATUS_CURRENT = 0x02,
+};
+
struct kodak6800_printsize {
uint8_t hdr; /* Always 0x06 */
uint16_t width; /* BE */
uint16_t height; /* BE */
- uint8_t hdr2; /* Always 0x01 */
+ uint8_t type; /* MEDIA_TYPE_* [ ie paper ] */
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];
@@ -106,7 +213,9 @@ struct kodak68x0_media_readback {
struct kodak6800_printsize sizes[];
} __attribute__((packed));
-#define KODAK68x0_MEDIA_6R 0x0b
+#define KODAK68x0_MEDIA_6R 0x0b
+#define KODAK68x0_MEDIA_UNK 0x03
+#define KODAK68x0_MEDIA_NONE 0x00
#define CMDBUF_LEN 17
@@ -117,39 +226,60 @@ struct kodak6800_ctx {
uint8_t endp_down;
int type;
- int media;
+
+ uint8_t jobid;
+
+ struct kodak68x0_media_readback *media;
struct kodak6800_hdr hdr;
uint8_t *databuf;
int datalen;
};
-#define READBACK_LEN 68
-char *kodak68x0_error_codes(uint8_t code1, uint8_t code2)
+/* Baseline commands */
+static int kodak6800_do_cmd(struct kodak6800_ctx *ctx,
+ void *cmd, int cmd_len,
+ void *resp, int resp_len,
+ int *actual_len)
{
- if (code1 == 0x80 && code2 == 0xd0)
- return "Control Error";
+ int ret;
+
+ /* Write command */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmd, cmd_len)))
+ return (ret < 0) ? ret : -99;
+
+ /* Read response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ resp, resp_len, actual_len);
+ if (ret < 0)
+ return ret;
- return "Unknown Type (please report!)";
+ return 0;
}
static void kodak68x0_dump_mediainfo(struct kodak68x0_media_readback *media)
{
int i;
+ if (media->media == KODAK68x0_MEDIA_NONE) {
+ INFO("No Media Loaded\n");
+ return;
+ }
+
if (media->media == KODAK68x0_MEDIA_6R) {
- DEBUG("Media type: 6R (Kodak 197-4096 or equivalent)\n");
+ INFO("Media type: 6R (Kodak 197-4096 or equivalent)\n");
} else {
- DEBUG("Media type %02x (unknown, please report!)\n", media->media);
+ INFO("Media type %02x (unknown, please report!)\n", media->media);
}
- DEBUG("Legal print sizes:\n");
+ INFO("Legal print sizes:\n");
for (i = 0 ; i < media->count ; i++) {
- DEBUG("\t%d: %dx%d (%02x) %s\n", i,
+ INFO("\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");
+ INFO("\n");
}
static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx, struct kodak68x0_media_readback *media)
@@ -167,62 +297,270 @@ static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx, struct kodak68x0_m
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)
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
+ media, MAX_MEDIA_LEN,
+ &num)))
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 ||
+ if (media->hdr != CMD_CODE_OK ||
media->null[0] != 0x00) {
ERROR("Unexpected response from media query!\n");
return CUPS_BACKEND_STOP;
}
- ctx->media = media->media;
+ return 0;
+}
+
+static int kodak68x0_canceljob(struct kodak6800_ctx *ctx,
+ int id)
+{
+ uint8_t req[16];
+ int ret, num;
+ struct kodak68x0_status_readback sts;
+
+ memset(req, 0, sizeof(req));
+
+ req[0] = 0x03;
+ req[1] = 0x1b;
+ req[2] = 0x43;
+ req[3] = 0x48;
+ req[4] = 0x43;
+ req[5] = 0x13;
+ req[6] = id;
+
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
+ &sts, sizeof(sts),
+ &num)))
+ return ret;
+
+ /* Validate proper response */
+ if (sts.hdr != CMD_CODE_OK) {
+ ERROR("Unexpected response from job cancel!\n");
+ return -99;
+ }
return 0;
}
+/* Structure dumps */
+static char *kodak68x0_status_str(struct kodak68x0_status_readback *resp)
+{
+ switch(resp->status1) {
+ case STATE_STATUS1_STANDBY:
+ return "Standby (Ready)";
+ case STATE_STATUS1_WAIT:
+ switch (be32_to_cpu(resp->status2)) {
+ case WAIT_STATUS2_INIT:
+ return "Wait (Initializing)";
+ case WAIT_STATUS2_RIBBON:
+ return "Wait (Ribbon Winding)";
+ case WAIT_STATUS2_THERMAL:
+ return "Wait (Thermal Protection)";
+ case WAIT_STATUS2_OPERATING:
+ return "Wait (Operating)";
+ case WAIT_STATUS2_BUSY:
+ return "Wait (Busy)";
+ default:
+ return "Wait (Unknown)";
+ }
+ case STATE_STATUS1_ERROR:
+ switch (be32_to_cpu(resp->status2)) {
+ case ERROR_STATUS2_CTRL_CIRCUIT:
+ switch (resp->errcode) {
+ case CTRL_CIR_ERROR_EEPROM1:
+ return "Error (EEPROM1)";
+ case CTRL_CIR_ERROR_EEPROM2:
+ return "Error (EEPROM2)";
+ case CTRL_CIR_ERROR_DSP:
+ return "Error (DSP)";
+ case CTRL_CIR_ERROR_CRC_MAIN:
+ return "Error (Main CRC)";
+ case CTRL_CIR_ERROR_DL_MAIN:
+ return "Error (Main Download)";
+ case CTRL_CIR_ERROR_CRC_DSP:
+ return "Error (DSP CRC)";
+ case CTRL_CIR_ERROR_DL_DSP:
+ return "Error (DSP Download)";
+ case CTRL_CIR_ERROR_ASIC:
+ return "Error (ASIC)";
+ case CTRL_CIR_ERROR_DRAM:
+ return "Error (DRAM)";
+ case CTRL_CIR_ERROR_DSPCOMM:
+ return "Error (DSP Communincation)";
+ default:
+ return "Error (Unknown Circuit)";
+ }
+ case ERROR_STATUS2_MECHANISM_CTRL:
+ switch (resp->errcode) {
+ case MECH_ERROR_HEAD_UP:
+ return "Error (Head Up Mechanism)";
+ case MECH_ERROR_HEAD_DOWN:
+ return "Error (Head Down Mechanism)";
+ case MECH_ERROR_MAIN_PINCH_UP:
+ return "Error (Main Pinch Up Mechanism)";
+ case MECH_ERROR_MAIN_PINCH_DOWN:
+ return "Error (Main Pinch Down Mechanism)";
+ case MECH_ERROR_SUB_PINCH_UP:
+ return "Error (Sub Pinch Up Mechanism)";
+ case MECH_ERROR_SUB_PINCH_DOWN:
+ return "Error (Sub Pinch Down Mechanism)";
+ case MECH_ERROR_FEEDIN_PINCH_UP:
+ return "Error (Feed-in Pinch Up Mechanism)";
+ case MECH_ERROR_FEEDIN_PINCH_DOWN:
+ return "Error (Feed-in Pinch Down Mechanism)";
+ case MECH_ERROR_FEEDOUT_PINCH_UP:
+ return "Error (Feed-out Pinch Up Mechanism)";
+ case MECH_ERROR_FEEDOUT_PINCH_DOWN:
+ return "Error (Feed-out Pinch Down Mechanism)";
+ case MECH_ERROR_CUTTER_LR:
+ return "Error (Left->Right Cutter)";
+ case MECH_ERROR_CUTTER_RL:
+ return "Error (Right->Left Cutter)";
+ default:
+ return "Error (Unknown Mechanism)";
+ }
+ case ERROR_STATUS2_SENSOR:
+ switch (resp->errcode) {
+ case SENSOR_ERROR_CUTTER:
+ return "Error (Cutter Sensor)";
+ case SENSOR_ERROR_HEAD_DOWN:
+ return "Error (Head Down Sensor)";
+ case SENSOR_ERROR_HEAD_UP:
+ return "Error (Head Up Sensor)";
+ case SENSOR_ERROR_MAIN_PINCH_DOWN:
+ return "Error (Main Pinch Down Sensor)";
+ case SENSOR_ERROR_MAIN_PINCH_UP:
+ return "Error (Main Pinch Up Sensor)";
+ case SENSOR_ERROR_FEED_PINCH_DOWN:
+ return "Error (Feed Pinch Down Sensor)";
+ case SENSOR_ERROR_FEED_PINCH_UP:
+ return "Error (Feed Pinch Up Sensor)";
+ case SENSOR_ERROR_EXIT_PINCH_DOWN:
+ return "Error (Exit Pinch Up Sensor)";
+ case SENSOR_ERROR_EXIT_PINCH_UP:
+ return "Error (Exit Pinch Up Sensor)";
+ case SENSOR_ERROR_LEFT_CUTTER:
+ return "Error (Left Cutter Sensor)";
+ case SENSOR_ERROR_RIGHT_CUTTER:
+ return "Error (Right Cutter Sensor)";
+ case SENSOR_ERROR_CENTER_CUTTER:
+ return "Error (Center Cutter Sensor)";
+ case SENSOR_ERROR_UPPER_CUTTER:
+ return "Error (Upper Cutter Sensor)";
+ case SENSOR_ERROR_PAPER_FEED_COVER:
+ return "Error (Paper Feed Cover)";
+ default:
+ return "Error (Unknown Sensor)";
+ }
+ case ERROR_STATUS2_COVER_OPEN:
+ switch (resp->errcode) {
+ case COVER_OPEN_ERROR_UPPER:
+ return "Error (Upper Cover Open)";
+ case COVER_OPEN_ERROR_LOWER:
+ return "Error (Lower Cover Open)";
+ default:
+ return "Error (Unknown Cover Open)";
+ }
+ case ERROR_STATUS2_TEMP_SENSOR:
+ switch (resp->errcode) {
+ case TEMP_SENSOR_ERROR_HEAD_HIGH:
+ return "Error (Head Temperature High)";
+ case TEMP_SENSOR_ERROR_HEAD_LOW:
+ return "Error (Head Temperature Low)";
+ case TEMP_SENSOR_ERROR_ENV_HIGH:
+ return "Error (Environmental Temperature High)";
+ case TEMP_SENSOR_ERROR_ENV_LOW:
+ return "Error (Environmental Temperature Low)";
+ default:
+ return "Error (Unknown Temperature)";
+ }
+ case ERROR_STATUS2_PAPER_JAM:
+ return "Error (Paper Jam)";
+ case ERROR_STATUS2_PAPER_EMPTY:
+ return "Error (Paper Empty)";
+ case ERROR_STATUS2_RIBBON_ERR:
+ return "Error (Ribbon)";
+ default:
+ return "Error (Unknown)";
+ }
+ default:
+ return "Unknown!";
+ }
+}
+
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);
+ char *detail;
+
+ switch (status->status) {
+ case STATUS_PRINTING:
+ detail = "Printing";
+ break;
+ case STATUS_IDLE:
+ detail = "Idle";
+ break;
+ default:
+ detail = "Unknown";
+ break;
+ }
+ INFO("Printer Status : %s\n", detail);
+
+ INFO("Printer State : %s # %02x %08x %02x\n",
+ kodak68x0_status_str(status),
+ status->status1, be32_to_cpu(status->status2), status->errcode);
+
+ INFO("Bank 1 ID: %d\n", status->b1_jobid);
+ INFO("\tPrints: %d/%d complete\n",
+ be16_to_cpu(status->b1_complete), be16_to_cpu(status->b1_total));
+ INFO("Bank 2 ID: %d\n", status->b2_jobid);
+ INFO("\tPrints: %d/%d complete\n",
+ be16_to_cpu(status->b2_complete), be16_to_cpu(status->b2_total));
+
+ switch (status->curve_status) {
+ case CURVE_TABLE_STATUS_INITIAL:
+ detail = "Initial/Default";
+ break;
+ case CURVE_TABLE_STATUS_USERSET:
+ detail = "User Stored";
+ break;
+ case CURVE_TABLE_STATUS_CURRENT:
+ detail = "Current";
+ break;
+ default:
+ detail = "Unknown";
+ break;
}
- DEBUG("Total prints : %d\n", be32_to_cpu(status->ctr0));
- DEBUG("Media prints : %d\n", be32_to_cpu(status->ctr2));
+ INFO("Tone Curve Status: %s\n", detail);
+
+ INFO("Counters:\n");
+ INFO("\tLifetime : %d\n", be32_to_cpu(status->lifetime));
+ INFO("\tThermal Head : %d\n", be32_to_cpu(status->maint));
+ INFO("\tCutter : %d\n", be32_to_cpu(status->cutter));
+
if (ctx->type == P_KODAK_6850) {
int max;
- if (ctx->media == KODAK68x0_MEDIA_6R) {
+
+ INFO("\tMedia : %d\n", be32_to_cpu(status->media));
+
+ if (ctx->media->media == KODAK68x0_MEDIA_6R) {
max = 375;
} else {
max = 0;
}
if (max) {
- DEBUG("Remaining prints : %d\n", max - be32_to_cpu(status->ctr2));
+ INFO("\t Remaining : %d\n", max - be32_to_cpu(status->media));
} else {
- DEBUG("Remaining prints : Unknown media type\n");
+ INFO("\t Remaining : Unknown\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");
+ INFO("Main FW version: %d\n", be16_to_cpu(status->main_fw));
+ INFO("DSP FW version : %d\n", be16_to_cpu(status->dsp_fw));
+ INFO("Donor : %d%%\n", status->donor);
+ INFO("\n");
}
static int kodak6800_get_status(struct kodak6800_ctx *ctx,
@@ -241,25 +579,16 @@ static int kodak6800_get_status(struct kodak6800_ctx *ctx,
req[4] = 0x43;
req[5] = 0x03;
- /* Send request */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- req, sizeof(req))))
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
+ status, sizeof(*status),
+ &num)))
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) {
+ /* Validate proper response */
+ if (status->hdr != CMD_CODE_OK) {
ERROR("Unexpected response from status query!\n");
- return CUPS_BACKEND_FAILED;
+ return -99;
}
return 0;
@@ -269,10 +598,6 @@ static int kodak6800_get_status(struct kodak6800_ctx *ctx,
#define UPDATE_SIZE 1536
static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
{
- libusb_device_handle *dev = ctx->dev;
- uint8_t endp_down = ctx->endp_down;
- uint8_t endp_up = ctx->endp_up;
-
uint8_t cmdbuf[16];
uint8_t respbuf[64];
int ret, num = 0;
@@ -304,18 +629,15 @@ static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
cmdbuf[14] = 0x00;
cmdbuf[15] = 0x00;
- if ((ret = send_data(dev, endp_down,
- cmdbuf, 16)))
- goto done;
-
- ret = read_data(dev, endp_up,
- respbuf, sizeof(respbuf), &num);
- if (ret < 0)
- goto done;
-
- if (num != 51) {
- ERROR("Short read! (%d/%d)\n", num, 51);
- ret = 4;
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
+ respbuf, sizeof(respbuf),
+ &num)))
+
+ /* Validate proper response */
+ if (respbuf[0] != CMD_CODE_OK) {
+ ERROR("Unexpected response from tonecurve query!\n");
+ ret = -99;
goto done;
}
@@ -332,13 +654,10 @@ static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
cmdbuf[9] = 0x45;
cmdbuf[10] = 0x20;
for (i = 0 ; i < 24 ; i++) {
- if ((ret = send_data(dev, endp_down,
- cmdbuf, 11)))
- goto done;
-
- ret = read_data(dev, endp_up,
- respbuf, sizeof(respbuf), &num);
- if (ret < 0)
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
+ respbuf, sizeof(respbuf),
+ &num)))
goto done;
if (num != 64) {
@@ -371,15 +690,11 @@ static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
/* We're done */
free(data);
- return 0;
+ return ret;
}
static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
{
- libusb_device_handle *dev = ctx->dev;
- uint8_t endp_down = ctx->endp_down;
- uint8_t endp_up = ctx->endp_up;
-
uint8_t cmdbuf[64];
uint8_t respbuf[64];
int ret, num = 0;
@@ -392,7 +707,7 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
ERROR("Memory Allocation Failure\n");
return -1;
}
-
+
INFO("Set Tone Curve from '%s'\n", fname);
/* Read in file */
@@ -430,21 +745,24 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
cmdbuf[14] = 0x00;
cmdbuf[15] = 0x00;
- if ((ret = send_data(dev, endp_down,
- cmdbuf, 16)))
- goto done;
-
- ret = read_data(dev, endp_up,
- respbuf, sizeof(respbuf), &num);
- if (ret < 0)
- goto done;
-
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
+ respbuf, sizeof(respbuf),
+ &num)))
+
+ /* Validate proper response */
if (num != 51) {
ERROR("Short read! (%d/%d)\n", num, 51);
ret = 4;
goto done;
}
+ if (respbuf[0] != CMD_CODE_OK) {
+ ERROR("Unexpected response from tonecurve set!\n");
+ ret = -99;
+ goto done;
+ }
+
ptr = (uint8_t*) data;
remain = UPDATE_SIZE;
while (remain > 0) {
@@ -456,24 +774,23 @@ static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
remain -= count;
ptr += count;
- /* Send next block over */
- if ((ret = send_data(dev, endp_down,
- cmdbuf, count+1)))
- goto done;
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, cmdbuf, count + 1,
+ respbuf, sizeof(respbuf),
+ &num)))
-
- ret = read_data(dev, endp_up,
- respbuf, sizeof(respbuf), &num);
- if (ret < 0)
- goto done;
-
if (num != 51) {
ERROR("Short read! (%d/%d)\n", num, 51);
ret = 4;
goto done;
}
+ if (respbuf[0] != CMD_CODE_OK) {
+ ERROR("Unexpected response from tonecurve set!\n");
+ ret = -99;
+ goto done;
+ }
};
-
+
done:
/* We're done */
free(data);
@@ -482,6 +799,12 @@ done:
static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
{
+ struct kodak6800_ctx ctx = {
+ .dev = dev,
+ .endp_up = endp_up,
+ .endp_down = endp_down,
+ };
+
int ret;
int num;
@@ -496,23 +819,19 @@ static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_
req[2] = 0x43;
req[3] = 0x48;
req[4] = 0x43;
- req[5] = 0x03;
+ req[5] = 0x12;
- /* Send request */
- if ((ret = send_data(dev, endp_down,
- req, sizeof(req))))
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(&ctx, req, sizeof(req),
+ resp, sizeof(resp),
+ &num)))
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;
+ return -2;
}
+
strncpy(buf, (char*)resp+24, buf_len);
buf[buf_len-1] = 0;
@@ -521,45 +840,35 @@ static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_
static int kodak6850_send_init(struct kodak6800_ctx *ctx)
{
- uint8_t cmdbuf[64];
+ uint8_t cmdbuf[16];
uint8_t rdbuf[64];
int ret = 0, num = 0;
- memset(cmdbuf, 0, CMDBUF_LEN);
+ memset(cmdbuf, 0, sizeof(cmdbuf));
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;
- }
-
+
+ /* Issue command and get response */
+ if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
+ rdbuf, sizeof(rdbuf),
+ &num)))
+ return -1;
+
if (num != 51) {
- ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n",
- num, READBACK_LEN, ctx->endp_up);
+ ERROR("Short read! (%d/%d)\n", num, 51);
return CUPS_BACKEND_FAILED;
}
-
- if (rdbuf[0] != 0x01 ||
+
+ if (rdbuf[0] != CMD_CODE_OK ||
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) {
@@ -575,6 +884,7 @@ static void kodak6800_cmdline(void)
DEBUG("\t\t[ -C filename ] # Set tone curve\n");
DEBUG("\t\t[ -m ] # Query media\n");
DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -X jobid ] # Cancel Job\n");
}
static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
@@ -582,49 +892,31 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
struct kodak6800_ctx *ctx = vctx;
int i, j = 0;
- /* Reset arg parsing */
- optind = 1;
- opterr = 0;
- while ((i = getopt(argc, argv, "C:c:ms")) >= 0) {
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:c:msX:")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'c':
- if (ctx) {
- j = kodak6800_get_tonecurve(ctx, optarg);
- break;
- }
- return 1;
+ j = kodak6800_get_tonecurve(ctx, optarg);
+ break;
case 'C':
- if (ctx) {
- j = kodak6800_set_tonecurve(ctx, optarg);
- break;
- }
- return 1;
+ j = kodak6800_set_tonecurve(ctx, optarg);
+ break;
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;
-
+ kodak68x0_dump_mediainfo(ctx->media);
+ break;
+ case 's': {
+ struct kodak68x0_status_readback status;
+ j = kodak6800_get_status(ctx, &status);
+ if (!j)
+ kodak68x0_dump_status(ctx, &status);
+ break;
+ }
+ case 'X':
+ j = kodak68x0_canceljob(ctx, atoi(optarg));
+ break;
default:
break; /* Ignore completely */
}
@@ -635,7 +927,6 @@ static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
-
static void *kodak6800_init(void)
{
struct kodak6800_ctx *ctx = malloc(sizeof(struct kodak6800_ctx));
@@ -645,8 +936,9 @@ static void *kodak6800_init(void)
}
memset(ctx, 0, sizeof(struct kodak6800_ctx));
+ ctx->media = malloc(MAX_MEDIA_LEN);
+
ctx->type = P_ANY;
- ctx->media = -1;
return ctx;
}
@@ -658,20 +950,23 @@ static void kodak6800_attach(void *vctx, struct libusb_device_handle *dev,
struct libusb_device *device;
struct libusb_device_descriptor desc;
- UNUSED(jobid);
-
- ctx->dev = dev;
+ ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
- /* Map out device type */
- if (desc.idProduct == USB_PID_KODAK_6850)
- ctx->type = P_KODAK_6850;
- else
- ctx->type = P_KODAK_6800;
+ ctx->type = lookup_printer_type(&kodak6800_backend,
+ desc.idVendor, desc.idProduct);
+
+ /* Ensure jobid is sane */
+ ctx->jobid = (jobid & 0x7f) + 1;
+
+ /* Query media info */
+ if (kodak6800_get_mediainfo(ctx, ctx->media)) {
+ ERROR("Can't query media\n");
+ }
}
static void kodak6800_teardown(void *vctx) {
@@ -746,144 +1041,123 @@ static int kodak6800_main_loop(void *vctx, int copies) {
struct kodak6800_ctx *ctx = vctx;
struct kodak68x0_status_readback status;
- uint8_t cmdbuf[CMDBUF_LEN];
-
- uint8_t mediabuf[MAX_MEDIA_LEN];
- struct kodak68x0_media_readback *media = (struct kodak68x0_media_readback*)mediabuf;
-
int num, ret;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ /* Fix max print count. */
+ if (copies > 9999) // XXX test against remaining media
+ copies = 9999;
+
/* Printer handles generating copies.. */
- if (ctx->hdr.copies < copies)
- ctx->hdr.copies = copies;
- copies = 1;
-
- /* Query loaded media */
- INFO("Querying loaded media\n");
- ret = kodak6800_get_mediainfo(ctx, media);
- if (ret < 0)
- return CUPS_BACKEND_FAILED;
-
- /* Appears to depend on media */
- if (media->media != KODAK68x0_MEDIA_6R &&
- media->media != 0x03) {
- ERROR("Unrecognized media type %02x\n", media->media);
+ ctx->hdr.copies = cpu_to_be16(uint16_to_packed_bcd(copies));
+
+ /* Validate media */
+ if (ctx->media->media != KODAK68x0_MEDIA_6R &&
+ ctx->media->media != KODAK68x0_MEDIA_UNK) {
+ ERROR("Unrecognized media type %02x\n", ctx->media->media);
return CUPS_BACKEND_STOP;
}
/* 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)
+ for (num = 0 ; num < ctx->media->count; num++) {
+ if (ctx->media->sizes[num].height == ctx->hdr.rows &&
+ ctx->media->sizes[num].width == ctx->hdr.columns &&
+ ctx->media->sizes[num].code2 == 0x00)
break;
}
- if (num == media->count) {
+ if (num == ctx->media->count) {
ERROR("Print size unsupported by media!\n");
return CUPS_BACKEND_HOLD;
}
-top:
INFO("Waiting for printer idle\n");
while(1) {
if (kodak6800_get_status(ctx, &status))
return CUPS_BACKEND_FAILED;
- 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);
+ if (status.status1 == STATE_STATUS1_ERROR) {
+ INFO("Printer State: %s # %02x %08x %02x\n",
+ kodak68x0_status_str(&status),
+ status.status1, be32_to_cpu(status.status2), status.errcode);
return CUPS_BACKEND_FAILED;
}
- 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;
- }
-
- 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 {
+ if (status.status == STATUS_IDLE)
break;
- }
+
+ /* See if we have an open bank */
+ if (!status.b1_remain ||
+ !status.b2_remain)
+ break;
+
+ sleep(1);
}
if (ctx->type == P_KODAK_6850) {
- INFO("Sending 6850 init sequence\n");
+// INFO("Sending 6850 init sequence\n");
ret = kodak6850_send_init(ctx);
if (ret)
return ret;
- 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... */
+
+ ctx->hdr.jobid = ctx->jobid;
+
+#if 0
+ /* If we want to disable 4x6 rewind on 8x6 media.. */
if (ctx->hdr.size == 0x00 &&
- be16_to_cpu(media->sizes[0].width) == 0x0982) {
- cmdbuf[14] = 0x06;
- cmdbuf[16] = 0x01;
+ be16_to_cpu(ctx->media->sizes[0].width) == 0x0982) {
+ ctx->hdr.size = 0x06;
+ ctx->hdr.mode = 0x01;
}
-
- INFO("Sending image header\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- cmdbuf, CMDBUF_LEN)))
+#endif
+
+ INFO("Initiating Print Job\n");
+ if ((ret = kodak6800_do_cmd(ctx, (uint8_t*) &ctx->hdr, sizeof(ctx->hdr),
+ &status, sizeof(status),
+ &num)))
return ret;
- sleep(1);
+
+ if (status.hdr != CMD_CODE_OK) {
+ ERROR("Unexpected response from print command!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+// sleep(1); // Appears to be necessary for reliability
INFO("Sending image data\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
+ 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) {
+ do {
+ sleep(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);
+ if (status.status1 == STATE_STATUS1_ERROR) {
+ INFO("Printer State: %s # %02x %08x %02x\n",
+ kodak68x0_status_str(&status),
+ status.status1, be32_to_cpu(status.status2), status.errcode);
return CUPS_BACKEND_FAILED;
- } else {
+ }
+
+ /* If all prints are complete, we're done! */
+ if (status.b1_jobid == ctx->hdr.jobid && status.b1_complete == status.b1_total)
+ break;
+ if (status.b2_jobid == ctx->hdr.jobid && status.b2_complete == status.b2_total)
+ break;
+
+ if (fast_return) {
+ INFO("Fast return mode enabled.\n");
break;
}
- sleep(1);
- }
-
- /* Clean up */
- if (terminate)
- copies = 1;
- INFO("Print complete (%d copies remaining)\n", copies - 1);
+ } while (1);
- if (copies && --copies) {
- goto top;
- }
+ INFO("Print complete\n");
return CUPS_BACKEND_OK;
}
@@ -891,7 +1165,7 @@ top:
/* Exported */
struct dyesub_backend kodak6800_backend = {
.name = "Kodak 6800/6850",
- .version = "0.43",
+ .version = "0.51",
.uri_prefix = "kodak6800",
.cmdline_usage = kodak6800_cmdline,
.cmdline_arg = kodak6800_cmdline_arg,
@@ -901,7 +1175,7 @@ struct dyesub_backend kodak6800_backend = {
.read_parse = kodak6800_read_parse,
.main_loop = kodak6800_main_loop,
.query_serno = kodak6800_query_serno,
- .devices = {
+ .devices = {
{ USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak"},
{ USB_VID_KODAK, USB_PID_KODAK_6850, P_KODAK_6850, "Kodak"},
{ 0, 0, 0, ""}
@@ -915,148 +1189,25 @@ struct dyesub_backend kodak6800_backend = {
6850 Adds support for 5x7, with 1548 pixels per row and 2140 columns.
- Header:
+ All fields are BIG ENDIAN unless otherwise specified.
- 03 1b 43 48 43 0a 00 01 00 Fixed header
- 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.
- SS 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850)
- LL Laminate, 0x00 (off) or 0x01 (on)
- UU 0x01 for multi-cut, 0x00 otherwise.
+ Header:
- Note: For 4x6 prints on 6x8 media, print size (SS) is set to 0x06 and the
- final octet is set to 0x01.
+ 03 1b 43 48 43 0a 00 01 Fixed header
+ NN NN Number of copies in BCD form (0001->9999)
+ WW WW Number of columns (Fixed at 1844 on 6800)
+ HH HH Number of rows.
+ SS Print size -- 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850)
+ LL Laminate mode -- 0x00 (off) or 0x01 (on)
+ UU Print mode -- 0x00 (normal) or (0x01) 4x6 on 8x6
************************************************************************
- Kodak 6800 Printer Comms:
-
- [[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]
-
- 01 02 01 00 00 00 00 00 00 00 a2 7b 00 00 a2 7b
- 00 00 02 f4 00 00 e6 b1 00 00 00 1a 00 03 00 e8
- 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 [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 == 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, see above ]
- 01
-
-<- [51 octets]
-
- 01 02 01 00 00 00 00 00 00 00 a2 7b 00 00 a2 7b
- 00 00 02 f4 00 00 e6 b1 00 00 00 1a 00 03 00 e8
- 00 01 00 83 01 00 00 01 00 00 00 01 00 00 00 00 [ note the "01" after "83", and the extra two "01"s ]
- 00 00 00
-
--> [4K of plane data]
--> ...
--> [4K of plane data]
--> [remainder of plane data + 17 bytes of 0xff]
-
--> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query]
-<- [51 octets]
-
- 01 02 01 00 00 00 00 00 00 00 a2 7c 00 00 a2 7c [ note a2 7c vs a2 7b ]
- 00 00 01 7a 00 00 e6 b3 00 00 00 1a 00 03 00 e8 [ note 01 7a vs 02 f4, e6 b3 vs e6 b1 ]
- 00 01 00 83 01 00 00 00 00 01 00 01 00 00 00 00 [ note the moved '01' in the middle ]
- 00 00 00
-
--> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [ status query ]
-<- [51 octets, repeats]
-
- Possible Serial number query:
-
--> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00
-<- [32 octets]
-
- 00 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [[ Pascal string? ]]
- 20 20 20 20 20 20 20 20 36 30 34 33 4d 32 38 31 [[ ..." 6043M281" ]]
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 65 00 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
- [[ Followed by reset. ]]
-
- Read tone curve data:
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 72 01 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 20
-<- [64 octets]
-
- 81 01 07 07 27 07 72 07 c8 07 f8 07 22 07 48 08
- 68 08 88 08 b3 08 db 08 f7 08 09 09 2e 09 49 09
- 65 09 80 09 aa 09 ca 09 e2 09 fa 09 12 0a 32 0a
- 42 0a 66 0a 81 0a 9a 0a c3 0a d9 0a ee 0a 04 0b
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 20
-<- [64 octets]
-
- [[ repeats for total of 24 packets. total of 1.5KiB. ]]
-
- Write tone curve data:
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 77 01 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 00 00 46 06 53 06 c0 06 07 07 37 07 5d 07 87
- 07 a1 07 c8 07 08 08 08 08 08 08 48 08 68 08 88
- 08 a9 08 b9 08 d9 08 f9 08 12 09 2e 09 49 09 70
- 09 89 08 99 09 ba 09 ca 08 da 09 0a 0a 24 0a 38
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 0a 53 0a 66 0a 81 0a ...
- ....
--> 03 cf 38 0a 39 3d 39 79 39 96 39 b6 39 fb 39 01
- 34 0a 34 08 3a 0c 1a 10 3a
-<- [51 octets]
-
- [[ typical status response ]]
-
- [[ total of 24 packets * 64, and then one final packet of 25: 1562 total. ]]
- [[ It apepars the extra 25 bytes are to compensate for the leading '03' on
- each of the 25 URBs. ]]
-
- ***********************************************************************
+ Note: 6800 is Shinko CHC-S1145-5A, 6850 is Shinko CHC-S1145-5B
- Kodak 6850 Printer Comms:
+ Both are very similar to Shinko S1245!
- [[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]
-
- 01 02 01 00 00 00 00 00 00 00 21 75 00 00 08 52
- 00 00 01 29 00 00 3b 0a 00 00 00 0e 00 03 02 90
- 00 01 02 1d 03 00 00 00 00 01 00 01 00 00 00 00
- 00 00 00
+ ************************************************************************
-> 03 1b 43 48 43 4c 00 00 00 00 00 00 00 00 00 00 [???]
<- [51 octets]
@@ -1071,149 +1222,4 @@ struct dyesub_backend kodak6800_backend = {
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 [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 == 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, see above ]
- 01
-
-<- [51 octets]
-
- 01 02 01 00 00 00 00 00 00 00 21 75 00 00 08 52
- 00 00 01 29 00 00 3b 0a 00 00 00 0e 00 03 02 90
- 00 01 02 1d 04 00 00 01 00 00 00 01 00 00 00 00 [ note the "04" after "1d", and the moved '01' ]
- 00 00 00
-
--> [4K of plane data]
--> ...
--> [4K of plane data]
--> [remainder of plane data]
-
--> 03 1b 43 48 43 03 00 00 00 00 00 00 00 00 00 00 [status query]
-<- [51 octets]
-
- 01 02 01 00 00 00 00 00 00 00 21 76 00 00 08 53 [ note 21 76, 08 53, 01 2a incremented by 1 ]
- 00 00 01 2a 00 00 3b 0c 00 00 00 0e 00 03 02 90 [ note 3b 0c incremeted by 2 ]
- 00 01 02 1d 04 00 00 01 00 00 00 01 00 00 00 00
- 00 00 00
-
- Possible Serial number query:
-
--> 03 1b 43 48 43 12 00 00 00 00 00 00 00 00 00 00
- 00
-<- [32 octets]
-
- 00 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 [[ Pascal string? ]]
- 20 20 20 20 20 20 20 20 36 30 39 37 4b 53 34 39 [[ ..." 6097KS49" ]]
-
- Read tone curve data:
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 72 01 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 20
-<- [64 octets]
-
- 81 01 07 07 27 07 72 07 c8 07 f8 07 22 07 48 08
- 68 08 88 08 b3 08 db 08 f7 08 09 09 2e 09 49 09
- 65 09 80 09 aa 09 ca 09 e2 09 fa 09 12 0a 32 0a
- 42 0a 66 0a 81 0a 9a 0a c3 0a d9 0a ee 0a 04 0b
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 20
-<- [64 octets]
-
- [[ repeats for total of 24 packets. total of 1.5KiB. ]]
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 65 00 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
-
- Maybe this resets the calibration table:
-
--> 03 1b 43 48 43 05 00 00 00 00 00 00 00 00 00 00 [???]
-<- [34 octets]
-
- 01 00 04 00 00 00 01 00 01 00 02 00 00 00 01 00
- 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 00 00
-
- Write tone curve data:
-
--> 03 1b 43 48 43 0c 54 4f 4e 45 77 01 00 00 00 00
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 00 00 46 06 53 06 c0 06 07 07 37 07 5d 07 87
- 07 a1 07 c8 07 08 08 08 08 08 08 48 08 68 08 88
- 08 a9 08 b9 08 d9 08 f9 08 12 09 2e 09 49 09 70
- 09 89 08 99 09 ba 09 ca 08 da 09 0a 0a 24 0a 38
-<- [51 octets]
-
- [[ typical status response ]]
-
--> 03 0a 53 0a 66 0a 81 0a ...
- ....
--> 03 cf 38 0a 39 3d 39 79 39 96 39 b6 39 fb 39 01
- 34 0a 34 08 3a 0c 1a 10 3a
-<- [51 octets]
-
- [[ typical status response ]]
-
- [[ total of 24 packets * 64, and then one final packet of 25: 1562 total. ]]
- [[ It apepars the extra 25 bytes are to compensate for the leading '03' on
- each of the 25 URBs. ]]
-
- 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
-
-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
-
-??? 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
-
-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 2b9e56d..dcff841 100644
--- a/src/cups/mitsu70x_print.c
+++ b/src/cups/mitsu70x_print.c
@@ -35,6 +35,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND mitsu70x_backend
+
#include "backend_common.h"
#define USB_VID_MITSU 0x06D3
@@ -49,14 +51,13 @@ struct mitsu70x_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
uint8_t *databuf;
int datalen;
uint16_t rows;
uint16_t cols;
-
- int k60;
};
/* Program states */
@@ -155,12 +156,8 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
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;
-
+ ctx->type = lookup_printer_type(&mitsu70x_backend,
+ desc.idVendor, desc.idProduct);
}
@@ -357,7 +354,7 @@ static int mitsu70x_get_status(struct mitsu70x_ctx *ctx, struct mitsu70x_status_
static int mitsu70x_main_loop(void *vctx, int copies) {
struct mitsu70x_ctx *ctx = vctx;
- struct mitsu70x_state rdbuf, rdbuf2;
+ struct mitsu70x_state rdbuf = { .hdr = 0 }, rdbuf2 = { .hdr = 0 };
int last_state = -1, state = S_IDLE;
int ret;
@@ -424,7 +421,7 @@ top:
INFO("Sending header sequence\n");
/* K60 may require fixups */
- if (ctx->k60) {
+ if (ctx->type == P_MITSU_K60) {
struct mitsu70x_hdr *hdr = (struct mitsu70x_hdr*) (ctx->databuf + sizeof(struct mitsu70x_hdr));
/* K60 only has a lower deck */
hdr->deck = 1;
@@ -539,7 +536,7 @@ static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
{
int ret, i;
- struct mitsu70x_status_resp resp;
+ struct mitsu70x_status_resp resp = { .hdr = { 0 } };
struct mitsu70x_ctx ctx = {
.dev = dev,
@@ -571,17 +568,18 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
struct mitsu70x_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "s")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "s")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 's':
- if (ctx) {
- j = mitsu70x_query_status(ctx);
- break;
- }
- return 1;
+ j = mitsu70x_query_status(ctx);
+ break;
default:
break; /* Ignore completely */
}
@@ -596,7 +594,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.31",
+ .version = "0.32",
.uri_prefix = "mitsu70x",
.cmdline_usage = mitsu70x_cmdline,
.cmdline_arg = mitsu70x_cmdline_arg,
@@ -608,9 +606,9 @@ struct dyesub_backend mitsu70x_backend = {
.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_K60, P_MITSU_K60, ""},
// { USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D70X, ""},
- { USB_VID_KODAK, USB_PID_KODAK305, P_MITSU_D70X, ""},
+ { USB_VID_KODAK, USB_PID_KODAK305, P_MITSU_K60, ""},
{ 0, 0, 0, ""}
}
};
diff --git a/src/cups/mitsu9550_print.c b/src/cups/mitsu9550_print.c
index 7b83e6c..952baa3 100644
--- a/src/cups/mitsu9550_print.c
+++ b/src/cups/mitsu9550_print.c
@@ -35,6 +35,8 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND mitsu9550_backend
+
#include "backend_common.h"
#define USB_VID_MITSU 0x06D3
@@ -46,14 +48,13 @@ struct mitsu9550_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
uint8_t *databuf;
int datalen;
int is_s_variant;
- int fast_return;
-
uint16_t rows;
uint16_t cols;
};
@@ -149,10 +150,6 @@ static void *mitsu9550_init(void)
}
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;
}
@@ -172,8 +169,8 @@ static void mitsu9550_attach(void *vctx, struct libusb_device_handle *dev,
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
- if (desc.idProduct == USB_PID_MITSU_9550DS)
- ctx->is_s_variant = 1;
+ ctx->type = lookup_printer_type(&mitsu9550_backend,
+ desc.idVendor, desc.idProduct);
}
@@ -288,28 +285,28 @@ static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int st
static int validate_media(int type, int cols, int rows) {
switch(type) {
case 0x01: /* 3.5x5 */
- if (cols != 1812 || rows != 1240)
+ if (cols != 1812 && rows != 1240)
return 1;
break;
case 0x02: /* 4x6 */
case 0x03: /* PC ??? */
if (cols != 2152)
return 1;
- if (rows != 1416 || rows != 1184 ||
+ if (rows != 1416 && rows != 1184 &&
rows != 1240)
return 1;
break;
case 0x04: /* 5x7 */
if (cols != 1812)
return 1;
- if (rows != 1240 || rows != 2452)
+ 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)
+ if (rows != 1416 && rows != 2972 &&
+ rows != 2956 && rows != 3146)
return 1;
break;
case 0x06: /* V */
@@ -332,15 +329,15 @@ static int mitsu9550_main_loop(void *vctx, int copies) {
if (!ctx)
return CUPS_BACKEND_FAILED;
-
- /* This printer handles copies internally */
+
+ /* Update printjob header to reflect number of requested copies */
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) {
+ if (ctx->type == P_MITSU_9550S) {
int num;
/* Send "unknown 1" command */
@@ -405,7 +402,7 @@ top:
/* Now it's time for the actual print job! */
- if (ctx->is_s_variant) {
+ if (ctx->type == P_MITSU_9550S) {
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x44;
cmd.cmd[2] = 0;
@@ -463,7 +460,7 @@ top:
(uint8_t*) ptr, sizeof(struct mitsu9550_hdr3))))
return CUPS_BACKEND_FAILED;
ptr += sizeof(struct mitsu9550_hdr3);
- if (!ctx->is_s_variant) {
+ if (ctx->type != P_MITSU_9550S) {
// XXX need to investigate what hdr4 is about
if ((ret = send_data(ctx->dev, ctx->endp_down,
(uint8_t*) ptr, sizeof(struct mitsu9550_hdr4))))
@@ -471,7 +468,7 @@ top:
}
ptr += sizeof(struct mitsu9550_hdr4);
- if (ctx->is_s_variant) {
+ if (ctx->type == P_MITSU_9550S) {
/* Send "start data" command */
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x5a;
@@ -546,7 +543,7 @@ top:
}
}
- if (ctx->is_s_variant) {
+ if (ctx->type == P_MITSU_9550S) {
/* Send "end data" command */
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x50;
@@ -592,12 +589,12 @@ top:
if (!sts->sts1) /* If printer transitions to idle */
break;
- if (ctx->fast_return && !be16_to_cpu(sts->copies)) { /* No remaining prints */
+ if (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 */
+ if (fast_return && !sts->sts5) { /* Ready for another job */
INFO("Fast return mode enabled.\n");
break;
}
@@ -605,18 +602,7 @@ top:
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;
- }
+ INFO("Print complete\n");
return CUPS_BACKEND_OK;
}
@@ -744,7 +730,6 @@ 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)
@@ -752,30 +737,21 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
struct mitsu9550_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "mfs")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "ms")) >= 0) {
switch(i) {
- case 'm':
- if (ctx) {
- j = mitsu9550_query_media(ctx);
- break;
- }
- return 1;
+ GETOPT_PROCESS_GLOBAL
+ case 'm':
+ j = mitsu9550_query_media(ctx);
+ break;
case 's':
- if (ctx) {
- j = mitsu9550_query_status(ctx);
- break;
- }
- return 1;
-
- case 'f':
- if (ctx) {
- ctx->fast_return = 1;
- break;
- }
- return 1;
+ j = mitsu9550_query_status(ctx);
+ break;
default:
break; /* Ignore completely */
}
@@ -789,7 +765,7 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend mitsu9550_backend = {
.name = "Mitsubishi CP-9550DW-S",
- .version = "0.12",
+ .version = "0.15",
.uri_prefix = "mitsu9550",
.cmdline_usage = mitsu9550_cmdline,
.cmdline_arg = mitsu9550_cmdline_arg,
@@ -801,7 +777,7 @@ struct dyesub_backend mitsu9550_backend = {
.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, ""},
+ { USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, ""},
{ 0, 0, 0, ""}
}
};
diff --git a/src/cups/selphy_print.c b/src/cups/selphy_print.c
index 2c9bab0..8da09e0 100644
--- a/src/cups/selphy_print.c
+++ b/src/cups/selphy_print.c
@@ -35,8 +35,12 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND canonselphy_backend
+
#include "backend_common.h"
+#define P_ES40_CP790 (P_END + 1) // used for detection only
+
/* Exported */
#define USB_VID_CANON 0x04a9
#define USB_PID_CANON_CP10 0x304A
@@ -291,13 +295,6 @@ static struct printer_data selphy_printers[] = {
.paper_code_offset = -1,
.error_detect = es3_error_detect,
},
- /* PLACEHOLDER FOR DETECTION PURPOSES ONLY */
- { .type = P_ES40_CP790,
- .model = "SELPHY ES40/CP790",
- .init_length = 16,
- .foot_length = 12,
- .pgcode_offset = 2,
- },
{ .type = P_ES40,
.model = "SELPHY ES40",
.init_length = 16,
@@ -504,6 +501,7 @@ struct canonselphy_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
struct printer_data *printer;
@@ -546,6 +544,8 @@ static void *canonselphy_init(void)
return ctx;
}
+extern struct dyesub_backend canonselphy_backend;
+
static void canonselphy_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
@@ -562,26 +562,11 @@ static void canonselphy_attach(void *vctx, struct libusb_device_handle *dev,
device = libusb_get_device(dev);
libusb_get_device_descriptor(device, &desc);
- /* Special cases for some models */
- if (ctx->printer->type == P_ES40_CP790) {
- int i;
- int printer_type;
-
-
- if (desc.idProduct == USB_PID_CANON_CP790)
- printer_type = P_CP790;
- else if (desc.idProduct == USB_PID_CANON_ES40)
- printer_type = P_ES40;
+ ctx->type = lookup_printer_type(&canonselphy_backend,
+ desc.idVendor, desc.idProduct);
- for (i = 0; selphy_printers[i].type != -1; i++) {
- if (selphy_printers[i].type == printer_type) {
- ctx->printer = &selphy_printers[i];
- break;
- }
- }
- } else if (desc.idProduct == USB_PID_CANON_CP900) {
+ if (desc.idProduct == USB_PID_CANON_CP900)
ctx->cp900 = 1;
- }
}
static void canonselphy_teardown(void *vctx) {
@@ -627,6 +612,15 @@ static int canonselphy_early_parse(void *vctx, int data_fd)
}
printer_type = parse_printjob(ctx->buffer, &ctx->bw_mode, &ctx->plane_len);
+ /* Special cases for some models */
+ if (printer_type == P_ES40_CP790) {
+ if (ctx->type == P_CP790)
+ printer_type = P_CP790;
+ else
+ printer_type = P_ES40;
+ }
+
+ /* Look up the printer entry */
for (i = 0; selphy_printers[i].type != -1; i++) {
if (selphy_printers[i].type == printer_type) {
ctx->printer = &selphy_printers[i];
@@ -638,14 +632,19 @@ static int canonselphy_early_parse(void *vctx, int data_fd)
return -1;
}
+ INFO("%sFile intended for a '%s' printer\n", ctx->bw_mode? "B/W " : "", ctx->printer->model);
+
+ if (ctx->printer->type != ctx->type) {
+ ERROR("Printer/Job mismatch (%d/%d)\n", ctx->type, ctx->printer->type);
+ return -1;
+ }
+
ctx->plane_len += 12; /* Add in plane header length! */
if (ctx->printer->pgcode_offset != -1)
ctx->paper_code = ctx->printer->paper_codes[ctx->buffer[ctx->printer->pgcode_offset]];
else
ctx->paper_code = -1;
- INFO("%sFile intended for a '%s' printer\n", ctx->bw_mode? "B/W " : "", ctx->printer->model);
-
return printer_type;
}
@@ -657,6 +656,11 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
if (!ctx)
return CUPS_BACKEND_FAILED;
+ /* Perform early parsing */
+ i = canonselphy_early_parse(ctx, data_fd);
+ if (i < 0)
+ return CUPS_BACKEND_FAILED;
+
if (ctx->header) {
free(ctx->header);
ctx->header = NULL;
@@ -794,7 +798,7 @@ top:
/* Make sure paper/ribbon is correct */
if (ctx->paper_code != -1) {
- if (ctx->printer->type == P_CP_XXX) {
+ if (ctx->type == P_CP_XXX) {
uint8_t pc = rdbuf[ctx->printer->paper_code_offset];
if (((pc >> 4) & 0xf) != (ctx->paper_code & 0x0f)) {
@@ -825,7 +829,7 @@ top:
return CUPS_BACKEND_HOLD; /* Hold this job, don't stop queue */
}
}
- } else if (ctx->printer->type == P_CP790) {
+ } else if (ctx->type == P_CP790) {
uint8_t ribbon = rdbuf[4] >> 4;
uint8_t paper = rdbuf[5];
@@ -949,14 +953,36 @@ top:
return CUPS_BACKEND_OK;
}
+static int canonselphy_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct canonselphy_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ /* Reset arg parsing */
+ optind = 1;
+ opterr = 0;
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL)) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
struct dyesub_backend canonselphy_backend = {
.name = "Canon SELPHY CP/ES",
- .version = "0.87",
+ .version = "0.89",
.uri_prefix = "canonselphy",
+ .cmdline_arg = canonselphy_cmdline_arg,
.init = canonselphy_init,
.attach = canonselphy_attach,
.teardown = canonselphy_teardown,
- .early_parse = canonselphy_early_parse,
.read_parse = canonselphy_read_parse,
.main_loop = canonselphy_main_loop,
.devices = {
@@ -980,7 +1006,7 @@ struct dyesub_backend canonselphy_backend = {
{ USB_VID_CANON, USB_PID_CANON_CP760, P_CP_XXX, ""},
{ USB_VID_CANON, USB_PID_CANON_CP770, P_CP_XXX, ""},
{ USB_VID_CANON, USB_PID_CANON_CP780, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP790, P_ES40_CP790, ""},
+ { USB_VID_CANON, USB_PID_CANON_CP790, P_CP790, ""},
{ USB_VID_CANON, USB_PID_CANON_CP800, P_CP_XXX, ""},
{ USB_VID_CANON, USB_PID_CANON_CP810, P_CP_XXX, ""},
{ USB_VID_CANON, USB_PID_CANON_CP900, P_CP_XXX, ""},
@@ -989,7 +1015,7 @@ struct dyesub_backend canonselphy_backend = {
{ USB_VID_CANON, USB_PID_CANON_ES20, P_ES2_20, ""},
{ USB_VID_CANON, USB_PID_CANON_ES3, P_ES3_30, ""},
{ USB_VID_CANON, USB_PID_CANON_ES30, P_ES3_30, ""},
- { USB_VID_CANON, USB_PID_CANON_ES40, P_ES40_CP790, ""},
+ { USB_VID_CANON, USB_PID_CANON_ES40, P_ES40, ""},
{ 0, 0, 0, ""}
}
};
diff --git a/src/cups/shinko_s1245_print.c b/src/cups/shinko_s1245_print.c
new file mode 100644
index 0000000..72b5ec9
--- /dev/null
+++ b/src/cups/shinko_s1245_print.c
@@ -0,0 +1,1621 @@
+/*
+ * Shinko/Sinfonia CHC-S1245 CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * Low-level documentation was provided by Sinfonia, Inc. Thank you!
+ *
+ * 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>
+
+#define BACKEND shinkos1245_backend
+
+#include "backend_common.h"
+
+/* Structure of printjob header. All fields are LITTLE ENDIAN */
+struct s1245_printjob_hdr {
+ uint32_t len1; /* Fixed at 0x10 */
+ uint32_t model; /* Equal to the printer model (eg '1245' or '2145' decimal) */
+ uint32_t unk2; /* Null */
+ uint32_t unk3; /* Fixed at 0x01 */
+
+ uint32_t len2; /* Fixed at 0x64 */
+ uint32_t unk5; /* Null */
+ uint32_t media; /* Fixed at 0x10 */
+ uint32_t unk6; /* Null */
+
+ uint32_t method; /* Print Method */
+ uint32_t mode; /* Print Mode */
+ uint32_t unk7; /* Null */
+ int32_t mattedepth; /* 0x7fffffff for glossy, 0x00 +- 25 for matte */
+
+ uint32_t dust; /* Dust control */
+ uint32_t columns;
+ uint32_t rows;
+ uint32_t copies;
+
+ uint32_t unk10; /* Null */
+ uint32_t unk11; /* Null */
+ uint32_t unk12; /* Null */
+ uint32_t unk13; /* 0xceffffff */
+
+ uint32_t unk14; /* Null */
+ uint32_t unk15; /* 0xceffffff */
+ uint32_t dpi; /* Fixed at '300' (decimal) */
+ uint32_t unk16; /* 0xceffffff */
+
+ uint32_t unk17; /* Null */
+ uint32_t unk18; /* 0xceffffff */
+ uint32_t unk19; /* Null */
+ uint32_t unk20; /* Null */
+
+ uint32_t unk21; /* Null */
+} __attribute__((packed));
+
+/* Printer data structures */
+struct shinkos1245_cmd_hdr {
+ uint8_t prefix; /* 0x03 */
+ uint8_t hdr[4]; /* 0x1b 0x43 0x48 0x43 */
+} __attribute__((packed));
+
+/* Get Printer ID */
+struct shinkos1245_cmd_getid {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x12 */
+ uint8_t pad[11];
+} __attribute__((packed));
+
+struct shinkos1245_resp_getid {
+ uint8_t id; /* 0x00 */
+ uint8_t data[23]; /* padded with 0x20 (space) */
+ uint8_t reserved[8]; // XXX actual serial number?
+} __attribute__((packed));
+
+/* Set Printer ID -- Returns Status */
+struct shinkos1245_cmd_setid {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[2]; /* 0x0a 0x22 */
+ uint8_t id; /* 0x00 */
+ uint8_t data[23]; /* pad with 0x20 (space) */
+} __attribute__((packed));
+
+/* Print -- Returns Status */
+struct shinkos1245_cmd_print {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[2]; /* 0x0a 0x00 */
+ uint8_t id; /* 1-255 */
+ uint16_t count; /* # Copies in BCD, 1-9999 */
+ uint16_t columns; /* Fixed at 2446 */
+ uint16_t rows;
+ uint8_t media; /* Fixed at 0x10 */
+ uint8_t mode; /* dust removal and lamination mode */
+ uint8_t combo; /* aka "print method" in the spool file */
+} __attribute__((packed));
+
+/* Get Status */
+struct shinkos1245_cmd_getstatus {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x03 */
+ uint8_t pad[10];
+} __attribute__((packed));
+
+struct shinkos1245_resp_status {
+ uint8_t code;
+ uint8_t print_status;
+ struct {
+ uint8_t status1;
+ uint32_t status2; /* BE */
+ uint8_t error;
+ } state;
+ struct {
+ uint32_t lifetime; /* BE */
+ uint32_t maint; /* BE */
+ uint32_t media; /* BE */
+ uint32_t cutter; /* BE */
+ uint8_t reserved;
+ uint8_t ver_boot;
+ uint8_t ver_ctrl;
+ uint8_t control_flag; // 0x00 == epson, 0x01 == cypress
+ } counters;
+ struct {
+ uint16_t main_boot;
+ uint16_t main_control;
+ uint16_t dsp_boot;
+ uint16_t dsp_control;
+ } versions;
+ struct {
+ uint8_t bank1_id;
+ uint8_t bank2_id;
+ uint16_t bank1_remain; /* BE */
+ uint16_t bank1_complete; /* BE */
+ uint16_t bank1_spec; /* BE */
+ uint16_t bank2_remain; /* BE */
+ uint16_t bank2_complete; /* BE */
+ uint16_t bank2_spec; /* BE */
+ } counters2;
+ uint8_t curve_status;
+} __attribute__((packed));
+
+enum {
+ CMD_CODE_OK = 1,
+ CMD_CODE_BAD = 2,
+};
+
+enum {
+ STATUS_PRINTING = 1,
+ STATUS_IDLE = 2,
+};
+
+enum {
+ STATE_STATUS1_STANDBY = 1,
+ STATE_STATUS1_ERROR = 2,
+ STATE_STATUS1_WAIT = 3,
+};
+
+#define STATE_STANDBY_STATUS2 0x0
+
+enum {
+ WAIT_STATUS2_INIT = 0,
+ WAIT_STATUS2_RIBBON = 1,
+ WAIT_STATUS2_THERMAL = 2,
+ WAIT_STATUS2_OPERATING = 3,
+ WAIT_STATUS2_BUSY = 4,
+};
+
+#define ERROR_STATUS2_CTRL_CIRCUIT (1<<31)
+#define ERROR_STATUS2_MECHANISM_CTRL (1<<30)
+#define ERROR_STATUS2_SENSOR (1<<13)
+#define ERROR_STATUS2_COVER_OPEN (1<<12)
+#define ERROR_STATUS2_TEMP_SENSOR (1<<9)
+#define ERROR_STATUS2_PAPER_JAM (1<<8)
+#define ERROR_STATUS2_PAPER_EMPTY (1<<6)
+#define ERROR_STATUS2_RIBBON_ERR (1<<4)
+
+enum {
+ CTRL_CIR_ERROR_EEPROM1 = 0x01,
+ CTRL_CIR_ERROR_EEPROM2 = 0x02,
+ CTRL_CIR_ERROR_DSP = 0x04,
+ CTRL_CIR_ERROR_CRC_MAIN = 0x06,
+ CTRL_CIR_ERROR_DL_MAIN = 0x07,
+ CTRL_CIR_ERROR_CRC_DSP = 0x08,
+ CTRL_CIR_ERROR_DL_DSP = 0x09,
+ CTRL_CIR_ERROR_ASIC = 0x0a,
+ CTRL_CIR_ERROR_DRAM = 0x0b,
+ CTRL_CIR_ERROR_DSPCOMM = 0x29,
+};
+
+enum {
+ MECH_ERROR_HEAD_UP = 0x01,
+ MECH_ERROR_HEAD_DOWN = 0x02,
+ MECH_ERROR_MAIN_PINCH_UP = 0x03,
+ MECH_ERROR_MAIN_PINCH_DOWN = 0x04,
+ MECH_ERROR_SUB_PINCH_UP = 0x05,
+ MECH_ERROR_SUB_PINCH_DOWN = 0x06,
+ MECH_ERROR_FEEDIN_PINCH_UP = 0x07,
+ MECH_ERROR_FEEDIN_PINCH_DOWN = 0x08,
+ MECH_ERROR_FEEDOUT_PINCH_UP = 0x09,
+ MECH_ERROR_FEEDOUT_PINCH_DOWN = 0x0a,
+ MECH_ERROR_CUTTER_LR = 0x0b,
+ MECH_ERROR_CUTTER_RL = 0x0c,
+};
+
+enum {
+ SENSOR_ERROR_CUTTER = 0x05,
+ SENSOR_ERROR_HEAD_DOWN = 0x09,
+ SENSOR_ERROR_HEAD_UP = 0x0a,
+ SENSOR_ERROR_MAIN_PINCH_DOWN = 0x0b,
+ SENSOR_ERROR_MAIN_PINCH_UP = 0x0c,
+ SENSOR_ERROR_FEED_PINCH_DOWN = 0x0d,
+ SENSOR_ERROR_FEED_PINCH_UP = 0x0e,
+ SENSOR_ERROR_EXIT_PINCH_DOWN = 0x0f,
+ SENSOR_ERROR_EXIT_PINCH_UP = 0x10,
+ SENSOR_ERROR_LEFT_CUTTER = 0x11,
+ SENSOR_ERROR_RIGHT_CUTTER = 0x12,
+ SENSOR_ERROR_CENTER_CUTTER = 0x13,
+ SENSOR_ERROR_UPPER_CUTTER = 0x14,
+ SENSOR_ERROR_PAPER_FEED_COVER = 0x15,
+};
+
+enum {
+ TEMP_SENSOR_ERROR_HEAD_HIGH = 0x01,
+ TEMP_SENSOR_ERROR_HEAD_LOW = 0x02,
+ TEMP_SENSOR_ERROR_ENV_HIGH = 0x03,
+ TEMP_SENSOR_ERROR_ENV_LOW = 0x04,
+};
+
+enum {
+ COVER_OPEN_ERROR_UPPER = 0x01,
+ COVER_OPEN_ERROR_LOWER = 0x02,
+};
+
+enum {
+ PAPER_EMPTY_ERROR = 0x00,
+};
+
+enum {
+ RIBBON_ERROR = 0x00,
+};
+
+enum {
+ CURVE_TABLE_STATUS_INITIAL = 0x00,
+ CURVE_TABLE_STATUS_USERSET = 0x01,
+ CURVE_TABLE_STATUS_CURRENT = 0x02,
+};
+
+// XXX Paper jam has 0x01 -> 0xff as error codes
+
+/* Query media info */
+struct shinkos1245_cmd_getmedia {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x1a/0x2a/0x3a for A/B/C */
+ uint8_t pad[10];
+} __attribute__((packed));
+
+struct shinkos1245_mediadesc {
+ uint8_t code; /* Fixed at 0x10 */
+ uint16_t columns; /* BE */
+ uint16_t rows; /* BE */
+ uint8_t type; /* MEDIA_TYPE_* */
+ uint8_t print_type; /* aka "print method" in the spool file */
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+#define NUM_MEDIAS 5 /* Maximum per message */
+
+struct shinkos1245_resp_media {
+ uint8_t code;
+ uint8_t reserved[5];
+ uint8_t count; /* 1-5? */
+ struct shinkos1245_mediadesc data[NUM_MEDIAS];
+} __attribute__((packed));
+
+enum {
+ MEDIA_TYPE_UNKNOWN = 0x00,
+ MEDIA_TYPE_PAPER = 0x01,
+};
+
+enum {
+ PRINT_TYPE_STANDARD = 0x00,
+ PRINT_TYPE_8x5_2up = 0x01,
+ PRINT_TYPE_8x4_2up = 0x02,
+ PRINT_TYPE_8x6_8x4 = 0x03,
+ PRINT_TYPE_8x5 = 0x04,
+ PRINT_TYPE_8x4 = 0x05,
+ PRINT_TYPE_8x6 = 0x06,
+ PRINT_TYPE_8x6_2up = 0x07,
+ PRINT_TYPE_8x4_3up = 0x08,
+ PRINT_TYPE_8x8 = 0x09,
+};
+
+/* Cancel Job -- returns Status */
+struct shinkos1245_cmd_canceljob {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x13 */
+ uint8_t id; /* 1-255 */
+ uint8_t pad[9];
+} __attribute__((packed));
+
+/* Reset printer -- returns Status */
+struct shinkos1245_cmd_reset {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0xc0 */
+ uint8_t pad[10];
+} __attribute__((packed));
+
+/* Tone curve manipulation -- returns Status */
+struct shinkos1245_cmd_tone {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0xc0 */
+ uint8_t tone[4]; /* 0x54 0x4f 0x4e 0x45 */
+ uint8_t cmd2[1]; /* 0x72/0x77/0x65/0x20 for read/write/end/data */
+ union {
+ struct {
+ uint8_t tone_table;
+ uint8_t param_table;
+ uint8_t pad[3];
+ } read_write;
+ struct {
+ uint8_t pad[5];
+ } end_data;
+ };
+} __attribute__((packed));
+
+enum {
+ TONE_TABLE_STANDARD = 0,
+ TONE_TABLE_USER = 1,
+ TONE_TABLE_CURRENT = 2,
+};
+enum {
+ PARAM_TABLE_STANDARD = 1,
+ PARAM_TABLE_FINE = 2,
+};
+
+#define TONE_CURVE_SIZE 1536
+#define TONE_CURVE_DATA_BLOCK_SIZE 64
+
+/* Query Model information */
+struct shinkos1245_cmd_getmodel {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x02 */
+ uint8_t pad[10];
+} __attribute__((packed));
+
+struct shinkos1245_resp_getmodel {
+ uint8_t vendor_id[4];
+ uint8_t product_id[4];
+ uint8_t strings[40];
+} __attribute__((packed));
+
+
+/* Query and Set Matte info, returns a Matte response */
+struct shinkos1245_cmd_getmatte {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x20 */
+ uint8_t mode; /* Fixed at 0x00 */
+ uint8_t pad[9];
+} __attribute__((packed));
+
+struct shinkos1245_cmd_setmatte {
+ struct shinkos1245_cmd_hdr hdr;
+ uint8_t cmd[1]; /* 0x21 */
+ uint8_t mode; /* Fixed at 0x00 */
+ int8_t level; /* -25->+25 */
+ uint8_t pad[8];
+} __attribute__((packed));
+
+struct shinkos1245_resp_matte {
+ uint8_t code;
+ uint8_t mode;
+ int8_t level;
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+#define MATTE_MODE_MATTE 0x00
+
+/* Private data stucture */
+struct shinkos1245_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ uint8_t jobid;
+
+ struct s1245_printjob_hdr hdr;
+
+ struct shinkos1245_mediadesc medias[15];
+ int num_medias;
+
+ uint8_t *databuf;
+ int datalen;
+ int tonecurve;
+};
+
+enum {
+ S_IDLE = 0,
+ S_PRINTER_READY_CMD,
+ S_PRINTER_SENT_DATA,
+ S_FINISHED,
+};
+
+
+/* Basic printer I/O stuffs */
+static void shinkos1245_fill_hdr(struct shinkos1245_cmd_hdr *hdr)
+{
+ hdr->prefix = 0x03;
+ hdr->hdr[0] = 0x1b;
+ hdr->hdr[1] = 0x43;
+ hdr->hdr[2] = 0x48;
+ hdr->hdr[3] = 0x43;
+}
+
+static int shinkos1245_do_cmd(struct shinkos1245_ctx *ctx,
+ void *cmd, int cmd_len,
+ void *resp, int resp_len,
+ int *actual_len)
+{
+ int ret;
+
+ /* Write command */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmd, cmd_len)))
+ return (ret < 0) ? ret : -99;
+
+ /* Read response */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ resp, resp_len, actual_len);
+ if (ret < 0)
+ return ret;
+ if (*actual_len < resp_len) {
+ ERROR("Short read! (%d/%d))\n", *actual_len, resp_len);
+ return -99;
+ }
+
+ return ret;
+}
+
+static int shinkos1245_get_status(struct shinkos1245_ctx *ctx,
+ struct shinkos1245_resp_status *resp)
+{
+ struct shinkos1245_cmd_getstatus cmd;
+ int ret, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x03;
+ memset(cmd.pad, 0, sizeof(cmd.pad));
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ resp, sizeof(*resp), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute GET_STATUS command\n");
+ return ret;
+ }
+ if (resp->code != CMD_CODE_OK) {
+ ERROR("Bad return code on GET_STATUS (%02x)\n",
+ resp->code);
+ return -99;
+ }
+
+ return 0;
+}
+
+static int shinkos1245_get_media(struct shinkos1245_ctx *ctx)
+{
+ struct shinkos1245_cmd_getmedia cmd;
+ struct shinkos1245_resp_media resp;
+ int i, j;
+ int ret = 0, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ memset(cmd.pad, 0, sizeof(cmd.pad));
+ for (i = 1 ; i <= 3 ; i++) {
+ cmd.cmd[0] = 0x0a || (i << 4);
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute GET_MEDIA command\n");
+ return ret;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on GET_MEDIA (%02x)\n",
+ resp.code);
+ return -99;
+ }
+
+ if (resp.count > NUM_MEDIAS)
+ resp.count = NUM_MEDIAS;
+
+ /* Store media info */
+ for (j = 0; j < resp.count ; j++) {
+ ctx->medias[ctx->num_medias].code = resp.data[j].code;
+ ctx->medias[ctx->num_medias].columns = be16_to_cpu(resp.data[j].columns);
+ ctx->medias[ctx->num_medias].rows = be16_to_cpu(resp.data[j].rows);
+ ctx->medias[ctx->num_medias].type = resp.data[j].type;
+ ctx->medias[ctx->num_medias].print_type = resp.data[j].print_type;
+ ctx->num_medias++;
+ }
+
+ if (resp.count < 5)
+ break;
+ }
+ return ret;
+}
+
+static int shinkos1245_get_printerid(struct shinkos1245_ctx *ctx,
+ struct shinkos1245_resp_getid *resp)
+{
+ struct shinkos1245_cmd_getid cmd;
+ int ret, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x12;
+ memset(cmd.pad, 0, sizeof(cmd.pad));
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ resp, sizeof(*resp), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute GET_PRINTERID command\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int shinkos1245_set_printerid(struct shinkos1245_ctx *ctx,
+ char *id)
+{
+ struct shinkos1245_cmd_setid cmd;
+ struct shinkos1245_resp_status sts;
+
+ int ret, num;
+ int i;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x0a;
+ cmd.cmd[1] = 0x22;
+
+ for (i = 0 ; i < (int)sizeof(cmd.data) ; i++) {
+ if (*id)
+ cmd.data[i] = (uint8_t) *id;
+ else
+ cmd.data[i] = ' ';
+ }
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &sts, sizeof(sts), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute SET_PRINTERID command\n");
+ return ret;
+ }
+ if (sts.code != CMD_CODE_OK) {
+ ERROR("Bad return code on SET_PRINTERID command\n");
+ return -99;
+ }
+ return 0;
+}
+
+static int shinkos1245_canceljob(struct shinkos1245_ctx *ctx,
+ int id)
+{
+ struct shinkos1245_cmd_canceljob cmd;
+ struct shinkos1245_resp_status sts;
+
+ int ret, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x13;
+ cmd.id = id;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &sts, sizeof(sts), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute CANCELJOB command\n");
+ return ret;
+ }
+ if (sts.code != CMD_CODE_OK) {
+ ERROR("Bad return code on CANCELJOB command\n");
+ return -99;
+ }
+ return 0;
+}
+
+static int shinkos1245_set_matte(struct shinkos1245_ctx *ctx,
+ int intensity)
+{
+ struct shinkos1245_cmd_setmatte cmd;
+ struct shinkos1245_resp_matte sts;
+
+ int ret, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x21;
+ cmd.mode = MATTE_MODE_MATTE;
+ cmd.level = intensity;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &sts, sizeof(sts), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute SET_MATTE command\n");
+ return ret;
+ }
+ if (sts.code == CMD_CODE_OK)
+ return 0;
+ if (sts.code == CMD_CODE_BAD)
+ return 1;
+
+ ERROR("Bad return code (%02x) on SET_MATTE command\n", sts.code);
+ return -99;
+}
+
+static int shinkos1245_get_matte(struct shinkos1245_ctx *ctx,
+ int *intensity)
+{
+ struct shinkos1245_cmd_getmatte cmd;
+ struct shinkos1245_resp_matte sts;
+
+ int ret, num;
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x20;
+ cmd.mode = MATTE_MODE_MATTE;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &sts, sizeof(sts), &num);
+ if (ret < 0) {
+ ERROR("Failed to execute GET_MATTE command\n");
+ return ret;
+ }
+ if (sts.code != CMD_CODE_OK) {
+ ERROR("Bad return code (%02x) on GET_MATTE command\n", sts.code);
+ return -99;
+ }
+ *intensity = sts.level;
+
+ return 0;
+}
+
+
+/* Structure dumps */
+static char *shinkos1245_status_str(struct shinkos1245_resp_status *resp)
+{
+ switch(resp->state.status1) {
+ case STATE_STATUS1_STANDBY:
+ return "Standby (Ready)";
+ case STATE_STATUS1_WAIT:
+ switch (resp->state.status2) {
+ case WAIT_STATUS2_INIT:
+ return "Wait (Initializing)";
+ case WAIT_STATUS2_RIBBON:
+ return "Wait (Ribbon Winding)";
+ case WAIT_STATUS2_THERMAL:
+ return "Wait (Thermal Protection)";
+ case WAIT_STATUS2_OPERATING:
+ return "Wait (Operating)";
+ case WAIT_STATUS2_BUSY:
+ return "Wait (Busy)";
+ default:
+ return "Wait (Unknown)";
+ }
+ case STATE_STATUS1_ERROR:
+ switch (resp->state.status2) {
+ case ERROR_STATUS2_CTRL_CIRCUIT:
+ switch (resp->state.error) {
+ case CTRL_CIR_ERROR_EEPROM1:
+ return "Error (EEPROM1)";
+ case CTRL_CIR_ERROR_EEPROM2:
+ return "Error (EEPROM2)";
+ case CTRL_CIR_ERROR_DSP:
+ return "Error (DSP)";
+ case CTRL_CIR_ERROR_CRC_MAIN:
+ return "Error (Main CRC)";
+ case CTRL_CIR_ERROR_DL_MAIN:
+ return "Error (Main Download)";
+ case CTRL_CIR_ERROR_CRC_DSP:
+ return "Error (DSP CRC)";
+ case CTRL_CIR_ERROR_DL_DSP:
+ return "Error (DSP Download)";
+ case CTRL_CIR_ERROR_ASIC:
+ return "Error (ASIC)";
+ case CTRL_CIR_ERROR_DRAM:
+ return "Error (DRAM)";
+ case CTRL_CIR_ERROR_DSPCOMM:
+ return "Error (DSP Communincation)";
+ default:
+ return "Error (Unknown Circuit)";
+ }
+ case ERROR_STATUS2_MECHANISM_CTRL:
+ switch (resp->state.error) {
+ case MECH_ERROR_HEAD_UP:
+ return "Error (Head Up Mechanism)";
+ case MECH_ERROR_HEAD_DOWN:
+ return "Error (Head Down Mechanism)";
+ case MECH_ERROR_MAIN_PINCH_UP:
+ return "Error (Main Pinch Up Mechanism)";
+ case MECH_ERROR_MAIN_PINCH_DOWN:
+ return "Error (Main Pinch Down Mechanism)";
+ case MECH_ERROR_SUB_PINCH_UP:
+ return "Error (Sub Pinch Up Mechanism)";
+ case MECH_ERROR_SUB_PINCH_DOWN:
+ return "Error (Sub Pinch Down Mechanism)";
+ case MECH_ERROR_FEEDIN_PINCH_UP:
+ return "Error (Feed-in Pinch Up Mechanism)";
+ case MECH_ERROR_FEEDIN_PINCH_DOWN:
+ return "Error (Feed-in Pinch Down Mechanism)";
+ case MECH_ERROR_FEEDOUT_PINCH_UP:
+ return "Error (Feed-out Pinch Up Mechanism)";
+ case MECH_ERROR_FEEDOUT_PINCH_DOWN:
+ return "Error (Feed-out Pinch Down Mechanism)";
+ case MECH_ERROR_CUTTER_LR:
+ return "Error (Left->Right Cutter)";
+ case MECH_ERROR_CUTTER_RL:
+ return "Error (Right->Left Cutter)";
+ default:
+ return "Error (Unknown Mechanism)";
+ }
+ case ERROR_STATUS2_SENSOR:
+ switch (resp->state.error) {
+ case SENSOR_ERROR_CUTTER:
+ return "Error (Cutter Sensor)";
+ case SENSOR_ERROR_HEAD_DOWN:
+ return "Error (Head Down Sensor)";
+ case SENSOR_ERROR_HEAD_UP:
+ return "Error (Head Up Sensor)";
+ case SENSOR_ERROR_MAIN_PINCH_DOWN:
+ return "Error (Main Pinch Down Sensor)";
+ case SENSOR_ERROR_MAIN_PINCH_UP:
+ return "Error (Main Pinch Up Sensor)";
+ case SENSOR_ERROR_FEED_PINCH_DOWN:
+ return "Error (Feed Pinch Down Sensor)";
+ case SENSOR_ERROR_FEED_PINCH_UP:
+ return "Error (Feed Pinch Up Sensor)";
+ case SENSOR_ERROR_EXIT_PINCH_DOWN:
+ return "Error (Exit Pinch Up Sensor)";
+ case SENSOR_ERROR_EXIT_PINCH_UP:
+ return "Error (Exit Pinch Up Sensor)";
+ case SENSOR_ERROR_LEFT_CUTTER:
+ return "Error (Left Cutter Sensor)";
+ case SENSOR_ERROR_RIGHT_CUTTER:
+ return "Error (Right Cutter Sensor)";
+ case SENSOR_ERROR_CENTER_CUTTER:
+ return "Error (Center Cutter Sensor)";
+ case SENSOR_ERROR_UPPER_CUTTER:
+ return "Error (Upper Cutter Sensor)";
+ case SENSOR_ERROR_PAPER_FEED_COVER:
+ return "Error (Paper Feed Cover)";
+ default:
+ return "Error (Unknown Sensor)";
+ }
+ case ERROR_STATUS2_COVER_OPEN:
+ switch (resp->state.error) {
+ case COVER_OPEN_ERROR_UPPER:
+ return "Error (Upper Cover Open)";
+ case COVER_OPEN_ERROR_LOWER:
+ return "Error (Lower Cover Open)";
+ default:
+ return "Error (Unknown Cover Open)";
+ }
+ case ERROR_STATUS2_TEMP_SENSOR:
+ switch (resp->state.error) {
+ case TEMP_SENSOR_ERROR_HEAD_HIGH:
+ return "Error (Head Temperature High)";
+ case TEMP_SENSOR_ERROR_HEAD_LOW:
+ return "Error (Head Temperature Low)";
+ case TEMP_SENSOR_ERROR_ENV_HIGH:
+ return "Error (Environmental Temperature High)";
+ case TEMP_SENSOR_ERROR_ENV_LOW:
+ return "Error (Environmental Temperature Low)";
+ default:
+ return "Error (Unknown Temperature)";
+ }
+ case ERROR_STATUS2_PAPER_JAM:
+ return "Error (Paper Jam)";
+ case ERROR_STATUS2_PAPER_EMPTY:
+ return "Error (Paper Empty)";
+ case ERROR_STATUS2_RIBBON_ERR:
+ return "Error (Ribbon)";
+ default:
+ return "Error (Unknown)";
+ }
+ default:
+ return "Unknown!";
+ }
+}
+
+static char* shinkos1245_tonecurves(int type, int table)
+{
+ switch (type) {
+ case TONE_TABLE_STANDARD:
+ switch (table) {
+ case PARAM_TABLE_STANDARD:
+ return "Standard/Standard";
+ case PARAM_TABLE_FINE:
+ return "Standard/Fine";
+ default:
+ return "Standard/Unknown";
+ }
+ case TONE_TABLE_USER:
+ switch (table) {
+ case PARAM_TABLE_STANDARD:
+ return "User/Standard";
+ case PARAM_TABLE_FINE:
+ return "User/Fine";
+ default:
+ return "User/Unknown";
+ }
+ case TONE_TABLE_CURRENT:
+ switch (table) {
+ case PARAM_TABLE_STANDARD:
+ return "Current/Standard";
+ case PARAM_TABLE_FINE:
+ return "Current/Fine";
+ default:
+ return "Current/Unknown";
+ }
+ default:
+ return "Unknown";
+ }
+}
+
+static void shinkos1245_dump_status(struct shinkos1245_resp_status *sts)
+{
+ char *detail;
+ switch (sts->print_status) {
+ case STATUS_PRINTING:
+ detail = "Printing";
+ break;
+ case STATUS_IDLE:
+ detail = "Idle";
+ break;
+ default:
+ detail = "Unknown";
+ break;
+ }
+ INFO("Printer Status: %s\n", detail);
+
+ /* Byteswap */
+ sts->state.status2 = be32_to_cpu(sts->state.status2);
+
+ INFO("Printer State: %s # %02x %08x %02x\n",
+ shinkos1245_status_str(sts),
+ sts->state.status1, sts->state.status2, sts->state.error);
+ INFO("Counters:\n");
+ INFO("\tLifetime : %d\n", be32_to_cpu(sts->counters.lifetime));
+ INFO("\tThermal Head : %d\n", be32_to_cpu(sts->counters.maint));
+ INFO("\tMedia : %d\n", be32_to_cpu(sts->counters.media));
+ INFO("\tCutter : %d\n", be32_to_cpu(sts->counters.cutter));
+
+ INFO("Versions:\n");
+ INFO("\tUSB Boot : %d\n", sts->counters.ver_boot);
+ INFO("\tUSB Control : %d\n", sts->counters.ver_ctrl);
+ INFO("\tMain Boot : %d\n", be16_to_cpu(sts->versions.main_boot));
+ INFO("\tMain Control: %d\n", be16_to_cpu(sts->versions.main_control));
+ INFO("\tDSP Boot : %d\n", be16_to_cpu(sts->versions.dsp_boot));
+ INFO("\tDSP Control : %d\n", be16_to_cpu(sts->versions.dsp_control));
+
+// INFO("USB TypeFlag: %02x\n", sts->counters.control_flag);
+
+ INFO("Bank 1 ID: %d\n", sts->counters2.bank1_id);
+ INFO("\tPrints: %d/%d complete\n",
+ be16_to_cpu(sts->counters2.bank1_complete),
+ be16_to_cpu(sts->counters2.bank1_spec));
+ INFO("Bank 2 ID: %d\n", sts->counters2.bank2_id);
+ INFO("\tPrints: %d/%d complete\n",
+ be16_to_cpu(sts->counters2.bank2_complete),
+ be16_to_cpu(sts->counters2.bank2_spec));
+
+ switch (sts->curve_status) {
+ case CURVE_TABLE_STATUS_INITIAL:
+ detail = "Initial/Default";
+ break;
+ case CURVE_TABLE_STATUS_USERSET:
+ detail = "User Stored";
+ break;
+ case CURVE_TABLE_STATUS_CURRENT:
+ detail = "Current";
+ break;
+ default:
+ detail = "Unknown";
+ break;
+ }
+ INFO("Tone Curve Status: %s\n", detail);
+}
+
+static void shinkos1245_dump_media(struct shinkos1245_mediadesc *medias,
+ int count)
+{
+ int i;
+
+ INFO("Supported print sizes: %d\n", count);
+
+ for (i = 0 ; i < count ; i++) {
+ INFO("\t %02x: %04d*%04d (%02x/%02d)\n",
+ medias[i].print_type,
+ medias[i].columns,
+ medias[i].rows,
+ medias[i].code, medias[i].type);
+ }
+}
+
+static int get_tonecurve(struct shinkos1245_ctx *ctx, int type, int table, char *fname)
+{
+ int ret = 0, num, remaining;
+ uint8_t *data, *ptr;
+
+ struct shinkos1245_cmd_tone cmd;
+ struct shinkos1245_resp_status resp;
+
+ INFO("Dump %s Tone Curve to '%s'\n", shinkos1245_tonecurves(type, table), fname);
+
+ /* Issue a tone_read_start */
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x0c;
+ cmd.tone[0] = 0x54;
+ cmd.tone[1] = 0x4f;
+ cmd.tone[2] = 0x4e;
+ cmd.tone[3] = 0x45;
+ cmd.cmd2[0] = 0x72;
+ cmd.read_write.tone_table = type;
+ cmd.read_write.param_table = table;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_READ command\n");
+ return ret;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_READ (%02x)\n",
+ resp.code);
+ return -99;
+ }
+
+ /* Get the data out */
+ remaining = TONE_CURVE_SIZE;
+ data = malloc(remaining);
+ if (!data) {
+ ERROR("Memory Allocation Failure!\n");
+ return -11;
+ }
+ ptr = data;
+
+ while(remaining) {
+ /* Issue a tone_data message */
+ cmd.cmd2[0] = 0x20;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_DATA command\n");
+ goto done;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_DATA (%02x)\n",
+ resp.code);
+ ret = -99;
+ goto done;
+ }
+
+ /* And read back 64-bytes of data */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ ptr, TONE_CURVE_DATA_BLOCK_SIZE, &num);
+ if (num != TONE_CURVE_DATA_BLOCK_SIZE) {
+ ret = -99;
+ goto done;
+ }
+ if (ret < 0)
+ goto done;
+ ptr += num;
+ }
+
+ /* Issue a tone_end */
+ cmd.cmd2[0] = 0x65;
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_END command\n");
+ goto done;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_END (%02x)\n",
+ resp.code);
+ ret = -99;
+ goto done;
+ }
+
+ /* Open file and write it out */
+ {
+ int tc_fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+ if (tc_fd < 0) {
+ ret = tc_fd;
+ goto done;
+ }
+
+ ret = write(tc_fd, data, TONE_CURVE_SIZE);
+ if (ret < 0)
+ goto done;
+ close(tc_fd);
+ }
+
+done:
+ free(data);
+
+ return ret;
+}
+
+static int set_tonecurve(struct shinkos1245_ctx *ctx, int type, int table, char *fname)
+{
+ int ret = 0, num, remaining;
+ uint8_t *data, *ptr;
+
+ struct shinkos1245_cmd_tone cmd;
+ struct shinkos1245_resp_status resp;
+
+ INFO("Read %d/%d Tone Curve from '%s'\n", type, table, fname); // XXX
+
+ /* Allocate space */
+ remaining = TONE_CURVE_SIZE;
+ data = malloc(remaining);
+ if (!data) {
+ ERROR("Memory Allocation Failure!\n");
+ return -11;
+ }
+ ptr = data;
+
+ /* Open file and read it in */
+ {
+ int tc_fd = open(fname, O_RDONLY);
+ if (tc_fd < 0) {
+ ret = tc_fd;
+ goto done;
+ }
+
+ ret = read(tc_fd, data, TONE_CURVE_SIZE);
+ if (ret < 0) {
+ close(tc_fd);
+ goto done;
+ }
+
+ close(tc_fd);
+ }
+
+ /* Issue a tone_write_start */
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x0c;
+ cmd.tone[0] = 0x54;
+ cmd.tone[1] = 0x4f;
+ cmd.tone[2] = 0x4e;
+ cmd.tone[3] = 0x45;
+ cmd.cmd2[0] = 0x77;
+ cmd.read_write.tone_table = type;
+ cmd.read_write.param_table = table;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_WRITE command\n");
+ goto done;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_WRITE (%02x)\n",
+ resp.code);
+ ret = -99;
+ goto done;
+ }
+
+ while(remaining) {
+ /* Issue a tone_data message */
+ cmd.cmd2[0] = 0x20;
+
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_DATA command\n");
+ goto done;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_DATA (%02x)\n",
+ resp.code);
+ ret = -99;
+ goto done;
+ }
+
+ /* Write 64-bytes of data */
+ ret = send_data(ctx->dev, ctx->endp_up,
+ ptr, TONE_CURVE_DATA_BLOCK_SIZE);
+ if (ret < 0)
+ goto done;
+ ptr += num;
+ }
+
+ /* Issue a tone_end */
+ cmd.cmd2[0] = 0x65;
+ ret = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &resp, sizeof(resp), &num);
+
+ if (ret < 0) {
+ ERROR("Failed to execute TONE_END command\n");
+ goto done;
+ }
+ if (resp.code != CMD_CODE_OK) {
+ ERROR("Bad return code on TONE_END (%02x)\n",
+ resp.code);
+ ret = -99;
+ goto done;
+ }
+
+done:
+ free(data);
+
+ return ret;
+}
+
+
+/* Driver API */
+
+static void shinkos1245_cmdline(void)
+{
+ DEBUG("\t\t[ -m ] # Query media\n");
+ DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -u ] # Query user string\n");
+ DEBUG("\t\t[ -U sometext ] # Set user string\n");
+ DEBUG("\t\t[ -X jobid ] # Abort a printjob\n");
+ DEBUG("\t\t[ -F ] # Tone curve refers to FINE mode\n");
+ DEBUG("\t\t[ -c filename ] # Get user/NV tone curve\n");
+ DEBUG("\t\t[ -C filename ] # Set user/NV tone curve\n");
+ DEBUG("\t\t[ -l filename ] # Get current tone curve\n");
+ DEBUG("\t\t[ -L filename ] # Set current tone curve\n");
+}
+
+int shinkos1245_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct shinkos1245_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "c:C:l:L:FmsuU:X:")) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ case 'F':
+ ctx->tonecurve = PARAM_TABLE_FINE;
+ break;
+ case 'c':
+ j = get_tonecurve(ctx, TONE_TABLE_USER, ctx->tonecurve, optarg);
+ break;
+ case 'C':
+ j = set_tonecurve(ctx, TONE_TABLE_USER, ctx->tonecurve, optarg);
+ break;
+ case 'l':
+ j = get_tonecurve(ctx, TONE_TABLE_CURRENT, ctx->tonecurve, optarg);
+ break;
+ case 'L':
+ j = set_tonecurve(ctx, TONE_TABLE_CURRENT, ctx->tonecurve, optarg);
+ break;
+ case 'm':
+ j = shinkos1245_get_media(ctx);
+ if (!j)
+ shinkos1245_dump_media(ctx->medias, ctx->num_medias);
+ break;
+ case 's': {
+ struct shinkos1245_resp_status sts;
+ j = shinkos1245_get_status(ctx, &sts);
+ if (!j)
+ shinkos1245_dump_status(&sts);
+ break;
+ }
+ case 'u': {
+ struct shinkos1245_resp_getid resp;
+ j = shinkos1245_get_printerid(ctx, &resp);
+ if (!j) {
+ char buffer[sizeof(resp.data)+1];
+ memcpy(buffer, resp.data, sizeof(resp.data));
+ buffer[sizeof(resp.data)] = 0;
+ INFO("Printer ID: %02x '%s'\n", resp.id, buffer);
+ }
+ break;
+ }
+ case 'U':
+ j = shinkos1245_set_printerid(ctx, optarg);
+ break;
+ case 'X':
+ j = shinkos1245_canceljob(ctx, atoi(optarg));
+ break;
+ default:
+ break; /* Ignore completely */
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+static void *shinkos1245_init(void)
+{
+ struct shinkos1245_ctx *ctx = malloc(sizeof(struct shinkos1245_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct shinkos1245_ctx));
+
+ ctx->tonecurve = PARAM_TABLE_STANDARD;
+
+ return ctx;
+}
+
+static void shinkos1245_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct shinkos1245_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ ctx->type = lookup_printer_type(&shinkos1245_backend,
+ desc.idVendor, desc.idProduct);
+
+ /* Ensure jobid is sane */
+ ctx->jobid = (jobid & 0x7f) + 1;
+}
+
+
+static void shinkos1245_teardown(void *vctx) {
+ struct shinkos1245_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+
+ free(ctx);
+}
+
+static int shinkos1245_read_parse(void *vctx, int data_fd) {
+ struct shinkos1245_ctx *ctx = vctx;
+ int ret;
+ uint8_t tmpbuf[4];
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ /* Read in then validate header */
+ ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
+ if (ret < 0)
+ return ret;
+ if (ret < 0 || ret != sizeof(ctx->hdr))
+ return CUPS_BACKEND_CANCEL;
+
+ if (le32_to_cpu(ctx->hdr.len1) != 0x10 ||
+ le32_to_cpu(ctx->hdr.len2) != 0x64 ||
+ le32_to_cpu(ctx->hdr.dpi) != 300) {
+ ERROR("Unrecognized header data format!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ ctx->hdr.model = le32_to_cpu(ctx->hdr.model);
+
+ if(ctx->hdr.model != 1245) {
+ ERROR("Unrecognized printer (%d)!\n", ctx->hdr.model);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Finish byteswapping */
+ ctx->hdr.media = le32_to_cpu(ctx->hdr.media);
+ ctx->hdr.method = le32_to_cpu(ctx->hdr.method);
+ ctx->hdr.mode = le32_to_cpu(ctx->hdr.mode);
+ ctx->hdr.mattedepth = le32_to_cpu(ctx->hdr.mattedepth);
+ ctx->hdr.dust = le32_to_cpu(ctx->hdr.dust);
+ ctx->hdr.columns = le32_to_cpu(ctx->hdr.columns);
+ ctx->hdr.rows = le32_to_cpu(ctx->hdr.rows);
+ ctx->hdr.copies = le32_to_cpu(ctx->hdr.copies);
+
+ /* Allocate space */
+ if (ctx->databuf) {
+ free(ctx->databuf);
+ ctx->databuf = NULL;
+ }
+
+ ctx->datalen = ctx->hdr.rows * ctx->hdr.columns * 3;
+ ctx->databuf = malloc(ctx->datalen);
+ if (!ctx->databuf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ {
+ int remain = ctx->datalen;
+ uint8_t *ptr = ctx->databuf;
+ do {
+ ret = read(data_fd, ptr, remain);
+ if (ret < 0) {
+ ERROR("Read failed (%d/%d/%d)\n",
+ ret, remain, ctx->datalen);
+ perror("ERROR: Read failed");
+ return ret;
+ }
+ ptr += ret;
+ remain -= ret;
+ } while (remain);
+ }
+
+ /* Make sure footer is sane too */
+ ret = read(data_fd, tmpbuf, 4);
+ if (ret != 4) {
+ ERROR("Read failed (%d/%d/%d)\n",
+ ret, 4, 4);
+ perror("ERROR: Read failed");
+ return ret;
+ }
+ if (tmpbuf[0] != 0x04 ||
+ tmpbuf[1] != 0x03 ||
+ tmpbuf[2] != 0x02 ||
+ tmpbuf[3] != 0x01) {
+ ERROR("Unrecognized footer data format!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int shinkos1245_main_loop(void *vctx, int copies) {
+ struct shinkos1245_ctx *ctx = vctx;
+ int i, num, last_state = -1, state = S_IDLE;
+ struct shinkos1245_resp_status status1, status2;
+
+ // XXX query printer info
+
+ /* Query Media information if necessary */
+ if (!ctx->num_medias)
+ shinkos1245_get_media(ctx);
+ if (!ctx->num_medias) {
+ ERROR("Media Query Error\n");
+ return CUPS_BACKEND_FAILED;
+ }
+ /* Make sure print size is supported */
+ for (i = 0 ; i < ctx->num_medias ; i++) {
+ if (ctx->hdr.media == ctx->medias[i].code &&
+ ctx->hdr.method == ctx->medias[i].print_type &&
+ ctx->hdr.rows == ctx->medias[i].rows &&
+ ctx->hdr.columns == ctx->medias[i].columns)
+ break;
+ }
+ if (i == ctx->num_medias) {
+ ERROR("Unsupported print type\n");
+ return CUPS_BACKEND_HOLD;
+ }
+
+ /* Fix max print count. */
+ if (copies > 9999) // XXX test against remaining media
+ copies = 9999;
+
+top:
+ if (state != last_state) {
+ if (dyesub_debug)
+ DEBUG("last_state %d new %d\n", last_state, state);
+ }
+
+ /* Send status query */
+ i = shinkos1245_get_status(ctx, &status1);
+ if (i < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (memcmp(&status1, &status2, sizeof(status1))) {
+ memcpy(&status2, &status1, sizeof(status1));
+ // status changed, check for errors and whatnot
+ } else if (state == last_state) {
+ sleep(1);
+ goto top;
+ }
+
+ /* Make sure we're not in an error state */
+ if (status1.state.status1 == STATE_STATUS1_ERROR)
+ goto printer_error;
+
+ last_state = state;
+
+ fflush(stderr);
+
+ switch (state) {
+ case S_IDLE:
+ INFO("Waiting for printer idle\n");
+
+ if (status1.state.status1 == STATE_STATUS1_STANDBY) {
+ state = S_PRINTER_READY_CMD;
+ break;
+ }
+
+ if (status1.print_status == STATUS_IDLE) {
+ state = S_PRINTER_READY_CMD;
+ break;
+ }
+
+ // XXX what about STATUS_WAIT ?
+ // XXX see if printer has an empty bank?
+
+ /* If the printer is "busy" check to see if there's any
+ open memory banks so we can queue the next print */
+ if (!status1.counters2.bank1_remain ||
+ !status1.counters2.bank2_remain) {
+ state = S_PRINTER_READY_CMD;
+ break;
+ }
+ break;
+ case S_PRINTER_READY_CMD: {
+ struct shinkos1245_cmd_print cmd;
+
+ /* Set matte intensity */
+ if (ctx->hdr.mattedepth != 0x7fffffff) {
+ int current = -1;
+ i = shinkos1245_get_matte(ctx, &current);
+ if (i < 0)
+ goto printer_error;
+ if (current != ctx->hdr.mattedepth) {
+ i = shinkos1245_set_matte(ctx, ctx->hdr.mattedepth);
+ if (i < 0)
+ goto printer_error;
+ if (i > 0) {
+ INFO("Can't set matte intensity when printing in progres...\n");
+ state = S_IDLE;
+ sleep(1);
+ break;
+ }
+ }
+ }
+
+ INFO("Initiating print job (internal id %d)\n", ctx->jobid);
+
+ shinkos1245_fill_hdr(&cmd.hdr);
+ cmd.cmd[0] = 0x0a;
+ cmd.cmd[1] = 0x00;
+
+ cmd.id = ctx->jobid;
+ cmd.count = cpu_to_be16(uint16_to_packed_bcd(copies));
+ cmd.columns = cpu_to_be16(ctx->hdr.columns);
+ cmd.rows = cpu_to_be16(ctx->hdr.rows);
+ cmd.media = ctx->hdr.media;
+ cmd.mode = (ctx->hdr.mode & 0x3f) || ((ctx->hdr.dust & 0x3) << 6);
+ cmd.combo = ctx->hdr.method;
+
+ /* Issue print commmand */
+ i = shinkos1245_do_cmd(ctx, &cmd, sizeof(cmd),
+ &status1, sizeof(status1),
+ &num);
+ if (i < 0)
+ goto printer_error;
+
+ /* Check for buffer full state, and wait if we're full */
+ if (status1.code != CMD_CODE_OK) {
+ if (status1.print_status == STATUS_PRINTING) {
+ sleep(1);
+ break;
+ } else {
+ goto printer_error;
+ }
+ }
+
+ /* Check for error states */
+ if (status1.state.status1 == STATE_STATUS1_ERROR)
+ goto printer_error;
+
+ /* Send over data */
+ INFO("Sending image data to printer\n");
+ if ((i = 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);
+ state = S_PRINTER_SENT_DATA;
+ break;
+ }
+ case S_PRINTER_SENT_DATA:
+ if (fast_return) {
+ INFO("Fast return mode enabled.\n");
+ state = S_FINISHED;
+ }
+ /* Check for completion */
+ if (status1.print_status == STATUS_IDLE)
+ state = S_FINISHED;
+
+ break;
+ default:
+ break;
+ }
+
+ if (state != S_FINISHED)
+ goto top;
+
+ INFO("Print complete\n");
+
+ if (copies && --copies) {
+ state = S_IDLE;
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+
+printer_error:
+ /* Byteswap */
+ status1.state.status2 = be32_to_cpu(status1.state.status2);
+
+ ERROR("Printer Error: %s # %02x %08x %02x\n",
+ shinkos1245_status_str(&status1),
+ status1.state.status1, status1.state.status2, status1.state.error);
+
+ return CUPS_BACKEND_FAILED;
+}
+
+static int shinkos1245_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
+{
+ struct shinkos1245_resp_getid resp;
+ int i;
+
+ struct shinkos1245_ctx ctx = {
+ .dev = dev,
+ .endp_up = endp_up,
+ .endp_down = endp_down,
+ };
+
+ i = shinkos1245_get_printerid(&ctx, &resp);
+ if (i < 0)
+ return CUPS_BACKEND_FAILED;
+
+ for (i = 0 ; i < (int) sizeof(resp.data) && i < buf_len; i++) {
+ buf[i] = resp.data[i];
+ }
+
+ /* Ensure null-termination */
+ if (i < buf_len)
+ buf[i] = 0;
+ else
+ buf[buf_len-1] = 0;
+
+ return CUPS_BACKEND_OK;
+}
+
+/* Exported */
+#define USB_VID_SHINKO 0x10CE
+#define USB_PID_SHINKO_S1245 0x0007
+
+struct dyesub_backend shinkos1245_backend = {
+ .name = "Shinko/Sinfonia CHC-S1245",
+ .version = "0.07WIP",
+ .uri_prefix = "shinkos1245",
+ .cmdline_usage = shinkos1245_cmdline,
+ .cmdline_arg = shinkos1245_cmdline_arg,
+ .init = shinkos1245_init,
+ .attach = shinkos1245_attach,
+ .teardown = shinkos1245_teardown,
+ .read_parse = shinkos1245_read_parse,
+ .main_loop = shinkos1245_main_loop,
+ .query_serno = shinkos1245_query_serno,
+ .devices = {
+ { USB_VID_SHINKO, USB_PID_SHINKO_S1245, P_SHINKO_S1245, ""},
+ { 0, 0, 0, ""}
+ }
+};
+
+/* CHC-S1245 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 00 00 00 00 01 00 00 00 MM == Model (ie 1245d)
+ 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == Media Size (0x10 fixed)
+ MM 00 00 00 PP 00 00 00 00 00 00 00 ZZ ZZ ZZ ZZ MM = Print Method (aka cut control), PP = Default/Glossy/Matte (0x01/0x03/0x05), ZZ == matte intensity (0x7fffffff for glossy, else 0x00000000 +- 25 for matte)
+ VV 00 00 00 WW WW 00 00 HH HH 00 00 XX 00 00 00 VV == dust; 0x00 default, 0x01 off, 0x02 on, 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.
+ 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 ]]
+
+
+*/
diff --git a/src/cups/shinko_s2145_print.c b/src/cups/shinko_s2145_print.c
index 5196528..c6fd88f 100644
--- a/src/cups/shinko_s2145_print.c
+++ b/src/cups/shinko_s2145_print.c
@@ -39,8 +39,9 @@
#include <fcntl.h>
#include <signal.h>
-#include "backend_common.h"
+#define BACKEND shinkos2145_backend
+#include "backend_common.h"
enum {
S_IDLE = 0,
@@ -53,7 +54,7 @@ enum {
struct s2145_printjob_hdr {
uint32_t len1; /* Fixed at 0x10 */
uint32_t model; /* Equal to the printer model (eg '2145' or '1245' decimal) */
- uint32_t med_type; /* 6145 only, media type */
+ uint32_t unk2;
uint32_t unk3; /* Fixed at 0x01 */
uint32_t len2; /* Fixed at 0x64 */
@@ -61,9 +62,9 @@ struct s2145_printjob_hdr {
uint32_t media;
uint32_t unk6;
- 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 method;
+ uint32_t mode;
+ uint32_t unk7;
uint32_t unk8;
uint32_t unk9;
@@ -94,13 +95,12 @@ struct shinkos2145_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
+
uint8_t jobid;
- uint8_t fast_return;
struct s2145_printjob_hdr hdr;
- uint32_t model;
-
uint8_t *databuf;
int datalen;
};
@@ -684,11 +684,11 @@ struct s2145_status_resp {
static char *bank_statuses(uint8_t v)
{
switch (v) {
- case 0:
+ case BANK_STATUS_FREE:
return "Free";
- case 1:
+ case BANK_STATUS_XFER:
return "Xfer";
- case 2:
+ case BANK_STATUS_FULL:
return "Full";
default:
return "Unknown";
@@ -723,7 +723,7 @@ struct s2145_mediainfo_item {
uint16_t columns;
uint16_t rows;
uint8_t media_type;
- uint8_t print_type;
+ uint8_t print_type; /* The same as the "print method" */
uint8_t reserved[3];
} __attribute__((packed));
@@ -900,7 +900,7 @@ static int get_fwinfo(struct shinkos2145_ctx *ctx)
(uint8_t*)&cmd, sizeof(cmd),
sizeof(*resp),
&num)) < 0) {
- ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
+ ERROR("Failed to execute %s command (%d)\n", cmd_names(cmd.hdr.cmd), ret);
continue;
}
@@ -1136,7 +1136,7 @@ static int get_tonecurve(struct shinkos2145_ctx *ctx, int type, char *fname)
int ret, num = 0;
uint8_t *data;
- uint16_t curves[768];
+ uint16_t curves[UPDATE_SIZE] = { 0 } ;
int i,j;
@@ -1161,6 +1161,7 @@ static int get_tonecurve(struct shinkos2145_ctx *ctx, int type, char *fname)
if (!data) {
ERROR("Memory allocation failure! (%d bytes)\n",
resp->total_size * 2);
+ return -1;
}
i = 0;
@@ -1189,11 +1190,11 @@ static int get_tonecurve(struct shinkos2145_ctx *ctx, int type, char *fname)
goto done;
}
- for (i = 0 ; i < 768; i++) {
+ for (i = 0 ; i < UPDATE_SIZE; i++) {
/* Byteswap appropriately */
curves[i] = cpu_to_be16(le16_to_cpu(curves[i]));
- write(tc_fd, &curves[i], sizeof(uint16_t));
}
+ write(tc_fd, curves, UPDATE_SIZE * sizeof(uint16_t));
close(tc_fd);
}
@@ -1210,11 +1211,12 @@ static int set_tonecurve(struct shinkos2145_ctx *ctx, int target, char *fname)
INFO("Set %s Tone Curve from '%s'\n", update_targets(target), fname);
- uint16_t *data = malloc(UPDATE_SIZE);
+ uint16_t *data = malloc(UPDATE_SIZE * sizeof(uint16_t));
if (!data) {
ERROR("Memory allocation failure! (%d bytes)\n",
UPDATE_SIZE);
+ return -1;
}
/* Read in file */
@@ -1223,26 +1225,26 @@ static int set_tonecurve(struct shinkos2145_ctx *ctx, int target, char *fname)
ret = -1;
goto done;
}
- if (read(tc_fd, data, UPDATE_SIZE) != UPDATE_SIZE) {
+ if (read(tc_fd, data, UPDATE_SIZE * sizeof(uint16_t)) != (UPDATE_SIZE * sizeof(uint16_t))) {
ret = -2;
goto done;
}
close(tc_fd);
/* Byteswap data to local CPU.. */
- for (ret = 0; ret < UPDATE_SIZE ; ret+=2) {
+ for (ret = 0; ret < UPDATE_SIZE ; ret++) {
data[ret] = be16_to_cpu(data[ret]);
}
/* Set up command */
cmd.target = target;
cmd.reserved = 0;
- cmd.size = cpu_to_le32(UPDATE_SIZE);
+ cmd.size = cpu_to_le32(UPDATE_SIZE * sizeof(uint16_t));
cmd.hdr.cmd = cpu_to_le16(S2145_CMD_UPDATE);
cmd.hdr.len = cpu_to_le16(sizeof(struct s2145_update_cmd)-sizeof(cmd.hdr));
/* Byteswap data to format printer is expecting.. */
- for (ret = 0; ret < UPDATE_SIZE ; ret+=2) {
+ for (ret = 0; ret < UPDATE_SIZE ; ret++) {
data[ret] = cpu_to_le16(data[ret]);
}
@@ -1256,7 +1258,7 @@ static int set_tonecurve(struct shinkos2145_ctx *ctx, int target, char *fname)
/* Sent transfer */
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t *) data, UPDATE_SIZE))) {
+ (uint8_t *) data, UPDATE_SIZE * sizeof(uint16_t)))) {
goto done;
}
@@ -1274,10 +1276,10 @@ static void shinkos2145_cmdline(void)
DEBUG("\t\t[ -e ] # Query error log\n");
DEBUG("\t\t[ -f ] # Use fast return mode\n");
DEBUG("\t\t[ -F ] # Flash Printer LED\n");
+ DEBUG("\t\t[ -i ] # Query printer info\n");
DEBUG("\t\t[ -l filename ] # Get current tone curve\n");
DEBUG("\t\t[ -L filename ] # Set current tone curve\n");
DEBUG("\t\t[ -m ] # Query media\n");
- DEBUG("\t\t[ -i ] # Query printer info\n");
DEBUG("\t\t[ -r ] # Reset user/NV tone curve\n");
DEBUG("\t\t[ -R ] # Reset printer to factory defaults\n");
DEBUG("\t\t[ -s ] # Query status\n");
@@ -1291,112 +1293,65 @@ int shinkos2145_cmdline_arg(void *vctx, int argc, char **argv)
struct shinkos2145_ctx *ctx = vctx;
int i, j = 0;
+ if (!ctx)
+ return -1;
+
/* Reset arg parsing */
optind = 1;
opterr = 0;
- while ((i = getopt(argc, argv, "b:c:C:efFil:L:mr:R:suU:X:")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "b:c:C:eFil:L:mr:R:suU:X:")) >= 0) {
switch(i) {
+ GETOPT_PROCESS_GLOBAL
case 'b':
- if (ctx) {
- if (optarg[0] == '1')
- j = button_set(ctx, BUTTON_ENABLED);
- else if (optarg[0] == '0')
- j = button_set(ctx, BUTTON_DISABLED);
- else
- return -1;
- break;
- }
- return 1;
+ if (optarg[0] == '1')
+ j = button_set(ctx, BUTTON_ENABLED);
+ else if (optarg[0] == '0')
+ j = button_set(ctx, BUTTON_DISABLED);
+ else
+ return -1;
+ break;
case 'c':
- if (ctx) {
- j = get_tonecurve(ctx, TONECURVE_USER, optarg);
- break;
- }
- return 1;
+ j = get_tonecurve(ctx, TONECURVE_USER, optarg);
+ break;
case 'C':
- if (ctx) {
- j = set_tonecurve(ctx, TONECURVE_USER, optarg);
- break;
- }
- return 1;
+ j = set_tonecurve(ctx, TONECURVE_USER, optarg);
+ break;
case 'e':
- if (ctx) {
- j = get_errorlog(ctx);
- break;
- }
- return 1;
- case 'f':
- if (ctx) {
- ctx->fast_return = 1;
- break;
- }
- return 1;
+ j = get_errorlog(ctx);
+ break;
case 'F':
- if (ctx) {
- j = flash_led(ctx);
- break;
- }
- return 1;
+ j = flash_led(ctx);
+ break;
case 'i':
- if (ctx) {
- j = get_fwinfo(ctx);
- break;
- }
- return 1;
+ j = get_fwinfo(ctx);
+ break;
case 'l':
- if (ctx) {
- j = get_tonecurve(ctx, TONECURVE_CURRENT, optarg);
- break;
- }
- return 1;
+ j = get_tonecurve(ctx, TONECURVE_CURRENT, optarg);
+ break;
case 'L':
- if (ctx) {
- j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
- break;
- }
- return 1;
+ j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
+ break;
case 'm':
- if (ctx) {
- j = get_mediainfo(ctx);
- break;
- }
- return 1;
+ j = get_mediainfo(ctx);
+ break;
case 'r':
- if (ctx) {
- j = reset_curve(ctx, RESET_USER_CURVE);
- break;
- }
- return 1;
+ j = reset_curve(ctx, RESET_USER_CURVE);
+ break;
case 'R':
- if (ctx) {
- j = reset_curve(ctx, RESET_PRINTER);
- break;
- }
- return 1;
+ j = reset_curve(ctx, RESET_PRINTER);
+ break;
case 's':
- if (ctx) {
- j = get_status(ctx);
- break;
- }
- return 1;
+ j = get_status(ctx);
+ break;
case 'u':
- if (ctx) {
- j = get_user_string(ctx);
- break;
- }
- return 1;
+ j = get_user_string(ctx);
+ break;
case 'U':
- if (ctx) {
- j = set_user_string(ctx, optarg);
- break;
- }
- return 1;
+ j = set_user_string(ctx, optarg);
+ break;
case 'X':
- if (ctx) {
- j = cancel_job(ctx, optarg);
- break;
- }
- return 1;
+ j = cancel_job(ctx, optarg);
+ break;
default:
break; /* Ignore completely */
}
@@ -1418,10 +1373,6 @@ static void *shinkos2145_init(void)
}
memset(ctx, 0, sizeof(struct shinkos2145_ctx));
- /* Use Fast return by default in CUPS mode */
- if (getenv("DEVICE_URI") || getenv("FAST_RETURN"))
- ctx->fast_return = 1;
-
return ctx;
}
@@ -1429,16 +1380,23 @@ static void shinkos2145_attach(void *vctx, struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct shinkos2145_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ ctx->type = lookup_printer_type(&shinkos2145_backend,
+ desc.idVendor, desc.idProduct);
+
/* Ensure jobid is sane */
ctx->jobid = (jobid & 0x7f) + 1;
}
-
static void shinkos2145_teardown(void *vctx) {
struct shinkos2145_ctx *ctx = vctx;
@@ -1451,18 +1409,19 @@ static void shinkos2145_teardown(void *vctx) {
free(ctx);
}
-static int shinkos2145_early_parse(void *vctx, int data_fd) {
+static int shinkos2145_read_parse(void *vctx, int data_fd) {
struct shinkos2145_ctx *ctx = vctx;
- int printer_type, ret;
+ int ret;
+ uint8_t tmpbuf[4];
if (!ctx)
- return -1;
+ return CUPS_BACKEND_FAILED;
/* 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; /* deliberate */
+ return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(ctx->hdr));
perror("ERROR: Read failed");
@@ -1473,42 +1432,20 @@ static int shinkos2145_early_parse(void *vctx, int data_fd) {
le32_to_cpu(ctx->hdr.len2) != 0x64 ||
le32_to_cpu(ctx->hdr.dpi) != 300) {
ERROR("Unrecognized header data format!\n");
- return -1;
+ return CUPS_BACKEND_CANCEL;
}
- ctx->model = le32_to_cpu(ctx->hdr.model);
-
- switch(ctx->model) {
- case 2145:
- printer_type = P_SHINKO_S2145;
- break;
- case 6145:
- case 6245:
- default:
+ if (le32_to_cpu(ctx->hdr.model) != 2145) {
ERROR("Unrecognized printer (%d)!\n", le32_to_cpu(ctx->hdr.model));
- return -1;
+ return CUPS_BACKEND_CANCEL;
}
- 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) {
@@ -1585,7 +1522,8 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
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)))
+ le16_to_cpu(media->items[i].rows) == cpu_to_le16(le32_to_cpu(ctx->hdr.rows)) &&
+ media->items[i].print_type == le32_to_cpu(ctx->hdr.method))
break;
}
if (i == media->count) {
@@ -1593,7 +1531,9 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_HOLD;
}
- top:
+ // XXX check copies against remaining media!
+
+top:
if (state != last_state) {
if (dyesub_debug)
DEBUG("last_state %d new %d\n", last_state, state);
@@ -1645,19 +1585,13 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
print->hdr.cmd = cpu_to_le16(S2145_CMD_PRINTJOB);
print->hdr.len = cpu_to_le16(sizeof (*print) - sizeof(*cmd));
- 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;
- }
+ 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 ((ret = s2145_do_cmd(ctx,
cmdbuf, sizeof(*print),
@@ -1671,6 +1605,9 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
if (sts->hdr.error == ERROR_BUFFER_FULL) {
INFO("Printer Buffers full, retrying\n");
break;
+ } else if ((sts->hdr.status & 0xf0) == 0x30 || sts->hdr.status == 0x21) {
+ INFO("Printer busy (%s), retrying\n", status_str(sts->hdr.status));
+ break;
} else if (sts->hdr.status != ERROR_NONE)
goto printer_error;
}
@@ -1685,7 +1622,7 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
state = S_PRINTER_SENT_DATA;
break;
case S_PRINTER_SENT_DATA:
- if (ctx->fast_return) {
+ if (fast_return) {
INFO("Fast return mode enabled.\n");
state = S_FINISHED;
} else if (sts->hdr.status == STATUS_READY ||
@@ -1700,19 +1637,7 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
if (state != S_FINISHED)
goto top;
- /* 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) {
- state = S_IDLE;
- goto top;
- }
+ INFO("Print complete\n");
return CUPS_BACKEND_OK;
@@ -1764,29 +1689,21 @@ static int shinkos2145_query_serno(struct libusb_device_handle *dev, uint8_t end
/* 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",
- .version = "0.40",
+ .version = "0.46",
.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, ""}
}
};
@@ -1810,67 +1727,4 @@ 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/shinko_s6245_print.c b/src/cups/shinko_s6245_print.c
new file mode 100644
index 0000000..e4b57e9
--- /dev/null
+++ b/src/cups/shinko_s6245_print.c
@@ -0,0 +1,1863 @@
+/*
+ * Shinko/Sinfonia CHC-S6245 CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * Low-level documentation was provided by Sinfonia, Inc. Thank you!
+ *
+ * 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 <time.h>
+
+#define BACKEND shinkos6245_backend
+
+#include "backend_common.h"
+
+
+enum {
+ S_IDLE = 0,
+ S_PRINTER_READY_CMD,
+ S_PRINTER_SENT_DATA,
+ S_FINISHED,
+};
+
+/* Structure of printjob header. All fields are LITTLE ENDIAN */
+struct s6245_printjob_hdr {
+ uint32_t len1; /* Fixed at 0x10 */
+ uint32_t model; /* Equal to the printer model (eg '6245' or '1245' decimal) */
+ uint32_t unk2;
+ uint32_t unk3; /* Fixed at 0x01 */
+
+ uint32_t len2; /* Fixed at 0x64 */
+ uint32_t unk5;
+ uint32_t media; // 8x4->8x12
+ uint32_t unk6;
+
+ uint32_t unk7;
+ uint32_t unk7a;
+ uint32_t oc_mode; /* 6145/6245 only, Matte/Glossy/None */
+ uint32_t unk8;
+
+ uint32_t unk9;
+ uint32_t columns;
+ uint32_t rows;
+ uint32_t copies;
+
+ uint32_t unk10;
+ uint32_t unk11;
+ uint32_t unk12;
+ uint32_t unk13;
+
+ uint32_t unk14;
+ uint32_t unk15;
+ uint32_t dpi; /* Fixed at '300' (decimal) */
+ uint32_t unk16;
+
+ uint32_t unk17;
+ uint32_t unk18;
+ uint32_t unk19;
+ uint32_t unk20;
+
+ uint32_t unk21;
+} __attribute__((packed));
+
+/* Private data stucture */
+struct shinkos6245_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ uint8_t jobid;
+
+ struct s6245_printjob_hdr hdr;
+
+ uint8_t *databuf;
+ int datalen;
+};
+
+/* Structs for printer */
+struct s6245_cmd_hdr {
+ uint16_t cmd;
+ uint16_t len; /* Not including this header */
+} __attribute__((packed));
+
+#define S6245_CMD_GETSTATUS 0x0001
+#define S6245_CMD_MEDIAINFO 0x0002
+#define S6245_CMD_ERRORLOG 0x0004
+#define S6245_CMD_GETPARAM 0x0005
+#define S6245_CMD_GETSERIAL 0x0006
+#define S6245_CMD_PRINTSTAT 0x0007
+#define S6245_CMD_EXTCOUNTER 0x0008
+
+#define S6245_CMD_PRINTJOB 0x4001
+#define S6245_CMD_CANCELJOB 0x4002
+#define S6245_CMD_FLASHLED 0x4003
+#define S6245_CMD_RESET 0x4004
+#define S6245_CMD_READTONE 0x4005
+#define S6245_CMD_SETPARAM 0x4007
+
+#define S6245_CMD_GETEEPROM 0x400E
+#define S6245_CMD_SETEEPROM 0x400F
+#define S6245_CMD_SETTIME 0x4011
+
+#define S6245_CMD_FWINFO 0xC003
+#define S6245_CMD_UPDATE 0xC004
+
+static char *cmd_names(uint16_t v) {
+ switch (le16_to_cpu(v)) {
+ case S6245_CMD_GETSTATUS:
+ return "Get Status";
+ case S6245_CMD_MEDIAINFO:
+ return "Get Media Info";
+ case S6245_CMD_ERRORLOG:
+ return "Get Error Log";
+ case S6245_CMD_GETPARAM:
+ return "Get Parameter";
+ case S6245_CMD_GETSERIAL:
+ return "Get Serial Number";
+ case S6245_CMD_PRINTSTAT:
+ return "Get Print ID Status";
+ case S6245_CMD_EXTCOUNTER:
+ return "Get Extended Counters";
+ case S6245_CMD_PRINTJOB:
+ return "Print";
+ case S6245_CMD_CANCELJOB:
+ return "Cancel Print";
+ case S6245_CMD_FLASHLED:
+ return "Flash LEDs";
+ case S6245_CMD_RESET:
+ return "Reset";
+ case S6245_CMD_READTONE:
+ return "Read Tone Curve";
+ case S6245_CMD_SETPARAM:
+ return "Set Parameter";
+ case S6245_CMD_GETEEPROM:
+ return "Get EEPROM Backup Parameter";
+ case S6245_CMD_SETEEPROM:
+ return "Set EEPROM Backup Parameter";
+ case S6245_CMD_SETTIME:
+ return "Time Setting";
+ case S6245_CMD_FWINFO:
+ return "Get Firmware Info";
+ case S6245_CMD_UPDATE:
+ return "Update";
+ default:
+ return "Unknown Command";
+ }
+};
+
+struct s6245_print_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t id;
+ uint16_t count;
+ uint16_t columns;
+ uint16_t rows;
+ uint8_t reserved[8]; // columns and rows repeated, then nulls
+ uint8_t mode;
+ uint8_t method;
+ uint8_t reserved2;
+} __attribute__((packed));
+
+#define PRINT_MODE_NO_OC 0x01
+#define PRINT_MODE_GLOSSY 0x02
+#define PRINT_MODE_MATTE 0x03
+
+#if 0
+static char *print_modes(uint8_t v) {
+ switch (v) {
+ case PRINT_MODE_NO_OC:
+ return "No Overcoat";
+ case PRINT_MODE_GLOSSY:
+ return "Glossy";
+ case PRINT_MODE_MATTE:
+ return "Matte";
+ default:
+ return "Unknown";
+ }
+}
+#endif
+
+#define PRINT_METHOD_STD 0x00
+#define PRINT_METHOD_COMBO_2 0x02
+#define PRINT_METHOD_COMBO_3 0x03
+
+#define PRINT_METHOD_DISABLE_ERR 0x10
+
+static char *print_methods (uint8_t v) {
+ switch (v & 0xf) {
+ case PRINT_METHOD_STD:
+ return "Standard";
+ case PRINT_METHOD_COMBO_2:
+ return "2up";
+ case PRINT_METHOD_COMBO_3:
+ return "3up";
+ default:
+ return "Unknown";
+ }
+}
+
+struct s6245_cancel_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t id;
+} __attribute__((packed));
+
+struct s6245_reset_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+ uint8_t curveid;
+} __attribute__((packed));
+
+#define RESET_PRINTER 0x03
+#define RESET_TONE_CURVE 0x04
+
+#define TONE_CURVE_ID 0x01
+
+struct s6245_readtone_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+ uint8_t curveid;
+} __attribute__((packed));
+
+#define READ_TONE_CURVE_USER 0x01
+#define READ_TONE_CURVE_CURR 0x02
+
+struct s6245_setparam_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+ uint32_t param;
+} __attribute__((packed));
+
+#define PARAM_DRIVER_MODE 0x3e
+#define PARAM_PAPER_MODE 0x3f
+#define PARAM_SLEEP_TIME 0x54
+
+#define PARAM_DRIVER_WIZOFF 0x00000000
+#define PARAM_DRIVER_WIZON 0x00000001
+
+#define PARAM_PAPER_NOCUT 0x00000000
+#define PARAM_PAPER_CUTLOAD 0x00000001
+
+#define PARAM_SLEEP_5MIN 0x00000000
+#define PARAM_SLEEP_15MIN 0x00000001
+#define PARAM_SLEEP_30MIN 0x00000002
+#define PARAM_SLEEP_60MIN 0x00000003
+#define PARAM_SLEEP_120MIN 0x00000004
+#define PARAM_SLEEP_240MIN 0x00000005
+
+struct s6245_seteeprom_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t data[256]; /* Maxlen */
+} __attribute__((packed));
+
+struct s6245_settime_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t enable; /* 0 or 1 */
+ uint8_t second;
+ uint8_t minute;
+ uint8_t hour;
+ uint8_t day;
+ uint8_t month;
+ uint8_t year;
+} __attribute__((packed));
+
+struct s6245_errorlog_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint16_t index; /* 0 is latest */
+} __attribute__((packed));
+
+struct s6245_getparam_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+} __attribute__((packed));
+
+struct s6245_getprintidstatus_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t id;
+} __attribute__((packed));
+
+struct s6245_fwinfo_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+} __attribute__((packed));
+
+#define FWINFO_TARGET_MAIN_BOOT 0x01
+#define FWINFO_TARGET_MAIN_APP 0x02
+#define FWINFO_TARGET_PRINT_TABLES 0x03
+#define FWINFO_TARGET_DSP 0x04
+
+static char *fwinfo_targets (uint8_t v) {
+ switch (v) {
+ case FWINFO_TARGET_MAIN_BOOT:
+ return "Main Boot ";
+ case FWINFO_TARGET_MAIN_APP:
+ return "Main App ";
+ case FWINFO_TARGET_DSP:
+ return "DSP ";
+ case FWINFO_TARGET_PRINT_TABLES:
+ return "Print Tables";
+ default:
+ return "Unknown ";
+ }
+}
+
+struct s6245_update_cmd {
+ struct s6245_cmd_hdr hdr;
+ uint8_t target;
+ uint8_t curve_id;
+ uint8_t reset; // ??
+ uint8_t reserved[3];
+ uint32_t size;
+} __attribute__((packed));
+
+#define UPDATE_TARGET_USER 0x03
+#define UPDATE_TARGET_CURRENT 0x04
+
+static char *update_targets (uint8_t v) {
+ switch (v) {
+ case UPDATE_TARGET_USER:
+ return "User";
+ case UPDATE_TARGET_CURRENT:
+ return "Current";
+ default:
+ return "Unknown";
+ }
+}
+
+#define UPDATE_SIZE 0x600
+/* Update is three channels, Y, M, C;
+ each is 256 entries of 11-bit data padded to 16-bits.
+ Printer expects LE data. We use BE data on disk.
+*/
+
+struct s6245_status_hdr {
+ uint8_t result;
+ uint8_t error;
+ uint8_t printer_major;
+ uint8_t printer_minor;
+ uint8_t reserved[2];
+ uint8_t mode;
+ uint8_t status;
+ uint16_t payload_len;
+} __attribute__((packed));
+
+#define RESULT_SUCCESS 0x01
+#define RESULT_FAIL 0x02
+
+#define ERROR_NONE 0x00
+#define ERROR_INVALID_PARAM 0x01
+#define ERROR_MAIN_APP_INACTIVE 0x02
+#define ERROR_COMMS_TIMEOUT 0x03
+#define ERROR_MAINT_NEEDED 0x04
+#define ERROR_BAD_COMMAND 0x05
+#define ERROR_PRINTER 0x11
+#define ERROR_BUFFER_FULL 0x21
+
+static char *error_codes(uint8_t major, uint8_t minor)
+{
+ switch(major) {
+ case 0x01: /* "Controller Error" */
+ switch(minor) {
+ case 0x01:
+ return "Controller: EEPROM Write Timeout";
+ case 0x09:
+ return "Controller: DSP FW Boot";
+ case 0x0A:
+ return "Controller: Invalid Print Parameter Table";
+ case 0x0B:
+ return "Controller: DSP FW Mismatch";
+ case 0x0C:
+ return "Controller: Print Parameter Table Mismatch";
+ case 0x0D:
+ return "Controller: FPGA Configuration Failed";
+ case 0x0F:
+ return "Controller: Main FW Checksum";
+ case 0x10:
+ return "Controller: Flash Write Failed";
+ case 0x11:
+ return "Controller: DSP Checksum";
+ case 0x12:
+ return "Controller: DSP FW Write Failed";
+ case 0x13:
+ return "Controller: Print Parameter Table Checksum";
+ case 0x14:
+ return "Controller: Print Parameter Table Write Failed";
+ case 0x15:
+ return "Controller: User Tone Curve Write Failed";
+ case 0x16:
+ return "Controller: MSP Communication";
+ case 0x17:
+ return "Controller: THV Autotuning";
+ case 0x18:
+ return "Controller: THV Value Out of Range";
+ case 0x19:
+ return "Controller: Thermal Head";
+ case 0x1B:
+ return "Controller: DSP Communication";
+ case 0x1C:
+ return "Controller: DSP DMA Failed";
+ default:
+ return "Controller: Unknown";
+ }
+ case 0x02: /* "Mechanical Error" */
+ switch (minor) {
+ case 0x01:
+ return "Mechanical: Pinch Head Home";
+ case 0x02:
+ return "Mechanical: Pinch Head (position 1)";
+ case 0x03:
+ return "Mechanical: Pinch Head (position 2)";
+ case 0x04:
+ return "Mechanical: Pinch Head (position 3)";
+ case 0x0B:
+ return "Mechanical: Cutter (Right)";
+ case 0x0C:
+ return "Mechanical: Cutter (Left)";
+ default:
+ return "Mechanical: Unknown";
+ }
+ case 0x03: /* "Sensor Error" */
+ switch (minor) {
+ case 0x01:
+ return "Sensor: Head Up";
+ case 0x02:
+ return "Sensor: Head Down";
+ case 0x0B:
+ return "Sensor: Cutter Left";
+ case 0x0C:
+ return "Sensor: Cutter Right";
+ case 0x0D:
+ return "Sensor: Cutter Left+Right";
+ case 0x15:
+ return "Sensor: Head Up Unstable";
+ case 0x16:
+ return "Sensor: Head Down Unstable";
+ case 0x17:
+ return "Sensor: Cutter Left Unstable";
+ case 0x18:
+ return "Sensor: Cutter Right Unstable";
+ case 0x19:
+ return "Sensor: Cover Open Unstable";
+ case 0x1E:
+ return "Sensor: Ribbon Mark (Cyan)";
+ case 0x1F:
+ return "Sensor: Ribbon Mark (OC)";
+ default:
+ return "Sensor: Unknown";
+ }
+ case 0x04: /* "Temperature Sensor Error" */
+ switch (minor) {
+ case 0x01:
+ return "Temp Sensor: Thermal Head Low";
+ case 0x02:
+ return "Temp Sensor: Thermal Head High";
+ case 0x05:
+ return "Temp Sensor: Environment Low";
+ case 0x06:
+ return "Temp Sensor: Environment High";
+ case 0x07:
+ return "Temp Sensor: Preheat";
+ case 0x08:
+ return "Temp Sensor: Thermal Protect";
+ default:
+ return "Temp Sensor: Unknown";
+ }
+ case 0x5: /* "Paper Jam" */
+ switch (minor) {
+ case 0x01:
+ return "Paper Jam: Loading Paper Top On";
+ case 0x02:
+ return "Paper Jam: Loading Print Position On";
+ case 0x03:
+ return "Paper Jam: Loading Print Position Off";
+ case 0x04:
+ return "Paper Jam: Loading Paper Top Off";
+ case 0x05:
+ return "Paper Jam: Loading Cut Print Position Off";
+ case 0x0C:
+ return "Paper Jam: Initializing Print Position Off";
+ case 0x0D:
+ return "Paper Jam: Initializing Print Position On";
+ case 0x15:
+ return "Paper Jam: Printing Print Position Off";
+ case 0x16:
+ return "Paper Jam: Printing Paper Top On";
+ case 0x17:
+ return "Paper Jam: Printing Paper Top Off";
+ case 0x1F:
+ return "Paper Jam: Precut Print Position Off";
+ case 0x20:
+ return "Paper Jam: Precut Print Position On";
+
+ case 0x29:
+ return "Paper Jam: Printing Paper Top On";
+ case 0x2A:
+ return "Paper Jam: Printing Pre-Yellow Print Position Off";
+ case 0x2B:
+ return "Paper Jam: Printing Yellow Print Position Off";
+ case 0x2C:
+ return "Paper Jam: Printing Yellow Print Position On";
+ case 0x2D:
+ return "Paper Jam: Printing Pre-Magenta Print Position Off";
+ case 0x2E:
+ return "Paper Jam: Printing Magenta Print Position On";
+ case 0x2F:
+ return "Paper Jam: Printing Magenta Print Position Off";
+ case 0x30:
+ return "Paper Jam: Printing Pre-Cyan Print Position Off";
+ case 0x31:
+ return "Paper Jam: Printing Cyan Print Position On";
+ case 0x32:
+ return "Paper Jam: Printing Cyan Print Position Off";
+ case 0x33:
+ return "Paper Jam: Printing Pre-OC Print Position Off";
+ case 0x34:
+ return "Paper Jam: Printing OC Print Position On";
+ case 0x35:
+ return "Paper Jam: Printing OC Print Position Off";
+ case 0x36:
+ return "Paper Jam: Cut Print Position Off";
+ case 0x37:
+ return "Paper Jam: Home Position Off";
+ case 0x38:
+ return "Paper Jam: Paper Top Off";
+ case 0x39:
+ return "Paper Jam: Print Position On";
+
+ case 0x51:
+ return "Paper Jam: Paper Empty On, Top On, Position On";
+ case 0x52:
+ return "Paper Jam: Paper Empty On, Top On, Position Off";
+ case 0x53:
+ return "Paper Jam: Paper Empty On, Top Off, Print Position On";
+ case 0x54:
+ return "Paper Jam: Paper Empty On, Top Of, Position Off";
+ case 0x55:
+ return "Paper Jam: Paper Empty Off, Top On, Position On";
+ case 0x56:
+ return "Paper Jam: Paper Empty Off, Top On, Position Off";
+ case 0x57:
+ return "Paper Jam: Paper Empty Off, Top Off, Position On";
+ case 0x60:
+ return "Paper Jam: Cutter Right";
+ case 0x61:
+ return "Paper Jam: Cutter Left";
+
+ default:
+ return "Paper Jam: Unknown";
+ }
+ case 0x06: /* User Error */
+ switch (minor) {
+ case 0x01:
+ return "Drawer Unit Open";
+ case 0x02:
+ return "Incorrect Ribbon";
+ case 0x03:
+ return "No/Empty Ribbon";
+ case 0x04:
+ return "Mismatched Ribbon";
+ case 0x08:
+ return "No Paper";
+ case 0x0C:
+ return "Paper End";
+ default:
+ return "Unknown";
+ }
+ default:
+ return "Unknown";
+ }
+}
+
+static char *error_str(uint8_t v) {
+ switch (v) {
+ case ERROR_NONE:
+ return "None";
+ case ERROR_INVALID_PARAM:
+ return "Invalid Command Parameter";
+ case ERROR_MAIN_APP_INACTIVE:
+ return "Main App Inactive";
+ case ERROR_COMMS_TIMEOUT:
+ return "Main Communication Timeout";
+ case ERROR_MAINT_NEEDED:
+ return "Maintainence Needed";
+ case ERROR_BAD_COMMAND:
+ return "Inappropriate Command";
+ case ERROR_PRINTER:
+ return "Printer Error";
+ case ERROR_BUFFER_FULL:
+ return "Buffer Full";
+ default:
+ return "Unknown";
+ }
+}
+
+#define STATUS_READY 0x00
+#define STATUS_INIT_CPU 0x31
+#define STATUS_INIT_RIBBON 0x32
+#define STATUS_INIT_PAPER 0x33
+#define STATUS_THERMAL_PROTECT 0x34
+#define STATUS_USING_PANEL 0x35
+#define STATUS_SELF_DIAG 0x36
+#define STATUS_DOWNLOADING 0x37
+
+#define STATUS_FEEDING_PAPER 0x61
+#define STATUS_PRE_HEAT 0x62
+#define STATUS_PRINT_Y 0x63
+#define STATUS_BACK_FEED_Y 0x64
+#define STATUS_PRINT_M 0x65
+#define STATUS_BACK_FEED_M 0x66
+#define STATUS_PRINT_C 0x67
+#define STATUS_BACK_FEED_C 0x68
+#define STATUS_PRINT_OP 0x69
+#define STATUS_PAPER_CUT 0x6A
+#define STATUS_PAPER_EJECT 0x6B
+#define STATUS_BACK_FEED_E 0x6C
+
+static char *status_str(uint8_t v) {
+ switch (v) {
+ case STATUS_READY:
+ return "Ready";
+ case STATUS_INIT_CPU:
+ return "Initializing CPU";
+ case STATUS_INIT_RIBBON:
+ return "Initializing Ribbon";
+ case STATUS_INIT_PAPER:
+ return "Loading Paper";
+ case STATUS_THERMAL_PROTECT:
+ return "Thermal Protection";
+ case STATUS_USING_PANEL:
+ return "Using Operation Panel";
+ case STATUS_SELF_DIAG:
+ return "Processing Self Diagnosis";
+ case STATUS_DOWNLOADING:
+ return "Processing Download";
+ case STATUS_FEEDING_PAPER:
+ return "Feeding Paper";
+ case STATUS_PRE_HEAT:
+ return "Pre-Heating";
+ case STATUS_PRINT_Y:
+ return "Printing Yellow";
+ case STATUS_BACK_FEED_Y:
+ return "Back-Feeding - Yellow Complete";
+ case STATUS_PRINT_M:
+ return "Printing Magenta";
+ case STATUS_BACK_FEED_M:
+ return "Back-Feeding - Magenta Complete";
+ case STATUS_PRINT_C:
+ return "Printing Cyan";
+ case STATUS_BACK_FEED_C:
+ return "Back-Feeding - Cyan Complete";
+ case STATUS_PRINT_OP:
+ return "Laminating";
+ case STATUS_PAPER_CUT:
+ return "Cutting Paper";
+ case STATUS_PAPER_EJECT:
+ return "Ejecting Paper";
+ case STATUS_BACK_FEED_E:
+ return "Back-Feeding - Ejected";
+ case ERROR_PRINTER:
+ return "Printer Error";
+ default:
+ return "Unknown";
+ }
+}
+
+struct s6245_status_resp {
+ struct s6245_status_hdr hdr;
+ uint32_t count_lifetime;
+ uint32_t count_maint;
+ uint32_t count_paper;
+ uint32_t count_cutter;
+ uint32_t count_head;
+ uint32_t count_ribbon_left;
+ uint32_t reserved;
+
+ uint8_t bank1_printid;
+ uint16_t bank1_remaining;
+ uint16_t bank1_finished;
+ uint16_t bank1_specified;
+ uint8_t bank1_status;
+
+ uint8_t bank2_printid;
+ uint16_t bank2_remaining;
+ uint16_t bank2_finished;
+ uint16_t bank2_specified;
+ uint8_t bank2_status;
+
+ uint8_t reserved2[16];
+ uint8_t tonecurve_status;
+ uint8_t reserved3[6];
+} __attribute__((packed));
+
+#define BANK_STATUS_FREE 0x00
+#define BANK_STATUS_XFER 0x01
+#define BANK_STATUS_FULL 0x02
+#define BANK_STATUS_PRINTING 0x12
+
+static char *bank_statuses(uint8_t v)
+{
+ switch (v) {
+ case BANK_STATUS_FREE:
+ return "Free";
+ case BANK_STATUS_XFER:
+ return "Xfer";
+ case BANK_STATUS_FULL:
+ return "Full";
+ case BANK_STATUS_PRINTING:
+ return "Printing";
+ default:
+ return "Unknown";
+ }
+}
+
+#define TONECURVE_INIT 0x00
+#define TONECURVE_USER 0x01
+#define TONECURVE_CURRENT 0x02
+
+static char *tonecurve_statuses (uint8_t v)
+{
+ switch(v) {
+ case 0:
+ return "Initial";
+ case 1:
+ return "UserSet";
+ case 2:
+ return "Current";
+ default:
+ return "Unknown";
+ }
+}
+
+struct s6245_geteeprom_resp {
+ struct s6245_status_hdr hdr;
+ uint8_t data[256];
+} __attribute__((packed));
+
+struct s6245_readtone_resp {
+ struct s6245_status_hdr hdr;
+ uint16_t total_size;
+} __attribute__((packed));
+
+struct s6245_mediainfo_item {
+ uint8_t media_code;
+ uint16_t columns;
+ uint16_t rows;
+ uint8_t reserved;
+ uint8_t print_method; /* PRINT_METHOD_* */
+ uint8_t reserved2[3];
+} __attribute__((packed));
+
+#define MEDIA_8x10 0x10
+#define MEDIA_8x12 0x11
+#define MEDIA_8x4 0x20
+#define MEDIA_8x5 0x21
+#define MEDIA_8x6 0x22
+#define MEDIA_8x8 0x23
+#define MEDIA_8x4_2 0x30
+#define MEDIA_8x5_2 0x31
+#define MEDIA_8x6_2 0x32
+#define MEDIA_8x4_3 0x40
+
+static char *print_medias (uint8_t v) {
+ switch (v) {
+ case MEDIA_8x10:
+ return "8x10";
+ case MEDIA_8x12:
+ return "8x12";
+ case MEDIA_8x4:
+ return "8x4";
+ case MEDIA_8x5:
+ return "8x5";
+ case MEDIA_8x6:
+ return "8x6";
+ case MEDIA_8x8:
+ return "8x8";
+ case MEDIA_8x4_2:
+ return "8x4*2";
+ case MEDIA_8x5_2:
+ return "8x5*2";
+ case MEDIA_8x6_2:
+ return "8x6*2";
+ case MEDIA_8x4_3:
+ return "8x4*3";
+ default:
+ return "Unknown";
+ }
+}
+
+struct s6245_mediainfo_resp {
+ struct s6245_status_hdr hdr;
+ uint8_t count;
+ struct s6245_mediainfo_item items[10]; /* Not all necessarily used */
+} __attribute__((packed));
+
+struct s6245_errorlog_resp {
+ struct s6245_status_hdr hdr;
+ uint16_t error_count;
+ uint8_t error_major;
+ uint8_t error_minor;
+ uint16_t reserved;
+ uint32_t print_counter;
+ uint16_t ribbon_remain;
+ uint8_t ribbon_takeup_diameter;
+ uint8_t ribbon_supply_diameter;
+ uint16_t main_fw_ver;
+ uint16_t dsp_fw_ver;
+ uint16_t print_param_ver;
+ uint16_t boot_fw_ver;
+ uint8_t time_sec;
+ uint8_t time_min;
+ uint8_t time_hour;
+ uint8_t time_day;
+ uint8_t time_month;
+ uint8_t time_year;
+ uint16_t reserved2;
+ uint8_t printer_thermistor;
+ uint8_t head_thermistor;
+ uint8_t printer_humidity;
+ uint8_t reserved3[13];
+ uint8_t status;
+ uint8_t reserved4[3];
+ uint16_t image_cols;
+ uint16_t image_rows;
+ uint8_t reserved5[8];
+} __attribute__((packed));
+
+struct s6245_getparam_resp {
+ struct s6245_status_hdr hdr;
+ uint32_t param;
+} __attribute__((packed));
+
+struct s6245_getserial_resp {
+ struct s6245_status_hdr hdr;
+ uint8_t data[8];
+} __attribute__((packed));
+
+struct s6245_getprintidstatus_resp {
+ struct s6245_status_hdr hdr;
+ uint8_t id;
+ uint16_t remaining;
+ uint16_t finished;
+ uint16_t specified;
+ uint16_t status;
+} __attribute__((packed));
+
+#define STATUS_WAITING 0x0000
+#define STATUS_PRINTING 0x0100
+#define STATUS_COMPLETED 0x0200
+#define STATUS_ERROR 0xFFFF
+
+struct s6245_getextcounter_resp {
+ struct s6245_status_hdr hdr;
+ uint32_t lifetime_distance; /* Inches */
+ uint32_t maint_distance;
+ uint32_t head_distance;
+ uint8_t reserved[32];
+} __attribute__((packed));
+
+struct s6245_fwinfo_resp {
+ struct s6245_status_hdr hdr;
+ uint8_t name[8];
+ uint8_t type[16];
+ uint8_t date[10];
+ uint8_t major;
+ uint8_t minor;
+ uint16_t checksum;
+} __attribute__((packed));
+
+
+
+#define READBACK_LEN 512 /* Needs to be larger than largest response hdr */
+#define CMDBUF_LEN sizeof(struct s6245_print_cmd)
+
+uint8_t rdbuf[READBACK_LEN];
+
+static int s6245_do_cmd(struct shinkos6245_ctx *ctx,
+ uint8_t *cmd, int cmdlen,
+ int minlen, int *num)
+{
+ int ret;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+
+ libusb_device_handle *dev = ctx->dev;
+ uint8_t endp_up = ctx->endp_up;
+ uint8_t endp_down = ctx->endp_down;
+
+ if ((ret = send_data(dev, endp_down,
+ cmd, cmdlen)))
+ return (ret < 0) ? ret : -99;
+
+ ret = read_data(dev, endp_up,
+ rdbuf, READBACK_LEN, num);
+
+ if (ret < 0)
+ return ret;
+ if (*num < minlen) {
+ ERROR("Short read! (%d/%d))\n", *num, minlen);
+ return -99;
+ }
+
+ if (resp->result != RESULT_SUCCESS) {
+ INFO("Printer Status: %02x (%s)\n", resp->status,
+ status_str(resp->status));
+ INFO(" Result: 0x%02x Error: 0x%02x (0x%02x/0x%02x = %s)\n",
+ resp->result, resp->error, resp->printer_major,
+ resp->printer_minor, error_codes(resp->printer_major, resp->printer_minor));
+ return -99;
+ }
+
+ return ret;
+}
+
+static int get_status(struct shinkos6245_ctx *ctx)
+{
+ struct s6245_cmd_hdr cmd;
+ struct s6245_status_resp *resp = (struct s6245_status_resp *) rdbuf;
+ struct s6245_getextcounter_resp *resp2 = (struct s6245_getextcounter_resp *) rdbuf;
+ int ret, num = 0;
+
+ cmd.cmd = cpu_to_le16(S6245_CMD_GETSTATUS);
+ cmd.len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return ret;
+ }
+
+ INFO("Printer Status: 0x%02x (%s)\n", resp->hdr.status,
+ status_str(resp->hdr.status));
+ if (resp->hdr.status == ERROR_PRINTER) {
+ if(resp->hdr.error == ERROR_NONE)
+ resp->hdr.error = resp->hdr.status;
+ INFO(" Error 0x%02x (%s) 0x%02x/0x%02x (%s)\n",
+ resp->hdr.error,
+ error_str(resp->hdr.error),
+ resp->hdr.printer_major,
+ resp->hdr.printer_minor, error_codes(resp->hdr.printer_major, resp->hdr.printer_minor));
+ }
+ if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6245_status_resp) - sizeof(struct s6245_status_hdr)))
+ return 0;
+
+ INFO(" Print Counts:\n");
+ INFO("\tSince Paper Changed:\t%08u\n", le32_to_cpu(resp->count_paper));
+ INFO("\tLifetime:\t\t%08u\n", le32_to_cpu(resp->count_lifetime));
+ INFO("\tMaintainence:\t\t%08u\n", le32_to_cpu(resp->count_maint));
+ INFO("\tPrint Head:\t\t%08u\n", le32_to_cpu(resp->count_head));
+ INFO(" Cutter Actuations:\t%08u\n", le32_to_cpu(resp->count_cutter));
+ INFO(" Ribbon Remaining:\t%08u\n", le32_to_cpu(resp->count_ribbon_left));
+ INFO("Bank 1: 0x%02x (%s) Job %03u @ %03u/%03u (%03u remaining)\n",
+ resp->bank1_status, bank_statuses(resp->bank1_status),
+ resp->bank1_printid,
+ le16_to_cpu(resp->bank1_finished),
+ le16_to_cpu(resp->bank1_specified),
+ le16_to_cpu(resp->bank1_remaining));
+
+ INFO("Bank 2: 0x%02x (%s) Job %03d @ %03d/%03d (%03d remaining)\n",
+ resp->bank2_status, bank_statuses(resp->bank1_status),
+ resp->bank2_printid,
+ le16_to_cpu(resp->bank2_finished),
+ le16_to_cpu(resp->bank2_specified),
+ le16_to_cpu(resp->bank2_remaining));
+
+ INFO("Tonecurve Status: 0x%02x (%s)\n", resp->tonecurve_status, tonecurve_statuses(resp->tonecurve_status));
+
+ /* Query Extended counters */
+ cmd.cmd = cpu_to_le16(S6245_CMD_EXTCOUNTER);
+ cmd.len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp2),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return ret;
+ }
+ if (le16_to_cpu(resp2->hdr.payload_len) != (sizeof(struct s6245_getextcounter_resp) - sizeof(struct s6245_status_hdr)))
+ return 0;
+
+ INFO("Lifetime Distance: %08d inches\n", le32_to_cpu(resp2->lifetime_distance));
+ INFO("Maintainence Distance: %08d inches\n", le32_to_cpu(resp2->maint_distance));
+ INFO("Head Distance: %08d inches\n", le32_to_cpu(resp2->head_distance));
+
+ return 0;
+}
+
+static int get_fwinfo(struct shinkos6245_ctx *ctx)
+{
+ struct s6245_fwinfo_cmd cmd;
+ struct s6245_fwinfo_resp *resp = (struct s6245_fwinfo_resp *)rdbuf;
+ int num = 0;
+ int i;
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_FWINFO);
+ cmd.hdr.len = cpu_to_le16(1);
+
+ INFO("FW Information:\n");
+
+ for (i = FWINFO_TARGET_MAIN_BOOT ; i <= FWINFO_TARGET_PRINT_TABLES ; i++) {
+ int ret;
+ cmd.target = i;
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command (%d)\n", cmd_names(cmd.hdr.cmd), ret);
+ continue;
+ }
+
+ if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6245_fwinfo_resp) - sizeof(struct s6245_status_hdr)))
+ continue;
+
+ INFO(" %s\t ver %02x.%02x\n", fwinfo_targets(i),
+ resp->major, resp->minor);
+#if 0
+ INFO(" name: '%s'\n", resp->name);
+ INFO(" type: '%s'\n", resp->type);
+ INFO(" date: '%s'\n", resp->date);
+ INFO(" version: %02x.%02x (CRC %04x)\n", resp->major, resp->minor,
+ le16_to_cpu(resp->checksum));
+#endif
+ }
+ return 0;
+}
+
+static int get_errorlog(struct shinkos6245_ctx *ctx)
+{
+ struct s6245_errorlog_cmd cmd;
+ struct s6245_errorlog_resp *resp = (struct s6245_errorlog_resp *) rdbuf;
+ int num = 0;
+ int i = 0;
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_ERRORLOG);
+ cmd.hdr.len = cpu_to_le16(2);
+
+ do {
+ int ret;
+ cmd.index = i;
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command (%d)\n", cmd_names(cmd.hdr.cmd), ret);
+ return ret;
+ }
+
+ if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6245_errorlog_resp) - sizeof(struct s6245_status_hdr)))
+ return -2;
+
+ INFO("Stored Error ID %d:\n", i);
+ INFO(" %04d-%02d-%02d %02d:%02d:%02d @ %08u prints : 0x%02x/0x%02x (%s)\n",
+ resp->time_year + 2000, resp->time_month, resp->time_day,
+ resp->time_hour, resp->time_min, resp->time_sec,
+ le32_to_cpu(resp->print_counter),
+ resp->error_major, resp->error_minor,
+ error_codes(resp->error_major, resp->error_minor));
+ INFO(" Temp: %02d/%02d Hum: %02d\n",
+ resp->printer_thermistor, resp->head_thermistor, resp->printer_humidity);
+ } while (++i < le16_to_cpu(resp->error_count));
+
+ return 0;
+}
+
+static int get_mediainfo(struct shinkos6245_ctx *ctx)
+{
+ struct s6245_cmd_hdr cmd;
+ struct s6245_mediainfo_resp *resp = (struct s6245_mediainfo_resp *) rdbuf;
+ int ret, num = 0;
+ int i;
+
+ cmd.cmd = cpu_to_le16(S6245_CMD_MEDIAINFO);
+ cmd.len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return ret;
+ }
+
+ if (le16_to_cpu(resp->hdr.payload_len) != (sizeof(struct s6245_mediainfo_resp) - sizeof(struct s6245_status_hdr)))
+ return -2;
+
+ INFO("Supported Media Information: %d entries:\n", resp->count);
+ for (i = 0 ; i < resp->count ; i++) {
+ INFO(" %02d: C 0x%02x (%s), %04dx%04d, P 0x%02x (%s)\n", i,
+ resp->items[i].media_code, print_medias(resp->items[i].media_code),
+ le16_to_cpu(resp->items[i].columns),
+ le16_to_cpu(resp->items[i].rows),
+ resp->items[i].print_method, print_methods(resp->items[i].print_method));
+ }
+ return 0;
+}
+
+static int cancel_job(struct shinkos6245_ctx *ctx, char *str)
+{
+ struct s6245_cancel_cmd cmd;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ int ret, num = 0;
+
+ if (!str)
+ return -1;
+
+ cmd.id = atoi(str);
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_CANCELJOB);
+ cmd.hdr.len = cpu_to_le16(1);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int flash_led(struct shinkos6245_ctx *ctx)
+{
+ struct s6245_cmd_hdr cmd;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ int ret, num = 0;
+
+ cmd.cmd = cpu_to_le16(S6245_CMD_FLASHLED);
+ cmd.len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int set_param(struct shinkos6245_ctx *ctx, int target, uint32_t param)
+{
+ struct s6245_setparam_cmd cmd;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ int ret, num = 0;
+
+ /* Set up command */
+ cmd.target = target;
+ cmd.param = cpu_to_le32(param);
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_SETPARAM);
+ cmd.hdr.len = cpu_to_le16(sizeof(struct s6245_setparam_cmd)-sizeof(cmd.hdr));
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command (%d)\n", cmd_names(cmd.hdr.cmd), ret);
+ }
+
+ return ret;
+}
+
+static int reset_curve(struct shinkos6245_ctx *ctx, int target)
+{
+ struct s6245_reset_cmd cmd;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ int ret, num = 0;
+
+ cmd.target = target;
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_RESET);
+ cmd.hdr.len = cpu_to_le16(1);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_tonecurve(struct shinkos6245_ctx *ctx, int type, char *fname)
+{
+ struct s6245_readtone_cmd cmd;
+ struct s6245_readtone_resp *resp = (struct s6245_readtone_resp *) rdbuf;
+ int ret, num = 0;
+
+ uint8_t *data;
+ uint16_t curves[UPDATE_SIZE] = { 0 };
+
+ int i,j;
+
+ cmd.target = type;
+ cmd.curveid = TONE_CURVE_ID;
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_READTONE);
+ cmd.hdr.len = cpu_to_le16(1);
+
+ INFO("Dump %s Tone Curve to '%s'\n", tonecurve_statuses(type), fname);
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
+ return ret;
+ }
+
+ resp->total_size = le16_to_cpu(resp->total_size);
+
+ data = malloc(resp->total_size * 2);
+ if (!data) {
+ ERROR("Memory Allocation Failure!\n");
+ return -1;
+ }
+
+ i = 0;
+ while (i < resp->total_size) {
+ ret = read_data(ctx->dev, ctx->endp_up,
+ data + i,
+ resp->total_size * 2 - i,
+ &num);
+ if (ret < 0)
+ goto done;
+ i += num;
+ }
+
+ i = j = 0;
+ while (i < resp->total_size) {
+ memcpy(curves + j, data + i+2, data[i+1]);
+ j += data[i+1] / 2;
+ i += data[i+1] + 2;
+ }
+
+ /* Open file and write it out */
+ {
+ int tc_fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+ if (tc_fd < 0) {
+ ret = -1;
+ goto done;
+ }
+
+ for (i = 0 ; i < UPDATE_SIZE; i++) {
+ /* Byteswap appropriately */
+ curves[i] = cpu_to_be16(le16_to_cpu(curves[i]));
+ }
+ write(tc_fd, curves, UPDATE_SIZE * sizeof(uint16_t));
+ close(tc_fd);
+ }
+
+done:
+ free(data);
+ return ret;
+}
+
+static int set_tonecurve(struct shinkos6245_ctx *ctx, int target, char *fname)
+{
+ struct s6245_update_cmd cmd;
+ struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ int ret, num = 0;
+
+ INFO("Set %s Tone Curve from '%s'\n", update_targets(target), fname);
+
+ uint16_t *data = malloc(UPDATE_SIZE * sizeof(uint16_t));
+ if (!data) {
+ ERROR("Memory Allocation Failure!\n");
+ return -1;
+ }
+
+ /* Read in file */
+ int tc_fd = open(fname, O_RDONLY);
+ if (tc_fd < 0) {
+ ret = -1;
+ goto done;
+ }
+ if (read(tc_fd, data, UPDATE_SIZE * sizeof(uint16_t)) != (UPDATE_SIZE * sizeof(uint16_t))) {
+ ret = -2;
+ goto done;
+ }
+ close(tc_fd);
+ /* Byteswap data to local CPU.. */
+ for (ret = 0; ret < UPDATE_SIZE ; ret++) {
+ data[ret] = be16_to_cpu(data[ret]);
+ }
+
+ /* Set up command */
+ cmd.target = target;
+ cmd.reserved[0] = cmd.reserved[1] = cmd.reserved[2] = 0;
+ cmd.reset = 0;
+ cmd.size = cpu_to_le32(UPDATE_SIZE * sizeof(uint16_t));
+
+ cmd.hdr.cmd = cpu_to_le16(S6245_CMD_UPDATE);
+ cmd.hdr.len = cpu_to_le16(sizeof(struct s6245_update_cmd)-sizeof(cmd.hdr));
+
+ /* Byteswap data to format printer is expecting.. */
+ for (ret = 0; ret < UPDATE_SIZE ; ret++) {
+ data[ret] = cpu_to_le16(data[ret]);
+ }
+
+ if ((ret = s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
+ goto done;
+ }
+
+ /* Sent transfer */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t *) data, UPDATE_SIZE * sizeof(uint16_t)))) {
+ goto done;
+ }
+
+done:
+ free(data);
+
+ return ret;
+}
+
+static void shinkos6245_cmdline(void)
+{
+ DEBUG("\t\t[ -c filename ] # Get user/NV tone curve\n");
+ DEBUG("\t\t[ -C filename ] # Set user/NV tone curve\n");
+ DEBUG("\t\t[ -e ] # Query error log\n");
+ DEBUG("\t\t[ -F ] # Flash Printer LED\n");
+ DEBUG("\t\t[ -i ] # Query printer info\n");
+ DEBUG("\t\t[ -k num ] # Set sleep time (5-240 minutes)\n");
+ DEBUG("\t\t[ -l filename ] # Get current tone curve\n");
+ DEBUG("\t\t[ -L filename ] # Set current tone curve\n");
+ DEBUG("\t\t[ -m ] # Query media\n");
+ DEBUG("\t\t[ -r ] # Reset user/NV tone curve\n");
+ DEBUG("\t\t[ -R ] # Reset printer to factory defaults\n");
+ DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -X jobid ] # Abort a printjob\n");
+}
+
+int shinkos6245_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct shinkos6245_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "c:C:eFik:l:L:mr:R:sX:")) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ case 'c':
+ j = get_tonecurve(ctx, TONECURVE_USER, optarg);
+ break;
+ case 'C':
+ j = set_tonecurve(ctx, TONECURVE_USER, optarg);
+ break;
+ case 'e':
+ j = get_errorlog(ctx);
+ break;
+ case 'F':
+ j = flash_led(ctx);
+ break;
+ case 'i':
+ j = get_fwinfo(ctx);
+ break;
+ case 'k': {
+ uint32_t i = atoi(optarg);
+ if (i < 5)
+ i = 0;
+ else if (i < 15)
+ i = 1;
+ else if (i < 30)
+ i = 2;
+ else if (i < 60)
+ i = 3;
+ else if (i < 120)
+ i = 4;
+ else if (i < 240)
+ i = 5;
+ else
+ i = 5;
+
+ j = set_param(ctx, PARAM_SLEEP_TIME, i);
+ break;
+ }
+ case 'l':
+ j = get_tonecurve(ctx, TONECURVE_CURRENT, optarg);
+ break;
+ case 'L':
+ j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
+ break;
+ case 'm':
+ j = get_mediainfo(ctx);
+ break;
+ case 'r':
+ j = reset_curve(ctx, RESET_TONE_CURVE);
+ break;
+ case 'R':
+ j = reset_curve(ctx, RESET_PRINTER);
+ break;
+ case 's':
+ j = get_status(ctx);
+ break;
+ case 'X':
+ j = cancel_job(ctx, optarg);
+ break;
+ default:
+ break; /* Ignore completely */
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+static void *shinkos6245_init(void)
+{
+ struct shinkos6245_ctx *ctx = malloc(sizeof(struct shinkos6245_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct shinkos6245_ctx));
+
+ return ctx;
+}
+
+static void shinkos6245_attach(void *vctx, struct libusb_device_handle *dev,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct shinkos6245_ctx *ctx = vctx;
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ ctx->type = lookup_printer_type(&shinkos6245_backend,
+ desc.idVendor, desc.idProduct);
+
+ /* Ensure jobid is sane */
+ ctx->jobid = (jobid & 0x7f) + 1;
+}
+
+static void shinkos6245_teardown(void *vctx) {
+ struct shinkos6245_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ if (ctx->databuf)
+ free(ctx->databuf);
+
+ free(ctx);
+}
+
+static int shinkos6245_read_parse(void *vctx, int data_fd) {
+ struct shinkos6245_ctx *ctx = vctx;
+ int ret;
+ uint8_t tmpbuf[4];
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ /* 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 CUPS_BACKEND_CANCEL;
+ ERROR("Read failed (%d/%d/%d)\n",
+ ret, 0, (int)sizeof(ctx->hdr));
+ perror("ERROR: Read failed");
+ return ret;
+ }
+
+ if (le32_to_cpu(ctx->hdr.len1) != 0x10 ||
+ le32_to_cpu(ctx->hdr.len2) != 0x64 ||
+ le32_to_cpu(ctx->hdr.dpi) != 300) {
+ ERROR("Unrecognized header data format!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ if (le32_to_cpu(ctx->hdr.model) != 6245) {
+ ERROR("Unrecognized printer (%d)!\n", le32_to_cpu(ctx->hdr.model));
+
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ 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 CUPS_BACKEND_FAILED;
+ }
+
+ {
+ int remain = ctx->datalen;
+ uint8_t *ptr = ctx->databuf;
+ do {
+ ret = read(data_fd, ptr, remain);
+ if (ret < 0) {
+ ERROR("Read failed (%d/%d/%d)\n",
+ ret, remain, ctx->datalen);
+ perror("ERROR: Read failed");
+ return ret;
+ }
+ ptr += ret;
+ remain -= ret;
+ } while (remain);
+ }
+
+ /* Make sure footer is sane too */
+ ret = read(data_fd, tmpbuf, 4);
+ if (ret != 4) {
+ ERROR("Read failed (%d/%d/%d)\n",
+ ret, 4, 4);
+ perror("ERROR: Read failed");
+ return ret;
+ }
+ if (tmpbuf[0] != 0x04 ||
+ tmpbuf[1] != 0x03 ||
+ tmpbuf[2] != 0x02 ||
+ tmpbuf[3] != 0x01) {
+ ERROR("Unrecognized footer data format!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int shinkos6245_main_loop(void *vctx, int copies) {
+ struct shinkos6245_ctx *ctx = vctx;
+
+ int ret, num;
+ uint8_t cmdbuf[CMDBUF_LEN];
+ uint8_t rdbuf2[READBACK_LEN];
+
+ int i, last_state = -1, state = S_IDLE;
+ uint8_t mcut;
+
+ struct s6245_cmd_hdr *cmd = (struct s6245_cmd_hdr *) cmdbuf;;
+ struct s6245_print_cmd *print = (struct s6245_print_cmd *) cmdbuf;
+ struct s6245_status_resp *sts = (struct s6245_status_resp *) rdbuf;
+ struct s6245_mediainfo_resp *media = (struct s6245_mediainfo_resp *) rdbuf;
+
+ /* Cap copies */
+ // XXX 120 for 8x10 media, 100 for 8x12 media (S6245)
+ // 250 for 8x12, 300 for 8x10 (Kodak 8810)
+ if (copies > 120)
+ copies = 120;
+
+ /* Set up mcut */
+ switch (le32_to_cpu(ctx->hdr.media)) {
+ case MEDIA_8x4_2:
+ case MEDIA_8x5_2:
+ case MEDIA_8x6_2:
+ mcut = PRINT_METHOD_COMBO_2;
+ break;
+ case MEDIA_8x4_3:
+ mcut = PRINT_METHOD_COMBO_3;
+ break;
+ default:
+ mcut = PRINT_METHOD_STD;
+ }
+ // XXX what about mcut |= PRINT_METHOD_DISABLE_ERR;
+
+ /* Send Media Query */
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmd->cmd = cpu_to_le16(S6245_CMD_MEDIAINFO);
+ cmd->len = cpu_to_le16(0);
+
+ if ((ret = s6245_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 s6245_mediainfo_resp) - sizeof(struct s6245_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;
+ }
+
+ /* Send Set Time */
+ {
+ struct s6245_settime_cmd *stime = (struct s6245_settime_cmd *)cmdbuf;
+ time_t now = time(NULL);
+ struct tm *cur = localtime(&now);
+
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmd->cmd = cpu_to_le16(S6245_CMD_SETTIME);
+ cmd->len = cpu_to_le16(0);
+ stime->enable = 1;
+ stime->second = cur->tm_sec;
+ stime->minute = cur->tm_min;
+ stime->hour = cur->tm_hour;
+ stime->day = cur->tm_mday;
+ stime->month = cur->tm_mon;
+ stime->year = cur->tm_year + 1900 - 2000;
+
+ if ((ret = s6245_do_cmd(ctx,
+ cmdbuf, sizeof(*stime),
+ sizeof(struct s6245_status_hdr),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(stime->hdr.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+ if (sts->hdr.result != RESULT_SUCCESS)
+ goto printer_error;
+ }
+
+ // XXX check copies against remaining media!
+
+top:
+ if (state != last_state) {
+ if (dyesub_debug)
+ DEBUG("last_state %d new %d\n", last_state, state);
+ }
+
+ /* Send Status Query */
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ cmd->cmd = cpu_to_le16(S6245_CMD_GETSTATUS);
+ cmd->len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(ctx,
+ cmdbuf, sizeof(*cmd),
+ sizeof(struct s6245_status_hdr),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
+ memcpy(rdbuf2, rdbuf, READBACK_LEN);
+
+ INFO("Printer Status: 0x%02x (%s)\n",
+ sts->hdr.status, status_str(sts->hdr.status));
+ 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;
+
+ fflush(stderr);
+
+ switch (state) {
+ case S_IDLE:
+ INFO("Waiting for printer idle\n");
+ /* If either bank is free, continue */
+ if (sts->bank1_status == BANK_STATUS_FREE ||
+ sts->bank2_status == BANK_STATUS_FREE)
+ state = S_PRINTER_READY_CMD;
+
+ break;
+ case S_PRINTER_READY_CMD:
+ // XXX send "get eeprom backup command"
+
+ INFO("Initiating print job (internal id %d)\n", ctx->jobid);
+
+ memset(cmdbuf, 0, CMDBUF_LEN);
+ print->hdr.cmd = cpu_to_le16(S6245_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->mode = le32_to_cpu(ctx->hdr.oc_mode);
+ print->method = mcut;
+
+ if ((ret = s6245_do_cmd(ctx,
+ cmdbuf, sizeof(*print),
+ sizeof(struct s6245_status_hdr),
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(print->hdr.cmd));
+ return ret;
+ }
+
+ if (sts->hdr.result != RESULT_SUCCESS) {
+ if (sts->hdr.error == ERROR_BUFFER_FULL) {
+ INFO("Printer Buffers full, retrying\n");
+ break;
+ } else if ((sts->hdr.status & 0xf0) == 0x30 || sts->hdr.status == 0x21) {
+ INFO("Printer busy (%s), retrying\n", status_str(sts->hdr.status));
+ break;
+ } else if (sts->hdr.status != ERROR_NONE)
+ goto printer_error;
+ }
+
+ INFO("Sending image data to printer\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);
+ state = S_PRINTER_SENT_DATA;
+ break;
+ case S_PRINTER_SENT_DATA:
+ if (fast_return) {
+ INFO("Fast return mode enabled.\n");
+ state = S_FINISHED;
+ } else if (sts->hdr.status == STATUS_READY) {
+ state = S_FINISHED;
+ }
+ break;
+ default:
+ break;
+ };
+
+ if (state != S_FINISHED)
+ goto top;
+
+ INFO("Print complete\n");
+
+ return CUPS_BACKEND_OK;
+
+printer_error:
+ ERROR("Printer reported error: %#x (%s) status: %#x (%s) -> %#x.%#x (%s)\n",
+ sts->hdr.error,
+ error_str(sts->hdr.error),
+ sts->hdr.status,
+ status_str(sts->hdr.status),
+ sts->hdr.printer_major, sts->hdr.printer_minor,
+ error_codes(sts->hdr.printer_major, sts->hdr.printer_minor));
+ return CUPS_BACKEND_FAILED;
+}
+
+static int shinkos6245_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
+{
+ struct s6245_cmd_hdr cmd;
+ struct s6245_getserial_resp *resp = (struct s6245_getserial_resp*) rdbuf;
+ int ret, num = 0;
+
+ struct shinkos6245_ctx ctx = {
+ .dev = dev,
+ .endp_up = endp_up,
+ .endp_down = endp_down,
+ };
+
+ cmd.cmd = cpu_to_le16(S6245_CMD_GETSERIAL);
+ cmd.len = cpu_to_le16(0);
+
+ if ((ret = s6245_do_cmd(&ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp) - 1,
+ &num)) < 0) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return ret;
+ }
+
+ /* Null-terminate */
+ resp->hdr.payload_len = le16_to_cpu(resp->hdr.payload_len);
+ if (resp->hdr.payload_len > 23)
+ resp->hdr.payload_len = 23;
+ resp->data[resp->hdr.payload_len] = 0;
+ strncpy(buf, (char*)resp->data, buf_len);
+ buf[buf_len-1] = 0; /* ensure it's null terminated */
+
+ return CUPS_BACKEND_OK;
+}
+
+/* Exported */
+#define USB_VID_SHINKO 0x10CE
+#define USB_PID_SHINKO_S6245 0x001D
+
+struct dyesub_backend shinkos6245_backend = {
+ .name = "Shinko/Sinfonia CHC-S6245",
+ .version = "0.04WIP",
+ .uri_prefix = "shinkos6245",
+ .cmdline_usage = shinkos6245_cmdline,
+ .cmdline_arg = shinkos6245_cmdline_arg,
+ .init = shinkos6245_init,
+ .attach = shinkos6245_attach,
+ .teardown = shinkos6245_teardown,
+ .read_parse = shinkos6245_read_parse,
+ .main_loop = shinkos6245_main_loop,
+ .query_serno = shinkos6245_query_serno,
+ .devices = {
+ { USB_VID_SHINKO, USB_PID_SHINKO_S6245, P_SHINKO_S6245, ""},
+ { 0, 0, 0, ""}
+ }
+};
+
+/* 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 ]]
+
+*/
diff --git a/src/cups/sony_updr150_print.c b/src/cups/sony_updr150_print.c
index 5df9742..0121443 100644
--- a/src/cups/sony_updr150_print.c
+++ b/src/cups/sony_updr150_print.c
@@ -35,25 +35,27 @@
#include <fcntl.h>
#include <signal.h>
+#define BACKEND updr150_backend
+
#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
+#define USB_PID_SONY_UPCR10 0x0226
/* Private data stucture */
struct updr150_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
uint8_t *databuf;
int datalen;
uint32_t copies_offset;
- uint8_t type;
};
static void* updr150_init(void)
@@ -82,11 +84,9 @@ static void updr150_attach(void *vctx, struct libusb_device_handle *dev,
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->type = lookup_printer_type(&updr150_backend,
+ desc.idVendor, desc.idProduct);
ctx->copies_offset = 0;
}
@@ -255,10 +255,30 @@ top:
return CUPS_BACKEND_OK;
}
+static int updr150_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct updr150_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL)) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
struct dyesub_backend updr150_backend = {
.name = "Sony UP-DR150/UP-DR200/UP-CR10",
- .version = "0.17",
+ .version = "0.18",
.uri_prefix = "sonyupdr150",
+ .cmdline_arg = updr150_cmdline_arg,
.init = updr150_init,
.attach = updr150_attach,
.teardown = updr150_teardown,
diff --git a/src/cups/test-ppds b/src/cups/test-ppds
index 7dd004b..542fd27 100644..100755
--- a/src/cups/test-ppds
+++ b/src/cups/test-ppds
@@ -10,7 +10,7 @@ make EXTRA_GENPPD_OPTS='-b -Z' ppd-clean ppd-global ppd-nls ppd-nonls
# Also, a number of our media sizes aren't named correctly, but we'll
# accept those issues rather than cluttering the namespace further and/or
# changing tag names.
-cupstestppdopts='-I profiles -W sizes'
+cupstestppdopts='-I profiles -W sizes -I filters'
ppd_count=`find ppd \( -name '*.ppd.gz' -o -name '*.ppd' \) -print | wc -l`
diff --git a/src/cups/test-rastertogutenprint.in b/src/cups/test-rastertogutenprint.in
index 373f127..0574704 100755
--- a/src/cups/test-rastertogutenprint.in
+++ b/src/cups/test-rastertogutenprint.in
@@ -23,12 +23,15 @@ fi
single=''
all_models=''
verbose=''
+valgrind=0
make_ppds=1
md5dir=''
outdir=''
cupsargs=''
postscript=''
npages=3
+enable_static='@ENABLE_STATIC@'
+enable_shared='@ENABLE_SHARED@'
usage() {
echo "Usage: test-rastertogutenprint [-s] [-v|--valgrind]"
@@ -40,7 +43,7 @@ set_args() {
case "$1" in
-s) single=1 ;;
-h*|--h*) usage ;;
- -v|--valgrind) valopts='--tool=memcheck' ; valgrind=`expr $valgrind + 1` ;;
+ -v|--valgrind) valopts='--tool=memcheck' ; valgrind=$((valgrind + 1)) ;;
-c|--cachegrind) valopts='--tool=cachegrind'; valgrind=4 ;;
-g|--gdb-attach) valopts='--gdb-attach=yes' ;;
-V|--verbose) verbose=1 ;;
@@ -59,6 +62,12 @@ set_args() {
set_args `getopt hvcgsVnO:m:o:p: "$@"`
+if [ "$valgrind" -gt 0 -a "$enable_shared" != "no" ] ; then
+ echo 'Valgrind is not compatible with --enable-shared in tree.' 1>&2
+ echo 'Please use autogen.sh --disable-shared.' 1>&2
+ exit 1
+fi
+
if [ -n "$outdir" -a ! -d "$outdir" ] ; then
mkdir -p "$outdir"
fi
@@ -136,10 +145,10 @@ is_duplicate() {
run_rastertogp() {
case "$valgrind" in
- 1) valgrind $valopts -q --num-callers=50 --leak-check=yes --error-limit=no ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
- 2) valgrind $valopts --num-callers=50 --leak-resolution=high --leak-check=yes --error-limit=no ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
- 3) valgrind $valopts --error-limit=no --num-callers=50 --show-reachable=yes --leak-resolution=high --leak-check=yes ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
- 4) valgrind $valopts ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
+ 1) valgrind $valopts -q --log-fd=3 --num-callers=50 --leak-check=yes --error-limit=no ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
+ 2) valgrind $valopts --log-fd=3 --num-callers=50 --leak-resolution=high --leak-check=yes --error-limit=no ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
+ 3) valgrind $valopts --log-fd=3 --error-limit=no --num-callers=50 --show-reachable=yes --leak-resolution=high --leak-check=yes ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
+ 4) valgrind $valopts --log-fd=3 ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
5) cat ;;
*) ./rastertogutenprint.$version 1 1 1 1 "$cupsargs" ;;
esac
@@ -241,17 +250,17 @@ if [ -d ppd/C ] ; then
PPD=$f
export PPD
if [ -x "$cupsdir/cgpdftoraster" ] ; then
- output="`($cupsdir/cgpdftoraster 1 1 1 1 $pages < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/cgpdftoraster 1 1 1 1 $pages < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -f "$tfile" -a -x "$cupsdir/gstoraster" ] ; then
- output="`($cupsdir/gstoraster 1 1 1 1 \"$cupsargs\" < $tfile 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/gstoraster 1 1 1 1 \"$cupsargs\" < $tfile 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -f "$tfile" ] ; then
- output="`($cupsdir/pstops 1 1 1 1 \"$cupsargs\" < $tfile 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/pstops 1 1 1 1 \"$cupsargs\" < $tfile 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -x "$cupsdir/pstoraster" ] ; then
- output="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | $cupsdir/pstops 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | $cupsdir/pstops 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -x "$cupsdir/gstoraster" ] ; then
- output="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | $cupsdir/gstoraster 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < $sdir/../../doc/gutenprint-users-manual.pdf 2>/dev/null | $cupsdir/gstoraster 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
else
- output="`($cupsdir/imagetoraster 1 1 1 1 \"$pages$cupsargs\" < calibrate.ppm 2>/dev/null | run_rastertogp | do_output) 2>&1`"
+ output="`($cupsdir/imagetoraster 1 1 1 1 \"$pages$cupsargs\" < calibrate.ppm 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2`"
fi
if [ $? -ne 0 ] ; then
retval=1