summaryrefslogtreecommitdiff
path: root/src/cups
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2018-09-25 08:33:05 +0200
committerDidier Raboud <odyx@debian.org>2018-09-25 08:33:05 +0200
commite50542121e724e851fc5d6c68bb773f80c0bc12c (patch)
tree655c3f6331a6e8fd8b09ceb4da8f5896484ae16a /src/cups
parent9dd97a029bf391c42b1dc76f2f7c5e386bb8f466 (diff)
New upstream version 5.3.1
Diffstat (limited to 'src/cups')
-rw-r--r--src/cups/COPYING3
-rw-r--r--src/cups/Makefile.am143
-rw-r--r--src/cups/Makefile.in478
-rw-r--r--src/cups/backend_canonselphy.c572
-rw-r--r--src/cups/backend_canonselphyneo.c261
-rw-r--r--src/cups/backend_citizencw01.c908
-rw-r--r--src/cups/backend_common.c774
-rw-r--r--src/cups/backend_common.h149
-rw-r--r--src/cups/backend_dnpds40.c1355
-rw-r--r--src/cups/backend_kodak1400.c208
-rw-r--r--src/cups/backend_kodak605.c257
-rw-r--r--src/cups/backend_kodak6800.c215
-rw-r--r--src/cups/backend_magicard.c1143
-rw-r--r--src/cups/backend_mitsu70x.c1409
-rw-r--r--src/cups/backend_mitsu9550.c955
-rw-r--r--src/cups/backend_mitsud90.c1456
-rw-r--r--src/cups/backend_mitsup95d.c420
-rw-r--r--src/cups/backend_shinkos1245.c224
-rw-r--r--src/cups/backend_shinkos2145.c331
-rw-r--r--src/cups/backend_shinkos6145.c421
-rw-r--r--src/cups/backend_shinkos6245.c545
-rw-r--r--src/cups/backend_sonyupdr150.c396
-rw-r--r--src/cups/blacklist27
-rw-r--r--src/cups/command.types3
-rw-r--r--src/cups/commandtoepson.c3
-rw-r--r--src/cups/cups-calibrate.c3
-rw-r--r--src/cups/cups-genppd.c607
-rw-r--r--src/cups/cups-genppdupdate.in47
-rw-r--r--src/cups/genppd.c910
-rw-r--r--src/cups/genppd.h91
-rw-r--r--src/cups/gutenprint.c253
-rw-r--r--src/cups/i18n.c3
-rw-r--r--src/cups/i18n.h3
-rw-r--r--src/cups/min-pagesize.in42
-rw-r--r--src/cups/rastertogutenprint.c (renamed from src/cups/rastertoprinter.c)88
-rwxr-xr-xsrc/cups/test-ppds56
-rw-r--r--src/cups/test-ppds.in127
-rw-r--r--src/cups/test-rastertogutenprint.check.in77
-rw-r--r--[-rwxr-xr-x]src/cups/test-rastertogutenprint.in555
39 files changed, 10573 insertions, 4945 deletions
diff --git a/src/cups/COPYING b/src/cups/COPYING
index 960fe74..b2579a3 100644
--- a/src/cups/COPYING
+++ b/src/cups/COPYING
@@ -1,8 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
diff --git a/src/cups/Makefile.am b/src/cups/Makefile.am
index 4ef097d..2f70701 100644
--- a/src/cups/Makefile.am
+++ b/src/cups/Makefile.am
@@ -11,8 +11,7 @@
## 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.
+## along with this program. If not, see <https://www.gnu.org/licenses/>.
## Process this file with automake to produce Makefile.in.
@@ -52,9 +51,11 @@ endif
LOCAL_CPPFLAGS = $(GUTENPRINT_CFLAGS) $(CUPS_CFLAGS) -DBASE_VERSION=$(BASE_VERSION) -DSBINDIR=\"$(sbindir)/\"
-STP_NONLS_ENV= STP_MODULE_PATH=$(top_builddir)/src/main/.libs:$(top_builddir)/src/main STP_DATA_PATH=$(top_srcdir)/src/xml
+PPD_DIR=ppd
-STP_ENV= $(STP_NONLS_ENV) STP_LOCALEDIR=$(top_srcdir)/src/cups/catalog
+STP_NONLS_ENV= STP_MODULE_PATH=$(top_builddir)/src/main/.libs:$(top_builddir)/src/main STP_DATA_PATH=$(top_srcdir)/src/xml STP_LOCALEDIR=
+
+STP_ENV= $(STP_NONLS_ENV) STP_LOCALEDIR=$(top_builddir)/src/cups/$(PPD_DIR)catalog
## Programs
if BUILD_TRANSLATED_CUPS_PPDS
@@ -96,8 +97,14 @@ install-exec-hook:
mv $(DESTDIR)$(pkglibdir)/backend/backend_gutenprint "$(DESTDIR)$(pkglibdir)/backend/gutenprint$(GUTENPRINT_MAJOR_VERSION)$(GUTENPRINT_MINOR_VERSION)+usb"
endif
-TESTS= test-ppds test-rastertogutenprint
-noinst_SCRIPTS=test-rastertogutenprint
+AM_TESTS_ENVIRONMENT=$(STP_ENV)
+test-rastertogutenprint: min-pagesize
+test-rastertogutenprint.check: test-rastertogutenprint
+TESTS= test-ppds test-rastertogutenprint.check
+noinst_SCRIPTS=test-ppds \
+ test-rastertogutenprint \
+ test-rastertogutenprint.check \
+ min-pagesize
endif
if BUILD_GENPPD_STATIC
@@ -114,23 +121,23 @@ commandtoepson_SOURCES = commandtoepson.c
commandtoepson_LDADD = $(CUPS_LIBS)
if BUILD_LIBUSB_BACKENDS
-backend_gutenprint_SOURCES = backend_canonselphy.c backend_canonselphyneo.c backend_kodak1400.c backend_kodak6800.c backend_kodak605.c backend_shinkos2145.c backend_sonyupdr150.c backend_dnpds40.c backend_mitsu70x.c backend_citizencw01.c backend_mitsu9550.c backend_common.c backend_common.h backend_shinkos1245.c backend_shinkos6145.c backend_shinkos6245.c backend_mitsup95d.c
+backend_gutenprint_SOURCES = backend_canonselphy.c backend_canonselphyneo.c backend_kodak1400.c backend_kodak6800.c backend_kodak605.c backend_shinkos2145.c backend_sonyupdr150.c backend_dnpds40.c backend_mitsu70x.c backend_mitsu9550.c backend_common.c backend_common.h backend_shinkos1245.c backend_shinkos6145.c backend_shinkos6245.c backend_mitsup95d.c backend_magicard.c backend_mitsud90.c
backend_gutenprint_LDADD = $(LIBUSB_LIBS) $(LIBUSB_BACKEND_LIBDEPS)
backend_gutenprint_CPPFLAGS = $(LIBUSB_CFLAGS) -DURI_PREFIX=\"gutenprint$(GUTENPRINT_MAJOR_VERSION)$(GUTENPRINT_MINOR_VERSION)+usb\" -DLIBUSB_PRE_1_0_10
endif
-cups_genppd_@GUTENPRINT_RELEASE_VERSION@_SOURCES = genppd.c i18n.c i18n.h
+cups_genppd_@GUTENPRINT_RELEASE_VERSION@_SOURCES = cups-genppd.c genppd.c genppd.h i18n.c i18n.h
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GENPPD_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = genppd.c i18n.c i18n.h
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DCUPS_DRIVER_INTERFACE -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = gutenprint.c genppd.c genppd.h i18n.c i18n.h
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GENPPD_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
-rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = rastertoprinter.c i18n.c i18n.h
+rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = rastertogutenprint.c i18n.c i18n.h
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
@@ -158,17 +165,17 @@ endif
if BUILD_LIBUSB_BACKENDS
INSTALL_BLACKLIST=install-blacklist
install-blacklist:
- $(mkdir_p) $(DESTDIR)$(cupsdata_blacklistdir)
+ $(MKDIR_P) $(DESTDIR)$(cupsdata_blacklistdir)
$(INSTALL_DATA) $(srcdir)/blacklist $(DESTDIR)$(cupsdata_blacklistdir)/net.sf.gimp-print.usb-quirks
endif
install-data-local: $(INSTALL_DATA_LOCAL_DEPS) $(INSTALL_BLACKLIST)
if test -n "$(CUPS_PKG)" -a -n "$(INSTALL_DATA_LOCAL_DEPS)" ; then \
- $(mkdir_p) $(DESTDIR)$(cups_modeldir); \
+ $(MKDIR_P) $(DESTDIR)$(cups_modeldir); \
cd ppd ; \
for language in * ; do \
cd ..; \
- $(mkdir_p) $(DESTDIR)$(cups_modeldir)/$$language; \
+ $(MKDIR_P) $(DESTDIR)$(cups_modeldir)/$$language; \
cd ppd/$$language; \
for ppdfile in * ; do \
(cd ../..; $(INSTALL_DATA) ppd/$$language/$$ppdfile $(DESTDIR)$(cups_modeldir)/$$language) ; \
@@ -176,10 +183,10 @@ install-data-local: $(INSTALL_DATA_LOCAL_DEPS) $(INSTALL_BLACKLIST)
cd ..; \
done \
fi
- $(mkdir_p) "$(DESTDIR)$(localedir)"
+ $(MKDIR_P) "$(DESTDIR)$(localedir)"
for file in $(srcdir)/../../po/*.po; do \
lang=`basename $$file .po`; \
- $(mkdir_p) "$(DESTDIR)$(localedir)/$$lang"; \
+ $(MKDIR_P) "$(DESTDIR)$(localedir)/$$lang"; \
$(INSTALL_DATA) $$file "$(DESTDIR)$(localedir)/$$lang/gutenprint_$$lang.po"; \
done
@@ -208,13 +215,15 @@ install-data-hook:
-rmdir $(DESTDIR)$(cupsexec_backenddir)
-rmdir $(DESTDIR)$(cupsdata_blacklistdir)
-rmdir $(DESTDIR)$(bindir)
+ -rmdir $(DESTDIR)$(sbindir)
-rmdir $(DESTDIR)$(pkglibdir)
-rmdir $(DESTDIR)$(pkgsysconfdir)
-rmdir `dirname $(DESTDIR)$(pkgdatadir)`
-rmdir `dirname $(DESTDIR)$(pkglibdir)`
-rmdir `dirname $(DESTDIR)$(pkgsysconfdir)`
-.PHONY: ppd ppd-stamp-pre ppd-stamp-nonls ppd-stamp-nls ppd-stamp-phony ppd-catalog-clean ppd-clean $(INSTALL_BLACKLIST)
+.PHONY: ppd ppd-stamp-pre ppd-stamp-nonls ppd-stamp-nls ppd-stamp-phony \
+ ppd-catalog-clean ppd-clean $(INSTALL_BLACKLIST)
all-local: $(INSTALL_DATA_LOCAL_DEPS)
@@ -228,76 +237,111 @@ ppd-stamp: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(top_srcdir)/src/xml/xml-st
ppd-stamp-phony: $(PPD)
ppd-catalog-clean:
- $(RM) -rf catalog
+ $(RM) -rf $(PPD_DIR)catalog
ppd-clean:
- $(RM) -rf ppd
+ $(RM) -rf $(PPD_DIR)
ppd-stamp-pre: ppd-catalog-clean ppd-clean
ppd-catalog: ppd-catalog-clean
- $(mkdir_p) catalog
- for file in $(srcdir)/../../po/*.po; do \
+ $(MKDIR_P) catalog
+ for file in $(top_srcdir)/po/*.po; do \
lang=`basename $$file .po`; \
- $(mkdir_p) "catalog/$$lang"; \
- $(INSTALL_DATA) $$file "catalog/$$lang/gutenprint_$$lang.po"; \
+ $(MKDIR_P) "$(PPD_DIR)catalog/$$lang"; \
+ $(INSTALL_DATA) $$file "$(PPD_DIR)catalog/$$lang/gutenprint_$$lang.po"; \
done
ppd-nonls: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- $(mkdir_p) ppd/C
+ @echo "Non-localized PPDs:"
+ $(MKDIR_P) $(PPD_DIR)/C
$(MAKE) ppd-catalog-clean
- LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ $(EXTRA_GENPPD_OPTS) -l C -p ppd/C
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C @WHICH_PPDS@
ppd-nonls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- $(mkdir_p) ppd/C
+ @echo "Non-localized PPDs (all):"
+ $(MKDIR_P) $(PPD_DIR)/C
$(MAKE) ppd-catalog-clean
- LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ $(EXTRA_GENPPD_OPTS) -l C -p ppd/C -a
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C -a
+
+ppd-nonls-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Non-localized PPDs (simplified):"
+ $(MKDIR_P) $(PPD_DIR)/C
+ $(MAKE) ppd-catalog-clean
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C -s
ppd-global: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
@echo "Global PPDs:"
- $(mkdir_p) ppd/Global
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global @WHICH_PPDS@
$(MAKE) ppd-catalog-clean
ppd-global-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- @echo "Global PPDs:"
- $(mkdir_p) ppd/Global
+ @echo "Global PPDs (all):"
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -a
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -a
+ $(MAKE) ppd-catalog-clean
+
+ppd-global-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Global PPDs (simplified):"
+ $(MKDIR_P) $(PPD_DIR)/Global
+ $(MAKE) ppd-catalog
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -s
$(MAKE) ppd-catalog-clean
ppd-global-ln: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
@echo "Global PPDs (localized numbers for testing):"
- $(mkdir_p) ppd/Global
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -N
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N @WHICH_PPDS@
$(MAKE) ppd-catalog-clean
ppd-global-ln-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- @echo "Global PPDs (localized numbers for testing):"
- $(mkdir_p) ppd/Global
+ @echo "Global PPDs (all, localized numbers for testing):"
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -N -a
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N -a
+ $(MAKE) ppd-catalog-clean
+
+ppd-global-ln-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Global PPDs (all, localized numbers for testing):"
+ $(MKDIR_P) $(PPD_DIR)/Global
+ $(MAKE) ppd-catalog
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N -s
$(MAKE) ppd-catalog-clean
ppd-nls: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ ppd-nonls
- $(mkdir_p) ppd
+ @echo "Localized PPD files:"
+ $(MKDIR_P) ppd
+ $(MAKE) ppd-catalog
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
+ echo -n "$$language: " ; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l $$language -p $(PPD_DIR)/$$language; \
+ done
+ $(MAKE) ppd-catalog-clean
+
+ppd-nls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ ppd-nonls
+ @echo "Localized PPD files (all):"
+ $(MKDIR_P) ppd
$(MAKE) ppd-catalog
- for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ -L` ; do \
- $(mkdir_p) ppd/$$language ; \
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
echo -n "$$language: " ; \
- LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p ppd/$$language; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p $(PPD_DIR)/$$language -a; \
done
$(MAKE) ppd-catalog-clean
-ppd-nls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ ppd-nonls
- $(mkdir_p) ppd
+ppd-nls-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ ppd-nonls
+ @echo "Localized PPD files (simplified):"
+ $(MKDIR_P) ppd
$(MAKE) ppd-catalog
- for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ -L` ; do \
- $(mkdir_p) ppd/$$language ; \
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
echo -n "$$language: " ; \
- LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p ppd/$$language -a; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p $(PPD_DIR)/$$language -s; \
done
$(MAKE) ppd-catalog-clean
@@ -319,7 +363,7 @@ clean-local: ppd-catalog-clean ppd-clean
## Clean
CLEANFILES = ppd-stamp
-DISTCLEANFILES = cups-genppdupdate
+DISTCLEANFILES = cups-genppdupdate test-ppds
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = \
@@ -328,5 +372,4 @@ EXTRA_DIST = \
blacklist \
calibrate.ppm \
command.txt \
- command.types \
- test-ppds
+ command.types
diff --git a/src/cups/Makefile.in b/src/cups/Makefile.in
index 04419cb..605047b 100644
--- a/src/cups/Makefile.in
+++ b/src/cups/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,7 +22,17 @@
VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -83,12 +93,6 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-DIST_COMMON = $(top_srcdir)/scripts/global.mk $(srcdir)/Makefile.in \
- $(srcdir)/Makefile.am $(srcdir)/Info.plist.in \
- $(srcdir)/cups-genppdupdate.in \
- $(srcdir)/test-rastertogutenprint.in \
- $(top_srcdir)/scripts/depcomp \
- $(top_srcdir)/scripts/test-driver COPYING README
@BUILD_CUPS_1_2_TRUE@cupsexec_driver_PROGRAMS = gutenprint.@GUTENPRINT_RELEASE_VERSION@$(EXEEXT)
@BUILD_CUPS_TRUE@bin_PROGRAMS = cups-calibrate$(EXEEXT)
@BUILD_CUPS_TRUE@sbin_PROGRAMS = cups-genppd.@GUTENPRINT_RELEASE_VERSION@$(EXEEXT)
@@ -99,21 +103,23 @@ DIST_COMMON = $(top_srcdir)/scripts/global.mk $(srcdir)/Makefile.in \
subdir = src/cups
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
- $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
- $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
- $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
- $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/stp.m4 $(top_srcdir)/m4/stp_cups.m4 \
- $(top_srcdir)/m4/stp_gimp.m4 $(top_srcdir)/m4/stp_option.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/stp.m4 \
+ $(top_srcdir)/m4/stp_cups.m4 $(top_srcdir)/m4/stp_option.m4 \
$(top_srcdir)/m4/stp_release.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
-CONFIG_CLEAN_FILES = Info.plist cups-genppdupdate \
- test-rastertogutenprint
+CONFIG_CLEAN_FILES = Info.plist cups-genppdupdate test-ppds \
+ min-pagesize test-rastertogutenprint \
+ test-rastertogutenprint.check
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(cupsexec_backenddir)" \
@@ -128,9 +134,10 @@ am__backend_gutenprint_SOURCES_DIST = backend_canonselphy.c \
backend_canonselphyneo.c backend_kodak1400.c \
backend_kodak6800.c backend_kodak605.c backend_shinkos2145.c \
backend_sonyupdr150.c backend_dnpds40.c backend_mitsu70x.c \
- backend_citizencw01.c backend_mitsu9550.c backend_common.c \
- backend_common.h backend_shinkos1245.c backend_shinkos6145.c \
- backend_shinkos6245.c backend_mitsup95d.c
+ backend_mitsu9550.c backend_common.c backend_common.h \
+ backend_shinkos1245.c backend_shinkos6145.c \
+ backend_shinkos6245.c backend_mitsup95d.c backend_magicard.c \
+ backend_mitsud90.c
@BUILD_LIBUSB_BACKENDS_TRUE@am_backend_gutenprint_OBJECTS = backend_gutenprint-backend_canonselphy.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_canonselphyneo.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_kodak1400.$(OBJEXT) \
@@ -140,13 +147,14 @@ am__backend_gutenprint_SOURCES_DIST = backend_canonselphy.c \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_sonyupdr150.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_dnpds40.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_mitsu70x.$(OBJEXT) \
-@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_citizencw01.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_mitsu9550.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_common.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_shinkos1245.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_shinkos6145.$(OBJEXT) \
@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_shinkos6245.$(OBJEXT) \
-@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_mitsup95d.$(OBJEXT)
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_mitsup95d.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_magicard.$(OBJEXT) \
+@BUILD_LIBUSB_BACKENDS_TRUE@ backend_gutenprint-backend_mitsud90.$(OBJEXT)
backend_gutenprint_OBJECTS = $(am_backend_gutenprint_OBJECTS)
am__DEPENDENCIES_1 =
@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_DEPENDENCIES = \
@@ -165,7 +173,7 @@ commandtoepson_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_cups_calibrate_OBJECTS = cups-calibrate.$(OBJEXT)
cups_calibrate_OBJECTS = $(am_cups_calibrate_OBJECTS)
cups_calibrate_DEPENDENCIES =
-am_cups_genppd_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
+am_cups_genppd_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.$(OBJEXT) \
cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.$(OBJEXT) \
cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.$(OBJEXT)
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
@@ -178,19 +186,20 @@ cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LINK = $(LIBTOOL) $(AM_V_lt) \
$(CFLAGS) $(cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS) \
$(LDFLAGS) -o $@
am_gutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
+ gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.$(OBJEXT) \
gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.$(OBJEXT) \
gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.$(OBJEXT)
gutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
$(am_gutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS)
gutenprint_@GUTENPRINT_RELEASE_VERSION@_DEPENDENCIES = \
- $(am__DEPENDENCIES_1) $(GUTENPRINT_LIBS)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(GUTENPRINT_LIBS)
gutenprint_@GUTENPRINT_RELEASE_VERSION@_LINK = $(LIBTOOL) $(AM_V_lt) \
--tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
$(CCLD) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) \
$(CFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS) \
$(LDFLAGS) -o $@
am_rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
- rastertoprinter.$(OBJEXT) i18n.$(OBJEXT)
+ rastertogutenprint.$(OBJEXT) i18n.$(OBJEXT)
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS = \
$(am_rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_OBJECTS)
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_DEPENDENCIES = \
@@ -242,7 +251,34 @@ am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/scripts/depcomp
-am__depfiles_maybe = depfiles
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = \
+ ./$(DEPDIR)/backend_gutenprint-backend_canonselphy.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_canonselphyneo.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_common.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_dnpds40.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_kodak1400.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_kodak605.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_kodak6800.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_magicard.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_mitsu70x.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_mitsud90.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_mitsup95d.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_shinkos1245.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_shinkos2145.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_shinkos6145.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_shinkos6245.Po \
+ ./$(DEPDIR)/backend_gutenprint-backend_sonyupdr150.Po \
+ ./$(DEPDIR)/commandtocanon.Po ./$(DEPDIR)/commandtoepson.Po \
+ ./$(DEPDIR)/cups-calibrate.Po \
+ ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po \
+ ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po \
+ ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.Po \
+ ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po \
+ ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po \
+ ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.Po \
+ ./$(DEPDIR)/i18n.Po ./$(DEPDIR)/rastertogutenprint.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -475,6 +511,13 @@ TEST_LOGS = $(am__test_logs2:.test.log=.log)
TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/scripts/test-driver
TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Info.plist.in $(srcdir)/Makefile.in \
+ $(srcdir)/cups-genppdupdate.in $(srcdir)/min-pagesize.in \
+ $(srcdir)/test-ppds.in \
+ $(srcdir)/test-rastertogutenprint.check.in \
+ $(srcdir)/test-rastertogutenprint.in \
+ $(top_srcdir)/scripts/depcomp $(top_srcdir)/scripts/global.mk \
+ $(top_srcdir)/scripts/test-driver COPYING README
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
pkgdatadir = $(cups_conf_datadir)
pkglibdir = $(cups_conf_serverbin)
@@ -487,6 +530,8 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+BASH = @BASH@
+BASHREAL = @BASHREAL@
BUILD_CUPS_PPDS = @BUILD_CUPS_PPDS@
BZIP2 = @BZIP2@
CC = @CC@
@@ -507,7 +552,6 @@ DB2PDF = @DB2PDF@
DB2PS = @DB2PS@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
-DIALOG = @DIALOG@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
@@ -524,6 +568,7 @@ EXEEXT = @EXEEXT@
FGREP = @FGREP@
FIND = @FIND@
GENPPD_LIBS = @GENPPD_LIBS@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GIMP2_CFLAGS = @GIMP2_CFLAGS@
GIMP2_LIBS = @GIMP2_LIBS@
GIMPTOOL2_CHECK = @GIMPTOOL2_CHECK@
@@ -586,10 +631,12 @@ LTALLOCA = @LTALLOCA@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
MAINTAINER_CFLAGS = @MAINTAINER_CFLAGS@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MINIMAL_PRINTERS_TO_TEST = @MINIMAL_PRINTERS_TO_TEST@
MKDIR_P = @MKDIR_P@
MSGFMT = @MSGFMT@
MSGFMT_015 = @MSGFMT_015@
@@ -613,7 +660,6 @@ PKGROOT = @PKGROOT@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
-PLUG_IN_PATH = @PLUG_IN_PATH@
POSUB = @POSUB@
RANLIB = @RANLIB@
RELEASE_DATE = @RELEASE_DATE@
@@ -631,9 +677,11 @@ VERSION = @VERSION@
WHICH_PPDS = @WHICH_PPDS@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
XZ = @XZ@
YACC = @YACC@
YFLAGS = @YFLAGS@
+ZPAQ = @ZPAQ@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -701,7 +749,6 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include $(LOCAL_CPPFLAGS) $(GNUCFLAGS)
-GUTENPRINTUI_LIBS = $(top_builddir)/src/gutenprintui/libgutenprintui.la
empty =
BASE_VERSION = \"@GUTENPRINT_BASE_VERSION@\"
pkgsysconfdir = $(cups_conf_serverroot)
@@ -713,8 +760,9 @@ cupsexec_filterdir = $(pkglibdir)/filter
@CUPS_PPDS_AT_TOP_LEVEL_TRUE@cups_modeldir = $(pkgdatadir)/model/
@CUPS_PPDS_AT_TOP_LEVEL_TRUE@DONT_UNINSTALL_PPDS = true
LOCAL_CPPFLAGS = $(GUTENPRINT_CFLAGS) $(CUPS_CFLAGS) -DBASE_VERSION=$(BASE_VERSION) -DSBINDIR=\"$(sbindir)/\"
-STP_NONLS_ENV = STP_MODULE_PATH=$(top_builddir)/src/main/.libs:$(top_builddir)/src/main STP_DATA_PATH=$(top_srcdir)/src/xml
-STP_ENV = $(STP_NONLS_ENV) STP_LOCALEDIR=$(top_srcdir)/src/cups/catalog
+PPD_DIR = ppd
+STP_NONLS_ENV = STP_MODULE_PATH=$(top_builddir)/src/main/.libs:$(top_builddir)/src/main STP_DATA_PATH=$(top_srcdir)/src/xml STP_LOCALEDIR=
+STP_ENV = $(STP_NONLS_ENV) STP_LOCALEDIR=$(top_builddir)/src/cups/$(PPD_DIR)catalog
@BUILD_GLOBALIZED_CUPS_PPDS_FALSE@@BUILD_TRANSLATED_CUPS_PPDS_TRUE@PPD = $(PPD_NLS_1)
@BUILD_GLOBALIZED_CUPS_PPDS_TRUE@@BUILD_TRANSLATED_CUPS_PPDS_TRUE@PPD = ppd-global
@BUILD_TRANSLATED_CUPS_PPDS_FALSE@PPD = ppd-nonls
@@ -722,8 +770,13 @@ STP_ENV = $(STP_NONLS_ENV) STP_LOCALEDIR=$(top_srcdir)/src/cups/catalog
@BUILD_TRANSLATED_CUPS_PPDS_TRUE@TRANSLATE_PPDS = -DCUPS_TRANSLATED_PPDS
@BUILD_SIMPLIFIED_CUPS_PPDS_TRUE@BUILD_SIMPLE_PPDS = -DGENERATE_SIMPLIFIED_PPDS
@BUILD_CUPS_TRUE@sbin_SCRIPTS = cups-genppdupdate
-@BUILD_CUPS_TRUE@TESTS = test-ppds test-rastertogutenprint
-@BUILD_CUPS_TRUE@noinst_SCRIPTS = test-rastertogutenprint
+@BUILD_CUPS_TRUE@AM_TESTS_ENVIRONMENT = $(STP_ENV)
+@BUILD_CUPS_TRUE@TESTS = test-ppds test-rastertogutenprint.check
+@BUILD_CUPS_TRUE@noinst_SCRIPTS = test-ppds \
+@BUILD_CUPS_TRUE@ test-rastertogutenprint \
+@BUILD_CUPS_TRUE@ test-rastertogutenprint.check \
+@BUILD_CUPS_TRUE@ min-pagesize
+
@BUILD_GENPPD_STATIC_TRUE@STATIC_LDOPTS = -static -export-dynamic
cups_calibrate_SOURCES = cups-calibrate.c
cups_calibrate_LDADD = -lm
@@ -731,18 +784,18 @@ commandtocanon_SOURCES = commandtocanon.c
commandtocanon_LDADD = $(CUPS_LIBS)
commandtoepson_SOURCES = commandtoepson.c
commandtoepson_LDADD = $(CUPS_LIBS)
-@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_SOURCES = backend_canonselphy.c backend_canonselphyneo.c backend_kodak1400.c backend_kodak6800.c backend_kodak605.c backend_shinkos2145.c backend_sonyupdr150.c backend_dnpds40.c backend_mitsu70x.c backend_citizencw01.c backend_mitsu9550.c backend_common.c backend_common.h backend_shinkos1245.c backend_shinkos6145.c backend_shinkos6245.c backend_mitsup95d.c
+@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_SOURCES = backend_canonselphy.c backend_canonselphyneo.c backend_kodak1400.c backend_kodak6800.c backend_kodak605.c backend_shinkos2145.c backend_sonyupdr150.c backend_dnpds40.c backend_mitsu70x.c backend_mitsu9550.c backend_common.c backend_common.h backend_shinkos1245.c backend_shinkos6145.c backend_shinkos6245.c backend_mitsup95d.c backend_magicard.c backend_mitsud90.c
@BUILD_LIBUSB_BACKENDS_TRUE@backend_gutenprint_LDADD = $(LIBUSB_LIBS) $(LIBUSB_BACKEND_LIBDEPS)
@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
+cups_genppd_@GUTENPRINT_RELEASE_VERSION@_SOURCES = cups-genppd.c genppd.c genppd.h i18n.c i18n.h
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GENPPD_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
cups_genppd_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = genppd.c i18n.c i18n.h
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DCUPS_DRIVER_INTERFACE -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
-gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = gutenprint.c genppd.c genppd.h i18n.c i18n.h
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS = -DALL_LINGUAS='"$(ALL_LINGUAS)"' $(BUILD_SIMPLE_PPDS) $(TRANSLATE_PPDS)
+gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GENPPD_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
gutenprint_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
-rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = rastertoprinter.c i18n.c i18n.h
+rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_SOURCES = rastertogutenprint.c i18n.c i18n.h
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_LDADD = $(CUPS_LIBS) $(GUTENPRINT_LIBS) @LIBICONV@
rastertogutenprint_@GUTENPRINT_RELEASE_VERSION@_LDFLAGS = $(STATIC_LDOPTS)
@BUILD_CUPS_TRUE@CUPS_PKG = calibrate.ppm
@@ -753,7 +806,7 @@ pkgsysconf_DATA = $(CUPS_CONF)
@USE_NLS_TRUE@PPD_NLS_1 = ppd-nls
@BUILD_LIBUSB_BACKENDS_TRUE@INSTALL_BLACKLIST = install-blacklist
CLEANFILES = ppd-stamp
-DISTCLEANFILES = cups-genppdupdate
+DISTCLEANFILES = cups-genppdupdate test-ppds
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = \
COPYING \
@@ -761,8 +814,7 @@ EXTRA_DIST = \
blacklist \
calibrate.ppm \
command.txt \
- command.types \
- test-ppds
+ command.types
all: all-am
@@ -780,16 +832,15 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cups/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/cups/Makefile
-.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
-$(top_srcdir)/scripts/global.mk:
+$(top_srcdir)/scripts/global.mk $(am__empty):
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -803,8 +854,14 @@ Info.plist: $(top_builddir)/config.status $(srcdir)/Info.plist.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
cups-genppdupdate: $(top_builddir)/config.status $(srcdir)/cups-genppdupdate.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+test-ppds: $(top_builddir)/config.status $(srcdir)/test-ppds.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+min-pagesize: $(top_builddir)/config.status $(srcdir)/min-pagesize.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
test-rastertogutenprint: $(top_builddir)/config.status $(srcdir)/test-rastertogutenprint.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+test-rastertogutenprint.check: $(top_builddir)/config.status $(srcdir)/test-rastertogutenprint.check.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
@@ -1120,45 +1177,54 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_canonselphy.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_canonselphyneo.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_citizencw01.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_common.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_dnpds40.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak1400.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak605.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak6800.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsu70x.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsup95d.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos1245.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos2145.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos6145.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos6245.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_sonyupdr150.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@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups-calibrate.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i18n.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rastertoprinter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_canonselphy.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_canonselphyneo.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_common.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_dnpds40.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak1400.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak605.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_kodak6800.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_magicard.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsu70x.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsud90.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_mitsup95d.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos1245.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos2145.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos6145.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_shinkos6245.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_gutenprint-backend_sonyupdr150.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandtocanon.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commandtoepson.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups-calibrate.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i18n.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rastertogutenprint.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1293,20 +1359,6 @@ backend_gutenprint-backend_mitsu70x.obj: backend_mitsu70x.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_mitsu70x.obj `if test -f 'backend_mitsu70x.c'; then $(CYGPATH_W) 'backend_mitsu70x.c'; else $(CYGPATH_W) '$(srcdir)/backend_mitsu70x.c'; fi`
-backend_gutenprint-backend_citizencw01.o: backend_citizencw01.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_citizencw01.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_citizencw01.Tpo -c -o backend_gutenprint-backend_citizencw01.o `test -f 'backend_citizencw01.c' || echo '$(srcdir)/'`backend_citizencw01.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_citizencw01.Tpo $(DEPDIR)/backend_gutenprint-backend_citizencw01.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_citizencw01.c' object='backend_gutenprint-backend_citizencw01.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-backend_citizencw01.o `test -f 'backend_citizencw01.c' || echo '$(srcdir)/'`backend_citizencw01.c
-
-backend_gutenprint-backend_citizencw01.obj: backend_citizencw01.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_citizencw01.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_citizencw01.Tpo -c -o backend_gutenprint-backend_citizencw01.obj `if test -f 'backend_citizencw01.c'; then $(CYGPATH_W) 'backend_citizencw01.c'; else $(CYGPATH_W) '$(srcdir)/backend_citizencw01.c'; fi`
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_citizencw01.Tpo $(DEPDIR)/backend_gutenprint-backend_citizencw01.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_citizencw01.c' object='backend_gutenprint-backend_citizencw01.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-backend_citizencw01.obj `if test -f 'backend_citizencw01.c'; then $(CYGPATH_W) 'backend_citizencw01.c'; else $(CYGPATH_W) '$(srcdir)/backend_citizencw01.c'; fi`
-
backend_gutenprint-backend_mitsu9550.o: backend_mitsu9550.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_mitsu9550.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_mitsu9550.Tpo -c -o backend_gutenprint-backend_mitsu9550.o `test -f 'backend_mitsu9550.c' || echo '$(srcdir)/'`backend_mitsu9550.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_mitsu9550.Tpo $(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po
@@ -1391,6 +1443,48 @@ backend_gutenprint-backend_mitsup95d.obj: backend_mitsup95d.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_mitsup95d.obj `if test -f 'backend_mitsup95d.c'; then $(CYGPATH_W) 'backend_mitsup95d.c'; else $(CYGPATH_W) '$(srcdir)/backend_mitsup95d.c'; fi`
+backend_gutenprint-backend_magicard.o: backend_magicard.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_magicard.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_magicard.Tpo -c -o backend_gutenprint-backend_magicard.o `test -f 'backend_magicard.c' || echo '$(srcdir)/'`backend_magicard.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_magicard.Tpo $(DEPDIR)/backend_gutenprint-backend_magicard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_magicard.c' object='backend_gutenprint-backend_magicard.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-backend_magicard.o `test -f 'backend_magicard.c' || echo '$(srcdir)/'`backend_magicard.c
+
+backend_gutenprint-backend_magicard.obj: backend_magicard.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_magicard.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_magicard.Tpo -c -o backend_gutenprint-backend_magicard.obj `if test -f 'backend_magicard.c'; then $(CYGPATH_W) 'backend_magicard.c'; else $(CYGPATH_W) '$(srcdir)/backend_magicard.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_magicard.Tpo $(DEPDIR)/backend_gutenprint-backend_magicard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_magicard.c' object='backend_gutenprint-backend_magicard.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-backend_magicard.obj `if test -f 'backend_magicard.c'; then $(CYGPATH_W) 'backend_magicard.c'; else $(CYGPATH_W) '$(srcdir)/backend_magicard.c'; fi`
+
+backend_gutenprint-backend_mitsud90.o: backend_mitsud90.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_mitsud90.o -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_mitsud90.Tpo -c -o backend_gutenprint-backend_mitsud90.o `test -f 'backend_mitsud90.c' || echo '$(srcdir)/'`backend_mitsud90.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_mitsud90.Tpo $(DEPDIR)/backend_gutenprint-backend_mitsud90.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_mitsud90.c' object='backend_gutenprint-backend_mitsud90.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-backend_mitsud90.o `test -f 'backend_mitsud90.c' || echo '$(srcdir)/'`backend_mitsud90.c
+
+backend_gutenprint-backend_mitsud90.obj: backend_mitsud90.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(backend_gutenprint_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backend_gutenprint-backend_mitsud90.obj -MD -MP -MF $(DEPDIR)/backend_gutenprint-backend_mitsud90.Tpo -c -o backend_gutenprint-backend_mitsud90.obj `if test -f 'backend_mitsud90.c'; then $(CYGPATH_W) 'backend_mitsud90.c'; else $(CYGPATH_W) '$(srcdir)/backend_mitsud90.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/backend_gutenprint-backend_mitsud90.Tpo $(DEPDIR)/backend_gutenprint-backend_mitsud90.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_mitsud90.c' object='backend_gutenprint-backend_mitsud90.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-backend_mitsud90.obj `if test -f 'backend_mitsud90.c'; then $(CYGPATH_W) 'backend_mitsud90.c'; else $(CYGPATH_W) '$(srcdir)/backend_mitsud90.c'; fi`
+
+cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.o: cups-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@-cups-genppd.o -MD -MP -MF $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Tpo -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.o `test -f 'cups-genppd.c' || echo '$(srcdir)/'`cups-genppd.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Tpo $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cups-genppd.c' object='cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.o `test -f 'cups-genppd.c' || echo '$(srcdir)/'`cups-genppd.c
+
+cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.obj: cups-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@-cups-genppd.obj -MD -MP -MF $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Tpo -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.obj `if test -f 'cups-genppd.c'; then $(CYGPATH_W) 'cups-genppd.c'; else $(CYGPATH_W) '$(srcdir)/cups-genppd.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Tpo $(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cups-genppd.c' object='cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.obj `if test -f 'cups-genppd.c'; then $(CYGPATH_W) 'cups-genppd.c'; else $(CYGPATH_W) '$(srcdir)/cups-genppd.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
@@ -1419,6 +1513,20 @@ cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.obj: i18n.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cups_genppd_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -c -o cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.obj `if test -f 'i18n.c'; then $(CYGPATH_W) 'i18n.c'; else $(CYGPATH_W) '$(srcdir)/i18n.c'; fi`
+gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.o: gutenprint.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -MT gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.o -MD -MP -MF $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Tpo -c -o gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.o `test -f 'gutenprint.c' || echo '$(srcdir)/'`gutenprint.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Tpo $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gutenprint.c' object='gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -c -o gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.o `test -f 'gutenprint.c' || echo '$(srcdir)/'`gutenprint.c
+
+gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.obj: gutenprint.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -MT gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.obj -MD -MP -MF $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Tpo -c -o gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.obj `if test -f 'gutenprint.c'; then $(CYGPATH_W) 'gutenprint.c'; else $(CYGPATH_W) '$(srcdir)/gutenprint.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Tpo $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gutenprint.c' object='gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.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) $(AM_CPPFLAGS) $(CPPFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -c -o gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.obj `if test -f 'gutenprint.c'; then $(CYGPATH_W) 'gutenprint.c'; else $(CYGPATH_W) '$(srcdir)/gutenprint.c'; fi`
+
gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.o: genppd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gutenprint_@GUTENPRINT_RELEASE_VERSION@_CFLAGS) $(CFLAGS) -MT gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.o -MD -MP -MF $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Tpo -c -o gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.o `test -f 'genppd.c' || echo '$(srcdir)/'`genppd.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Tpo $(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
@@ -1577,7 +1685,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
if test -n "$$am__remaking_logs"; then \
echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
"recursion detected" >&2; \
- else \
+ elif test -n "$$redo_logs"; then \
am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
fi; \
if $(am__make_dryrun); then :; else \
@@ -1667,7 +1775,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
fi; \
$$success || exit 1
-check-TESTS:
+check-TESTS:
@list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
@@ -1695,9 +1803,9 @@ test-ppds.log: test-ppds
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
-test-rastertogutenprint.log: test-rastertogutenprint
- @p='test-rastertogutenprint'; \
- b='test-rastertogutenprint'; \
+test-rastertogutenprint.check.log: test-rastertogutenprint.check
+ @p='test-rastertogutenprint.check'; \
+ b='test-rastertogutenprint.check'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
@@ -1717,7 +1825,10 @@ test-rastertogutenprint.log: test-rastertogutenprint
@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
-distdir: $(DISTFILES)
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
@@ -1804,7 +1915,34 @@ clean-am: clean-binPROGRAMS clean-cupsexec_backendPROGRAMS \
mostlyclean-am
distclean: distclean-am
- -rm -rf ./$(DEPDIR)
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_canonselphy.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_canonselphyneo.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_common.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_dnpds40.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak1400.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak605.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak6800.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_magicard.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsu70x.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsud90.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsup95d.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos1245.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos2145.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos6145.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos6245.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_sonyupdr150.Po
+ -rm -f ./$(DEPDIR)/commandtocanon.Po
+ -rm -f ./$(DEPDIR)/commandtoepson.Po
+ -rm -f ./$(DEPDIR)/cups-calibrate.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.Po
+ -rm -f ./$(DEPDIR)/i18n.Po
+ -rm -f ./$(DEPDIR)/rastertogutenprint.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -1856,7 +1994,34 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -rf ./$(DEPDIR)
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_canonselphy.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_canonselphyneo.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_common.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_dnpds40.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak1400.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak605.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_kodak6800.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_magicard.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsu70x.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsu9550.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsud90.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_mitsup95d.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos1245.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos2145.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos6145.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_shinkos6245.Po
+ -rm -f ./$(DEPDIR)/backend_gutenprint-backend_sonyupdr150.Po
+ -rm -f ./$(DEPDIR)/commandtocanon.Po
+ -rm -f ./$(DEPDIR)/commandtoepson.Po
+ -rm -f ./$(DEPDIR)/cups-calibrate.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-cups-genppd.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
+ -rm -f ./$(DEPDIR)/cups_genppd_@GUTENPRINT_RELEASE_VERSION@-i18n.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-genppd.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-gutenprint.Po
+ -rm -f ./$(DEPDIR)/gutenprint_@GUTENPRINT_RELEASE_VERSION@-i18n.Po
+ -rm -f ./$(DEPDIR)/i18n.Po
+ -rm -f ./$(DEPDIR)/rastertogutenprint.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -1882,8 +2047,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-cupsexec_backendPROGRAMS \
.MAKE: check-am install-am install-data-am install-exec-am \
install-strip
-.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-TESTS \
- check-am clean clean-binPROGRAMS \
+.PHONY: CTAGS GTAGS TAGS all all-am all-local am--depfiles check \
+ check-TESTS check-am clean clean-binPROGRAMS \
clean-cupsexec_backendPROGRAMS clean-cupsexec_driverPROGRAMS \
clean-cupsexec_filterPROGRAMS clean-generic clean-libtool \
clean-local clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
@@ -1909,6 +2074,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-cupsexec_backendPROGRAMS \
uninstall-pkgdataDATA uninstall-pkgsysconfDATA \
uninstall-sbinPROGRAMS uninstall-sbinSCRIPTS
+.PRECIOUS: Makefile
+
@SET_MAKE@
@@ -1918,10 +2085,6 @@ $(top_builddir)/src/main/libgutenprint.la:
cd $(top_builddir)/src/main; \
$(MAKE)
-$(top_builddir)/src/gutenprintui/libgutenprintui.la:
- cd $(top_builddir)/src/gutenprintui; \
- $(MAKE)
-
$(top_builddir)/src/gutenprintui2/libgutenprintui2.la:
cd $(top_builddir)/src/gutenprintui2; \
$(MAKE)
@@ -1929,17 +2092,19 @@ $(top_builddir)/src/gutenprintui2/libgutenprintui2.la:
@BUILD_CUPS_TRUE@@BUILD_LIBUSB_BACKENDS_TRUE@install-exec-hook:
@BUILD_CUPS_TRUE@@BUILD_LIBUSB_BACKENDS_TRUE@ chmod 700 $(DESTDIR)$(pkglibdir)/backend/backend_gutenprint
@BUILD_CUPS_TRUE@@BUILD_LIBUSB_BACKENDS_TRUE@ mv $(DESTDIR)$(pkglibdir)/backend/backend_gutenprint "$(DESTDIR)$(pkglibdir)/backend/gutenprint$(GUTENPRINT_MAJOR_VERSION)$(GUTENPRINT_MINOR_VERSION)+usb"
+@BUILD_CUPS_TRUE@test-rastertogutenprint: min-pagesize
+@BUILD_CUPS_TRUE@test-rastertogutenprint.check: test-rastertogutenprint
@BUILD_LIBUSB_BACKENDS_TRUE@install-blacklist:
-@BUILD_LIBUSB_BACKENDS_TRUE@ $(mkdir_p) $(DESTDIR)$(cupsdata_blacklistdir)
+@BUILD_LIBUSB_BACKENDS_TRUE@ $(MKDIR_P) $(DESTDIR)$(cupsdata_blacklistdir)
@BUILD_LIBUSB_BACKENDS_TRUE@ $(INSTALL_DATA) $(srcdir)/blacklist $(DESTDIR)$(cupsdata_blacklistdir)/net.sf.gimp-print.usb-quirks
install-data-local: $(INSTALL_DATA_LOCAL_DEPS) $(INSTALL_BLACKLIST)
if test -n "$(CUPS_PKG)" -a -n "$(INSTALL_DATA_LOCAL_DEPS)" ; then \
- $(mkdir_p) $(DESTDIR)$(cups_modeldir); \
+ $(MKDIR_P) $(DESTDIR)$(cups_modeldir); \
cd ppd ; \
for language in * ; do \
cd ..; \
- $(mkdir_p) $(DESTDIR)$(cups_modeldir)/$$language; \
+ $(MKDIR_P) $(DESTDIR)$(cups_modeldir)/$$language; \
cd ppd/$$language; \
for ppdfile in * ; do \
(cd ../..; $(INSTALL_DATA) ppd/$$language/$$ppdfile $(DESTDIR)$(cups_modeldir)/$$language) ; \
@@ -1947,10 +2112,10 @@ install-data-local: $(INSTALL_DATA_LOCAL_DEPS) $(INSTALL_BLACKLIST)
cd ..; \
done \
fi
- $(mkdir_p) "$(DESTDIR)$(localedir)"
+ $(MKDIR_P) "$(DESTDIR)$(localedir)"
for file in $(srcdir)/../../po/*.po; do \
lang=`basename $$file .po`; \
- $(mkdir_p) "$(DESTDIR)$(localedir)/$$lang"; \
+ $(MKDIR_P) "$(DESTDIR)$(localedir)/$$lang"; \
$(INSTALL_DATA) $$file "$(DESTDIR)$(localedir)/$$lang/gutenprint_$$lang.po"; \
done
@@ -1979,13 +2144,15 @@ install-data-hook:
-rmdir $(DESTDIR)$(cupsexec_backenddir)
-rmdir $(DESTDIR)$(cupsdata_blacklistdir)
-rmdir $(DESTDIR)$(bindir)
+ -rmdir $(DESTDIR)$(sbindir)
-rmdir $(DESTDIR)$(pkglibdir)
-rmdir $(DESTDIR)$(pkgsysconfdir)
-rmdir `dirname $(DESTDIR)$(pkgdatadir)`
-rmdir `dirname $(DESTDIR)$(pkglibdir)`
-rmdir `dirname $(DESTDIR)$(pkgsysconfdir)`
-.PHONY: ppd ppd-stamp-pre ppd-stamp-nonls ppd-stamp-nls ppd-stamp-phony ppd-catalog-clean ppd-clean $(INSTALL_BLACKLIST)
+.PHONY: ppd ppd-stamp-pre ppd-stamp-nonls ppd-stamp-nls ppd-stamp-phony \
+ ppd-catalog-clean ppd-clean $(INSTALL_BLACKLIST)
all-local: $(INSTALL_DATA_LOCAL_DEPS)
@@ -1999,76 +2166,111 @@ ppd-stamp: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(top_srcdir)/src/xml/xml-st
ppd-stamp-phony: $(PPD)
ppd-catalog-clean:
- $(RM) -rf catalog
+ $(RM) -rf $(PPD_DIR)catalog
ppd-clean:
- $(RM) -rf ppd
+ $(RM) -rf $(PPD_DIR)
ppd-stamp-pre: ppd-catalog-clean ppd-clean
ppd-catalog: ppd-catalog-clean
- $(mkdir_p) catalog
- for file in $(srcdir)/../../po/*.po; do \
+ $(MKDIR_P) catalog
+ for file in $(top_srcdir)/po/*.po; do \
lang=`basename $$file .po`; \
- $(mkdir_p) "catalog/$$lang"; \
- $(INSTALL_DATA) $$file "catalog/$$lang/gutenprint_$$lang.po"; \
+ $(MKDIR_P) "$(PPD_DIR)catalog/$$lang"; \
+ $(INSTALL_DATA) $$file "$(PPD_DIR)catalog/$$lang/gutenprint_$$lang.po"; \
done
ppd-nonls: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- $(mkdir_p) ppd/C
+ @echo "Non-localized PPDs:"
+ $(MKDIR_P) $(PPD_DIR)/C
$(MAKE) ppd-catalog-clean
- LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ $(EXTRA_GENPPD_OPTS) -l C -p ppd/C
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C @WHICH_PPDS@
ppd-nonls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- $(mkdir_p) ppd/C
+ @echo "Non-localized PPDs (all):"
+ $(MKDIR_P) $(PPD_DIR)/C
+ $(MAKE) ppd-catalog-clean
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C -a
+
+ppd-nonls-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Non-localized PPDs (simplified):"
+ $(MKDIR_P) $(PPD_DIR)/C
$(MAKE) ppd-catalog-clean
- LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ $(EXTRA_GENPPD_OPTS) -l C -p ppd/C -a
+ LC_ALL= LANG= LANGUAGE= $(STP_NONLS_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l C -p $(PPD_DIR)/C -s
ppd-global: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
@echo "Global PPDs:"
- $(mkdir_p) ppd/Global
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global @WHICH_PPDS@
$(MAKE) ppd-catalog-clean
ppd-global-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- @echo "Global PPDs:"
- $(mkdir_p) ppd/Global
+ @echo "Global PPDs (all):"
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -a
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -a
+ $(MAKE) ppd-catalog-clean
+
+ppd-global-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Global PPDs (simplified):"
+ $(MKDIR_P) $(PPD_DIR)/Global
+ $(MAKE) ppd-catalog
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -s
$(MAKE) ppd-catalog-clean
ppd-global-ln: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
@echo "Global PPDs (localized numbers for testing):"
- $(mkdir_p) ppd/Global
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -N
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N @WHICH_PPDS@
$(MAKE) ppd-catalog-clean
ppd-global-ln-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
- @echo "Global PPDs (localized numbers for testing):"
- $(mkdir_p) ppd/Global
+ @echo "Global PPDs (all, localized numbers for testing):"
+ $(MKDIR_P) $(PPD_DIR)/Global
+ $(MAKE) ppd-catalog
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N -a
+ $(MAKE) ppd-catalog-clean
+
+ppd-global-ln-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@
+ @echo "Global PPDs (all, localized numbers for testing):"
+ $(MKDIR_P) $(PPD_DIR)/Global
$(MAKE) ppd-catalog
- LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -p ppd/Global -N -a
+ LC_ALL= LANG= LANGUAGE= $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -p $(PPD_DIR)/Global -N -s
$(MAKE) ppd-catalog-clean
ppd-nls: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ ppd-nonls
- $(mkdir_p) ppd
+ @echo "Localized PPD files:"
+ $(MKDIR_P) ppd
+ $(MAKE) ppd-catalog
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
+ echo -n "$$language: " ; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) -l $$language -p $(PPD_DIR)/$$language; \
+ done
+ $(MAKE) ppd-catalog-clean
+
+ppd-nls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ ppd-nonls
+ @echo "Localized PPD files (all):"
+ $(MKDIR_P) ppd
$(MAKE) ppd-catalog
- for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ -L` ; do \
- $(mkdir_p) ppd/$$language ; \
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
echo -n "$$language: " ; \
- LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p ppd/$$language; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p $(PPD_DIR)/$$language -a; \
done
$(MAKE) ppd-catalog-clean
-ppd-nls-a: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ ppd-nonls
- $(mkdir_p) ppd
+ppd-nls-s: cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ ppd-nonls
+ @echo "Localized PPD files (simplified):"
+ $(MKDIR_P) ppd
$(MAKE) ppd-catalog
- for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ -L` ; do \
- $(mkdir_p) ppd/$$language ; \
+ for language in `$(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ @WHICH_PPDS@ -L` ; do \
+ $(MKDIR_P) $(PPD_DIR)/$$language ; \
echo -n "$$language: " ; \
- LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p ppd/$$language -a; \
+ LC_ALL=$$language LANG=$$language LANGUAGE=$$language $(STP_ENV) ./cups-genppd.@GUTENPRINT_RELEASE_VERSION@ $(EXTRA_GENPPD_OPTS) @WHICH_PPDS@ -l $$language -p $(PPD_DIR)/$$language -s; \
done
$(MAKE) ppd-catalog-clean
diff --git a/src/cups/backend_canonselphy.c b/src/cups/backend_canonselphy.c
index 8b016df..42b3f45 100644
--- a/src/cups/backend_canonselphy.c
+++ b/src/cups/backend_canonselphy.c
@@ -1,7 +1,7 @@
/*
* Canon SELPHY ES/CP series CUPS backend -- libusb-1.0 version
*
- * (c) 2007-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2007-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -79,50 +80,55 @@
struct printer_data {
int type; /* P_??? */
char *model; /* eg "SELPHY ES1" */
- int init_length;
- int foot_length;
+ uint16_t init_length;
+ uint16_t foot_length;
int16_t init_readback[READBACK_LEN];
int16_t ready_y_readback[READBACK_LEN];
int16_t ready_m_readback[READBACK_LEN];
int16_t ready_c_readback[READBACK_LEN];
int16_t done_c_readback[READBACK_LEN];
uint8_t clear_error[READBACK_LEN];
- int clear_error_len;
+ uint8_t clear_error_len;
int16_t paper_codes[256];
- int16_t pgcode_offset; /* Offset into printjob for paper type */
- int16_t paper_code_offset; /* Offset in readback for paper type */
- int (*error_detect)(uint8_t *rdbuf);
- char *(*pgcode_names)(uint8_t pgcode);
+ int8_t pgcode_offset; /* Offset into printjob for paper type */
+ int8_t paper_code_offset; /* Offset in readback for paper type */
+ int8_t paper_code_offset2; /* Offset in readback for paper type (2nd) */
+ uint8_t (*error_detect)(uint8_t *rdbuf);
+ char *(*pgcode_names)(uint8_t *rdbuf, struct printer_data *printer);
};
-static char *generic_pgcode_names(uint8_t pgcode)
+static char *generic_pgcode_names(uint8_t *rdbuf, struct printer_data *printer)
{
+ uint8_t pgcode = 0, pgcode2 = 0;
+
+ if (printer->paper_code_offset != -1)
+ pgcode = rdbuf[printer->paper_code_offset];
+ if (printer->paper_code_offset2 != -1)
+ pgcode2 = rdbuf[printer->paper_code_offset2];
+
switch(pgcode & 0xf) {
case 0x01: return "P";
case 0x02: return "L";
- case 0x03: return "C";
+ case 0x03: return pgcode2 ? "Cl" : "C";
case 0x04: return "W";
case 0x0f: return "None";
default: return "Unknown";
}
}
-static int es1_error_detect(uint8_t *rdbuf)
+static uint8_t es1_error_detect(uint8_t *rdbuf)
{
if (rdbuf[1] == 0x01) {
- if (rdbuf[9] == 0x00) {
+ if (rdbuf[9] == 0x00)
ERROR("Cover open!\n");
- } else {
+ else
ERROR("Unknown error %02x\n", rdbuf[9]);
- }
return 1;
} else if (rdbuf[4] == 0x01 && rdbuf[5] == 0xff &&
rdbuf[6] == 0xff && rdbuf[7] == 0xff) {
- ATTR("marker-levels=%d\n", 0);
ERROR("No media loaded!\n");
return 1;
} else if (rdbuf[0] == 0x0f) {
- ATTR("marker-levels=%d\n", 0);
ERROR("Out of media!\n");
return 1;
}
@@ -130,7 +136,7 @@ static int es1_error_detect(uint8_t *rdbuf)
return 0;
}
-static int es2_error_detect(uint8_t *rdbuf)
+static uint8_t es2_error_detect(uint8_t *rdbuf)
{
if (rdbuf[0] == 0x16 &&
rdbuf[1] == 0x01) {
@@ -142,13 +148,11 @@ static int es2_error_detect(uint8_t *rdbuf)
rdbuf[4] == 0x05 &&
rdbuf[5] == 0x05 &&
rdbuf[6] == 0x02) {
- ATTR("marker-levels=%d\n", 0);
ERROR("No media loaded!\n");
return 1;
}
if (rdbuf[0] == 0x14) {
- ATTR("marker-levels=%d\n", 0);
ERROR("Out of media!\n");
return 1;
}
@@ -156,22 +160,19 @@ static int es2_error_detect(uint8_t *rdbuf)
return 0;
}
-static int es3_error_detect(uint8_t *rdbuf)
+static uint8_t es3_error_detect(uint8_t *rdbuf)
{
if (rdbuf[8] == 0x01) {
- if (rdbuf[10] == 0x0f) {
+ if (rdbuf[10] == 0x0f)
ERROR("Communications Error\n");
- } else if (rdbuf[10] == 0x01) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[10] == 0x01)
ERROR("No media loaded!\n");
- } else {
+ else
ERROR("Unknown error - %02x + %02x\n",
rdbuf[8], rdbuf[10]);
- }
return 1;
} else if (rdbuf[8] == 0x03 &&
rdbuf[10] == 0x02) {
- ATTR("marker-levels=%d\n", 0);
ERROR("No media loaded!\n");
return 1;
} else if (rdbuf[8] == 0x08 &&
@@ -193,7 +194,7 @@ static int es3_error_detect(uint8_t *rdbuf)
return 0;
}
-static int es40_error_detect(uint8_t *rdbuf)
+static uint8_t es40_error_detect(uint8_t *rdbuf)
{
/* ES40 */
if (!rdbuf[3])
@@ -201,17 +202,15 @@ static int es40_error_detect(uint8_t *rdbuf)
if (rdbuf[3] == 0x01)
ERROR("Generic communication error\n");
- else if (rdbuf[3] == 0x32) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[3] == 0x32)
ERROR("Cover open or media empty!\n");
- } else
+ else
ERROR("Unknown error - %02x\n", rdbuf[3]);
-
return 1;
}
-static int cp790_error_detect(uint8_t *rdbuf)
+static uint8_t cp790_error_detect(uint8_t *rdbuf)
{
/* CP790 */
if (rdbuf[5] == 0xff) {
@@ -221,18 +220,15 @@ static int cp790_error_detect(uint8_t *rdbuf)
ERROR("No paper tray loaded!\n");
return 1;
} else if (rdbuf[3]) {
- if ((rdbuf[3] & 0xf) == 0x02) { // 0x12 0x22
- ATTR("marker-levels=%d\n", 0);
+ if ((rdbuf[3] & 0xf) == 0x02) // 0x12 0x22
ERROR("No paper tray loaded!\n");
- } else if ((rdbuf[3] & 0xf) == 0x03) { // 0x13 0x23
- ATTR("marker-levels=%d\n", 0);
+ else if ((rdbuf[3] & 0xf) == 0x03) // 0x13 0x23
ERROR("Empty paper tray or feed error!\n");
- } else if (rdbuf[3] == 0x11)
+ else if (rdbuf[3] == 0x11)
ERROR("Paper feed error!\n");
- else if (rdbuf[3] == 0x21) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[3] == 0x21)
ERROR("Ribbon depleted!\n");
- } else
+ else
ERROR("Unknown error - %02x\n", rdbuf[3]);
return 1;
}
@@ -240,46 +236,42 @@ static int cp790_error_detect(uint8_t *rdbuf)
return 0;
}
-static char *cp10_pgcode_names(uint8_t pgcode)
+static char *cp10_pgcode_names(uint8_t *rdbuf, struct printer_data *printer)
{
- switch (pgcode) {
- default: return "C";
- };
+ UNUSED(rdbuf);
+ UNUSED(printer);
+
+ return "C"; /* Printer only supports one media type */
}
-static int cp10_error_detect(uint8_t *rdbuf)
+static uint8_t cp10_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[2])
return 0;
- if (rdbuf[2] == 0x80) {
- ATTR("marker-levels=%d\n", 0);
+ if (rdbuf[2] == 0x80)
ERROR("No ribbon loaded\n");
- } else if (rdbuf[2] == 0x08) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[2] == 0x08)
ERROR("Ribbon depleted!\n");
- } else if (rdbuf[2] == 0x01) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[2] == 0x01)
ERROR("No paper loaded!\n");
- } else
+ else
ERROR("Unknown error - %02x\n", rdbuf[2]);
return 1;
}
-static int cpxxx_error_detect(uint8_t *rdbuf)
+static uint8_t cpxxx_error_detect(uint8_t *rdbuf)
{
if (!rdbuf[2])
return 0;
- if (rdbuf[2] == 0x01) {
- ATTR("marker-levels=%d\n", 0);
+ if (rdbuf[2] == 0x01)
ERROR("Paper feed problem!\n");
- } else if (rdbuf[2] == 0x04)
+ else if (rdbuf[2] == 0x04)
ERROR("Ribbon problem!\n");
- else if (rdbuf[2] == 0x08) {
- ATTR("marker-levels=%d\n", 0);
+ else if (rdbuf[2] == 0x08)
ERROR("Ribbon depleted!\n");
- } else
+ else
ERROR("Unknown error - %02x\n", rdbuf[2]);
return 1;
}
@@ -298,6 +290,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 3,
.paper_code_offset = 6,
+ .paper_code_offset2 = -1,
.error_detect = es1_error_detect,
.pgcode_names = generic_pgcode_names,
},
@@ -314,6 +307,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 2,
.paper_code_offset = 4,
+ .paper_code_offset2 = 6,
.error_detect = es2_error_detect,
.pgcode_names = generic_pgcode_names,
},
@@ -330,6 +324,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 2,
.paper_code_offset = -1,
+ .paper_code_offset2 = -1,
.error_detect = es3_error_detect,
.pgcode_names = NULL,
},
@@ -346,6 +341,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 2,
.paper_code_offset = 11,
+ .paper_code_offset2 = -1,
.error_detect = es40_error_detect,
.pgcode_names = generic_pgcode_names,
},
@@ -362,6 +358,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 2,
.paper_code_offset = -1, /* Uses a different technique */
+ .paper_code_offset2 = -1,
.error_detect = cp790_error_detect,
.pgcode_names = generic_pgcode_names,
},
@@ -378,6 +375,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 3,
.paper_code_offset = 6,
+ .paper_code_offset2 = -1,
.error_detect = cpxxx_error_detect,
.pgcode_names = generic_pgcode_names,
},
@@ -394,6 +392,7 @@ static struct printer_data selphy_printers[] = {
.clear_error_len = 12,
.pgcode_offset = 2,
.paper_code_offset = -1,
+ .paper_code_offset2 = -1,
.error_detect = cp10_error_detect,
.pgcode_names = cp10_pgcode_names,
},
@@ -536,17 +535,9 @@ done:
}
/* Private data structure */
-struct canonselphy_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
- struct printer_data *printer;
-
- uint8_t bw_mode;
-
+struct canonselphy_printjob {
int16_t paper_code;
+ uint8_t bw_mode;
uint32_t plane_len;
@@ -556,11 +547,44 @@ struct canonselphy_ctx {
uint8_t *plane_c;
uint8_t *footer;
- uint8_t *buffer;
+ int copies;
+};
+
+struct canonselphy_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ struct printer_data *printer;
+ struct marker marker;
uint8_t cp900;
};
+static int canonselphy_get_status(struct canonselphy_ctx *ctx)
+{
+ uint8_t rdbuf[READBACK_LEN];
+ int ret, num;
+
+ /* Read in the printer status, twice. */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) rdbuf, READBACK_LEN, &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Media type: %s\n", ctx->printer->pgcode_names? ctx->printer->pgcode_names(rdbuf, ctx->printer) : "Unknown");
+ ctx->printer->error_detect(rdbuf);
+
+ return CUPS_BACKEND_OK;
+}
+
static int canonselphy_send_reset(struct canonselphy_ctx *ctx)
{
uint8_t rstcmd[12] = { 0x40, 0x10, 0x00, 0x00,
@@ -587,39 +611,84 @@ static void *canonselphy_init(void)
/* Static initialization */
setup_paper_codes();
- ctx->buffer = malloc(MAX_HEADER);
- if (!ctx->buffer) {
- ERROR("Memory Allocation Failure!\n");
- free(ctx);
- ctx = NULL;
- }
-
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)
+static int canonselphy_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct canonselphy_ctx *ctx = vctx;
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
+ int i, num;
+ uint8_t rdbuf[READBACK_LEN];
UNUSED(jobid);
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ ctx->type = type;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
+ if (ctx->type == P_CP900) {
+ ctx->type = P_CP_XXX;
+ ctx->cp900 = 1;
+ }
+ for (i = 0 ; selphy_printers[i].type != -1; i++) {
+ if (selphy_printers[i].type == ctx->type) {
+ ctx->printer = &selphy_printers[i];
+ }
+ }
+ if (!ctx->printer) {
+ ERROR("Error looking up printer type!\n");
+ return CUPS_BACKEND_FAILED;
+ }
- ctx->type = lookup_printer_type(&canonselphy_backend,
- desc.idVendor, desc.idProduct);
+ /* Fill out marker structure */
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.levelmax = -1; /* Unknown */
- if (desc.idProduct == USB_PID_CANON_CP900)
- ctx->cp900 = 1;
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Read printer status. Twice. */
+ i = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (i < 0)
+ return CUPS_BACKEND_FAILED;
+
+ i = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (i < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->printer->error_detect(rdbuf))
+ ctx->marker.levelnow = 0; /* Out of media */
+ else
+ ctx->marker.levelnow = -3; /* Unknown but OK */
+ ctx->marker.name = ctx->printer->pgcode_names? ctx->printer->pgcode_names(rdbuf, ctx->printer) : "Unknown";
+ } else {
+ // XXX handle MEDIA_CODE at some point.
+ // we don't do any error checking here.
+ ctx->marker.name = "Unknown";
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void canonselphy_cleanup_job(const void *vjob) {
+ const struct canonselphy_printjob *job = vjob;
+
+ if (job->header)
+ free(job->header);
+ if (job->plane_y)
+ free(job->plane_y);
+ if (job->plane_m)
+ free(job->plane_m);
+ if (job->plane_c)
+ free(job->plane_c);
+ if (job->footer)
+ free(job->footer);
+
+ free((void*)job);
}
static void canonselphy_teardown(void *vctx) {
@@ -628,64 +697,63 @@ static void canonselphy_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->header)
- free(ctx->header);
- if (ctx->plane_y)
- free(ctx->plane_y);
- if (ctx->plane_m)
- free(ctx->plane_m);
- if (ctx->plane_c)
- free(ctx->plane_c);
- if (ctx->footer)
- free(ctx->footer);
-
- if (ctx->buffer)
- free(ctx->buffer);
-
free(ctx);
}
-static int canonselphy_read_parse(void *vctx, int data_fd)
+static int canonselphy_read_parse(void *vctx, const void **vjob, int data_fd, int copies)
{
struct canonselphy_ctx *ctx = vctx;
int i, remain;
int printer_type;
int offset = 0;
+ uint8_t rdbuf[MAX_HEADER];
+
+ struct canonselphy_printjob *job = NULL;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
+
/* The CP900 job *may* have a 4-byte null footer after the
job contents. Ignore it if it comes through here.. */
- i = read(data_fd, ctx->buffer, 4);
+ i = read(data_fd, rdbuf, 4);
if (i != 4) {
if (i == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d)\n", i, 4);
perror("ERROR: Read failed");
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
/* if it's not the null header.. don't ignore! */
- if (ctx->buffer[0] != 0 ||
- ctx->buffer[1] != 0 ||
- ctx->buffer[2] != 0 ||
- ctx->buffer[3] != 0) {
+ if (rdbuf[0] != 0 ||
+ rdbuf[1] != 0 ||
+ rdbuf[2] != 0 ||
+ rdbuf[3] != 0) {
offset = 4;
}
/* Read the rest of the header.. */
- i = read(data_fd, ctx->buffer + offset, MAX_HEADER - offset);
+ i = read(data_fd, rdbuf + offset, MAX_HEADER - offset);
if (i != MAX_HEADER - offset) {
if (i == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d)\n",
i, MAX_HEADER - offset);
perror("ERROR: Read failed");
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
/* Figure out printer this file is intended for */
- printer_type = parse_printjob(ctx->buffer, &ctx->bw_mode, &ctx->plane_len);
+ printer_type = parse_printjob(rdbuf, &job->bw_mode, &job->plane_len);
/* Special cases for some models */
if (printer_type == P_ES40_CP790) {
if (ctx->type == P_CP790)
@@ -694,97 +762,71 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
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];
- break;
- }
- }
- if (!ctx->printer) {
- ERROR("Error mapping printjob to printer type!\n");
- return CUPS_BACKEND_FAILED;
- }
-
- INFO("%sFile intended for a '%s' printer\n", ctx->bw_mode? "B/W " : "", ctx->printer->model);
-
- if (ctx->printer->type != ctx->type) {
+ if (printer_type != ctx->type) {
ERROR("Printer/Job mismatch (%d/%d)\n", ctx->type, ctx->printer->type);
+ free(job);
return CUPS_BACKEND_CANCEL;
}
+ INFO("%sFile intended for a '%s' printer\n", job->bw_mode? "B/W " : "", ctx->printer->model);
+
/* Paper code setup */
if (ctx->printer->pgcode_offset != -1)
- ctx->paper_code = ctx->printer->paper_codes[ctx->buffer[ctx->printer->pgcode_offset]];
+ job->paper_code = ctx->printer->paper_codes[rdbuf[ctx->printer->pgcode_offset]];
else
- ctx->paper_code = -1;
+ job->paper_code = -1;
/* Add in plane header length! */
- ctx->plane_len += 12;
-
- /* Now prep for the job */
- if (ctx->header) {
- free(ctx->header);
- ctx->header = NULL;
- }
- if (ctx->plane_y) {
- free(ctx->plane_y);
- ctx->plane_y = NULL;
- }
- if (ctx->plane_m) {
- free(ctx->plane_m);
- ctx->plane_m = NULL;
- }
- if (ctx->plane_c) {
- free(ctx->plane_c);
- ctx->plane_c = NULL;
- }
- if (ctx->footer) {
- free(ctx->footer);
- ctx->footer = NULL;
- }
+ job->plane_len += 12;
/* Set up buffers */
- ctx->plane_y = malloc(ctx->plane_len);
- ctx->plane_m = malloc(ctx->plane_len);
- ctx->plane_c = malloc(ctx->plane_len);
- ctx->header = malloc(ctx->printer->init_length);
- ctx->footer = malloc(ctx->printer->foot_length);
- if (!ctx->plane_y || !ctx->plane_m || !ctx->plane_c || !ctx->header ||
- (ctx->printer->foot_length && !ctx->footer)) {
+ job->plane_y = malloc(job->plane_len);
+ job->plane_m = malloc(job->plane_len);
+ job->plane_c = malloc(job->plane_len);
+ job->header = malloc(ctx->printer->init_length);
+ job->footer = malloc(ctx->printer->foot_length);
+ if (!job->plane_y || !job->plane_m || !job->plane_c || !job->header ||
+ (ctx->printer->foot_length && !job->footer)) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ canonselphy_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
/* Move over chunks already read in */
- memcpy(ctx->header, ctx->buffer, ctx->printer->init_length);
- memcpy(ctx->plane_y, ctx->buffer+ctx->printer->init_length,
+ memcpy(job->header, rdbuf, ctx->printer->init_length);
+ memcpy(job->plane_y, rdbuf+ctx->printer->init_length,
MAX_HEADER-ctx->printer->init_length);
/* Read in YELLOW plane */
- remain = ctx->plane_len - (MAX_HEADER-ctx->printer->init_length);
+ remain = job->plane_len - (MAX_HEADER-ctx->printer->init_length);
while (remain > 0) {
- i = read(data_fd, ctx->plane_y + (ctx->plane_len - remain), remain);
- if (i < 0)
+ i = read(data_fd, job->plane_y + (job->plane_len - remain), remain);
+ if (i < 0) {
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
/* Read in MAGENTA plane */
- remain = ctx->plane_len;
+ remain = job->plane_len;
while (remain > 0) {
- i = read(data_fd, ctx->plane_m + (ctx->plane_len - remain), remain);
- if (i < 0)
+ i = read(data_fd, job->plane_m + (job->plane_len - remain), remain);
+ if (i < 0) {
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
/* Read in CYAN plane */
- remain = ctx->plane_len;
+ remain = job->plane_len;
while (remain > 0) {
- i = read(data_fd, ctx->plane_c + (ctx->plane_len - remain), remain);
- if (i < 0)
+ i = read(data_fd, job->plane_c + (job->plane_len - remain), remain);
+ if (i < 0) {
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
@@ -792,22 +834,36 @@ static int canonselphy_read_parse(void *vctx, int data_fd)
if (ctx->printer->foot_length) {
remain = ctx->printer->foot_length;
while (remain > 0) {
- i = read(data_fd, ctx->footer + (ctx->printer->foot_length - remain), remain);
- if (i < 0)
+ i = read(data_fd, job->footer + (ctx->printer->foot_length - remain), remain);
+ if (i < 0) {
+ canonselphy_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
}
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int canonselphy_main_loop(void *vctx, int copies) {
+static int canonselphy_main_loop(void *vctx, const void *vjob) {
struct canonselphy_ctx *ctx = vctx;
uint8_t rdbuf[READBACK_LEN], rdbuf2[READBACK_LEN];
int last_state = -1, state = S_IDLE;
int ret, num;
+ int copies;
+
+ const struct canonselphy_printjob *job = vjob;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
/* Read in the printer status to clear last state */
ret = read_data(ctx->dev, ctx->endp_up,
@@ -815,14 +871,6 @@ static int canonselphy_main_loop(void *vctx, int copies) {
if (ret < 0)
return CUPS_BACKEND_FAILED;
-
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", ctx->printer->pgcode_names? ctx->printer->pgcode_names(rdbuf[ctx->printer->paper_code_offset]) : "Unknown");
- ATTR("marker-types=ribbonWax\n");
- ATTR("marker-levels=%d\n", -3); /* ie Unknown but OK */
-
top:
if (state != last_state) {
@@ -843,6 +891,7 @@ top:
/* Error detection */
if (ctx->printer->error_detect(rdbuf)) {
+ dump_markers(&ctx->marker, 1, 0);
if (ctx->printer->clear_error_len)
/* Try to clear error state */
if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->printer->clear_error, ctx->printer->clear_error_len)))
@@ -866,10 +915,10 @@ top:
break;
/* Make sure paper/ribbon is correct */
- if (ctx->paper_code != -1) {
+ if (job->paper_code != -1) {
if (ctx->type == P_CP_XXX) {
uint8_t pc = rdbuf[ctx->printer->paper_code_offset];
- if (((pc >> 4) & 0xf) != (ctx->paper_code & 0x0f)) {
+ if (((pc >> 4) & 0xf) != (job->paper_code & 0x0f)) {
if (pc & 0xf0) {
ERROR("Incorrect paper tray loaded, aborting job!\n");
@@ -879,7 +928,7 @@ top:
return CUPS_BACKEND_STOP;
}
}
- if ((pc & 0xf) != (ctx->paper_code & 0xf)) {
+ if ((pc & 0xf) != (job->paper_code & 0xf)) {
if (pc & 0x0f) {
ERROR("Incorrect ribbon loaded, aborting job!\n");
return CUPS_BACKEND_HOLD;
@@ -891,9 +940,9 @@ top:
}
} else {
if (rdbuf[ctx->printer->paper_code_offset] !=
- ctx->paper_code) {
+ job->paper_code) {
ERROR("Incorrect media/ribbon loaded (%02x vs %02x), aborting job!\n",
- ctx->paper_code,
+ job->paper_code,
rdbuf[ctx->printer->paper_code_offset]);
return CUPS_BACKEND_HOLD; /* Hold this job, don't stop queue */
}
@@ -905,14 +954,14 @@ top:
if (ribbon == 0xf) {
ERROR("No ribbon loaded, aborting!\n");
return CUPS_BACKEND_STOP;
- } else if (ribbon != ctx->paper_code) {
+ } else if (ribbon != job->paper_code) {
ERROR("Incorrect ribbon loaded, aborting job!\n");
return CUPS_BACKEND_HOLD;
}
if (paper == 0xf) {
ERROR("No paper tray loaded, aborting!\n");
return CUPS_BACKEND_STOP;
- } else if (paper != ctx->paper_code) {
+ } else if (paper != job->paper_code) {
ERROR("Incorrect paper loaded, aborting job!\n");
return CUPS_BACKEND_HOLD;
}
@@ -923,7 +972,7 @@ top:
case S_PRINTER_READY:
INFO("Printing started; Sending init sequence\n");
/* Send printer init */
- if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->header, ctx->printer->init_length)))
+ if ((ret = send_data(ctx->dev, ctx->endp_down, job->header, ctx->printer->init_length)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_INIT_SENT;
@@ -934,19 +983,19 @@ top:
}
break;
case S_PRINTER_READY_Y:
- if (ctx->bw_mode)
+ if (job->bw_mode)
INFO("Sending BLACK plane\n");
else
INFO("Sending YELLOW plane\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_y, ctx->plane_len)))
+ if ((ret = send_data(ctx->dev, ctx->endp_down, job->plane_y, job->plane_len)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_Y_SENT;
break;
case S_PRINTER_Y_SENT:
if (!fancy_memcmp(rdbuf, ctx->printer->ready_m_readback, READBACK_LEN)) {
- if (ctx->bw_mode)
+ if (job->bw_mode)
state = S_PRINTER_DONE;
else
state = S_PRINTER_READY_M;
@@ -955,7 +1004,7 @@ top:
case S_PRINTER_READY_M:
INFO("Sending MAGENTA plane\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_m, ctx->plane_len)))
+ if ((ret = send_data(ctx->dev, ctx->endp_down, job->plane_m, job->plane_len)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_M_SENT;
@@ -968,7 +1017,7 @@ top:
case S_PRINTER_READY_C:
INFO("Sending CYAN plane\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->plane_c, ctx->plane_len)))
+ if ((ret = send_data(ctx->dev, ctx->endp_down, job->plane_c, job->plane_len)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_C_SENT;
@@ -996,7 +1045,7 @@ top:
if (ctx->printer->foot_length) {
INFO("Cleaning up\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down, ctx->footer, ctx->printer->foot_length)))
+ if ((ret = send_data(ctx->dev, ctx->endp_down, job->footer, ctx->printer->foot_length)))
return CUPS_BACKEND_FAILED;
}
state = S_FINISHED;
@@ -1030,12 +1079,15 @@ static int canonselphy_cmdline_arg(void *vctx, int argc, char **argv)
if (!ctx)
return -1;
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "R")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "Rs")) >= 0) {
switch(i) {
GETOPT_PROCESS_GLOBAL
case 'R':
canonselphy_send_reset(ctx);
break;
+ case 's':
+ canonselphy_get_status(ctx);
+ break;
}
if (j) return j;
@@ -1047,51 +1099,105 @@ static int canonselphy_cmdline_arg(void *vctx, int argc, char **argv)
static void canonselphy_cmdline(void)
{
DEBUG("\t\t[ -R ] # Reset printer\n");
+ DEBUG("\t\t[ -s ] # Query printer status\n");
+}
+
+static int canonselphy_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct canonselphy_ctx *ctx = vctx;
+ uint8_t rdbuf[READBACK_LEN];
+ int ret, num;
+
+ /* Read in the printer status, twice. */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) rdbuf, READBACK_LEN, &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (ctx->printer->error_detect(rdbuf))
+ ctx->marker.levelnow = 0;
+ else
+ ctx->marker.levelnow = -3;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
}
+static const char *canonselphy_prefixes[] = {
+ "canonselphy", // Family name
+ "canon-cp10", "canon-cp100", "canon-cp200", "canon-cp220",
+ "canon-cp300", "canon-cp330", "canon-cp400", "canon-cp500",
+ "canon-cp510", "canon-cp520", "canon-cp530", "canon-cp600",
+ "canon-cp710", "canon-cp720", "canon-cp730", "canon-cp740",
+ "canon-cp750", "canon-cp760", "canon-cp770", "canon-cp780",
+ "canon-cp790", "canon-cp800", "canon-cp810", "canon-cp900",
+ "canon-es1", "canon-es2", "canon-es20", "canon-es3",
+ "canon-es30", "canon-es40",
+ // backwards compatibility
+ "selphycp10", "selphycp100", "selphycp200", "selphycp220",
+ "selphycp300", "selphycp330", "selphycp400", "selphycp500",
+ "selphycp510", "selphycp520", "selphycp530", "selphycp600",
+ "selphycp710", "selphycp720", "selphycp730", "selphycp740",
+ "selphycp750", "selphycp760", "selphycp770", "selphycp780",
+ "selphycp790", "selphycp800", "selphycp810", "selphycp900",
+ "selphyes1", "selphyes2", "selphyes20", "selphyes3",
+ "selphyes30", "selphyes40",
+ NULL
+};
+
struct dyesub_backend canonselphy_backend = {
- .name = "Canon SELPHY CP/ES",
- .version = "0.94",
- .uri_prefix = "canonselphy",
+ .name = "Canon SELPHY CP/ES (legacy)",
+ .version = "0.104",
+ .uri_prefixes = canonselphy_prefixes,
.cmdline_usage = canonselphy_cmdline,
.cmdline_arg = canonselphy_cmdline_arg,
.init = canonselphy_init,
.attach = canonselphy_attach,
.teardown = canonselphy_teardown,
.read_parse = canonselphy_read_parse,
+ .cleanup_job = canonselphy_cleanup_job,
.main_loop = canonselphy_main_loop,
+ .query_markers = canonselphy_query_markers,
.devices = {
- { USB_VID_CANON, USB_PID_CANON_CP10, P_CP10, ""},
- { USB_VID_CANON, USB_PID_CANON_CP100, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP200, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP220, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP300, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP330, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP400, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP500, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP510, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP520, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP530, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP600, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP710, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP720, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP730, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP740, P_CP_XXX, ""},
- { USB_VID_CANON, USB_PID_CANON_CP750, P_CP_XXX, ""},
- { 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_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, ""},
- { USB_VID_CANON, USB_PID_CANON_ES1, P_ES1, ""},
- { USB_VID_CANON, USB_PID_CANON_ES2, P_ES2_20, ""},
- { 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, ""},
- { 0, 0, 0, ""}
+ { USB_VID_CANON, USB_PID_CANON_CP10, P_CP10, NULL, "canon-cp10"},
+ { USB_VID_CANON, USB_PID_CANON_CP100, P_CP_XXX, NULL, "canon-cp100"},
+ { USB_VID_CANON, USB_PID_CANON_CP200, P_CP_XXX, NULL, "canon-cp200"},
+ { USB_VID_CANON, USB_PID_CANON_CP220, P_CP_XXX, NULL, "canon-cp220"},
+ { USB_VID_CANON, USB_PID_CANON_CP300, P_CP_XXX, NULL, "selpyhcp300"},
+ { USB_VID_CANON, USB_PID_CANON_CP330, P_CP_XXX, NULL, "canon-cp330"},
+ { USB_VID_CANON, USB_PID_CANON_CP400, P_CP_XXX, NULL, "canon-cp400"},
+ { USB_VID_CANON, USB_PID_CANON_CP500, P_CP_XXX, NULL, "canon-cp500"},
+ { USB_VID_CANON, USB_PID_CANON_CP510, P_CP_XXX, NULL, "canon-cp510"},
+ { USB_VID_CANON, USB_PID_CANON_CP520, P_CP_XXX, NULL, "canon-cp520"},
+ { USB_VID_CANON, USB_PID_CANON_CP530, P_CP_XXX, NULL, "canon-cp530"},
+ { USB_VID_CANON, USB_PID_CANON_CP600, P_CP_XXX, NULL, "canon-cp600"},
+ { USB_VID_CANON, USB_PID_CANON_CP710, P_CP_XXX, NULL, "canon-cp710"},
+ { USB_VID_CANON, USB_PID_CANON_CP720, P_CP_XXX, NULL, "canon-cp720"},
+ { USB_VID_CANON, USB_PID_CANON_CP730, P_CP_XXX, NULL, "canon-cp730"},
+ { USB_VID_CANON, USB_PID_CANON_CP740, P_CP_XXX, NULL, "canon-cp740"},
+ { USB_VID_CANON, USB_PID_CANON_CP750, P_CP_XXX, NULL, "canon-cp750"},
+ { USB_VID_CANON, USB_PID_CANON_CP760, P_CP_XXX, NULL, "canon-cp760"},
+ { USB_VID_CANON, USB_PID_CANON_CP770, P_CP_XXX, NULL, "canon-cp770"},
+ { USB_VID_CANON, USB_PID_CANON_CP780, P_CP_XXX, NULL, "canon-cp780"},
+ { USB_VID_CANON, USB_PID_CANON_CP790, P_CP790, NULL, "canon-cp790"},
+ { USB_VID_CANON, USB_PID_CANON_CP800, P_CP_XXX, NULL, "canon-cp800"},
+ { USB_VID_CANON, USB_PID_CANON_CP810, P_CP_XXX, NULL, "canon-cp810"},
+ { USB_VID_CANON, USB_PID_CANON_CP900, P_CP_XXX, NULL, "canon-cp900"},
+ { USB_VID_CANON, USB_PID_CANON_ES1, P_ES1, NULL, "canon-es1"},
+ { USB_VID_CANON, USB_PID_CANON_ES2, P_ES2_20, NULL, "canon-es2"},
+ { USB_VID_CANON, USB_PID_CANON_ES20, P_ES2_20, NULL, "canon-es20"},
+ { USB_VID_CANON, USB_PID_CANON_ES3, P_ES3_30, NULL, "canon-es3"},
+ { USB_VID_CANON, USB_PID_CANON_ES30, P_ES3_30, NULL, "canon-es30"},
+ { USB_VID_CANON, USB_PID_CANON_ES40, P_ES40, NULL, "canon-es40"},
+ { 0, 0, 0, NULL, NULL}
}
};
/*
@@ -1184,10 +1290,8 @@ struct dyesub_backend canonselphy_backend = {
0x02 for L-papers
0x03 for C-papers
- [pg2] is: 0x00 for P & L papers
- 0x01 for Cl-paper
-
- *** note: may refer to Label (0x01) vs non-Label (0x00) media.
+ [pg2] is: 0x00 for Normal papers
+ 0x01 for Label papers
***************************************************************************
Selphy ES3/30:
diff --git a/src/cups/backend_canonselphyneo.c b/src/cups/backend_canonselphyneo.c
index 85f51b2..93f539d 100644
--- a/src/cups/backend_canonselphyneo.c
+++ b/src/cups/backend_canonselphyneo.c
@@ -1,7 +1,7 @@
/*
* Canon SELPHY CPneo series CUPS backend -- libusb-1.0 version
*
- * (c) 2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2016-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -45,6 +46,7 @@
#define USB_PID_CANON_CP910 0x327a
#define USB_PID_CANON_CP1000 0x32ae
#define USB_PID_CANON_CP1200 0x32b1
+#define USB_PID_CANON_CP1300 0x32db
/* Header data structure */
struct selphyneo_hdr {
@@ -59,13 +61,20 @@ struct selphyneo_readback {
} __attribute((packed));
/* Private data structure */
+struct selphyneo_printjob {
+ uint8_t *databuf;
+ uint32_t datalen;
+
+ int copies;
+};
+
struct selphyneo_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
+ int type;
- uint8_t *databuf;
- uint32_t datalen;
+ struct marker marker;
};
static char *selphyneo_statuses(uint8_t sts)
@@ -97,6 +106,8 @@ static char *selphyneo_errors(uint8_t err)
return "Paper Feed";
case 0x03:
return "No Paper";
+ case 0x05:
+ return "Incorrect Paper loaded";
case 0x06:
return "Ink Cassette Empty";
case 0x07:
@@ -105,6 +116,8 @@ static char *selphyneo_errors(uint8_t err)
return "No Paper and Ink";
case 0x0A:
return "Incorrect media for job";
+ case 0x0B:
+ return "Paper jam";
default:
return "Unknown Error";
}
@@ -140,6 +153,34 @@ static int selphyneo_send_reset(struct selphyneo_ctx *ctx)
return CUPS_BACKEND_OK;
}
+static int selphyneo_get_status(struct selphyneo_ctx *ctx)
+{
+ struct selphyneo_readback rdback;
+ int ret, num;
+
+ /* Read in the printer status to clear last state */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* And again, for the markers */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Printer state: %s\n", selphyneo_statuses(rdback.data[0]));
+ INFO("Media type: %s\n", selphynew_pgcodes(rdback.data[6]));
+ if (rdback.data[2]) {
+ INFO("Printer error: %s\n", selphyneo_errors(rdback.data[2]));
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
static void *selphyneo_init(void)
{
struct selphyneo_ctx *ctx = malloc(sizeof(struct selphyneo_ctx));
@@ -154,21 +195,60 @@ static void *selphyneo_init(void)
extern struct dyesub_backend selphyneo_backend;
-static void selphyneo_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int selphyneo_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct selphyneo_ctx *ctx = vctx;
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
+ struct selphyneo_readback rdback;
+ int ret, num;
UNUSED(jobid);
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ ctx->type = type;
+
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Read in the printer status to clear last state */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* And again, for the markers */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+ } else {
+ rdback.data[2] = 0;
+ rdback.data[6] = 0x01;
+ if (getenv("MEDIA_CODE"))
+ rdback.data[6] = atoi(getenv("MEDIA_CODE"));
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = selphynew_pgcodes(rdback.data[6]);
+ ctx->marker.levelmax = -1;
+ if (rdback.data[2]) {
+ ctx->marker.levelnow = 0;
+ } else {
+ ctx->marker.levelnow = -3;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void selphyneo_cleanup_job(const void *vjob) {
+ const struct selphyneo_printjob *job = vjob;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void selphyneo_teardown(void *vctx) {
@@ -177,29 +257,39 @@ static void selphyneo_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
-
free(ctx);
}
-static int selphyneo_read_parse(void *vctx, int data_fd)
+static int selphyneo_read_parse(void *vctx, const void **vjob, int data_fd, int copies)
{
struct selphyneo_ctx *ctx = vctx;
struct selphyneo_hdr hdr;
int i, remain;
+ struct selphyneo_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
+
/* Read the header.. */
i = read(data_fd, &hdr, sizeof(hdr));
if (i != sizeof(hdr)) {
- if (i == 0)
+ if (i == 0) {
+ selphyneo_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
ERROR("Read failed (%d/%d)\n",
i, (int)sizeof(hdr));
perror("ERROR: Read failed");
+ selphyneo_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
@@ -213,53 +303,63 @@ static int selphyneo_read_parse(void *vctx, int data_fd)
default:
ERROR("Unknown print size! (%02x, %ux%u)\n",
hdr.data[10], le32_to_cpu(hdr.cols), le32_to_cpu(hdr.rows));
+ selphyneo_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
+ // XXX Sanity check job against loaded media?
+
/* Allocate a buffer */
- ctx->datalen = 0;
- ctx->databuf = malloc(remain + sizeof(hdr));
- if (!ctx->databuf) {
+ job->datalen = 0;
+ job->databuf = malloc(remain + sizeof(hdr));
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ selphyneo_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
/* Store the read-in header */
- memcpy(ctx->databuf, &hdr, sizeof(hdr));
- ctx->datalen += sizeof(hdr);
+ memcpy(job->databuf, &hdr, sizeof(hdr));
+ job->datalen += sizeof(hdr);
/* Read in data */
while (remain > 0) {
- i = read(data_fd, ctx->databuf + ctx->datalen, remain);
- if (i < 0)
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i < 0) {
+ selphyneo_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
- ctx->datalen += i;
+ job->datalen += i;
}
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int selphyneo_main_loop(void *vctx, int copies) {
+static int selphyneo_main_loop(void *vctx, const void *vjob) {
struct selphyneo_ctx *ctx = vctx;
struct selphyneo_readback rdback;
int ret, num;
+ int copies;
- /* Read in the printer status to clear last state */
- ret = read_data(ctx->dev, ctx->endp_up,
- (uint8_t*) &rdback, sizeof(rdback), &num);
+ const struct selphyneo_printjob *job = vjob;
- /* And again, for the markers */
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
+
+ /* Read in the printer status to clear last state */
ret = read_data(ctx->dev, ctx->endp_up,
(uint8_t*) &rdback, sizeof(rdback), &num);
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", selphynew_pgcodes(rdback.data[6]));
-
- ATTR("marker-types=ribbonWax\n");
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
top:
INFO("Waiting for printer idle\n");
@@ -281,18 +381,20 @@ top:
break;
case 0x0A:
ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
- ATTR("marker-levels=%d\n", 0);
+ ctx->marker.levelnow = 0;
+ dump_markers(&ctx->marker, 1, 0);
return CUPS_BACKEND_CANCEL;
default:
ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
- ATTR("marker-levels=%d\n", 0);
+ ctx->marker.levelnow = 0;
+ dump_markers(&ctx->marker, 1, 0);
return CUPS_BACKEND_STOP;
}
sleep(1);
} while(1);
- ATTR("marker-levels=%d\n", -3); /* ie Unknown but OK */
+ dump_markers(&ctx->marker, 1, 0);
INFO("Sending spool data\n");
/* Send the data over in 256K chunks */
@@ -301,10 +403,10 @@ top:
int sent = 0;
while (chunk > 0) {
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf + sent, chunk)))
+ job->databuf + sent, chunk)))
return CUPS_BACKEND_FAILED;
sent += chunk;
- chunk = ctx->datalen - sent;
+ chunk = job->datalen - sent;
if (chunk > 256*1024)
chunk = 256*1024;
}
@@ -314,6 +416,9 @@ top:
ret = read_data(ctx->dev, ctx->endp_up,
(uint8_t*) &rdback, sizeof(rdback), &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
INFO("Waiting for printer acknowledgement\n");
do {
ret = read_data(ctx->dev, ctx->endp_up,
@@ -332,15 +437,17 @@ top:
break;
case 0x0A:
ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
- ATTR("marker-levels=%d\n", 0);
+ ctx->marker.levelnow = 0;
+ dump_markers(&ctx->marker, 1, 0);
return CUPS_BACKEND_CANCEL;
default:
ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]);
- ATTR("marker-levels=%d\n", 0);
+ ctx->marker.levelnow = 0;
+ dump_markers(&ctx->marker, 1, 0);
return CUPS_BACKEND_STOP;
}
- if (rdback.data[0] > 0x02 && fast_return) {
+ if (rdback.data[0] > 0x02 && fast_return && copies <= 1) {
INFO("Fast return mode enabled.\n");
break;
}
@@ -369,12 +476,15 @@ static int selphyneo_cmdline_arg(void *vctx, int argc, char **argv)
if (!ctx)
return -1;
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "R")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "Rs")) >= 0) {
switch(i) {
GETOPT_PROCESS_GLOBAL
case 'R':
selphyneo_send_reset(ctx);
break;
+ case 's':
+ selphyneo_get_status(ctx);
+ break;
}
if (j) return j;
@@ -386,25 +496,68 @@ static int selphyneo_cmdline_arg(void *vctx, int argc, char **argv)
static void selphyneo_cmdline(void)
{
DEBUG("\t\t[ -R ] # Reset printer\n");
+ DEBUG("\t\t[ -s ] # Query printer status\n");
}
+static int selphyneo_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct selphyneo_ctx *ctx = vctx;
+ struct selphyneo_readback rdback;
+ int ret, num;
+
+ /* Read in the printer status to clear last state */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ /* And again, for the markers */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &rdback, sizeof(rdback), &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+
+ if (rdback.data[2])
+ ctx->marker.levelnow = 0;
+ else
+ ctx->marker.levelnow = -3;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *canonselphyneo_prefixes[] = {
+ "canonselphyneo", // Family name
+ "canon-cp820", "canon-cp910", "canon-cp1000", "canon-cp1200", "canon-cp1300",
+ // backwards compatibility
+ "selphycp820", "selphycp910", "selphycp1000", "selphycp1200", "selphycp1300",
+ NULL
+};
+
struct dyesub_backend canonselphyneo_backend = {
- .name = "Canon SELPHY CPneo",
- .version = "0.08",
- .uri_prefix = "canonselphyneo",
+ .name = "Canon SELPHY CP (new)",
+ .version = "0.20",
+ .uri_prefixes = canonselphyneo_prefixes,
.cmdline_usage = selphyneo_cmdline,
.cmdline_arg = selphyneo_cmdline_arg,
.init = selphyneo_init,
.attach = selphyneo_attach,
+ .cleanup_job = selphyneo_cleanup_job,
.teardown = selphyneo_teardown,
.read_parse = selphyneo_read_parse,
.main_loop = selphyneo_main_loop,
+ .query_markers = selphyneo_query_markers,
.devices = {
- { USB_VID_CANON, USB_PID_CANON_CP820, P_CP910, ""},
- { USB_VID_CANON, USB_PID_CANON_CP910, P_CP910, ""},
- { USB_VID_CANON, USB_PID_CANON_CP1000, P_CP910, ""},
- { USB_VID_CANON, USB_PID_CANON_CP1200, P_CP910, ""},
- { 0, 0, 0, ""}
+ { USB_VID_CANON, USB_PID_CANON_CP820, P_CP910, NULL, "canon-cp820"},
+ { USB_VID_CANON, USB_PID_CANON_CP910, P_CP910, NULL, "canon-cp910"},
+ { USB_VID_CANON, USB_PID_CANON_CP1000, P_CP910, NULL, "canon-cp1000"},
+ { USB_VID_CANON, USB_PID_CANON_CP1200, P_CP910, NULL, "canon-cp1200"},
+ { USB_VID_CANON, USB_PID_CANON_CP1300, P_CP910, NULL, "canon-cp1300"},
+ { 0, 0, 0, NULL, NULL}
}
};
/*
@@ -468,9 +621,11 @@ struct dyesub_backend canonselphyneo_backend = {
00 None
02 No Paper (?)
03 No Paper
+ 05 Wrong Paper
07 No Ink
09 No Paper and Ink
0A Media/Job mismatch
+ 0B Paper Jam
ZZ == Media?
diff --git a/src/cups/backend_citizencw01.c b/src/cups/backend_citizencw01.c
deleted file mode 100644
index 46cb8ee..0000000
--- a/src/cups/backend_citizencw01.c
+++ /dev/null
@@ -1,908 +0,0 @@
-/*
- * Citizen CW-01 Photo Printer CUPS backend -- libusb-1.0 version
- *
- * (c) 2014-2016 Solomon Peachy <pizza@shaftnet.org>
- *
- * The latest version of this program can be found at:
- *
- * http://git.shaftnet.org/cgit/selphy_print.git
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * [http://www.gnu.org/licenses/gpl-2.0.html]
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#define BACKEND cw01_backend
-
-#include "backend_common.h"
-
-#define USB_VID_CITIZEN 0x1343
-#define USB_PID_CITIZEN_CW01 0x0002 // Maybe others?
-//#define USB_PID_OLMEC_OP900 XXXX
-
-/* Private data structure */
-struct cw01_spool_hdr {
- uint8_t type; /* 0x00 -> 0x06 */
- uint8_t res; /* vertical resolution; 0x00 == 334dpi, 0x01 == 600dpi */
- uint8_t copies; /* number of prints */
- uint8_t null0;
- uint32_t plane_len; /* LE */
- uint8_t null1[4];
-};
-#define DPI_334 0
-#define DPI_600 1
-
-#define TYPE_DSC 0
-#define TYPE_L 1
-#define TYPE_PC 2
-#define TYPE_2DSC 3
-#define TYPE_3L 4
-#define TYPE_A5 5
-#define TYPE_A6 6
-
-#define SPOOL_PLANE_HDR_LEN 1064
-#define PRINTER_PLANE_HDR_LEN 1088
-
-struct cw01_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
- uint8_t *databuf;
- struct cw01_spool_hdr hdr;
-};
-
-struct cw01_cmd {
- uint8_t esc; /* Fixed at ascii ESC, aka 0x1B */
- uint8_t p; /* Fixed at ascii 'P' aka 0x50 */
- uint8_t arg1[6];
- uint8_t arg2[16];
- uint8_t arg3[8]; /* Decimal value of arg4's length, or empty */
- uint8_t arg4[0]; /* Extra payload if arg3 is non-empty
- Doesn't have to be sent in the same URB */
-
- /* All unused elements are set to 0x20 (ie ascii space) */
-};
-
-#define min(__x, __y) ((__x) < (__y)) ? __x : __y
-
-static void cw01_build_cmd(struct cw01_cmd *cmd, char *arg1, char *arg2, uint32_t arg3_len)
-{
- memset(cmd, 0x20, sizeof(*cmd));
- cmd->esc = 0x1b;
- cmd->p = 0x50;
- memcpy(cmd->arg1, arg1, min(strlen(arg1), sizeof(cmd->arg1)));
- memcpy(cmd->arg2, arg2, min(strlen(arg2), sizeof(cmd->arg2)));
- if (arg3_len) {
- char buf[9];
- snprintf(buf, sizeof(buf), "%08u", arg3_len);
- memcpy(cmd->arg3, buf, 8);
- }
-
-}
-
-static void cw01_cleanup_string(char *start, int len)
-{
- char *ptr = strchr(start, 0x0d);
-
- if (ptr && (ptr - start < len)) {
- *ptr = 0x00; /* If there is a <CR>, terminate there */
- len = ptr - start;
- } else {
- start[--len] = 0x00; /* force null-termination */
- }
-
- /* Trim trailing spaces */
- while (len && start[len-1] == ' ') {
- start[--len] = 0;
- }
-}
-
-static char *cw01_media_types(char *str)
-{
- char tmp[4];
- int i;
-
- memcpy(tmp, str + 4, 3);
- tmp[3] = 0;
-
- i = atoi(tmp);
-
- switch (i) {
- case 100: return "UNK 100";
- case 110: return "UNK 110";
- case 200: return "?? 5x3.5 (L)";
- case 210: return "?? 5x7 (2L)";
- case 300: return "?? 6x4 (PC)";
- case 400: return "?? 6x9 (A5W)";
- default:
- break;
- }
-
- return "Unknown type";
-}
-
-static char *cw01_statuses(char *str)
-{
- char tmp[6];
- int i;
- memcpy(tmp, str, 5);
- tmp[5] = 0;
-
- i = atoi(tmp);
-
- switch (i) {
- case 0: return "Idle";
- case 1: return "Printing";
- case 500: return "Cooling Print Head";
- case 510: return "Cooling Paper Motor";
- case 1000: return "Cover Open";
- case 1010: return "No Scrap Box";
- case 1100: return "Paper End";
- case 1200: return "Ribbon End";
- case 1300: return "Paper Jam";
- case 1400: return "Ribbon Error";
- case 1500: return "Paper Definition Error";
- case 1600: return "Data Error";
- case 2000: return "Head Voltage Error";
- case 2100: return "Head Position Error";
- case 2200: return "Power Supply Fan Error";
- case 2300: return "Cutter Error";
- case 2400: return "Pinch Roller Error";
- case 2500: return "Abnormal Head Temperature";
- case 2600: return "Abnormal Media Temperature";
- case 2610: return "Abnormal Paper Motor Temperature";
- case 2700: return "Ribbon Tension Error";
- case 2800: return "RF-ID Module Error";
- case 3000: return "System Error";
- default:
- break;
- }
-
- return "Unknown Error";
-}
-
-static int cw01_do_cmd(struct cw01_ctx *ctx,
- struct cw01_cmd *cmd,
- uint8_t *data, int len)
-{
- int ret;
-
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*)cmd, sizeof(*cmd))))
- return ret;
-
- if (data && len)
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- data, len)))
- return ret;
-
- return CUPS_BACKEND_OK;
-}
-
-static uint8_t *cw01_resp_cmd(struct cw01_ctx *ctx,
- struct cw01_cmd *cmd,
- int *len)
-{
- char tmp[9];
- uint8_t *respbuf;
-
- int ret, i, num = 0;
-
- memset(tmp, 0, sizeof(tmp));
-
- if ((ret = cw01_do_cmd(ctx, cmd, NULL, 0)))
- return NULL;
-
- /* Read in the response header */
- ret = read_data(ctx->dev, ctx->endp_up,
- (uint8_t*)tmp, 8, &num);
- if (ret < 0)
- return NULL;
-
- if (num != 8) {
- ERROR("Short read! (%d/%d)\n", num, 8);
- return NULL;
- }
-
- i = atoi(tmp); /* Length of payload in bytes, possibly padded */
- respbuf = malloc(i);
- if (!respbuf) {
- ERROR("Memory Allocation Failure!\n");
- return NULL;
- }
-
- /* Read in the actual response */
- ret = read_data(ctx->dev, ctx->endp_up,
- respbuf, i, &num);
- if (ret < 0) {
- free(respbuf);
- return NULL;
- }
-
- if (num != i) {
- ERROR("Short read! (%d/%d)\n", num, i);
- free(respbuf);
- return NULL;
- }
-
- *len = num;
- return respbuf;
-}
-
-static int cw01_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
-{
- struct cw01_cmd cmd;
- uint8_t *resp;
- int len = 0;
-
- struct cw01_ctx ctx = {
- .dev = dev,
- .endp_up = endp_up,
- .endp_down = endp_down,
- };
-
- /* Get Serial Number */
- cw01_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
-
- resp = cw01_resp_cmd(&ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- strncpy(buf, (char*)resp, buf_len);
- buf[buf_len-1] = 0;
-
- free(resp);
-
- return CUPS_BACKEND_OK;
-}
-
-static void *cw01_init(void)
-{
- struct cw01_ctx *ctx = malloc(sizeof(struct cw01_ctx));
- if (!ctx) {
- ERROR("Memory Allocation Failure!\n");
- return NULL;
- }
- memset(ctx, 0, sizeof(struct cw01_ctx));
-
- return ctx;
-}
-
-static void cw01_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
-{
- struct cw01_ctx *ctx = vctx;
- 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) {
- struct cw01_ctx *ctx = vctx;
-
- if (!ctx)
- return;
-
- if (ctx->databuf)
- free(ctx->databuf);
- free(ctx);
-}
-
-static int cw01_read_parse(void *vctx, int data_fd) {
- struct cw01_ctx *ctx = vctx;
- int i, j, remain;
-
- if (!ctx)
- return CUPS_BACKEND_FAILED;
-
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
- }
-
- i = read(data_fd, (uint8_t*) &ctx->hdr, sizeof(struct cw01_spool_hdr));
-
- if (i < 0)
- return i;
- if (i == 0)
- return CUPS_BACKEND_CANCEL;
-
- if (i < (int)sizeof(struct cw01_spool_hdr))
- return CUPS_BACKEND_CANCEL;
-
- if (ctx->hdr.type > 0x06 || ctx->hdr.res > 0x01) {
- ERROR("Unrecognized header data format!\n");
- return CUPS_BACKEND_CANCEL;
- }
- ctx->hdr.plane_len = le32_to_cpu(ctx->hdr.plane_len);
- remain = ctx->hdr.plane_len * 3;
- ctx->databuf = malloc(remain);
- if (!ctx->databuf) {
- ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_CANCEL;
- }
-
- j = 0;
- while (remain) {
- i = read(data_fd, ctx->databuf + j, remain);
-
- if (i < 0)
- return i;
-
- remain -= i;
- j += i;
- }
-
- return CUPS_BACKEND_OK;
-}
-
-static int cw01_main_loop(void *vctx, int copies) {
- struct cw01_ctx *ctx = vctx;
- int ret;
- struct cw01_cmd cmd;
- uint8_t *resp = NULL;
- int len = 0;
- uint32_t tmp;
- uint8_t *ptr;
- char buf[9];
- uint8_t plane_hdr[PRINTER_PLANE_HDR_LEN];
-
- if (!ctx)
- return CUPS_BACKEND_FAILED;
-
-top:
-
- if (resp) free(resp);
-
- /* Query status */
- cw01_build_cmd(&cmd, "STATUS", "", 0);
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
- cw01_cleanup_string((char*)resp, len);
-
- /* If we're not idle */
- if (strcmp("00000", (char*)resp)) {
- if (!strcmp("00001", (char*)resp)) {
- free(resp);
- /* Query buffer state */
- cw01_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
- cw01_cleanup_string((char*)resp, len);
-
- /* Check to see if we have sufficient buffers */
- // XXX audit these rules...?
- if (!strcmp("FBP00", (char*)resp) ||
- (ctx->hdr.res == DPI_600 && !strcmp("FBP01", (char*)resp))) {
- INFO("Insufficient printer buffers, retrying...\n");
- sleep(1);
- goto top;
- }
- } else {
- ERROR("Printer Status: %s\n", cw01_statuses((char*)resp));
- free(resp);
- return CUPS_BACKEND_RETRY_CURRENT;
- }
- }
-
- free(resp);
- /* Get Vertical resolution */
- cw01_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
-#if 0
- if (ctx->hdr.res == DPI_600 && strcmp("RV0334", *char*)resp) {
- ERROR("600DPI prints not yet supported, need 600DPI CWD load");
- return CUPS_BACKEND_CANCEL;
- }
-#endif
-
- free(resp);
- resp = NULL;
-
- /* Set print quantity */ // 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);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- /* Cutter control. ??? */
- // cw01_build_cmd(&cmd, "CNTRL", "CUTTER", 8);
- //snprintf(buf, sizeof(buf), "%08d", ???);
- //ret = cw01_do_cmd(ctx, &cmd, (uint8_t*) buf, 8);
- //if (ret)
- // return CUPS_BACKEND_FAILED;
-
- /* Start sending image data */
- ptr = ctx->databuf;
-
- /* Generate plane header (same for all planes) */
- tmp = cpu_to_le32(ctx->hdr.plane_len) + 24;
- memset(plane_hdr, 0, PRINTER_PLANE_HDR_LEN);
- plane_hdr[0] = 0x42;
- plane_hdr[1] = 0x4d;
- memcpy(plane_hdr + 2, &tmp, sizeof(tmp));
- plane_hdr[10] = 0x40;
- plane_hdr[11] = 0x04;
- memcpy(plane_hdr + 14, ptr, SPOOL_PLANE_HDR_LEN);
-
- /******** Plane 1 */
- cw01_build_cmd(&cmd, "IMAGE", "YPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
- ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- /* Send plane data */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
- return CUPS_BACKEND_FAILED;
-
- ptr += ctx->hdr.plane_len;
-
- /******** Plane 2 */
- cw01_build_cmd(&cmd, "IMAGE", "MPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
- ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- /* Send plane data */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
- return CUPS_BACKEND_FAILED;
-
- ptr += ctx->hdr.plane_len;
-
- /******** Plane 3 */
- cw01_build_cmd(&cmd, "IMAGE", "CPLANE", ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN + PRINTER_PLANE_HDR_LEN);
- ret = cw01_do_cmd(ctx, &cmd, plane_hdr, PRINTER_PLANE_HDR_LEN);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- /* Send plane data */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- ptr + SPOOL_PLANE_HDR_LEN, ctx->hdr.plane_len - SPOOL_PLANE_HDR_LEN)))
- return CUPS_BACKEND_FAILED;
-
- /* ptr += ctx->hdr.plane_len; */
-
- /* Start print */
- cw01_build_cmd(&cmd, "CNTRL", "START", 0);
- ret = cw01_do_cmd(ctx, &cmd, NULL, 0);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- INFO("Print complete\n");
-
- if (resp) free(resp);
-
- return CUPS_BACKEND_OK;
-}
-
-static int cw01_get_info(struct cw01_ctx *ctx)
-{
- struct cw01_cmd cmd;
- uint8_t *resp;
- int len = 0;
-
- /* Get Serial Number */
- cw01_build_cmd(&cmd, "INFO", "SERIAL_NUMBER", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Serial Number: '%s'\n", (char*)resp);
-
- free(resp);
-
- /* Get Firmware Version */
- cw01_build_cmd(&cmd, "INFO", "FVER", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Firmware Version: '%s'\n", (char*)resp);
-
- free(resp);
-
- /* Get Sensor Info */
- cw01_build_cmd(&cmd, "INFO", "SENSOR", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Sensor Info: '%s'\n", (char*)resp);
- // XXX parse this out. Each token is 'XXX-###' delimited by '; '
-
- free(resp);
-
- /* Get Horizonal resolution */
- cw01_build_cmd(&cmd, "INFO", "RESOLUTION_H", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Horizontal Resolution: '%s' dpi\n", (char*)resp + 3);
-
- free(resp);
-
- /* Get Vertical resolution */
- cw01_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Vertical Resolution: '%s' dpi\n", (char*)resp + 3);
-
- free(resp);
-
- /* Get Media Color offset */
- cw01_build_cmd(&cmd, "INFO", "MCOLOR", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Media Color Offset: '%02x%02x%02x%02x'\n", *(resp+2), *(resp+3),
- *(resp+4), *(resp+5));
-
- free(resp);
-
- /* Get Media Lot */
- cw01_build_cmd(&cmd, "INFO", "MLOT", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Media Lot Code: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n",
- *(resp+2), *(resp+3), *(resp+4), *(resp+5), *(resp+6), *(resp+7),
- *(resp+8), *(resp+9), *(resp+10), *(resp+11), *(resp+12), *(resp+13));
-
- free(resp);
-
- /* Get Media ID Set (?) */
- cw01_build_cmd(&cmd, "MNT_RD", "MEDIA_ID_SET", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Media ID(?): '%s'\n", (char*)resp+4);
-
- free(resp);
-
- /* Get Color Control Data Version */
- cw01_build_cmd(&cmd, "TBL_RD", "Version", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Color Data Version: '%s'\n", (char*)resp);
-
- free(resp);
-
- /* Get Color Control Data Checksum */
- cw01_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Color Data Checksum: '%s'\n", (char*)resp);
-
- free(resp);
-
- return CUPS_BACKEND_OK;
-}
-
-static int cw01_get_status(struct cw01_ctx *ctx)
-{
- struct cw01_cmd cmd;
- uint8_t *resp;
- int len = 0;
-
- /* Generate command */
- cw01_build_cmd(&cmd, "STATUS", "", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Printer Status: %s => %s\n", (char*)resp, cw01_statuses((char*)resp));
-
- free(resp);
-
- /* Get remaining prints in this job */
- cw01_build_cmd(&cmd, "INFO", "PQTY", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Prints Remaining in job: '%s'\n", (char*)resp + 4);
-
- free(resp);
-
- /* Generate command */
- cw01_build_cmd(&cmd, "INFO", "FREE_PBUFFER", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Free Buffers: '%s'\n", (char*)resp + 3);
-
- free(resp);
-
- /* Get Media Info */
- cw01_build_cmd(&cmd, "INFO", "MEDIA", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Media Type: '%s'\n", cw01_media_types((char*)resp));
-
- free(resp);
-
- /* Get Media remaining */
- cw01_build_cmd(&cmd, "INFO", "MQTY", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Prints Remaining: '%s'\n", (char*)resp + 4);
-
- free(resp);
-
- return 0;
-}
-
-static int cw01_get_counters(struct cw01_ctx *ctx)
-{
- struct cw01_cmd cmd;
- uint8_t *resp;
- int len = 0;
-
- /* Generate command */
- cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_LIFE", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("Lifetime Counter: '%s'\n", (char*)resp+2);
-
- free(resp);
-
- /* Generate command */
- cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_A", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("A Counter: '%s'\n", (char*)resp+2);
-
- free(resp);
-
- /* Generate command */
- cw01_build_cmd(&cmd, "MNT_RD", "COUNTER_B", 0);
-
- resp = cw01_resp_cmd(ctx, &cmd, &len);
- if (!resp)
- return CUPS_BACKEND_FAILED;
-
- cw01_cleanup_string((char*)resp, len);
-
- INFO("B Counter: '%s'\n", (char*)resp+2);
-
- free(resp);
-
- return CUPS_BACKEND_OK;
-}
-
-static int cw01_clear_counter(struct cw01_ctx *ctx, char counter)
-{
- struct cw01_cmd cmd;
- char msg[4];
- int ret;
-
- /* Generate command */
- cw01_build_cmd(&cmd, "MNT_WT", "COUNTER_CLEAR", 4);
- msg[0] = 'C';
- msg[1] = counter;
- msg[2] = 0x0d; /* ie carriage return, ASCII '\r' */
- msg[3] = 0x00;
-
- if ((ret = cw01_do_cmd(ctx, &cmd, (uint8_t*)msg, 4)))
- return ret;
-
- return 0;
-}
-
-
-static void cw01_cmdline(void)
-{
- DEBUG("\t\t[ -i ] # Query printer info\n");
- DEBUG("\t\t[ -s ] # Query status\n");
- DEBUG("\t\t[ -n ] # Query counters\n");
- DEBUG("\t\t[ -N A|B|M ] # Clear counter A/B/M\n");
-}
-
-static int cw01_cmdline_arg(void *vctx, int argc, char **argv)
-{
- struct cw01_ctx *ctx = vctx;
- int i, j = 0;
-
- if (!ctx)
- return -1;
-
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "inN:s")) >= 0) {
- switch(i) {
- GETOPT_PROCESS_GLOBAL
- case 'i':
- j = cw01_get_info(ctx);
- break;
- case 'n':
- j = cw01_get_counters(ctx);
- break;
- case 'N':
- if (optarg[0] != 'A' &&
- optarg[0] != 'B')
- return CUPS_BACKEND_FAILED;
- j = cw01_clear_counter(ctx, optarg[0]);
- break;
- case 's':
- j = cw01_get_status(ctx);
- break;
- default:
- break; /* Ignore completely */
- }
-
- if (j) return j;
- }
-
- return 0;
-}
-
-/* Exported */
-struct dyesub_backend cw01_backend = {
- .name = "Citizen CW-01",
- .version = "0.12",
- .uri_prefix = "citizencw01",
- .cmdline_usage = cw01_cmdline,
- .cmdline_arg = cw01_cmdline_arg,
- .init = cw01_init,
- .attach = cw01_attach,
- .teardown = cw01_teardown,
- .read_parse = cw01_read_parse,
- .main_loop = cw01_main_loop,
- .query_serno = cw01_query_serno,
- .devices = {
- { USB_VID_CITIZEN, USB_PID_CITIZEN_CW01, P_CITIZEN_CW01, ""},
-// { USB_VID_CITIZEN, USB_PID_OLMEC_OP900, P_CITIZEN_CW01, ""},
- { 0, 0, 0, ""}
- }
-};
-
-/*
-
-Basic spool file format:
-
-TT RR NN 00 XX XX XX XX 00 00 00 00 <- FILE header.
-
- NN : copies (0x01 or more)
- RR : resolution; 0 == 334 dpi, 1 == 600dpi
- TT : type 0x02 == 4x6, 0x01 == 5x3.5
- XX XX XX XX : plane length (LE)
- plane length * 3 + 12 == file length.
-
-Followed by three planes, each with this header:
-
-28 00 00 00 00 08 00 00 RR RR 00 00 01 00 08 00
-00 00 00 00 00 00 00 00 5a 33 00 00 YY YY 00 00
-00 01 00 00 00 00 00 00
-
- RR RR : rows in LE format
- YY YY : 0x335a (334dpi) or 0x5c40 (600dpi)
-
-Followed by 1024 bytes of color tables:
-
- ff ff ff 00 ... 00 00 00 00
-
-1024+40 = 1064 bytes of header per plane.
-
-Always have 2048 columns of data.
-
-followed by (2048 * rows) bytes of data.
-
-*/
diff --git a/src/cups/backend_common.c b/src/cups/backend_common.c
index d88a7d8..09ea078 100644
--- a/src/cups/backend_common.c
+++ b/src/cups/backend_common.c
@@ -1,7 +1,7 @@
/*
* CUPS Backend common code
*
- * Copyright (c) 2007-2017 Solomon Peachy <pizza@shaftnet.org>
+ * Copyright (c) 2007-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,22 +18,29 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include "backend_common.h"
-#define BACKEND_VERSION "0.71G"
+#define BACKEND_VERSION "0.88G"
#ifndef URI_PREFIX
#error "Must Define URI_PREFIX"
#endif
#define NUM_CLAIM_ATTEMPTS 10
+#define URB_XFER_SIZE (64*1024)
+#define XFER_TIMEOUT 15000
+
+#define USB_SUBCLASS_PRINTER 0x1
+#define USB_INTERFACE_PROTOCOL_BIDIR 0x2
+
/* Global Variables */
int dyesub_debug = 0;
int terminate = 0;
@@ -42,11 +49,16 @@ int extra_vid = -1;
int extra_pid = -1;
int extra_type = -1;
int copies = 1;
+int test_mode = 0;
+int old_uri = 0;
+
+static int max_xfer_size = URB_XFER_SIZE;
+static int xfer_timeout = XFER_TIMEOUT;
/* Support Functions */
-static int backend_claim_interface(struct libusb_device_handle *dev, int iface)
+static int backend_claim_interface(struct libusb_device_handle *dev, int iface,
+ int num_claim_attempts)
{
- int attempts = NUM_CLAIM_ATTEMPTS;
int ret;
do {
ret = libusb_claim_interface(dev, iface);
@@ -54,15 +66,41 @@ static int backend_claim_interface(struct libusb_device_handle *dev, int iface)
break;
if (ret != LIBUSB_ERROR_BUSY)
break;
+ if (--num_claim_attempts == 0)
+ break;
sleep(1);
- } while (--attempts > 0);
+ } while (1);
if (ret)
- ERROR("Printer open failure (Could not claim printer interface after %d attempts) (%d)\n", NUM_CLAIM_ATTEMPTS, ret);
+ ERROR("Failed to claim interface %d (%d)\n", iface, ret);
return ret;
}
+static int lookup_printer_type(struct dyesub_backend *backend, uint16_t idVendor, uint16_t idProduct)
+{
+ int i;
+ int type = P_UNKNOWN;
+
+ 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;
+}
+
/* Interface **MUST** already be claimed! */
#define ID_BUF_SIZE 2048
static char *get_device_id(struct libusb_device_handle *dev, int iface)
@@ -103,6 +141,9 @@ static char *get_device_id(struct libusb_device_handle *dev, int iface)
goto done;
}
+ /* IEEE1284 length field includs the header! */
+ length -= 2;
+
/* Move, and terminate */
memmove(buf, buf + 2, length);
buf[length] = '\0';
@@ -194,7 +235,7 @@ int read_data(struct libusb_device_handle *dev, uint8_t endp,
buf,
buflen,
readlen,
- 10000);
+ xfer_timeout);
if (ret < 0) {
ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, *readlen, buflen, endp);
@@ -227,7 +268,7 @@ done:
}
int send_data(struct libusb_device_handle *dev, uint8_t endp,
- uint8_t *buf, int len)
+ const uint8_t *buf, int len)
{
int num = 0;
@@ -236,10 +277,10 @@ int send_data(struct libusb_device_handle *dev, uint8_t endp,
}
while (len) {
- int len2 = (len > 65536) ? 65536: len;
+ int len2 = (len > max_xfer_size) ? max_xfer_size: len;
int ret = libusb_bulk_transfer(dev, endp,
- buf, len2,
- &num, 15000);
+ (uint8_t*) buf, len2,
+ &num, xfer_timeout);
if ((dyesub_debug > 1 && len < 4096) ||
dyesub_debug > 2) {
@@ -350,27 +391,29 @@ static char *url_decode(char *str) {
/* And now back to our regularly-scheduled programming */
-static int print_scan_output(struct libusb_device *device,
- struct libusb_device_descriptor *desc,
- char *prefix, char *manuf2,
- int found,
- int scan_only, char *match_serno,
- struct dyesub_backend *backend)
+static int probe_device(struct libusb_device *device,
+ struct libusb_device_descriptor *desc,
+ const char *uri_prefix,
+ const char *prefix, char *manuf_override,
+ int found, int num_claim_attempts,
+ int scan_only, char *match_serno,
+ uint8_t *r_iface, uint8_t *r_altset,
+ uint8_t *r_endp_up, uint8_t *r_endp_down,
+ struct dyesub_backend *backend)
{
struct libusb_device_handle *dev;
char buf[256];
char *product = NULL, *serial = NULL, *manuf = NULL, *descr = NULL;
- int iface = 0; // XXX loop through interfaces
- int altset = 0; // XXX loop through altsetting
+ uint8_t iface, altset;
struct libusb_config_descriptor *config = NULL;
int dlen = 0;
struct deviceid_dict dict[MAX_DICT];
char *ieee_id = NULL;
int i;
-
uint8_t endp_up, endp_down;
DEBUG("Probing VID: %04X PID: %04x\n", desc->idVendor, desc->idProduct);
+ STATE("+connecting-to-device\n");
if (libusb_open(device, &dev)) {
ERROR("Could not open device %04x:%04x (need to be root?)\n", desc->idVendor, desc->idProduct);
@@ -378,43 +421,86 @@ static int print_scan_output(struct libusb_device *device,
goto abort;
}
+ /* XXX FIXME: Iterate through possible configurations? */
+ if (libusb_get_active_config_descriptor(device, &config)) {
+ found = -1;
+ goto abort_close;
+ }
+
+ /* Loop through all interfaces and altsettings to find candidates */
+ for (iface = 0 ; iface < config->bNumInterfaces ; iface ++) {
+ for (altset = 0 ; altset < config->interface[iface].num_altsetting ; altset++) {
+ /* Skip interfaces that don't have enough endpoints */
+ if (config->interface[iface].altsetting[altset].bNumEndpoints < 2) {
+ continue;
+ }
+
+#if 0
+ // Make sure it's a printer class device that supports bidir comms (XXX Is this always true?)
+ if (desc->bDeviceClass == LIBUSB_CLASS_PRINTER ||
+ (desc->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE &&
+ config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER &&
+ config->interface[iface].altsetting[altset].bInterfaceSubClass == USB_SUBCLASS_PRINTER &&
+ config->interface[iface].altsetting[altset].bInterfaceProtocol != USB_INTERFACE_PROTOCOL_BIDIR)) {
+ continue;
+ }
+#endif
+
+ /* Find the first set of endpoints! */
+ endp_up = endp_down = 0;
+ for (i = 0 ; i < config->interface[iface].altsetting[altset].bNumEndpoints ; i++) {
+ if ((config->interface[iface].altsetting[altset].endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) {
+ if (config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
+ endp_up = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
+ else
+ endp_down = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
+ }
+ if (endp_up && endp_down)
+ goto candidate;
+ }
+ }
+ }
+
+ /* If we got here, we didn't find a match. */
+ found = -1;
+ goto abort_close;
+
+candidate:
+
+ /* We've now found an interface/altset we need to query in more detail */
+ /* Detach the kernel driver */
if (libusb_kernel_driver_active(dev, iface))
libusb_detach_kernel_driver(dev, iface);
- if (backend_claim_interface(dev, iface)) {
+ /* Claim the interface so we can start querying things! */
+ if (backend_claim_interface(dev, iface, num_claim_attempts)) {
found = -1;
- goto abort_close;
- }
-
- if (libusb_get_active_config_descriptor(device, &config)) {
- found = -1;
goto abort_release;
}
- /* Find the endpoints */
- endp_up = endp_down = 0;
- for (i = 0 ; i < config->interface[iface].altsetting[altset].bNumEndpoints ; i++) {
- if ((config->interface[iface].altsetting[altset].endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) {
- if (config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
- endp_up = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
- else
- endp_down = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
+ /* Use the appropriate altesetting, but only if the
+ printer supports more than one. Some printers don't like
+ us unconditionally setting this. */
+ if (config->interface[iface].num_altsetting > 1) {
+ if (libusb_set_interface_alt_setting(dev, iface, altset)) {
+ ERROR("Failed to set alternative interface %d/%d\n", iface, altset);
+ found = -1;
+ goto abort_release;
}
- if (endp_up && endp_down)
- break;
}
/* Query IEEE1284 info only if it's a PRINTER class */
if (desc->bDeviceClass == LIBUSB_CLASS_PRINTER ||
(desc->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE &&
- config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER)) {
+ config->interface[iface].altsetting[altset].bInterfaceClass == LIBUSB_CLASS_PRINTER &&
+ config->interface[iface].altsetting[altset].bInterfaceSubClass == USB_SUBCLASS_PRINTER)) {
ieee_id = get_device_id(dev, iface);
dlen = parse1284_data(ieee_id, dict);
}
/* Look up mfg string. */
- if (manuf2 && strlen(manuf2)) {
- manuf = url_encode(manuf2); /* Backend supplied */
+ if (manuf_override && strlen(manuf_override)) {
+ manuf = url_encode(manuf_override); /* Backend supplied */
} else if ((manuf = dict_find("MANUFACTURER", dlen, dict))) {
manuf = url_encode(manuf);
} else if ((manuf = dict_find("MFG", dlen, dict))) {
@@ -502,20 +588,27 @@ static int print_scan_output(struct libusb_device *device,
}
if (scan_only) {
- int k = 0;
+ if (!old_uri) {
+ fprintf(stdout, "direct %s://%s/%s \"%s\" \"%s\" \"%s\" \"\"\n",
+ prefix, uri_prefix, serial,
+ descr, descr,
+ ieee_id ? ieee_id : "");
+ } else {
+ int k = 0;
- /* URLify the manuf and model strings */
- strncpy(buf, manuf, sizeof(buf) - 2);
- k = strlen(buf);
- buf[k++] = '/';
- buf[k] = 0;
+ /* URLify the manuf and model strings */
+ strncpy(buf, manuf, sizeof(buf) - 2);
+ k = strlen(buf);
+ buf[k++] = '/';
+ buf[k] = 0;
- strncpy(buf + k, product, sizeof(buf)-k);
+ strncpy(buf + k, product, sizeof(buf)-k);
- fprintf(stdout, "direct %s://%s?serial=%s&backend=%s \"%s\" \"%s\" \"%s\" \"\"\n",
- prefix, buf, serial, backend->uri_prefix,
- descr, descr,
- ieee_id? ieee_id : "");
+ fprintf(stdout, "direct %s://%s?serial=%s&backend=%s \"%s\" \"%s\" \"%s\" \"\"\n",
+ prefix, buf, serial, uri_prefix,
+ descr, descr,
+ ieee_id? ieee_id : "");
+ }
}
/* If a serial number was passed down, use it. */
@@ -527,6 +620,13 @@ static int print_scan_output(struct libusb_device *device,
DEBUG("VID: %04X PID: %04X Manuf: '%s' Product: '%s' Serial: '%s' found: %d\n",
desc->idVendor, desc->idProduct, manuf, product, serial, found);
+ if (found != -1) {
+ if (r_iface) *r_iface = iface;
+ if (r_altset) *r_altset = altset;
+ if (r_endp_up) *r_endp_up = endp_up;
+ if (r_endp_up) *r_endp_down = endp_down;
+ }
+
/* Free things up */
if(serial) free(serial);
if(manuf) free(manuf);
@@ -534,8 +634,6 @@ static int print_scan_output(struct libusb_device *device,
if(descr) free(descr);
if(ieee_id) free(ieee_id);
- if (config) libusb_free_config_descriptor(config);
-
abort_release:
libusb_release_interface(dev, iface);
@@ -543,13 +641,18 @@ abort_release:
abort_close:
libusb_close(dev);
+
abort:
+ if (config) libusb_free_config_descriptor(config);
+
/* Clean up the dictionary */
while (dlen--) {
free (dict[dlen].key);
free (dict[dlen].val);
}
+ STATE("-connecting-to-device\n");
+
return found;
}
@@ -567,7 +670,8 @@ extern struct dyesub_backend mitsu70x_backend;
extern struct dyesub_backend mitsu9550_backend;
extern struct dyesub_backend mitsup95d_backend;
extern struct dyesub_backend dnpds40_backend;
-extern struct dyesub_backend cw01_backend;
+extern struct dyesub_backend magicard_backend;
+extern struct dyesub_backend mitsud90_backend;
static struct dyesub_backend *backends[] = {
&canonselphy_backend,
@@ -581,10 +685,11 @@ static struct dyesub_backend *backends[] = {
&shinkos6245_backend,
&updr150_backend,
&mitsu70x_backend,
+ &mitsud90_backend,
&mitsu9550_backend,
&mitsup95d_backend,
&dnpds40_backend,
- &cw01_backend,
+ &magicard_backend,
NULL,
};
@@ -592,11 +697,25 @@ static int find_and_enumerate(struct libusb_context *ctx,
struct libusb_device ***list,
struct dyesub_backend *backend,
char *match_serno,
- int scan_only)
+ int scan_only, int num_claim_attempts,
+ uint8_t *r_iface, uint8_t *r_altset,
+ uint8_t *r_endp_up, uint8_t *r_endp_down)
{
int num;
int i, j = 0, k;
int found = -1;
+ const char *prefix = NULL;
+
+ if (test_mode >= TEST_MODE_NOATTACH) {
+ found = 1;
+ *r_endp_up = 0x82;
+ *r_endp_down = 0x01;
+ *r_iface = 0;
+ *r_altset = 0;
+ return found;
+ }
+
+ STATE("+org.gutenprint-searching-for-device\n");
/* Enumerate and find suitable device */
num = libusb_get_device_list(ctx, list);
@@ -616,11 +735,14 @@ static int find_and_enumerate(struct libusb_context *ctx,
extra_vid == desc.idVendor &&
extra_pid == desc.idProduct) {
found = i;
+ prefix = backends[k]->uri_prefixes[0];
goto match;
}
}
if (desc.idVendor == backends[k]->devices[j].vid &&
- desc.idProduct == backends[k]->devices[j].pid) {
+ (desc.idProduct == backends[k]->devices[j].pid ||
+ desc.idProduct == 0xffff)) {
+ prefix = backends[k]->devices[j].prefix;
found = i;
goto match;
}
@@ -630,16 +752,19 @@ static int find_and_enumerate(struct libusb_context *ctx,
continue;
match:
- found = print_scan_output((*list)[i], &desc,
- URI_PREFIX, backends[k]->devices[j].manuf_str,
- found,
- scan_only, match_serno,
- backends[k]);
+ found = probe_device((*list)[i], &desc, prefix,
+ URI_PREFIX, backends[k]->devices[j].manuf_str,
+ found, num_claim_attempts,
+ scan_only, match_serno,
+ r_iface, r_altset,
+ r_endp_up, r_endp_down,
+ backends[k]);
if (found != -1 && !scan_only)
break;
}
+ STATE("-org.gutenprint-searching-for-device\n");
return found;
}
@@ -652,22 +777,46 @@ static struct dyesub_backend *find_backend(char *uri_prefix)
for (i = 0; ; i++) {
struct dyesub_backend *backend = backends[i];
+ const char **alias;
if (!backend)
return NULL;
- if (!strcmp(uri_prefix, backend->uri_prefix))
- return backend;
+ for (alias = backend->uri_prefixes ; alias && *alias ; alias++) {
+ if (!strcmp(uri_prefix, *alias))
+ return backend;
+ }
}
return NULL;
}
+static int query_markers(struct dyesub_backend *backend, void *ctx, int full)
+{
+ struct marker *markers = NULL;
+ int marker_count = 0;
+ int ret;
+
+ if (!backend->query_markers)
+ return CUPS_BACKEND_OK;
+
+ if (test_mode >= TEST_MODE_NOPRINT)
+ return CUPS_BACKEND_OK;
+
+ ret = backend->query_markers(ctx, &markers, &marker_count);
+ if (ret)
+ return ret;
+
+ dump_markers(markers, marker_count, full);
+
+ return CUPS_BACKEND_OK;
+}
+
void print_license_blurb(void)
{
const char *license = "\n\
-Copyright 2007-2017 Solomon Peachy <pizza AT shaftnet DOT org>\n\
+Copyright 2007-2018 Solomon Peachy <pizza AT shaftnet DOT org>\n\
\n\
This program is free software; you can redistribute it and/or modify it\n\
under the terms of the GNU General Public License as published by the Free\n\
-Software Foundation; either version 2 of the License, or (at your option)\n\
+Software Foundation; either version 3 of the License, or (at your option)\n\
any later version.\n\
\n\
This program is distributed in the hope that it will be useful, but\n\
@@ -676,8 +825,7 @@ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n\
for more details.\n\
\n\
You should have received a copy of the GNU General Public License\n\
-along with this program; if not, write to the Free Software\n\
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\
+along with this program. If not, see https://www.gnu.org/licenses/.\n\
\n [http://www.gnu.org/licenses/gpl-2.0.html]\n\n";
fprintf(stderr, "%s", license);
@@ -687,7 +835,6 @@ void print_help(char *argv0, struct dyesub_backend *backend)
{
struct libusb_context *ctx = NULL;
struct libusb_device **list = NULL;
- int i;
char *ptr = strrchr(argv0, '/');
if (ptr)
@@ -701,7 +848,7 @@ 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(" DYESUB_DEBUG EXTRA_PID EXTRA_VID EXTRA_TYPE BACKEND SERIAL OLD_URI_SCHEME\n");
DEBUG("CUPS Usage:\n");
DEBUG("\tDEVICE_URI=someuri %s job user title num-copies options [ filename ]\n", URI_PREFIX);
DEBUG("\n");
@@ -712,18 +859,30 @@ void print_help(char *argv0, struct dyesub_backend *backend)
DEBUG(" [ -d copies ] \n");
DEBUG(" [ - | infile ] \n");
for (i = 0; ; i++) {
+ const char **alias;
+
backend = backends[i];
if (!backend)
break;
- DEBUG(" BACKEND=%s\t# %s version %s\n",
- backend->uri_prefix, backend->name, backend->version);
+ DEBUG("\t# %s version %s\n",
+ backend->name, backend->version);
+ DEBUG(" BACKEND=");
+ for (alias = backend->uri_prefixes ; alias && *alias ; alias++)
+ DEBUG2("%s ", *alias);
+ DEBUG2("\n");
+
if (backend->cmdline_usage)
backend->cmdline_usage();
}
} else {
+ const char **alias;
DEBUG("Standalone %s backend version %s\n",
backend->name, backend->version);
- DEBUG("\t%s\n", backend->uri_prefix);
+ DEBUG("\t supporting: ");
+ for (alias = backend->uri_prefixes ; alias && *alias ; alias++)
+ DEBUG2("%s ", *alias);
+ DEBUG2("\n");
+
DEBUG("\t[ -D ] [ -G ] [ -f ]\n");
if (backend->cmdline_usage)
backend->cmdline_usage();
@@ -731,35 +890,67 @@ void print_help(char *argv0, struct dyesub_backend *backend)
}
/* 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, 1);
+ find_and_enumerate(ctx, &list, backend, NULL, 1, 1, NULL, NULL, NULL, NULL);
libusb_free_device_list(list, 1);
- libusb_exit(ctx);
}
+int parse_cmdstream(struct dyesub_backend *backend, void *backend_ctx, int fd)
+{
+ FILE *fp = stdin;
+ char line[128];
+ char *lp;
+
+ if (fd != fileno(stdin)) {
+ fp = fdopen(fd, "r");
+ if (!fp) {
+ ERROR("Can't open data stream!\n");
+ return CUPS_BACKEND_FAILED;
+ }
+ }
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ /* Strip trailing newline */
+ lp = line + strlen(line) - 1;
+ if (*lp == '\n')
+ *lp = '\0';
+ /* And leading spaces */
+ for (lp = line; isspace(*lp); lp++);
+ /* And comments and blank lines */
+ if (*lp == '#' || !*lp)
+ continue;
+
+ /* Parse command! */
+ if (strncasecmp(lp, "ReportLevels", 12) == 0) {
+ query_markers(backend, backend_ctx, 1);
+/* XXX TODO: ReportStatus, AutoConfigure, PrintSelfTestPage? What about others, eg reset or cancel job? */
+ } else {
+ WARNING("Invalid printer command \"%s\"!\n", lp);
+ }
+ }
+
+ /* Clean up */
+ if (fp != stdin)
+ fclose(fp);
+
+ return CUPS_BACKEND_OK;
+};
+
int main (int argc, char **argv)
{
struct libusb_context *ctx = NULL;
struct libusb_device **list = NULL;
struct libusb_device_handle *dev;
- struct libusb_config_descriptor *config = NULL;
struct dyesub_backend *backend = NULL;
void * backend_ctx = NULL;
uint8_t endp_up, endp_down;
-
- int iface = 0; // XXX loop through interfaces
- int altset = 0; // XXX loop through altsetting
+ uint8_t iface, altset;
int data_fd = fileno(stdin);
+ const void *job = NULL;
+
int i;
- int claimed;
int ret = CUPS_BACKEND_OK;
@@ -768,12 +959,14 @@ int main (int argc, char **argv)
int current_page = 0;
char *uri;
+ char *type;
char *fname = NULL;
char *use_serno = NULL;
+ int printer_type;
DEBUG("Multi-Call Dye-sublimation CUPS Backend version %s\n",
BACKEND_VERSION);
- DEBUG("Copyright 2007-2016 Solomon Peachy\n");
+ DEBUG("Copyright 2007-2018 Solomon Peachy\n");
DEBUG("This free software comes with ABSOLUTELY NO WARRANTY! \n");
DEBUG("Licensed under the GNU GPL. Run with '-G' for more details.\n");
DEBUG("\n");
@@ -784,15 +977,30 @@ int main (int argc, char **argv)
if (getenv("EXTRA_PID"))
extra_pid = strtol(getenv("EXTRA_PID"), NULL, 16);
if (getenv("EXTRA_VID"))
- extra_pid = strtol(getenv("EXTRA_VID"), NULL, 16);
- if (getenv("EXTRA_PID"))
+ extra_vid = strtol(getenv("EXTRA_VID"), NULL, 16);
+ if (getenv("EXTRA_TYPE"))
extra_type = atoi(getenv("EXTRA_TYPE"));
if (getenv("BACKEND"))
backend = find_backend(getenv("BACKEND"));
if (getenv("FAST_RETURN"))
fast_return++;
+ if (getenv("MAX_XFER_SIZE"))
+ max_xfer_size = atoi(getenv("MAX_XFER_SIZE"));
+ if (getenv("XFER_TIMEOUT"))
+ xfer_timeout = atoi(getenv("XFER_TIMEOUT"));
+ if (getenv("TEST_MODE"))
+ test_mode = atoi(getenv("TEST_MODE"));
+ if (getenv("OLD_URI_SCHEME"))
+ old_uri = atoi(getenv("OLD_URI_SCHEME"));
+
+ if (test_mode >= TEST_MODE_NOATTACH && (extra_vid == -1 || extra_pid == -1)) {
+ ERROR("Must specify EXTRA_VID, EXTRA_PID in test mode > 1!\n");
+ exit(1);
+ }
+
use_serno = getenv("SERIAL");
- uri = getenv("DEVICE_URI"); /* CUPS backend mode? */
+ uri = getenv("DEVICE_URI"); /* CUPS backend mode! */
+ type = getenv("FINAL_CONTENT_TYPE"); /* CUPS content type -- ie raster or command */
if (uri) {
/* CUPS backend mode */
@@ -812,35 +1020,52 @@ int main (int argc, char **argv)
/* Figure out backend based on URI */
{
- char *ptr = strstr (uri, "backend="), *ptr2;
- if (!ptr) {
- ERROR("Invalid URI prefix (%s)\n", uri);
- exit(1);
- }
- ptr += 8;
- ptr2 = strchr(ptr, '&');
- if (ptr2)
- *ptr2 = 0;
+ char *ptr = strstr(uri, "backend="), *ptr2;
+ if (ptr) { /* Original format */
+ ptr += 8;
+ ptr2 = strchr(ptr, '&');
+ if (ptr2)
+ *ptr2 = 0;
+
+ backend = find_backend(ptr);
+ if (!backend) {
+ ERROR("Invalid backend (%s)\n", ptr);
+ exit(1);
+ }
+ if (ptr2)
+ *ptr2 = '&';
- backend = find_backend(ptr);
- if (!backend) {
- ERROR("Invalid backend (%s)\n", ptr);
- exit(1);
- }
- if (ptr2)
- *ptr2 = '&';
- }
+ use_serno = strchr(uri, '=');
+ if (!use_serno || !*(use_serno+1)) {
+ ERROR("Invalid URI (%s)\n", uri);
+ exit(1);
+ }
+ use_serno++;
+ ptr = strchr(use_serno, '&');
+ if (ptr)
+ *ptr = 0;
+ } else { /* New format */
+ // prefix://backend/serno
+ ptr = strchr(uri, '/');
+ ptr += 2;
+ use_serno = strchr(ptr, '/');
+ if (!use_serno || !*(use_serno+1)) {
+ ERROR("Invalid URI (%s)\n", uri);
+ exit(1);
+ }
+ *use_serno = 0;
+ use_serno++;
- use_serno = strchr(uri, '=');
- if (!use_serno || !*(use_serno+1)) {
- ERROR("Invalid URI (%s)\n", uri);
- exit(1);
- }
- use_serno++;
- {
- char *ptr = strchr(use_serno, '&');
- if (ptr)
- *ptr = 0;
+ backend = find_backend(ptr);
+ if (!backend) {
+ ERROR("Invalid backend (%s)\n", ptr);
+ exit(1);
+ }
+
+ ptr = strchr(ptr, '?');
+ if (ptr)
+ *ptr = 0;
+ }
}
/* Always enable fast return in CUPS mode */
@@ -875,86 +1100,111 @@ int main (int argc, char **argv)
ret = libusb_init(&ctx);
if (ret) {
ERROR("Failed to initialize libusb (%d)\n", ret);
- ret = CUPS_BACKEND_STOP;
+ ret = CUPS_BACKEND_RETRY_CURRENT;
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);
+ ret = CUPS_BACKEND_OK;
+ goto done;
}
/* 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);
+ ret = CUPS_BACKEND_OK;
+ goto done;
}
}
/* Enumerate devices */
- found = find_and_enumerate(ctx, &list, backend, use_serno, 0);
+ found = find_and_enumerate(ctx, &list, backend, use_serno, 0, NUM_CLAIM_ATTEMPTS, &iface, &altset, &endp_up, &endp_down);
if (found == -1) {
ERROR("Printer open failure (No matching printers found!)\n");
- ret = CUPS_BACKEND_HOLD;
+ ret = CUPS_BACKEND_RETRY;
goto done;
}
+ if (test_mode) {
+ WARNING("**** TEST MODE %d!\n", test_mode);
+ if (test_mode >= TEST_MODE_NOATTACH)
+ goto bypass;
+ }
+
/* Open an appropriate device */
ret = libusb_open(list[found], &dev);
if (ret) {
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
- ret = CUPS_BACKEND_STOP;
+ ret = CUPS_BACKEND_RETRY_CURRENT;
goto done;
}
- claimed = libusb_kernel_driver_active(dev, iface);
- if (claimed) {
+ /* Detach the kernel driver */
+ if (libusb_kernel_driver_active(dev, iface)) {
ret = libusb_detach_kernel_driver(dev, iface);
if (ret) {
ERROR("Printer open failure (Could not detach printer from kernel) (%d)\n", ret);
- ret = CUPS_BACKEND_STOP;
+ ret = CUPS_BACKEND_RETRY_CURRENT;
goto done_close;
}
}
- ret = backend_claim_interface(dev, iface);
+ /* Claim the interface so we can start using this! */
+ ret = backend_claim_interface(dev, iface, NUM_CLAIM_ATTEMPTS);
if (ret) {
- ret = CUPS_BACKEND_STOP;
+ ERROR("Printer open failure (Unable to claim interface) (%d)\n", ret);
+ ret = CUPS_BACKEND_RETRY;
goto done_close;
}
- ret = libusb_get_active_config_descriptor(list[found], &config);
- if (ret) {
- ERROR("Printer open failure (Could not fetch config descriptor) (%d)\n", ret);
- ret = CUPS_BACKEND_STOP;
- goto done_close;
- }
-
- endp_up = endp_down = 0;
- for (i = 0 ; i < config->interface[iface].altsetting[altset].bNumEndpoints ; i++) {
- if ((config->interface[iface].altsetting[altset].endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_BULK) {
- if (config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
- endp_up = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
- else
- endp_down = config->interface[iface].altsetting[altset].endpoint[i].bEndpointAddress;
+ /* Use the appropriate altesetting! */
+ if (altset != 0) {
+ ret = libusb_set_interface_alt_setting(dev, iface, altset);
+ if (ret) {
+ ERROR("Printer open failure (Unable to issue altsettinginterface) (%d)\n", ret);
+ ret = CUPS_BACKEND_RETRY;
+ goto done_close;
}
- if (endp_up && endp_down)
- break;
}
- if (config)
- libusb_free_config_descriptor(config);
-
+bypass:
/* Initialize backend */
DEBUG("Initializing '%s' backend (version %s)\n",
backend->name, backend->version);
backend_ctx = backend->init();
+ if (test_mode < TEST_MODE_NOATTACH) {
+ struct libusb_device *device;
+ struct libusb_device_descriptor desc;
+
+ device = libusb_get_device(dev);
+ libusb_get_device_descriptor(device, &desc);
+
+ printer_type = lookup_printer_type(backend,
+ desc.idVendor, desc.idProduct);
+ } else {
+ printer_type = lookup_printer_type(backend,
+ extra_vid, extra_pid);
+ }
+
+ if (printer_type <= P_UNKNOWN) {
+ ERROR("Unable to lookup printer type\n");
+ ret = CUPS_BACKEND_FAILED;
+ goto done_close;
+ }
+
/* Attach backend to device */
- backend->attach(backend_ctx, dev, endp_up, endp_down, jobid);
+ if (backend->attach(backend_ctx, dev, printer_type, endp_up, endp_down, jobid)) {
+ ERROR("Unable to attach to printer!");
+ ret = CUPS_BACKEND_FAILED;
+ goto done_close;
+ }
+
+// STATE("+org.gutenprint-attached-to-device\n");
if (!uri) {
if (backend->cmdline_arg(backend_ctx, argc, argv) < 0)
@@ -975,7 +1225,8 @@ int main (int argc, char **argv)
data_fd = open(fname, O_RDONLY);
if (data_fd < 0) {
perror("ERROR:Can't open input file");
- exit(1);
+ ret = CUPS_BACKEND_FAILED;
+ goto done;
}
}
@@ -983,13 +1234,15 @@ int main (int argc, char **argv)
i = fcntl(data_fd, F_GETFL, 0);
if (i < 0) {
perror("ERROR:Can't open input");
- exit(1);
+ ret = CUPS_BACKEND_FAILED;
+ goto done;
}
i &= ~O_NONBLOCK;
i = fcntl(data_fd, F_SETFL, i);
if (i < 0) {
perror("ERROR:Can't open input");
- exit(1);
+ ret = CUPS_BACKEND_FAILED;
+ goto done;
}
/* Ignore SIGPIPE */
@@ -999,19 +1252,52 @@ int main (int argc, char **argv)
/* Time for the main processing loop */
INFO("Printing started (%d copies)\n", copies);
+ /* See if it's a CUPS command stream, and if yes, handle it! */
+ if (type && !strcmp("application/vnd.cups-command", type))
+ {
+ ret = parse_cmdstream(backend, backend_ctx, data_fd);
+ goto done_claimed;
+ }
+
newpage:
/* Read in data */
- if ((ret = backend->read_parse(backend_ctx, data_fd))) {
+ if ((ret = backend->read_parse(backend_ctx, &job, data_fd, copies))) {
if (current_page)
goto done_multiple;
else
goto done_claimed;
}
+ /* The backend parser might not return a job due to job dependencies.
+ Try and read another page. */
+ if (!job)
+ goto newpage;
+
+ /* Create our own joblist if necessary */
+ if (!(backend->flags & BACKEND_FLAG_JOBLIST)) {
+ struct dyesub_joblist *list = dyesub_joblist_create(backend, backend_ctx);
+ if (!list)
+ goto done_claimed;
+ dyesub_joblist_addjob(list, job);
+ job = list;
+ }
+
+ /* Dump the full marker dump */
+ ret = query_markers(backend, backend_ctx, !current_page);
+ if (ret)
+ goto done_claimed;
+
INFO("Printing page %d\n", ++current_page);
- ret = backend->main_loop(backend_ctx, copies);
+ if (test_mode >= TEST_MODE_NOPRINT ) {
+ WARNING("**** TEST MODE, bypassing printing!\n");
+ } else {
+ ret = dyesub_joblist_print(job);
+ }
+
+ dyesub_joblist_cleanup(job);
+
if (ret)
goto done_claimed;
@@ -1019,6 +1305,11 @@ newpage:
if (!uri)
PAGE("%d %d\n", current_page, copies);
+ /* Dump a marker status update */
+ ret = query_markers(backend, backend_ctx, !current_page);
+ if (ret)
+ goto done_claimed;
+
/* Since we have no way of telling if there's more data remaining
to be read (without actually trying to read it), always assume
multiple print jobs. */
@@ -1033,49 +1324,113 @@ done_multiple:
ret = CUPS_BACKEND_OK;
done_claimed:
- libusb_release_interface(dev, iface);
+ if (test_mode < TEST_MODE_NOATTACH)
+ libusb_release_interface(dev, iface);
done_close:
-#if 0
- if (claimed)
- libusb_attach_kernel_driver(dev, iface);
-#endif
- libusb_close(dev);
+ if (test_mode < TEST_MODE_NOATTACH)
+ libusb_close(dev);
done:
- if (backend && backend_ctx)
+ if (backend && backend_ctx) {
backend->teardown(backend_ctx);
+// STATE("-org.gutenprint-attached-to-device");
+ }
if (list)
libusb_free_device_list(list, 1);
- if (ctx)
- libusb_exit(ctx);
+
+ libusb_exit(ctx);
return ret;
}
-int lookup_printer_type(struct dyesub_backend *backend, uint16_t idVendor, uint16_t idProduct)
+void dump_markers(struct marker *markers, int marker_count, int full)
{
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 (!full)
+ goto minimal;
+
+ ATTR("marker-colors=");
+ for (i = 0 ; i < marker_count; i++) {
+ DEBUG2(markers[i].color);
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+ ATTR("marker-high-levels=");
+ for (i = 0 ; i < marker_count; i++) {
+ DEBUG2("%d", 100);
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+ ATTR("marker-low-levels=");
+ for (i = 0 ; i < marker_count; i++) {
+ DEBUG2("%d", 10);
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+ ATTR("marker-names=");
+ for (i = 0 ; i < marker_count; i++) {
+ DEBUG2("'\"%s\"'", markers[i].name);
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+ ATTR("marker-types=");
+ for (i = 0 ; i < marker_count; i++) {
+ DEBUG2("ribbonWax");
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+minimal:
+ ATTR("marker-levels=");
+ for (i = 0 ; i < marker_count; i++) {
+ int val;
+ if (markers[i].levelmax <= 0 || markers[i].levelnow < 0)
+ val = (markers[i].levelnow <= 0) ? markers[i].levelnow : -1;
+ else if (markers[i].levelmax == 100)
+ val = markers[i].levelnow;
+ else
+ val = markers[i].levelnow * 100 / markers[i].levelmax;
+ DEBUG2("%d", val);
+ if ((i+1) < marker_count)
+ DEBUG2(",");
+ }
+ DEBUG2("\n");
+
+ /* Only dump a message if the marker is not a percentage */
+ if (markers[0].levelmax != 100) {
+ ATTR("marker-message=");
+ for (i = 0 ; i < marker_count; i++) {
+ switch (markers[i].levelnow) {
+ case -1:
+ DEBUG2("'\"Unable to query remaining prints on %s media\"'", markers[i].name);
+ break;
+ case -2:
+ DEBUG2("'\"Unknown remaining prints on %s media\"'", markers[i].name);
+ break;
+ case -3:
+ DEBUG2("'\"One or more remaining prints on %s media\"'", markers[i].name);
+ break;
+ default:
+ DEBUG2("'\"%d native prints remaining on %s media\"'", markers[i].levelnow, markers[i].name);
+ break;
}
+ if ((i+1) < marker_count)
+ DEBUG2(",");
}
- if (idVendor == backend->devices[i].vid &&
- idProduct == backend->devices[i].pid) {
- return backend->devices[i].type;
- }
+ DEBUG2("\n");
}
-
- return type;
}
uint16_t uint16_to_packed_bcd(uint16_t val)
@@ -1112,3 +1467,66 @@ uint32_t packed_bcd_to_uint32(char *in, int len)
}
return out;
}
+
+/* Job list manipulation */
+struct dyesub_joblist *dyesub_joblist_create(struct dyesub_backend *backend, void *ctx)
+{
+ struct dyesub_joblist *list;
+
+ list = malloc(sizeof(struct dyesub_joblist));
+ if (!list) {
+ ERROR("Memory allocation failure\n");
+ return NULL;
+ }
+ list->backend = backend;
+ list->ctx = ctx;
+ list->num_entries = 0;
+ list->copies = 1;
+
+ return list;
+}
+
+void dyesub_joblist_cleanup(const struct dyesub_joblist *list)
+{
+ int i;
+ for (i = 0; i < list->num_entries ; i++) {
+ if (list->entries[i])
+ list->backend->cleanup_job(list->entries[i]);
+ }
+ free((void*)list);
+}
+
+int dyesub_joblist_addjob(struct dyesub_joblist *list, const void *job)
+{
+ if (list->num_entries >= DYESUB_MAX_JOB_ENTRIES)
+ return 1;
+
+ list->entries[list->num_entries++] = job;
+
+ return 0;
+}
+
+int dyesub_joblist_print(const struct dyesub_joblist *list)
+{
+ int i, j;
+ int ret;
+ for (i = 0 ; i < list->copies ; i++) {
+ for (j = 0 ; j < list->num_entries ; j++) {
+ if (list->entries[j]) {
+ ret = list->backend->main_loop(list->ctx, list->entries[j]);
+ if (ret)
+ return ret;
+
+#if 0
+ /* Free up the job as we go along
+ if we're on the final copy */
+ if (i + 1 == list->copies) {
+ list->backend->cleanup_job(list->entries[j]);
+ list->entries[j] = NULL;
+ }
+#endif
+ }
+ }
+ }
+ return CUPS_BACKEND_OK;
+}
diff --git a/src/cups/backend_common.h b/src/cups/backend_common.h
index 4e489fc..3fd58db 100644
--- a/src/cups/backend_common.h
+++ b/src/cups/backend_common.h
@@ -1,7 +1,7 @@
/*
* CUPS Backend common code
*
- * (c) 2013-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -87,46 +88,51 @@
/* To enumerate supported devices */
enum {
- P_ANY = 0,
- P_ES1,
- P_ES2_20,
- P_ES3_30,
- P_ES40,
- P_CP790,
- P_CP_XXX,
- P_CP10,
- P_CP910,
- P_KODAK_6800,
- P_KODAK_6850,
- P_KODAK_1400_805,
- P_KODAK_605,
- P_KODAK_305,
- P_SHINKO_S2145,
- P_SHINKO_S1245,
- P_SHINKO_S6245,
- P_SHINKO_S6145,
- P_SHINKO_S6145D,
- P_SONY_UPDR150,
- P_SONY_UPCR10,
- P_MITSU_D70X,
- P_MITSU_D80,
- P_MITSU_K60,
- P_MITSU_9550,
- P_MITSU_9550S,
- P_MITSU_9600,
- P_MITSU_9800,
- P_MITSU_9800S,
- P_MITSU_9810,
- P_MITSU_P93D,
- P_MITSU_P95D,
- P_DNP_DS40,
- P_DNP_DS80,
- P_DNP_DS80D,
- P_CITIZEN_CW01,
- P_DNP_DSRX1,
- P_DNP_DS620,
- P_DNP_DS820,
- P_FUJI_ASK300,
+ P_UNKNOWN = 0,
+ P_CP_XXX = 1,
+ P_CP10 = 2,
+ P_CP790 = 3,
+ P_CP900 = 4,
+ P_CP910 = 5,
+ P_ES1 = 6,
+ P_ES2_20 = 7,
+ P_ES3_30 = 8,
+ P_ES40 = 9,
+ P_KODAK_1400_805 = 10,
+ P_KODAK_6800 = 11,
+ P_KODAK_6850 = 12,
+ P_KODAK_305 = 13,
+ P_KODAK_605 = 14,
+ P_SHINKO_S1245 = 15,
+ P_SHINKO_S2145 = 16,
+ P_SHINKO_S6145 = 17,
+ P_SHINKO_S6145D = 18,
+ P_SHINKO_S6245 = 19,
+ P_SONY_UPCR10 = 20,
+ P_SONY_UPDR150 = 21,
+ P_MITSU_9550 = 22,
+ P_MITSU_9550S = 23,
+ P_MITSU_9600 = 24,
+ P_MITSU_9800 = 25,
+ P_MITSU_9800S = 26,
+ P_MITSU_9810 = 27,
+ P_MITSU_D70X = 28,
+ P_MITSU_D80 = 29,
+ P_MITSU_D90 = 30,
+ P_MITSU_K60 = 31,
+ P_MITSU_P93D = 32,
+ P_MITSU_P95D = 33,
+ P_CITIZEN_CW01 = 34,
+ P_CITIZEN_OP900II = 35,
+ P_DNP_DS40 = 36,
+ P_DNP_DS620 = 37,
+ P_DNP_DS80 = 38,
+ P_DNP_DS80D = 39,
+ P_DNP_DS820 = 40,
+ P_DNP_DSRX1 = 41,
+ P_FUJI_ASK300 = 42,
+ P_MAGICARD = 43,
+ P_SONY_UPD89x = 44,
P_END,
};
@@ -135,31 +141,56 @@ struct device_id {
uint16_t pid;
int type; /* P_** */
char *manuf_str;
+ char *prefix;
+};
+
+struct marker {
+ const char *color; /* Eg "#00FFFF" */
+ const char *name; /* Eg "CK9015 (4x6)" */
+ int levelmax; /* Max media count, eg '600', or '-1' */
+ int levelnow; /* Remaining media, -3, -2, -1, 0..N. See CUPS. */
};
+#define BACKEND_FLAG_JOBLIST 0x00000001
+
/* Backend Functions */
struct dyesub_backend {
- char *name;
- char *version;
- char *uri_prefix;
+ const char *name;
+ const char *version;
+ const char **uri_prefixes;
+ uint32_t flags;
void (*cmdline_usage)(void); /* Optional */
void *(*init)(void);
- void (*attach)(void *ctx, struct libusb_device_handle *dev,
+ int (*attach)(void *ctx, struct libusb_device_handle *dev, int type,
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 (*read_parse)(void *ctx, int data_fd);
- int (*main_loop)(void *ctx, int copies);
+ int (*read_parse)(void *ctx, const void **job, int data_fd, int copies);
+ void (*cleanup_job)(const void *job);
+ int (*main_loop)(void *ctx, const void *job);
int (*query_serno)(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len); /* Optional */
- struct device_id devices[];
+ int (*query_markers)(void *ctx, struct marker **markers, int *count);
+ const struct device_id devices[];
+};
+
+#define DYESUB_MAX_JOB_ENTRIES 2
+
+struct dyesub_joblist {
+ // TODO: mutex/lock
+ struct dyesub_backend *backend;
+ void *ctx;
+ int num_entries;
+ int copies;
+ const void *entries[DYESUB_MAX_JOB_ENTRIES];
};
/* Exported functions */
int send_data(struct libusb_device_handle *dev, uint8_t endp,
- uint8_t *buf, int len);
+ const 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);
+
+void dump_markers(struct marker *markers, int marker_count, int full);
void print_license_blurb(void);
void print_help(char *argv0, struct dyesub_backend *backend);
@@ -167,6 +198,12 @@ void print_help(char *argv0, struct dyesub_backend *backend);
uint16_t uint16_to_packed_bcd(uint16_t val);
uint32_t packed_bcd_to_uint32(char *in, int len);
+/* Job list manipulation */
+struct dyesub_joblist *dyesub_joblist_create(struct dyesub_backend *backend, void *ctx);
+int dyesub_joblist_addjob(struct dyesub_joblist *list, const void *job);
+void dyesub_joblist_cleanup(const struct dyesub_joblist *list);
+int dyesub_joblist_print(const struct dyesub_joblist *list);
+
/* Global data */
extern int terminate;
extern int dyesub_debug;
@@ -175,6 +212,14 @@ extern int extra_vid;
extern int extra_pid;
extern int extra_type;
extern int copies;
+extern int test_mode;
+
+enum {
+ TEST_MODE_NONE = 0,
+ TEST_MODE_NOPRINT,
+ TEST_MODE_NOATTACH,
+ TEST_MODE_MAX,
+};
#if defined(BACKEND)
extern struct dyesub_backend BACKEND;
diff --git a/src/cups/backend_dnpds40.c b/src/cups/backend_dnpds40.c
index 0484eb9..b9ed3e4 100644
--- a/src/cups/backend_dnpds40.c
+++ b/src/cups/backend_dnpds40.c
@@ -1,7 +1,7 @@
/*
- * DNP DS40/DS80 Photo Printer CUPS backend -- libusb-1.0 version
+ * Citizen / DNP Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@@ -24,14 +24,16 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
//#define DNP_ONLY
+//#define CITIZEN_ONLY
/* Enables caching of last print type to speed up
job pipelining. Without this we always have to
@@ -52,19 +54,22 @@
#include "backend_common.h"
-#define USB_VID_CITIZEN 0x1343
-#define USB_PID_DNP_DS40 0x0003 // Also Citizen CX
-#define USB_PID_DNP_DS80 0x0004 // Also Citizen CX-W, and Mitsubishi CP-3800DW
-#define USB_PID_DNP_DSRX1 0x0005 // Also Citizen CY
-#define USB_PID_CITIZEN_CW02 0x0006
-#define USB_PID_DNP_DS80D 0x0007
-#define USB_PID_DNP_DS620_OLD 0x0008
+/* Private data structure */
+struct dnpds40_printjob {
+ uint8_t *databuf;
+ int datalen;
-#define USB_VID_DNP 0x1452
-#define USB_PID_DNP_DS620 0x8b01
-#define USB_PID_DNP_DS820 0x9001
+ int copies;
+ uint32_t dpi;
+ int matte;
+ int cutter;
+ uint32_t multicut;
+ int fullcut;
+ int printspeed;
+ int can_rewind;
+ int buf_needed;
+};
-/* Private data structure */
struct dnpds40_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
@@ -72,34 +77,29 @@ struct dnpds40_ctx {
int type;
+ /* Version and whatnot */
char *serno;
char *version;
-
- int buf_needed;
-
int ver_major;
int ver_minor;
+ /* State */
uint32_t media;
uint32_t duplex_media;
uint16_t media_count_new;
- uint32_t multicut;
uint32_t last_multicut;
int last_matte;
- int fullcut;
- int matte;
- int cutter;
- int can_rewind;
-
- int printspeed;
-
int mediaoffset;
- int manual_copies;
int correct_count;
+ int needs_mlot;
+
+ struct marker marker;
+ /* Printer capabilities */
uint32_t native_width;
+ uint32_t max_height;
int supports_6x9;
int supports_2x6;
int supports_3x5x2;
@@ -123,8 +123,6 @@ struct dnpds40_ctx {
int supports_lowspeed;
int supports_highdensity;
int supports_gamma;
- uint8_t *databuf;
- int datalen;
};
struct dnpds40_cmd {
@@ -197,6 +195,198 @@ struct dnpds40_cmd {
#define min(__x, __y) ((__x) < (__y)) ? __x : __y
+/* Legacy CW-01 spool file support */
+struct cw01_spool_hdr {
+ uint8_t type; /* 0x00 -> 0x06 */
+ uint8_t res; /* vertical resolution; 0x00 == 334dpi, 0x01 == 600dpi */
+ uint8_t copies; /* number of prints */
+ uint8_t null0;
+ uint32_t plane_len; /* LE */
+ uint8_t null1[4];
+};
+
+#define DPI_334 0
+#define DPI_600 1
+
+#define TYPE_DSC 0
+#define TYPE_L 1
+#define TYPE_PC 2
+#define TYPE_2DSC 3
+#define TYPE_3L 4
+#define TYPE_A5 5
+#define TYPE_A6 6
+/* Legacy CW-01 spool file support */
+
+static int cw01_read_parse(struct dnpds40_printjob *job, int data_fd,
+ struct cw01_spool_hdr *hdr, int read_data);
+static void dnpds40_cleanup_job(const void *vjob);
+
+#define JOB_EQUIV(__x) if (job1->__x != job2->__x) goto done
+
+static struct dnpds40_printjob *combine_jobs(const struct dnpds40_printjob *job1,
+ const struct dnpds40_printjob *job2)
+{
+ struct dnpds40_printjob *newjob = NULL;
+ uint32_t new_multicut;
+ uint16_t new_w, new_h;
+ uint16_t gap_bytes;
+
+ /* Sanity check */
+ if (!job1 || !job2)
+ goto done;
+
+ /* Make sure pertinent paremeters are the same */
+ JOB_EQUIV(dpi);
+ JOB_EQUIV(matte);
+ JOB_EQUIV(cutter);
+ JOB_EQUIV(fullcut);
+ JOB_EQUIV(multicut); // TODO: Support fancier modes for 8" models (eg 8x4+8x6, etc)
+ JOB_EQUIV(datalen); // <-- cheating a little?
+ // JOV_EQUIV(printspeed); <-- does it matter?
+
+ /* Any cutter means we shouldn't bother */
+ if (job1->fullcut || job1->cutter)
+ goto done;
+
+#if 0
+ // XXX TODO: 2x6*2 + 2x6*2 --> 8x6+cutter!
+ // problem is that 8x6" size is 4 rows smaller than 2* 4x6" prints, posing a problem.
+
+ /* Only handle cutter if it's for 2x6" strips */
+ if (job1->cutter != 0 && job1->cutter != 120)
+ goto done;
+#endif
+
+ /* Make sure we can combine these two prints */
+ switch (job1->multicut) {
+ case MULTICUT_5x3_5:
+ new_multicut = MULTICUT_5x3_5X2;
+ new_w = 1920;
+ new_h = 2176;
+ gap_bytes = 0;
+ break;
+ case MULTICUT_6x4:
+#if 0
+ if (job1->cutter != 120) {
+ new_multicut = MULTICUT_6x8;
+ new_h = 2436;
+ gap_bytes = -4;
+ } else {
+#endif
+ new_multicut = MULTICUT_6x4X2;
+ new_h = 2498;
+ gap_bytes = 18;
+#if 0
+ }
+#endif
+ new_w = 1920;
+ break;
+ case MULTICUT_6x4_5:
+ new_multicut = MULTICUT_6x4_5X2;
+ new_w = 1920;
+ new_h = 2802;
+ gap_bytes = 30;
+ break;
+ case MULTICUT_8x4:
+ new_multicut = MULTICUT_8x4X2;
+ new_w = 2560;
+ new_h = 2502;
+ gap_bytes = 30;
+ break;
+ case MULTICUT_8x5:
+ new_multicut = MULTICUT_8x5X2;
+ new_w = 2560;
+ new_h = 3102;
+ gap_bytes = 30;
+ break;
+ case MULTICUT_8x6:
+ new_multicut = MULTICUT_8x6X2;
+ new_w = 2560;
+ new_h = 3702;
+ gap_bytes = 30;
+ break;
+ default:
+ // 2-up 8x6 prints too?
+ /* Everything else is NOT handled */
+ goto done;
+ }
+ gap_bytes *= new_w;
+ if (job1->dpi == 600) {
+ gap_bytes *= 2;
+ new_h *= 2;
+ }
+
+ DEBUG("Combining jobs to save media\n");
+
+ /* Okay, it's kosher to proceed */
+
+ newjob = malloc(sizeof(*newjob));
+ if (!newjob) {
+ ERROR("Memory allocation failure!\n");
+ goto done;
+ }
+ memcpy(newjob, job1, sizeof(*newjob));
+
+ newjob->databuf = malloc(((new_w*new_h+1024+54+10))*3+1024);
+ newjob->datalen = 0;
+ newjob->multicut = new_multicut;
+ if (!newjob->databuf) {
+ dnpds40_cleanup_job(newjob);
+ newjob = NULL;
+ ERROR("Memory allocation failure!\n");
+ goto done;
+ }
+
+ /* Copy data blocks from job1 */
+ uint8_t *ptr, *ptr2;
+ char buf[9];
+ ptr = job1->databuf;
+ while(ptr && ptr < (job1->databuf + job1->datalen)) {
+ int i;
+ buf[8] = 0;
+ memcpy(buf, ptr + 24, 8);
+ i = atoi(buf) + 32;
+ memcpy(newjob->databuf + newjob->datalen, ptr, i);
+
+ /* If we're on a plane data block... */
+ if (!memcmp("PLANE", newjob->databuf + newjob->datalen + 9, 5)) {
+ long planelen = (new_w * new_h) + 1088;
+ uint32_t newlen;
+
+ /* Fix up length in command */
+ snprintf(buf, sizeof(buf), "%08ld", planelen);
+ memcpy(newjob->databuf + newjob->datalen + 24, buf, 8);
+
+ /* Alter BMP header */
+ newlen = cpu_to_le32(planelen);
+ memcpy(newjob->databuf + newjob->datalen + 32 + 2, &newlen, 4);
+
+ /* alter DIB header */
+ newlen = cpu_to_le32(new_h);
+ memcpy(newjob->databuf + newjob->datalen + 32 + 22, &newlen, 4);
+
+ /* Insert gap/padding after first image */
+ memset(newjob->databuf + newjob->datalen + i, 0, gap_bytes);
+ newjob->datalen += gap_bytes;
+
+ // locate job2's PLANE properly? Assumption is it's in the same place.
+ ptr2 = job2->databuf + (ptr - job1->databuf);
+ /* Copy over job2's image data */
+ memcpy(newjob->databuf + newjob->datalen + i,
+ ptr2 + 32 + 1088, i - 32 - 1088);
+ newjob->datalen += i - 32 - 1088; /* add in job2 length */
+ }
+
+ newjob->datalen += i;
+ ptr += i;
+ }
+
+done:
+ return newjob;
+}
+
+#undef JOB_EQUIV
+
static void dnpds40_build_cmd(struct dnpds40_cmd *cmd, char *arg1, char *arg2, uint32_t arg3_len)
{
memset(cmd, 0x20, sizeof(*cmd));
@@ -238,6 +428,8 @@ static char *dnpds40_printer_type(int type)
case P_DNP_DSRX1: return "DSRX1";
case P_DNP_DS620: return "DS620";
case P_DNP_DS820: return "DS820";
+ case P_CITIZEN_CW01: return "CW01";
+ case P_CITIZEN_OP900II: return "OP900ii";
default: break;
}
return "Unknown";
@@ -518,8 +710,6 @@ static void *dnpds40_init(void)
}
memset(ctx, 0, sizeof(struct dnpds40_ctx));
- ctx->type = P_ANY;
-
return ctx;
}
@@ -527,31 +717,53 @@ static void *dnpds40_init(void)
((ctx->ver_major > (__major)) || \
(ctx->ver_major == (__major) && ctx->ver_minor >= (__minor)))
-static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int dnpds40_query_mqty(struct dnpds40_ctx *ctx)
+{
+ struct dnpds40_cmd cmd;
+ uint8_t *resp;
+ int len = 0, count;
+
+ /* Get Media remaining */
+ dnpds40_build_cmd(&cmd, "INFO", "MQTY", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return -1;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ count = atoi((char*)resp+4);
+ free(resp);
+
+ if (count) {
+ /* Old-sk00l models report one less than they should */
+ if (!ctx->correct_count)
+ count++;
+
+ count -= ctx->mediaoffset;
+ }
+
+ return count;
+}
+
+static int dnpds40_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct dnpds40_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;
+ ctx->type = type;
- 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 */
+ if (test_mode < TEST_MODE_NOATTACH) {
struct dnpds40_cmd cmd;
uint8_t *resp;
int len = 0;
+ /* Get Firmware Version */
dnpds40_build_cmd(&cmd, "INFO", "FVER", 0);
resp = dnpds40_resp_cmd(ctx, &cmd, &len);
@@ -567,6 +779,8 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ptr = strtok(NULL, ".");
ctx->ver_minor = atoi(ptr);
free(resp);
+ } else {
+ return CUPS_BACKEND_FAILED;
}
/* Get Serial Number */
@@ -577,6 +791,8 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
dnpds40_cleanup_string((char*)resp, len);
ctx->serno = (char*) resp;
/* Do NOT free resp! */
+ } else {
+ return CUPS_BACKEND_FAILED;
}
/* Query Media Info */
@@ -598,53 +814,84 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->media--;
free(resp);
+ } else {
+ return CUPS_BACKEND_FAILED;
}
- }
- if (ctx->type == P_DNP_DS80D) {
- struct dnpds40_cmd cmd;
- uint8_t *resp;
- int len = 0;
+ if (ctx->type == P_DNP_DS80D) {
+ struct dnpds40_cmd cmd;
+ uint8_t *resp;
+ int len = 0;
- /* Query Duplex Media Info */
- dnpds40_build_cmd(&cmd, "INFO", "CUT_PAPER", 0);
+ /* Query Duplex Media Info */
+ dnpds40_build_cmd(&cmd, "INFO", "CUT_PAPER", 0);
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (resp) {
- char tmp[5];
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (resp) {
+ char tmp[5];
- dnpds40_cleanup_string((char*)resp, len);
+ dnpds40_cleanup_string((char*)resp, len);
- memcpy(tmp, resp + 4, 4);
- tmp[4] = 0;
+ memcpy(tmp, resp + 4, 4);
+ tmp[4] = 0;
- ctx->duplex_media = atoi(tmp);
+ ctx->duplex_media = atoi(tmp);
- /* Subtract out the paper status */
- if (ctx->duplex_media & 3)
- ctx->duplex_media -= (ctx->duplex_media & 3);
+ /* Subtract out the paper status */
+ if (ctx->duplex_media & 3)
+ ctx->duplex_media -= (ctx->duplex_media & 3);
- free(resp);
+ free(resp);
+ } else {
+ return CUPS_BACKEND_FAILED;
+ }
}
- }
-#ifdef DNP_ONLY
- /* Only allow DNP printers to work. Rebadged versions should not. */
+#if (defined(DNP_ONLY) || defined(CITIZEN_ONLY))
+ {
+ char buf[256];
+ buf[0] = 0;
+ libusb_get_string_descriptor_ascii(dev, desc->iManufacturer, (unsigned char*)buf, STR_LEN_MAX);
+ sanitize_string(buf);
+#ifdef DNP_ONLY /* Only allow DNP printers to work. */
+ if (strncmp(buf, "Dai", 3)) /* "Dai Nippon Printing" */
+ return CUPS_BACKEND_FAILED;
+#endif
+#ifdef CITIZEN_ONLY /* Only allow CITIZEN printers to work. */
+ if (strncmp(buf, "CIT", 3)) /* "CITIZEN SYSTEMS" */
+ return CUPS_BACKEND_FAILED;
+#endif
+ }
+#endif
+ } else {
+ ctx->ver_major = 3;
+ ctx->ver_minor = 0;
+ ctx->version = strdup("UNKNOWN");
+ switch(ctx->type) {
+ case P_DNP_DS80D:
+ ctx->duplex_media = 200;
+ /* Intentional fallthrough */
+ case P_DNP_DS80:
+ case P_DNP_DS820:
+ ctx->media = 510; /* 8x12 */
+ break;
+ case P_DNP_DSRX1:
+ ctx->media = 310; /* 6x8 */
+ break;
+ default:
+ ctx->media = 400; /* 6x9 */
+ break;
+ }
- { /* Validate USB Vendor String is "Dai Nippon Printing" */
- char buf[256];
- buf[0] = 0;
- libusb_get_string_descriptor_ascii(dev, desc->iManufacturer, (unsigned char*)buf, STR_LEN_MAX);
- sanitize_string(buf);
- if (strncmp(buf, "Dai", 3))
- return 0;
+ if (getenv("MEDIA_CODE"))
+ ctx->media = atoi(getenv("MEDIA_CODE"));
}
-#endif
/* Per-printer options */
switch (ctx->type) {
case P_DNP_DS40:
ctx->native_width = 1920;
+ ctx->max_height = 5480;
ctx->supports_6x9 = 1;
if (FW_VER_CHECK(1,04))
ctx->supports_counterp = 1;
@@ -652,10 +899,15 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->supports_matte = 1;
if (FW_VER_CHECK(1,40))
ctx->supports_2x6 = 1;
+ if (FW_VER_CHECK(1,50))
+ ctx->supports_3x5x2 = 1;
+ if (FW_VER_CHECK(1,60))
+ ctx->supports_fullcut = ctx->supports_6x6 = 1; // No 5x5!
break;
case P_DNP_DS80:
case P_DNP_DS80D:
ctx->native_width = 2560;
+ ctx->max_height = 7536;
if (FW_VER_CHECK(1,02))
ctx->supports_counterp = 1;
if (FW_VER_CHECK(1,30))
@@ -663,6 +915,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
break;
case P_DNP_DSRX1:
ctx->native_width = 1920;
+ ctx->max_height = 5480;
ctx->supports_counterp = 1;
ctx->supports_matte = 1;
if (FW_VER_CHECK(1,10))
@@ -670,12 +923,32 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
if (FW_VER_CHECK(1,20))
ctx->supports_3x5x2 = 1;
if (FW_VER_CHECK(2,00)) { /* AKA RX1HS */
+ ctx->needs_mlot = 1;
ctx->supports_mediaoffset = 1;
ctx->supports_iserial = 1;
}
+ if (FW_VER_CHECK(2,06)) {
+ ctx->supports_5x5 = ctx->supports_6x6 = 1;
+ }
+ break;
+ case P_CITIZEN_OP900II:
+ ctx->native_width = 1920;
+ ctx->max_height = 5480;
+ ctx->supports_counterp = 1;
+ ctx->supports_matte = 1;
+ ctx->supports_mqty_default = 1;
+ ctx->supports_6x9 = 1;
+ if (FW_VER_CHECK(1,11))
+ ctx->supports_2x6 = 1;
+ break;
+ case P_CITIZEN_CW01:
+ ctx->native_width = 2048;
+ ctx->max_height = 5480;
+ ctx->supports_6x9 = 1;
break;
case P_DNP_DS620:
ctx->native_width = 1920;
+ ctx->max_height = 5480;
ctx->correct_count = 1;
ctx->supports_counterp = 1;
ctx->supports_matte = 1;
@@ -706,6 +979,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
break;
case P_DNP_DS820:
ctx->native_width = 2560;
+ ctx->max_height = 7536;
ctx->correct_count = 1;
ctx->supports_counterp = 1;
ctx->supports_matte = 1;
@@ -728,8 +1002,8 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->supports_gamma = 1;
break;
default:
- ERROR("Unknown vid/pid %04x/%04x (%d)\n", desc.idVendor, desc.idProduct, ctx->type);
- return;
+ ERROR("Unknown printer type %d\n", ctx->type);
+ return CUPS_BACKEND_FAILED;
}
ctx->last_matte = -1;
@@ -748,7 +1022,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
}
#endif
- if (ctx->supports_mediaoffset) {
+ if (test_mode < TEST_MODE_NOATTACH && ctx->supports_mediaoffset) {
/* Get Media Offset */
struct dnpds40_cmd cmd;
uint8_t *resp;
@@ -759,12 +1033,14 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
if (resp) {
ctx->mediaoffset = atoi((char*)resp+4);
free(resp);
+ } else {
+ return CUPS_BACKEND_FAILED;
}
} else if (!ctx->correct_count) {
ctx->mediaoffset = 50;
}
- if (ctx->supports_mqty_default) {
+ if (test_mode < TEST_MODE_NOATTACH && ctx->supports_mqty_default) {
struct dnpds40_cmd cmd;
uint8_t *resp;
int len = 0;
@@ -777,6 +1053,8 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->media_count_new = atoi((char*)resp+4);
free(resp);
ctx->media_count_new -= ctx->mediaoffset;
+ } else {
+ return CUPS_BACKEND_FAILED;
}
} else {
/* Look it up for legacy models & FW */
@@ -799,12 +1077,15 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->media_count_new = 180;
break;
default:
- ctx->media_count_new = 999; // non-zero
+ ctx->media_count_new = 0;
break;
}
break;
case P_DNP_DSRX1:
switch (ctx->media) {
+ case 210: // 2L
+ ctx->media_count_new = 350;
+ break;
case 300: // PC
ctx->media_count_new = 700;
break;
@@ -812,7 +1093,42 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->media_count_new = 350;
break;
default:
- ctx->media_count_new = 999; // non-zero
+ ctx->media_count_new = 0;
+ break;
+ }
+ break;
+ case P_CITIZEN_OP900II:
+ switch (ctx->media) {
+ case 210: // 2L
+ ctx->media_count_new = 350;
+ break;
+ case 300: // PC
+ ctx->media_count_new = 600;
+ break;
+ case 310: // A5
+ ctx->media_count_new = 300;
+ break;
+ case 400: // A5W
+ ctx->media_count_new = 280;
+ break;
+ default:
+ ctx->media_count_new = 0;
+ break;
+ }
+ break;
+ case P_CITIZEN_CW01:
+ switch (ctx->media) {
+ case 300: // PC
+ ctx->media_count_new = 600;
+ break;
+ case 350: // 2L
+ ctx->media_count_new = 230;
+ break;
+ case 400: // A5W
+ ctx->media_count_new = 280;
+ break;
+ default:
+ ctx->media_count_new = 0;
break;
}
break;
@@ -826,15 +1142,32 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
ctx->media_count_new = 110;
break;
default:
- ctx->media_count_new = 999; // non-zero
+ ctx->media_count_new = 0;
break;
}
break;
default:
- ctx->media_count_new = 999; // non-zero
+ ctx->media_count_new = 0;
break;
}
}
+
+ /* Fill out marker structure */
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = dnpds40_media_types(ctx->media);
+ ctx->marker.levelmax = ctx->media_count_new;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void dnpds40_cleanup_job(const void *vjob) {
+ const struct dnpds40_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void dnpds40_teardown(void *vctx) {
@@ -843,7 +1176,7 @@ static void dnpds40_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->type == P_DNP_DS80D) {
+ if (test_mode < TEST_MODE_NOATTACH && ctx->type == P_DNP_DS80D) {
struct dnpds40_cmd cmd;
/* Check to see if last print was the front side
@@ -856,8 +1189,6 @@ static void dnpds40_teardown(void *vctx) {
}
}
- if (ctx->databuf)
- free(ctx->databuf);
if (ctx->serno)
free(ctx->serno);
if (ctx->version)
@@ -865,22 +1196,28 @@ static void dnpds40_teardown(void *vctx) {
free(ctx);
}
-#define MAX_PRINTJOB_LEN (((2560*7536+1024+54))*3+1024) /* Worst-case, YMC */
+#define MAX_PRINTJOB_LEN (((ctx->native_width*ctx->max_height+1024+54+10))*3+1024) /* Worst-case, YMC */
-static int dnpds40_read_parse(void *vctx, int data_fd) {
+static int dnpds40_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct dnpds40_ctx *ctx = vctx;
int run = 1;
char buf[9] = { 0 };
- uint32_t dpi;
+ struct dnpds40_printjob *job = NULL;
+ struct dyesub_joblist *list;
+ int can_combine = 0;
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
+ memset(job, 0, sizeof(*job));
+ job->printspeed = -1;
+ job->copies = copies;
/* There's no way to figure out the total job length in advance, we
have to parse the stream until we get to the image plane data,
@@ -891,100 +1228,114 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
the end of the job.
*/
- ctx->datalen = 0;
- ctx->databuf = malloc(MAX_PRINTJOB_LEN);
- if (!ctx->databuf) {
+ job->databuf = malloc(MAX_PRINTJOB_LEN);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_CANCEL;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
- /* Clear everything out */
- dpi = 0;
- ctx->matte = 0;
- ctx->cutter = 0;
- ctx->manual_copies = 0;
- ctx->multicut = 0;
- ctx->fullcut = 0;
- ctx->printspeed = -1;
- ctx->can_rewind = 0;
- ctx->buf_needed = 0;
-
while (run) {
int remain, i, j;
/* Read in command header */
- i = read(data_fd, ctx->databuf + ctx->datalen,
+ i = read(data_fd, job->databuf + job->datalen,
sizeof(struct dnpds40_cmd));
- if (i < 0)
+ if (i < 0) {
+ dnpds40_cleanup_job(job);
return i;
+ }
if (i == 0)
break;
- if (i < (int) sizeof(struct dnpds40_cmd))
+ if (i < (int) sizeof(struct dnpds40_cmd)) {
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
- if (ctx->databuf[ctx->datalen + 0] != 0x1b ||
- ctx->databuf[ctx->datalen + 1] != 0x50) {
- ERROR("Unrecognized header data format @%d!\n", ctx->datalen);
+ if (job->databuf[job->datalen + 0] != 0x1b ||
+ job->databuf[job->datalen + 1] != 0x50) {
+ struct cw01_spool_hdr hdr;
+ /* See if it's the "classic" CW01 header */
+ memcpy(&hdr, job->databuf + job->datalen, sizeof(hdr));
+ hdr.plane_len = le32_to_cpu(hdr.plane_len);
+
+ if (hdr.type > 0x06 ||
+ hdr.res > 0x01 ||
+ hdr.null1[0] || hdr.null1[1] || hdr.null1[2] || hdr.null1[3]) {
+ ERROR("Unrecognized header data format @%d!\n", job->datalen);
+ dnpds40_cleanup_job(job);
+ } else {
+ job->dpi = (hdr.res == DPI_600) ? 600 : 334;
+ i = cw01_read_parse(job, data_fd, &hdr, i);
+ if (i == CUPS_BACKEND_OK)
+ goto parsed;
+ else {
+ dnpds40_cleanup_job(job);
+ return i;
+ }
+ }
return CUPS_BACKEND_CANCEL;
}
/* Parse out length of data chunk, if any */
- memcpy(buf, ctx->databuf + ctx->datalen + 24, 8);
+ memcpy(buf, job->databuf + job->datalen + 24, 8);
j = atoi(buf);
/* Read in data chunk as quickly as possible */
remain = j;
while (remain > 0) {
- i = read(data_fd, ctx->databuf + ctx->datalen + sizeof(struct dnpds40_cmd),
+ i = read(data_fd, job->databuf + job->datalen + sizeof(struct dnpds40_cmd),
remain);
if (i < 0) {
- ERROR("Data Read Error: %d (%d/%d @%d)\n", i, remain, j, ctx->datalen);
+ ERROR("Data Read Error: %d (%d/%d @%d)\n", i, remain, j, job->datalen);
+ dnpds40_cleanup_job(job);
return i;
}
- if (i == 0)
+ if (i == 0) {
+ dnpds40_cleanup_job(job);
return 1;
- ctx->datalen += i;
+ }
+ job->datalen += i;
remain -= i;
}
- ctx->datalen -= j; /* Back it off */
+ job->datalen -= j; /* Back it off */
/* Check for some offsets */
- if(!memcmp("CNTRL QTY", ctx->databuf + ctx->datalen+2, 9)) {
+ if(!memcmp("CNTRL QTY", job->databuf + job->datalen+2, 9)) {
/* Ignore this. We will insert our own later on */
continue;
}
- if(!memcmp("CNTRL CUTTER", ctx->databuf + ctx->datalen+2, 12)) {
- memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- ctx->cutter = atoi(buf);
+ if(!memcmp("CNTRL CUTTER", job->databuf + job->datalen+2, 12)) {
+ memcpy(buf, job->databuf + job->datalen + 32, 8);
+ job->cutter = atoi(buf);
/* We'll insert it ourselves later */
continue;
}
- if(!memcmp("CNTRL BUFFCNTRL", ctx->databuf + ctx->datalen+2, 15)) {
+ if(!memcmp("CNTRL BUFFCNTRL", job->databuf + job->datalen+2, 15)) {
/* Ignore this. We will insert our own later on
if the printer and job support it. */
continue;
}
- if(!memcmp("CNTRL OVERCOAT", ctx->databuf + ctx->datalen+2, 14)) {
+ if(!memcmp("CNTRL OVERCOAT", job->databuf + job->datalen+2, 14)) {
if (ctx->supports_matte) {
- memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- ctx->matte = atoi(buf);
+ memcpy(buf, job->databuf + job->datalen + 32, 8);
+ job->matte = atoi(buf);
} else {
WARNING("Printer FW does not support matte prints, using glossy mode\n");
}
/* We'll insert our own later, if appropriate */
continue;
}
- if(!memcmp("IMAGE MULTICUT", ctx->databuf + ctx->datalen+2, 14)) {
- memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- ctx->multicut = atoi(buf);
+ if(!memcmp("IMAGE MULTICUT", job->databuf + job->datalen+2, 14)) {
+ memcpy(buf, job->databuf + job->datalen + 32, 8);
+ job->multicut = atoi(buf);
/* Backend automatically handles rewind support, so
ignore application requests to use it. */
- if (ctx->multicut > 400)
- ctx->multicut -= 400;
+ if (job->multicut > 400)
+ job->multicut -= 400;
/* We'll insert this ourselves later. */
continue;
}
- if(!memcmp("CNTRL FULL_CUTTER_SET", ctx->databuf + ctx->datalen+2, 21)) {
+ if(!memcmp("CNTRL FULL_CUTTER_SET", job->databuf + job->datalen+2, 21)) {
if (!ctx->supports_fullcut) {
WARNING("Printer FW does not support full cutter control!\n");
continue;
@@ -999,134 +1350,139 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
WARNING("Full cutter argument length incorrect, ignoring!\n");
continue;
} else if (!ctx->supports_adv_fullcut) {
- if (ctx->databuf[ctx->datalen + 32 + 12] != '0' ||
- ctx->databuf[ctx->datalen + 32 + 13] != '0' ||
- ctx->databuf[ctx->datalen + 32 + 14] != '0') {
+ if (job->databuf[job->datalen + 32 + 12] != '0' ||
+ job->databuf[job->datalen + 32 + 13] != '0' ||
+ job->databuf[job->datalen + 32 + 14] != '0') {
WARNING("Full cutter scrap setting not supported on this firmware, ignoring!\n");
continue;
}
}
// XXX enforce cut counts/sizes?
- ctx->fullcut = 1;
+ job->fullcut = 1;
}
- if(!memcmp("IMAGE YPLANE", ctx->databuf + ctx->datalen + 2, 12)) {
+ if(!memcmp("IMAGE YPLANE", job->databuf + job->datalen + 2, 12)) {
uint32_t y_ppm; /* Pixels Per Meter */
/* Validate vertical resolution */
- memcpy(&y_ppm, ctx->databuf + ctx->datalen + 32 + 42, sizeof(y_ppm));
+ memcpy(&y_ppm, job->databuf + job->datalen + 32 + 42, sizeof(y_ppm));
y_ppm = le32_to_cpu(y_ppm);
switch (y_ppm) {
case 11808:
- dpi = 300;
+ job->dpi = 300;
break;
case 23615:
- dpi = 600;
+ job->dpi = 600;
break;
default:
ERROR("Unrecognized printjob resolution (%u ppm)\n", y_ppm);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Validate horizontal size */
- memcpy(&y_ppm, ctx->databuf + ctx->datalen + 32 + 18, sizeof(y_ppm));
+ memcpy(&y_ppm, job->databuf + job->datalen + 32 + 18, sizeof(y_ppm));
y_ppm = le32_to_cpu(y_ppm);
if (y_ppm != ctx->native_width) {
ERROR("Incorrect horizontal resolution (%u), aborting!\n", y_ppm);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
}
- if(!memcmp("CNTRL PRINTSPEED", ctx->databuf + ctx->datalen + 2, 16)) {
+ if(!memcmp("CNTRL PRINTSPEED", job->databuf + job->datalen + 2, 16)) {
if (!ctx->supports_printspeed) {
WARNING("Printer does not support PRINTSPEED\n");
continue;
}
- memcpy(buf, ctx->databuf + ctx->datalen + 32, 8);
- ctx->printspeed = atoi(buf) / 10;
+ memcpy(buf, job->databuf + job->datalen + 32, 8);
+ job->printspeed = atoi(buf) / 10;
/* We'll insert this ourselves later. */
continue;
}
/* This is the last block.. */
- if(!memcmp("CNTRL START", ctx->databuf + ctx->datalen + 2, 11))
+ if(!memcmp("CNTRL START", job->databuf + job->datalen + 2, 11))
run = 0;
/* Add in the size of this chunk */
- ctx->datalen += sizeof(struct dnpds40_cmd) + j;
+ job->datalen += sizeof(struct dnpds40_cmd) + j;
}
-
+parsed:
/* If we have no data.. don't bother */
- if (!ctx->datalen)
+ if (!job->datalen) {
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
/* Sanity check matte mode */
- if (ctx->matte == 21 && !ctx->supports_finematte) {
+ if (job->matte == 21 && !ctx->supports_finematte) {
WARNING("Printer FW does not support Fine Matte mode, downgrading to normal matte\n");
- ctx->matte = 1;
- } else if (ctx->matte == 22 && !ctx->supports_luster) {
+ job->matte = 1;
+ } else if (job->matte == 22 && !ctx->supports_luster) {
WARNING("Printer FW does not support Luster mode, downgrading to normal matte\n");
- ctx->matte = 1;
- } else if (ctx->matte > 1 && !ctx->supports_advmatte) {
+ job->matte = 1;
+ } else if (job->matte > 1 && !ctx->supports_advmatte) {
WARNING("Printer FW does not support advanced matte modes, downgrading to normal matte\n");
- ctx->matte = 1;
+ job->matte = 1;
}
/* Pick a sane default value for printspeed if not specified */
- if (ctx->printspeed == -1 || ctx->printspeed > 3)
+ if (job->printspeed == -1 || job->printspeed > 3)
{
- if (dpi == 600)
- ctx->printspeed = 1;
+ if (job->dpi == 600)
+ job->printspeed = 1;
else
- ctx->printspeed = 0;
+ job->printspeed = 0;
}
/* And sanity-check whatever value is there */
- if (ctx->printspeed == 0 && dpi == 600) {
- ctx->printspeed = 1;
- } else if (ctx->printspeed == 1 && dpi == 300) {
- ctx->printspeed = 0;
+ if (job->printspeed == 0 && job->dpi == 600) {
+ job->printspeed = 1;
+ } else if (job->printspeed == 1 && job->dpi == 300) {
+ job->printspeed = 0;
}
/* Make sure MULTICUT is sane, most validation needs this */
- if (!ctx->multicut) {
+ if (!job->multicut && ctx->type != P_CITIZEN_CW01) {
WARNING("Missing or illegal MULTICUT command!\n");
- if (dpi == 300)
- ctx->buf_needed = 1;
+ if (job->dpi == 300)
+ job->buf_needed = 1;
else
- ctx->buf_needed = 2;
+ job->buf_needed = 2;
goto skip_checks;
}
/* Only DS80D supports Cut Paper types */
- if (ctx->multicut > 100 &&
+ if (job->multicut > 100 &&
ctx->type != P_DNP_DS80D) {
ERROR("Only DS80D supports cut-paper sizes!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Figure out the number of buffers we need. */
- ctx->buf_needed = 1;
+ job->buf_needed = 1;
- if (dpi == 600) {
+ if (job->dpi == 600) {
switch(ctx->type) {
case P_DNP_DS620:
- if (ctx->multicut == MULTICUT_6x9 ||
- ctx->multicut == MULTICUT_6x4_5X2)
- ctx->buf_needed = 2;
+ if (job->multicut == MULTICUT_6x9 ||
+ job->multicut == MULTICUT_6x4_5X2)
+ job->buf_needed = 2;
break;
case P_DNP_DS80: /* DS80/CX-W */
- if (ctx->matte && (ctx->multicut == MULTICUT_8xA4LEN ||
- ctx->multicut == MULTICUT_8x4X3 ||
- ctx->multicut == MULTICUT_8x8_8x4 ||
- ctx->multicut == MULTICUT_8x6X2 ||
- ctx->multicut == MULTICUT_8x12))
- ctx->buf_needed = 2;
+ if (job->matte && (job->multicut == MULTICUT_8xA4LEN ||
+ job->multicut == MULTICUT_8x4X3 ||
+ job->multicut == MULTICUT_8x8_8x4 ||
+ job->multicut == MULTICUT_8x6X2 ||
+ job->multicut == MULTICUT_8x12))
+ job->buf_needed = 2;
break;
case P_DNP_DS80D:
- if (ctx->matte) {
- int mcut = ctx->multicut;
+ if (job->matte) {
+ int mcut = job->multicut;
if (mcut > MULTICUT_S_BACK)
mcut -= MULTICUT_S_BACK;
@@ -1138,129 +1494,150 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
mcut == MULTICUT_8x8_8x4 ||
mcut == MULTICUT_8x6X2 ||
mcut == MULTICUT_8x12)
- ctx->buf_needed = 2;
+ job->buf_needed = 2;
if (mcut == MULTICUT_S_8x12 ||
mcut == MULTICUT_S_8x6X2 ||
mcut == MULTICUT_S_8x4X3)
- ctx->buf_needed = 2;
+ job->buf_needed = 2;
}
break;
case P_DNP_DS820:
// Nothing; all sizes only need 1 buffer
break;
+ case P_CITIZEN_CW01:
+ job->buf_needed = 2;
+ break;
default: /* DS40/CX/RX1/CY/everything else */
- if (ctx->matte) {
- if (ctx->multicut == MULTICUT_6x8 ||
- ctx->multicut == MULTICUT_6x9 ||
- ctx->multicut == MULTICUT_6x4X2 ||
- ctx->multicut == MULTICUT_5x7 ||
- ctx->multicut == MULTICUT_5x3_5X2)
- ctx->buf_needed = 2;
+ if (job->matte) {
+ if (job->multicut == MULTICUT_6x8 ||
+ job->multicut == MULTICUT_6x9 ||
+ job->multicut == MULTICUT_6x4X2 ||
+ job->multicut == MULTICUT_5x7 ||
+ job->multicut == MULTICUT_5x3_5X2)
+ job->buf_needed = 2;
} else {
- if (ctx->multicut == MULTICUT_6x8 ||
- ctx->multicut == MULTICUT_6x9 ||
- ctx->multicut == MULTICUT_6x4X2)
- ctx->buf_needed = 1;
+ if (job->multicut == MULTICUT_6x8 ||
+ job->multicut == MULTICUT_6x9 ||
+ job->multicut == MULTICUT_6x4X2)
+ job->buf_needed = 1;
}
break;
}
}
+ if (job->dpi == 334 && ctx->type != P_CITIZEN_CW01)
+ {
+ ERROR("Illegal resolution (%u) for printer!\n", job->dpi);
+ dnpds40_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
/* Sanity-check type vs loaded media */
- if (ctx->multicut < 100) {
+ if (job->multicut == 0)
+ goto skip_multicut;
+
+ if (job->multicut < 100) {
switch(ctx->media) {
case 200: //"5x3.5 (L)"
- if (ctx->multicut != MULTICUT_5x3_5) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut != MULTICUT_5x3_5) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
break;
case 210: //"5x7 (2L)"
- if (ctx->multicut != MULTICUT_5x3_5 && ctx->multicut != MULTICUT_5x7 &&
- ctx->multicut != MULTICUT_5x3_5X2 && ctx->multicut != MULTICUT_5x5) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut != MULTICUT_5x3_5 && job->multicut != MULTICUT_5x7 &&
+ job->multicut != MULTICUT_5x3_5X2 && job->multicut != MULTICUT_5x5) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Only 3.5x5 on 7x5 media can be rewound */
- if (ctx->multicut == MULTICUT_5x3_5)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_5x3_5)
+ job->can_rewind = 1;
break;
case 300: //"6x4 (PC)"
- if (ctx->multicut != MULTICUT_6x4) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut != MULTICUT_6x4) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
break;
case 310: //"6x8 (A5)"
- if (ctx->multicut != MULTICUT_6x4 && ctx->multicut != MULTICUT_6x8 &&
- ctx->multicut != MULTICUT_6x4X2 &&
- ctx->multicut != MULTICUT_6x6 && ctx->multicut != 30) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut != MULTICUT_6x4 && job->multicut != MULTICUT_6x8 &&
+ job->multicut != MULTICUT_6x4X2 &&
+ job->multicut != MULTICUT_6x6 && job->multicut != 30) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Only 6x4 on 6x8 media can be rewound */
- if (ctx->multicut == MULTICUT_6x4)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_6x4)
+ job->can_rewind = 1;
break;
case 400: //"6x9 (A5W)"
- if (ctx->multicut != MULTICUT_6x4 && ctx->multicut != MULTICUT_6x8 &&
- ctx->multicut != MULTICUT_6x9 && ctx->multicut != MULTICUT_6x4X2 &&
- ctx->multicut != MULTICUT_6x6 &&
- ctx->multicut != MULTICUT_6x4_5 && ctx->multicut != MULTICUT_6x4_5X2) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut != MULTICUT_6x4 && job->multicut != MULTICUT_6x8 &&
+ job->multicut != MULTICUT_6x9 && job->multicut != MULTICUT_6x4X2 &&
+ job->multicut != MULTICUT_6x6 &&
+ job->multicut != MULTICUT_6x4_5 && job->multicut != MULTICUT_6x4_5X2) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Only 6x4 or 6x4.5 on 6x9 media can be rewound */
- if (ctx->multicut == MULTICUT_6x4 || ctx->multicut == MULTICUT_6x4_5)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_6x4 || job->multicut == MULTICUT_6x4_5)
+ job->can_rewind = 1;
break;
case 500: //"8x10"
if (ctx->type == P_DNP_DS820 &&
- (ctx->multicut == MULTICUT_8x7 || ctx->multicut == MULTICUT_8x9)) {
+ (job->multicut == MULTICUT_8x7 || job->multicut == MULTICUT_8x9)) {
/* These are okay */
- } else if (ctx->multicut < MULTICUT_8x10 || ctx->multicut == MULTICUT_8x12 ||
- ctx->multicut == MULTICUT_8x6X2 || ctx->multicut >= MULTICUT_8x6_8x5 ) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ } else if (job->multicut < MULTICUT_8x10 || job->multicut == MULTICUT_8x12 ||
+ job->multicut == MULTICUT_8x6X2 || job->multicut >= MULTICUT_8x6_8x5 ) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* 8x4, 8x5 can be rewound */
- if (ctx->multicut == MULTICUT_8x4 ||
- ctx->multicut == MULTICUT_8x5)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_8x4 ||
+ job->multicut == MULTICUT_8x5)
+ job->can_rewind = 1;
break;
case 510: //"8x12"
- if (ctx->multicut < MULTICUT_8x10 || (ctx->multicut > MULTICUT_8xA4LEN && !(ctx->multicut == MULTICUT_8x7 || ctx->multicut == MULTICUT_8x9))) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ if (job->multicut < MULTICUT_8x10 || (job->multicut > MULTICUT_8xA4LEN && !(job->multicut == MULTICUT_8x7 || job->multicut == MULTICUT_8x9))) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* 8x4, 8x5, 8x6 can be rewound */
- if (ctx->multicut == MULTICUT_8x4 ||
- ctx->multicut == MULTICUT_8x5 ||
- ctx->multicut == MULTICUT_8x6)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_8x4 ||
+ job->multicut == MULTICUT_8x5 ||
+ job->multicut == MULTICUT_8x6)
+ job->can_rewind = 1;
break;
case 600: //"A4"
- if (ctx->multicut < MULTICUT_A5 || ctx->multicut > MULTICUT_A4x5X2) {
- ERROR("Incorrect media for job loaded (%d vs %d)\n", ctx->media, ctx->multicut);
+ if (job->multicut < MULTICUT_A5 || job->multicut > MULTICUT_A4x5X2) {
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* A4xn and A5 can be rewound */
- if (ctx->multicut == MULTICUT_A4x4 ||
- ctx->multicut == MULTICUT_A4x5 ||
- ctx->multicut == MULTICUT_A4x6 ||
- ctx->multicut == MULTICUT_A5)
- ctx->can_rewind = 1;
+ if (job->multicut == MULTICUT_A4x4 ||
+ job->multicut == MULTICUT_A4x5 ||
+ job->multicut == MULTICUT_A4x6 ||
+ job->multicut == MULTICUT_A5)
+ job->can_rewind = 1;
break;
default:
- ERROR("Unknown media (%u vs %u)!\n", ctx->media, ctx->multicut);
+ ERROR("Unknown media (%u vs %u)!\n", ctx->media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- } else if (ctx->multicut < 400) {
- int mcut = ctx->multicut;
+ } else if (job->multicut < 400) {
+ int mcut = job->multicut;
switch(ctx->duplex_media) {
case 100: //"8x10.75"
@@ -1272,7 +1649,8 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
if (mcut == MULTICUT_S_8x12 ||
mcut == MULTICUT_S_8x6X2 ||
mcut == MULTICUT_S_8x4X3) {
- ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->media, ctx->multicut);
+ ERROR("Incorrect media for job loaded (%u vs %u)\n", ctx->duplex_media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
break;
@@ -1280,73 +1658,111 @@ static int dnpds40_read_parse(void *vctx, int data_fd) {
/* Everything is legal */
break;
default:
- ERROR("Unknown duplexer media (%u vs %u)!\n", ctx->duplex_media, ctx->multicut);
+ ERROR("Unknown duplexer media (%u vs %u)!\n", ctx->duplex_media, job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
} else {
- ERROR("Multicut value out of range! (%u)\n", ctx->multicut);
+ ERROR("Multicut value out of range! (%u)\n", job->multicut);
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
/* Additional santity checks, make sure printer support exists */
- if (!ctx->supports_6x6 && ctx->multicut == MULTICUT_6x6) {
+ if (!ctx->supports_6x6 && job->multicut == MULTICUT_6x6) {
ERROR("Printer does not support 6x6 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (!ctx->supports_5x5 && ctx->multicut == MULTICUT_5x5) {
+ if (!ctx->supports_5x5 && job->multicut == MULTICUT_5x5) {
ERROR("Printer does not support 5x5 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if ((ctx->multicut == MULTICUT_6x4_5 || ctx->multicut == MULTICUT_6x4_5X2) &&
+ if ((job->multicut == MULTICUT_6x4_5 || job->multicut == MULTICUT_6x4_5X2) &&
!ctx->supports_6x4_5) {
ERROR("Printer does not support 6x4.5 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (ctx->multicut == MULTICUT_6x9 && !ctx->supports_6x9) {
+ if (job->multicut == MULTICUT_6x9 && !ctx->supports_6x9) {
ERROR("Printer does not support 6x9 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (ctx->multicut == MULTICUT_5x3_5X2 && !ctx->supports_3x5x2) {
+ if (job->multicut == MULTICUT_5x3_5X2 && !ctx->supports_3x5x2) {
ERROR("Printer does not support 3.5x5*2 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (ctx->fullcut && !ctx->supports_adv_fullcut &&
- ctx->multicut != MULTICUT_6x8) {
+skip_multicut:
+
+ if (job->fullcut && !ctx->supports_adv_fullcut &&
+ job->multicut != MULTICUT_6x8) {
ERROR("Printer does not support full control on sizes other than 6x8, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (ctx->cutter == 120) {
- if (ctx->multicut == MULTICUT_6x4 || ctx->multicut == MULTICUT_6x8) {
+ if (job->fullcut && job->cutter) {
+ WARNING("Cannot simultaneously use FULL_CUTTER and CUTTER, using the former\n");
+ job->cutter = 0;
+ }
+
+ if (job->cutter == 120) {
+ if (job->multicut == MULTICUT_6x4 || job->multicut == MULTICUT_6x8) {
if (!ctx->supports_2x6) {
ERROR("Printer does not support 2x6 prints, aborting!\n");
+ dnpds40_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
} else {
ERROR("Printer only supports legacy 2-inch cuts on 4x6 or 8x6 jobs!");
+ dnpds40_cleanup_job(job);
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? what about other printers?
- ctx->manual_copies = 1;
}
skip_checks:
- DEBUG("dpi %u matte %d mcut %u cutter %d, bufs %d spd %d\n",
- dpi, ctx->matte, ctx->multicut, ctx->cutter, ctx->buf_needed, ctx->printspeed);
+ DEBUG("job->dpi %u matte %d mcut %u cutter %d/%d, bufs %d spd %d\n",
+ job->dpi, job->matte, job->multicut, job->cutter, job->fullcut, job->buf_needed, job->printspeed);
+
+ list = dyesub_joblist_create(&dnpds40_backend, ctx);
+
+ can_combine = job->can_rewind; /* Any rewindable size can be stacked */
+
+ /* Try to combine prints */
+ if (copies > 1 && can_combine) {
+ struct dnpds40_printjob *combined;
+ combined = combine_jobs(job, job);
+ if (combined) {
+ combined->copies = job->copies / 2;
+ combined->can_rewind = 0;
+ dyesub_joblist_addjob(list, combined);
+
+ if (job->copies & 1) {
+ job->copies = 1;
+ } else {
+ dnpds40_cleanup_job(job);
+ job = NULL;
+ }
+ }
+ }
+ if (job) {
+ dyesub_joblist_addjob(list, job);
+ }
+
+ *vjob = list;
return CUPS_BACKEND_OK;
}
-static int dnpds40_main_loop(void *vctx, int copies) {
+static int dnpds40_main_loop(void *vctx, const void *vjob) {
struct dnpds40_ctx *ctx = vctx;
int ret;
struct dnpds40_cmd cmd;
@@ -1356,23 +1772,52 @@ static int dnpds40_main_loop(void *vctx, int copies) {
char buf[9];
int status;
int buf_needed;
+ int multicut;
int count = 0;
+ int manual_copies = 0;
+ int copies;
+
+ const struct dnpds40_printjob *job = vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
- buf_needed = ctx->buf_needed;
+ buf_needed = job->buf_needed;
+ multicut = job->multicut;
+ copies = job->copies;
/* If we switch major overcoat modes, we need both buffers */
- if (!!ctx->matte != ctx->last_matte)
+ if (!!job->matte != ctx->last_matte)
buf_needed = 2;
- if (ctx->media_count_new) {
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", dnpds40_media_types(ctx->media));
- ATTR("marker-types=ribbonWax\n");
+ if (job->cutter == 120) {
+ /* 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? what about other printers?
+ manual_copies = 1;
+ }
+
+ /* RX1HS requires HS media, but the only way to tell is that the
+ HS media reports a lot code, while the non-HS media does not. */
+ if (ctx->needs_mlot) {
+ /* Get Media Lot */
+ dnpds40_build_cmd(&cmd, "INFO", "MLOT", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ len = strlen((char*)resp);
+ free(resp);
+ if (!len) {
+ ERROR("Media does not report a valid lot number (non-HS media in RX1HS?)\n");
+ return CUPS_BACKEND_STOP;
+ }
}
top:
@@ -1442,34 +1887,17 @@ top:
{
/* Figure out remaining native prints */
- dnpds40_build_cmd(&cmd, "INFO", "MQTY", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
+ ctx->marker.levelnow = dnpds40_query_mqty(ctx);
+ if (ctx->marker.levelnow < 0)
return CUPS_BACKEND_FAILED;
+ dump_markers(&ctx->marker, 1, 0);
- dnpds40_cleanup_string((char*)resp, len);
-
- count = atoi((char*)resp+4);
- free(resp);
-
- if (count) {
- /* Old-sk00l models report one less than they should */
- if (!ctx->correct_count)
- count++;
-
- count -= ctx->mediaoffset;
- }
-
- if (ctx->media_count_new) {
- ATTR("marker-levels=%d\n", count * 100 / ctx->media_count_new);
- ATTR("marker-message=\"%d native prints remaining on '%s' ribbon\"\n", count, dnpds40_media_types(ctx->media));
- }
+ count = ctx->marker.levelnow; // For logic below.
/* See if we can rewind to save media */
- if (ctx->can_rewind && ctx->supports_rewind) {
+ if (job->can_rewind && ctx->supports_rewind) {
/* Tell printer to use rewind */
- ctx->multicut += 400;
+ multicut += 400;
/* Get Media remaining */
dnpds40_build_cmd(&cmd, "INFO", "RQTY", 0);
@@ -1483,6 +1911,26 @@ top:
free(resp);
}
+ if (ctx->type == P_CITIZEN_CW01) {
+ /* Get Vertical resolution */
+ dnpds40_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+#if 0 // XXX Fix 600dpi support on CW01
+ // have to read the last DPI, and send the correct CWD over?
+ if (ctx->dpi == 600 && strcmp("RV0334", *char*)resp) {
+ ERROR("600DPI prints not yet supported, need 600DPI CWD load");
+ return CUPS_BACKEND_CANCEL;
+ }
+#endif
+ free(resp);
+ }
+
/* Verify we have sufficient media for prints */
#if 0 // disabled this to allow error to be reported on the printer panel
@@ -1491,22 +1939,21 @@ top:
return CUPS_BACKEND_STOP;
}
#endif
-
if (count < copies) {
WARNING("Printer does not have sufficient remaining media (%d) to complete job (%d)\n", copies, count);
}
}
/* Store our last multicut state */
- ctx->last_multicut = ctx->multicut;
+ ctx->last_multicut = multicut;
/* Tell printer how many copies to make */
- snprintf(buf, sizeof(buf), "%07d\r", ctx->manual_copies ? 1 : copies);
+ snprintf(buf, sizeof(buf), "%07d\r", manual_copies ? 1 : copies);
dnpds40_build_cmd(&cmd, "CNTRL", "QTY", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
- if (!ctx->manual_copies)
+ if (!manual_copies)
copies = 1;
/* Enable job resumption on correctable errors */
@@ -1515,7 +1962,7 @@ top:
/* DS80D does not support BUFFCNTRL when using
cut media; all others support this */
if (ctx->type != P_DNP_DS80D ||
- ctx->multicut < 100) {
+ multicut < 100) {
dnpds40_build_cmd(&cmd, "CNTRL", "BUFFCNTRL", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
@@ -1524,15 +1971,15 @@ top:
/* Set overcoat parameters if appropriate */
if (ctx->supports_matte) {
- snprintf(buf, sizeof(buf), "%08d", ctx->matte);
+ snprintf(buf, sizeof(buf), "%08d", job->matte);
dnpds40_build_cmd(&cmd, "CNTRL", "OVERCOAT", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
}
/* Program in the cutter setting */
- if (ctx->cutter) {
- snprintf(buf, sizeof(buf), "%08d", ctx->cutter);
+ if (job->cutter) {
+ snprintf(buf, sizeof(buf), "%08d", job->cutter);
dnpds40_build_cmd(&cmd, "CNTRL", "CUTTER", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
@@ -1540,21 +1987,23 @@ top:
/* Send over the printspeed if appropriate */
if (ctx->supports_printspeed) {
- snprintf(buf, sizeof(buf), "%08d", ctx->printspeed * 10);
+ snprintf(buf, sizeof(buf), "%08d", job->printspeed * 10);
dnpds40_build_cmd(&cmd, "CNTRL", "PRINTSPEED", 8);
if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
return CUPS_BACKEND_FAILED;
}
- /* Program in the multicut setting */
- snprintf(buf, sizeof(buf), "%08u", ctx->multicut);
- dnpds40_build_cmd(&cmd, "IMAGE", "MULTICUT", 8);
- if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
- return CUPS_BACKEND_FAILED;
+ /* Program in the multicut setting, if one exists */
+ if (multicut) {
+ snprintf(buf, sizeof(buf), "%08u", multicut);
+ dnpds40_build_cmd(&cmd, "IMAGE", "MULTICUT", 8);
+ if ((ret = dnpds40_do_cmd(ctx, &cmd, (uint8_t*)buf, 8)))
+ return CUPS_BACKEND_FAILED;
+ }
/* Finally, send the stream over as individual data chunks */
- ptr = ctx->databuf;
- while(ptr && ptr < (ctx->databuf + ctx->datalen)) {
+ ptr = job->databuf;
+ while(ptr && ptr < (job->databuf + job->datalen)) {
int i;
buf[8] = 0;
memcpy(buf, ptr + 24, 8);
@@ -1568,10 +2017,11 @@ top:
}
sleep(1); /* Give things a moment */
- if (fast_return) {
+ if (fast_return && !manual_copies) {
INFO("Fast return mode enabled.\n");
} else {
INFO("Waiting for job to complete...\n");
+ int started = 0;
while (1) {
/* Query status */
@@ -1584,8 +2034,10 @@ top:
free(resp);
/* If we're idle or there's an error..*/
- if (status == 0)
+ if (status == 0 && started)
break;
+ if (status)
+ started = 1;
if (status >= 1000) {
ERROR("Printer encountered error: %s\n", dnpds40_statuses(status));
break;
@@ -1612,11 +2064,8 @@ top:
count -= ctx->mediaoffset;
}
-
- if (ctx->media_count_new) {
- ATTR("marker-levels=%d\n", count * 100 / ctx->media_count_new);
- ATTR("marker-message=\"%d native prints remaining on '%s' ribbon\"\n", count, dnpds40_media_types(ctx->media));
- }
+ ctx->marker.levelnow = count;
+ dump_markers(&ctx->marker, 1, 0);
}
/* Clean up */
@@ -1627,12 +2076,12 @@ top:
if (copies && --copies) {
/* No need to wait on buffers due to matte switching */
- buf_needed = ctx->buf_needed;
+ buf_needed = job->buf_needed;
goto top;
}
/* Finally, account for overcoat mode of last print */
- ctx->last_matte = !!ctx->matte;
+ ctx->last_matte = !!job->matte;
#ifdef STATE_DIR
{
/* Store last matte status into file */
@@ -1746,6 +2195,60 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
free(resp);
}
+ if (ctx->type == P_CITIZEN_CW01) {
+ /* Get Horizonal resolution */
+ dnpds40_build_cmd(&cmd, "INFO", "RESOLUTION_H", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Horizontal Resolution: %s dpi\n", (char*)resp + 3);
+
+ free(resp);
+
+ /* Get Vertical resolution */
+ dnpds40_build_cmd(&cmd, "INFO", "RESOLUTION_V", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Vertical Resolution: %s dpi\n", (char*)resp + 3);
+
+ free(resp);
+
+ /* Get Color Control Data Version */
+ dnpds40_build_cmd(&cmd, "TBL_RD", "Version", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ INFO("Color Data Version: %s ", (char*)resp);
+
+ free(resp);
+
+ /* Get Color Control Data Checksum */
+ dnpds40_build_cmd(&cmd, "MNT_RD", "CTRLD_CHKSUM", 0);
+
+ resp = dnpds40_resp_cmd(ctx, &cmd, &len);
+ if (!resp)
+ return CUPS_BACKEND_FAILED;
+
+ dnpds40_cleanup_string((char*)resp, len);
+
+ DEBUG2("(%s)\n", (char*)resp);
+
+ free(resp);
+ }
+
/* Get Media Color offset */
dnpds40_build_cmd(&cmd, "INFO", "MCOLOR", 0);
@@ -1798,6 +2301,9 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
free(resp);
+ if (ctx->type == P_CITIZEN_CW01)
+ goto skip;
+
/* Get Ribbon ID code (?) */
dnpds40_build_cmd(&cmd, "MNT_RD", "RIBBON_ID_CODE", 0);
@@ -1985,6 +2491,7 @@ static int dnpds40_get_info(struct dnpds40_ctx *ctx)
free(resp);
}
+skip:
return CUPS_BACKEND_OK;
}
@@ -2048,7 +2555,6 @@ static int dnpds40_get_status(struct dnpds40_ctx *ctx)
dnpds40_cleanup_string((char*)resp, len);
INFO("Free Buffers: %d\n", atoi((char*)resp + 3));
-
free(resp);
/* Report media */
@@ -2090,24 +2596,10 @@ static int dnpds40_get_status(struct dnpds40_ctx *ctx)
INFO("Native Prints Available on New Media: %u\n", ctx->media_count_new);
/* Get Media remaining */
- dnpds40_build_cmd(&cmd, "INFO", "MQTY", 0);
-
- resp = dnpds40_resp_cmd(ctx, &cmd, &len);
- if (!resp)
+ count = dnpds40_query_mqty(ctx);
+ if (count < 0)
return CUPS_BACKEND_FAILED;
- dnpds40_cleanup_string((char*)resp, len);
-
- count = atoi((char*)resp+4);
- free(resp);
-
- if (count) {
- /* Old-sk00l models report one less than they should */
- if (!ctx->correct_count)
- count++;
-
- count -= ctx->mediaoffset;
- }
INFO("Native Prints Remaining on Media: %d\n", count);
if (ctx->supports_rewind) {
@@ -2433,7 +2925,7 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
optarg[0] != 'B' &&
optarg[0] != 'M')
return CUPS_BACKEND_FAILED;
- if (!ctx->supports_matte) {
+ if (optarg[0] == 'M' && !ctx->supports_matte) {
ERROR("Printer FW does not support matte functions, please update!\n");
return CUPS_BACKEND_FAILED;
}
@@ -2483,28 +2975,203 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int dnpds40_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct dnpds40_ctx *ctx = vctx;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ ctx->marker.levelnow = dnpds40_query_mqty(ctx);
+ if (ctx->marker.levelnow < 0)
+ return CUPS_BACKEND_FAILED;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *dnpds40_prefixes[] = {
+ "dnp_citizen", "dnpds40", // Family names, do *not* nuke.
+ "dnp-ds40", "dnp-ds80", "dnp-ds80dx", "dnp-ds620", "dnp-ds820", "dnp-dsrx1",
+ "citizen-cw-01", "citizen-cw-02", "citizen-cx-02",
+ // backwards compatibility
+ "dnpds80", "dnpds80dx", "dnpds620", "dnpds820", "dnprx1",
+ "citizencw01", "citizencw02", "citizencx02",
+ // These are all extras.
+ "citizen-cx", "citizen-cx-w", "citizen-cy", "citizen-cy-02",
+ "citizen-op900", "citizen-op900ii",
+ NULL
+};
+
+#define USB_VID_CITIZEN 0x1343
+#define USB_PID_DNP_DS40 0x0003 // Also Citizen CX
+#define USB_PID_DNP_DS80 0x0004 // Also Citizen CX-W and Mitsubishi CP-3800DW
+#define USB_PID_DNP_DSRX1 0x0005 // Also Citizen CY
+#define USB_PID_DNP_DS80D 0x0008
+
+#define USB_PID_CITIZEN_CW01 0x0002 // Maybe others?
+#define USB_PID_CITIZEN_CW02 0x0006 // Also OP900II
+#define USB_PID_CITIZEN_CX02 0x000A
+
+#define USB_VID_DNP 0x1452
+#define USB_PID_DNP_DS620 0x8b01
+#define USB_PID_DNP_DS820 0x9001
+
/* Exported */
struct dyesub_backend dnpds40_backend = {
- .name = "DNP DS40/DS80/DSRX1/DS620",
- .version = "0.92",
- .uri_prefix = "dnpds40",
+ .name = "DNP DS-series / Citizen C-series",
+ .version = "0.109",
+ .uri_prefixes = dnpds40_prefixes,
+ .flags = BACKEND_FLAG_JOBLIST,
.cmdline_usage = dnpds40_cmdline,
.cmdline_arg = dnpds40_cmdline_arg,
.init = dnpds40_init,
.attach = dnpds40_attach,
.teardown = dnpds40_teardown,
.read_parse = dnpds40_read_parse,
+ .cleanup_job = dnpds40_cleanup_job,
.main_loop = dnpds40_main_loop,
.query_serno = dnpds40_query_serno,
+ .query_markers = dnpds40_query_markers,
.devices = {
- { USB_VID_CITIZEN, USB_PID_DNP_DS40, P_DNP_DS40, ""},
- { USB_VID_CITIZEN, USB_PID_DNP_DS80, P_DNP_DS80, ""},
- { USB_VID_CITIZEN, USB_PID_DNP_DSRX1, P_DNP_DSRX1, ""},
- { USB_VID_CITIZEN, USB_PID_DNP_DS620_OLD, P_DNP_DS620, ""},
- { USB_VID_DNP, USB_PID_DNP_DS620, P_DNP_DS620, ""},
- { USB_VID_DNP, USB_PID_DNP_DS80D, P_DNP_DS80D, ""},
- { USB_VID_CITIZEN, USB_PID_CITIZEN_CW02, P_DNP_DS40, ""},
- { USB_VID_DNP, USB_PID_DNP_DS820, P_DNP_DS820, ""},
- { 0, 0, 0, ""}
+ { USB_VID_CITIZEN, USB_PID_DNP_DS40, P_DNP_DS40, NULL, "dnp-ds40"}, // Also Citizen CX
+ { USB_VID_CITIZEN, USB_PID_DNP_DS80, P_DNP_DS80, NULL, "dnp-ds80"}, // Also Citizen CX-W and Mitsubishi CP-3800DW
+ { USB_VID_CITIZEN, USB_PID_DNP_DS80D, P_DNP_DS80D, NULL, "dnp-ds80dx"},
+ { USB_VID_CITIZEN, USB_PID_DNP_DSRX1, P_DNP_DSRX1, NULL, "dnp-dsrx1"}, // Also Citizen CY
+ { USB_VID_DNP, USB_PID_DNP_DS620, P_DNP_DS620, NULL, "dnp-ds620"},
+ { USB_VID_DNP, USB_PID_DNP_DS820, P_DNP_DS820, NULL, "dnp-ds820"},
+ { USB_VID_CITIZEN, USB_PID_CITIZEN_CW01, P_CITIZEN_CW01, NULL, "citizen-cw-01"}, // Also OP900 ?
+ { USB_VID_CITIZEN, USB_PID_CITIZEN_CW02, P_CITIZEN_OP900II, NULL, "citizen-cw-02"}, // Also OP900II
+ { USB_VID_CITIZEN, USB_PID_CITIZEN_CX02, P_DNP_DS620, NULL, "citizen-cx-02"},
+ { 0, 0, 0, NULL, NULL}
}
};
+
+/* Legacy CW-01 spool file support */
+
+static int cw01_read_parse(struct dnpds40_printjob *job, int data_fd,
+ struct cw01_spool_hdr *hdr, int read_data)
+{
+ int i, remain;
+ uint32_t j;
+ uint8_t *buf;
+ uint8_t plane_hdr[14];
+
+ remain = hdr->plane_len * 3;
+ buf = malloc(remain);
+ if (!buf) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ j = read_data - sizeof(*hdr);
+ memcpy(buf, job->databuf, j);
+ remain -= j;
+ /* Read in the remaining spool data */
+ while (remain) {
+ i = read(data_fd, buf + j, remain);
+
+ if (i < 0) {
+ free(buf);
+ return i;
+ }
+
+ remain -= i;
+ j += i;
+ }
+
+ /* Generate plane header (same for all planes) */
+ j = cpu_to_le32(hdr->plane_len) + 24;
+ memset(plane_hdr, 0, sizeof(plane_hdr));
+ plane_hdr[0] = 0x42;
+ plane_hdr[1] = 0x4d;
+ memcpy(plane_hdr + 2, &j, sizeof(j));
+ plane_hdr[10] = 0x40;
+ plane_hdr[11] = 0x04;
+
+ /* Okay, generate a new stream into job->databuf! */
+#if 0
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PCNTRL QTY 00000008%07d\r", hdr->copies);
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PCNTRL CUTTER 0000000800000000");
+#else
+ /* QTY is stripped from the stream, and CUTTER is stashed away */
+ job->cutter = 0;
+#endif
+
+ j = 0;
+
+ /* Y plane */
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PIMAGE YPLANE %08u", hdr->plane_len + 24);
+ memcpy(job->databuf + job->datalen, plane_hdr, sizeof(plane_hdr));
+ job->datalen += sizeof(plane_hdr);
+ memcpy(job->databuf + job->datalen, buf + j, hdr->plane_len);
+ job->datalen += hdr->plane_len;
+ j += hdr->plane_len;
+ memset(job->databuf + job->datalen, 0, 10);
+ job->datalen += 10;
+
+ /* M plane */
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PIMAGE MPLANE %08u", hdr->plane_len + 24);
+ memcpy(job->databuf + job->datalen, plane_hdr, sizeof(plane_hdr));
+ job->datalen += sizeof(plane_hdr);
+ memcpy(job->databuf + job->datalen, buf + j, hdr->plane_len);
+ job->datalen += hdr->plane_len;
+ j += hdr->plane_len;
+ memset(job->databuf + job->datalen, 0, 10);
+ job->datalen += 10;
+
+ /* C plane */
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PIMAGE CPLANE %08u", hdr->plane_len + 24);
+ memcpy(job->databuf + job->datalen, plane_hdr, sizeof(plane_hdr));
+ job->datalen += sizeof(plane_hdr);
+ memcpy(job->databuf + job->datalen, buf + j, hdr->plane_len);
+ job->datalen += hdr->plane_len;
+ j += hdr->plane_len;
+ memset(job->databuf + job->datalen, 0, 10);
+ job->datalen += 10;
+
+ /* Start */
+ job->datalen += sprintf((char*)job->databuf + job->datalen,
+ "\033PCNTRL START ");
+
+ /* We're done */
+ free(buf);
+
+ return CUPS_BACKEND_OK;
+}
+
+/*
+
+Basic spool file format for CW01
+
+TT RR NN 00 XX XX XX XX 00 00 00 00 <- FILE header.
+
+ NN : copies (0x01 or more)
+ RR : resolution; 0 == 334 dpi, 1 == 600dpi
+ TT : type 0x02 == 4x6, 0x01 == 5x3.5
+ XX XX XX XX : plane length (LE)
+ plane length * 3 + 12 == file length.
+
+Followed by three planes, each with this header:
+
+28 00 00 00 00 08 00 00 RR RR 00 00 01 00 08 00
+00 00 00 00 00 00 00 00 5a 33 00 00 YY YY 00 00
+00 01 00 00 00 00 00 00
+
+ RR RR : rows in LE format
+ YY YY : 0x335a (334dpi) or 0x5c40 (600dpi)
+
+Followed by 1024 bytes of color tables:
+
+ ff ff ff 00 ... 00 00 00 00
+
+1024+40 = 1064 bytes of header per plane.
+
+Always have 2048 columns of data.
+
+followed by (2048 * rows) bytes of data.
+
+*/
diff --git a/src/cups/backend_kodak1400.c b/src/cups/backend_kodak1400.c
index e87307f..99bd678 100644
--- a/src/cups/backend_kodak1400.c
+++ b/src/cups/backend_kodak1400.c
@@ -1,7 +1,7 @@
/*
* Kodak Professional 1400/805 CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -75,19 +76,26 @@ struct kodak1400_hdr {
/* Private data structure */
+struct kodak1400_printjob {
+ struct kodak1400_hdr hdr;
+ uint8_t *plane_r;
+ uint8_t *plane_g;
+ uint8_t *plane_b;
+
+ int copies;
+};
+
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;
- uint8_t *plane_g;
- uint8_t *plane_b;
+ struct marker marker;
};
static int send_plane(struct kodak1400_ctx *ctx,
+ const struct kodak1400_printjob *job,
uint8_t planeno, uint8_t *planedata,
uint8_t *cmdbuf)
{
@@ -113,9 +121,9 @@ static int send_plane(struct kodak1400_ctx *ctx,
cmdbuf[3] = planeno;
if (planedata) {
- temp16 = htons(ctx->hdr.columns);
+ temp16 = htons(job->hdr.columns);
memcpy(cmdbuf+7, &temp16, 2);
- temp16 = htons(ctx->hdr.rows);
+ temp16 = htons(job->hdr.rows);
memcpy(cmdbuf+9, &temp16, 2);
}
@@ -125,10 +133,10 @@ static int send_plane(struct kodak1400_ctx *ctx,
if (planedata) {
int i;
- for (i = 0 ; i < ctx->hdr.rows ; i++) {
+ for (i = 0 ; i < job->hdr.rows ; i++) {
if ((ret = send_data(ctx->dev, ctx->endp_down,
- planedata + i * ctx->hdr.columns,
- ctx->hdr.columns)))
+ planedata + i * job->hdr.columns,
+ job->hdr.columns)))
return ret;
}
}
@@ -292,24 +300,38 @@ static void *kodak1400_init(void)
return ctx;
}
-static void kodak1400_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int kodak1400_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ 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;
+ ctx->type = type;
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = "Unknown";
+ ctx->marker.levelmax = -1;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void kodak1400_cleanup_job(const void *vjob)
+{
+ const struct kodak1400_printjob *job = vjob;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
+ if (job->plane_r)
+ free(job->plane_r);
+ if (job->plane_g)
+ free(job->plane_g);
+ if (job->plane_b)
+ free(job->plane_b);
- ctx->type = lookup_printer_type(&kodak1400_backend,
- desc.idVendor, desc.idProduct);
+ free((void*)job);
}
static void kodak1400_teardown(void *vctx) {
@@ -318,83 +340,76 @@ static void kodak1400_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->plane_r)
- free(ctx->plane_r);
- if (ctx->plane_g)
- free(ctx->plane_g);
- if (ctx->plane_b)
- free(ctx->plane_b);
free(ctx);
}
-static int kodak1400_read_parse(void *vctx, int data_fd) {
+static int kodak1400_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct kodak1400_ctx *ctx = vctx;
int i, ret;
+ struct kodak1400_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->plane_r) {
- free(ctx->plane_r);
- ctx->plane_r = NULL;
- }
- if (ctx->plane_g) {
- free(ctx->plane_g);
- ctx->plane_g = NULL;
- }
- if (ctx->plane_b) {
- free(ctx->plane_b);
- ctx->plane_b = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
- if (ctx->hdr.hdr[0] != 'P' ||
- ctx->hdr.hdr[1] != 'G' ||
- ctx->hdr.hdr[2] != 'H' ||
- ctx->hdr.hdr[3] != 'D') {
+ if (job->hdr.hdr[0] != 'P' ||
+ job->hdr.hdr[1] != 'G' ||
+ job->hdr.hdr[2] != 'H' ||
+ job->hdr.hdr[3] != 'D') {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
- ctx->hdr.planesize = le32_to_cpu(ctx->hdr.planesize);
- ctx->hdr.rows = le16_to_cpu(ctx->hdr.rows);
- ctx->hdr.columns = le16_to_cpu(ctx->hdr.columns);
+ job->hdr.planesize = le32_to_cpu(job->hdr.planesize);
+ job->hdr.rows = le16_to_cpu(job->hdr.rows);
+ job->hdr.columns = le16_to_cpu(job->hdr.columns);
/* Set up plane data */
- ctx->plane_r = malloc(ctx->hdr.planesize);
- ctx->plane_g = malloc(ctx->hdr.planesize);
- ctx->plane_b = malloc(ctx->hdr.planesize);
- if (!ctx->plane_r || !ctx->plane_g || !ctx->plane_b) {
+ job->plane_r = malloc(job->hdr.planesize);
+ job->plane_g = malloc(job->hdr.planesize);
+ job->plane_b = malloc(job->hdr.planesize);
+ if (!job->plane_r || !job->plane_g || !job->plane_b) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
- for (i = 0 ; i < ctx->hdr.rows ; i++) {
+ for (i = 0 ; i < job->hdr.rows ; i++) {
int j;
uint8_t *ptr;
for (j = 0 ; j < 3 ; j++) {
int remain;
if (j == 0)
- ptr = ctx->plane_r + i * ctx->hdr.columns;
+ ptr = job->plane_r + i * job->hdr.columns;
else if (j == 1)
- ptr = ctx->plane_g + i * ctx->hdr.columns;
+ ptr = job->plane_g + i * job->hdr.columns;
else if (j == 2)
- ptr = ctx->plane_b + i * ctx->hdr.columns;
+ ptr = job->plane_b + i * job->hdr.columns;
+ else
+ ptr = NULL;
- remain = ctx->hdr.columns;
+ remain = job->hdr.columns;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%u) (%d/%u @ %d)\n",
- ret, remain, ctx->hdr.columns,
- i, ctx->hdr.rows, j);
+ ret, remain, job->hdr.columns,
+ i, job->hdr.rows, j);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
@@ -404,13 +419,15 @@ static int kodak1400_read_parse(void *vctx, int data_fd) {
}
}
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
static uint8_t idle_data[READBACK_LEN] = { 0xe4, 0x72, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
-static int kodak1400_main_loop(void *vctx, int copies) {
+static int kodak1400_main_loop(void *vctx, const void *vjob) {
struct kodak1400_ctx *ctx = vctx;
uint8_t rdbuf[READBACK_LEN], rdbuf2[READBACK_LEN];
@@ -418,6 +435,16 @@ static int kodak1400_main_loop(void *vctx, int copies) {
int last_state = -1, state = S_IDLE;
int num, ret;
uint16_t temp16;
+ int copies;
+
+ const struct kodak1400_printjob *job = vjob;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
top:
if (state != last_state) {
@@ -473,9 +500,9 @@ top:
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x5a;
cmdbuf[2] = 0x53;
- temp16 = be16_to_cpu(ctx->hdr.columns);
+ temp16 = be16_to_cpu(job->hdr.columns);
memcpy(cmdbuf+3, &temp16, 2);
- temp16 = be16_to_cpu(ctx->hdr.rows);
+ temp16 = be16_to_cpu(job->hdr.rows);
memcpy(cmdbuf+5, &temp16, 2);
if ((ret = send_data(ctx->dev, ctx->endp_down,
@@ -486,7 +513,7 @@ top:
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x59;
- cmdbuf[2] = ctx->hdr.matte; // ???
+ cmdbuf[2] = job->hdr.matte; // ???
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
@@ -496,7 +523,7 @@ top:
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x60;
- cmdbuf[2] = ctx->hdr.laminate;
+ cmdbuf[2] = job->hdr.laminate;
if (send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN))
@@ -506,7 +533,7 @@ top:
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x62;
- cmdbuf[2] = ctx->hdr.lam_strength;
+ cmdbuf[2] = job->hdr.lam_strength;
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
@@ -516,7 +543,7 @@ top:
memset(cmdbuf, 0, CMDBUF_LEN);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x61;
- cmdbuf[2] = ctx->hdr.unk1; // ???
+ cmdbuf[2] = job->hdr.unk1; // ???
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, CMDBUF_LEN)))
@@ -526,7 +553,7 @@ top:
break;
case S_PRINTER_READY_Y:
INFO("Sending YELLOW plane\n");
- if ((ret = send_plane(ctx, 1, ctx->plane_b, cmdbuf)))
+ if ((ret = send_plane(ctx, job, 1, job->plane_b, cmdbuf)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_Y;
break;
@@ -536,7 +563,7 @@ top:
break;
case S_PRINTER_READY_M:
INFO("Sending MAGENTA plane\n");
- if ((ret = send_plane(ctx, 2, ctx->plane_g, cmdbuf)))
+ if ((ret = send_plane(ctx, job, 2, job->plane_g, cmdbuf)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_M;
break;
@@ -546,13 +573,13 @@ top:
break;
case S_PRINTER_READY_C:
INFO("Sending CYAN plane\n");
- if ((ret = send_plane(ctx, 3, ctx->plane_r, cmdbuf)))
+ if ((ret = send_plane(ctx, job, 3, job->plane_r, cmdbuf)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_C;
break;
case S_PRINTER_SENT_C:
if (!memcmp(rdbuf, idle_data, READBACK_LEN)) {
- if (ctx->hdr.laminate)
+ if (job->hdr.laminate)
state = S_PRINTER_READY_L;
else
state = S_PRINTER_DONE;
@@ -560,7 +587,7 @@ top:
break;
case S_PRINTER_READY_L:
INFO("Laminating page\n");
- if ((ret = send_plane(ctx, 4, NULL, cmdbuf)))
+ if ((ret = send_plane(ctx, job, 4, NULL, cmdbuf)))
return CUPS_BACKEND_FAILED;
state = S_PRINTER_SENT_L;
break;
@@ -604,26 +631,53 @@ top:
return CUPS_BACKEND_OK;
}
+static int kodak1400_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct kodak1400_ctx *ctx = vctx;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
/* Exported */
#define USB_VID_KODAK 0x040A
#define USB_PID_KODAK_1400 0x4022
#define USB_PID_KODAK_805 0x4034
+#define USB_VID_MITSU 0x06D3
+#define USB_PID_MITSU_3020D 0x038B
+#define USB_PID_MITSU_3020DA 0x03AA
+
+static const char *kodak1400_prefixes[] = {
+ "kodak1400", // Family driver, do NOT nuke!
+ "kodak-1400", "kodak-805", "mitsubishi-3020d", "mitsubishi-3020da",
+ // backwards compatibility
+ "kodak805", "mitsu3020d", "mitsu3020da",
+ // Extras.
+ "mitsubishi-3020dae", "mitsubishi-3020de", "mitsubishi-3020du",
+ NULL,
+};
struct dyesub_backend kodak1400_backend = {
.name = "Kodak 1400/805",
- .version = "0.34",
- .uri_prefix = "kodak1400",
+ .version = "0.39",
+ .uri_prefixes = kodak1400_prefixes,
.cmdline_usage = kodak1400_cmdline,
.cmdline_arg = kodak1400_cmdline_arg,
.init = kodak1400_init,
.attach = kodak1400_attach,
.teardown = kodak1400_teardown,
+ .cleanup_job = kodak1400_cleanup_job,
.read_parse = kodak1400_read_parse,
.main_loop = kodak1400_main_loop,
+ .query_markers = kodak1400_query_markers,
.devices = {
- { USB_VID_KODAK, USB_PID_KODAK_1400, P_KODAK_1400_805, "Kodak"},
- { USB_VID_KODAK, USB_PID_KODAK_805, P_KODAK_1400_805, "Kodak"},
- { 0, 0, 0, ""}
+ { USB_VID_KODAK, USB_PID_KODAK_1400, P_KODAK_1400_805, "Kodak", "kodak-1400"},
+ { USB_VID_KODAK, USB_PID_KODAK_805, P_KODAK_1400_805, "Kodak", "kodak-805"},
+ { USB_VID_MITSU, USB_PID_MITSU_3020D, P_KODAK_1400_805, NULL, "mitsubishi-3020d"},
+ { USB_VID_MITSU, USB_PID_MITSU_3020DA, P_KODAK_1400_805, NULL, "mitsubishi-3020da" },
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_kodak605.c b/src/cups/backend_kodak605.c
index b301739..64524d4 100644
--- a/src/cups/backend_kodak605.c
+++ b/src/cups/backend_kodak605.c
@@ -1,7 +1,7 @@
/*
* Kodak 605 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -165,6 +166,12 @@ static const char *kodak68xx_mediatypes(int type)
#define CMDBUF_LEN 4
/* Private data structure */
+struct kodak605_printjob {
+ struct kodak605_hdr hdr;
+ uint8_t *databuf;
+ int datalen;
+};
+
struct kodak605_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
@@ -172,14 +179,10 @@ struct kodak605_ctx {
int type;
uint8_t jobid;
- struct kodak605_hdr hdr;
-
struct kodak605_media_list *media;
- uint8_t *databuf;
- int datalen;
+ struct marker marker;
- uint8_t last_donor;
};
static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_list *media)
@@ -216,6 +219,40 @@ static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_li
return 0;
}
+static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status *sts)
+{
+ uint8_t cmdbuf[4];
+
+ 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, sizeof(cmdbuf))))
+ return ret;
+
+ /* Read in the printer status */
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) sts, sizeof(*sts), &num);
+ if (ret < 0)
+ return ret;
+
+ if (num < (int)sizeof(*sts)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*sts));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (sts->hdr.result != RESULT_SUCCESS) {
+ ERROR("Unexpected response from status query (%x)!\n", sts->hdr.result);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ return 0;
+}
+
static void *kodak605_init(void)
{
struct kodak605_ctx *ctx = malloc(sizeof(struct kodak605_ctx));
@@ -227,40 +264,54 @@ static void *kodak605_init(void)
ctx->media = malloc(MAX_MEDIA_LEN);
- ctx->type = P_ANY;
-
return ctx;
}
-static void kodak605_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int kodak605_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct kodak605_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(&kodak605_backend,
- desc.idVendor, desc.idProduct);
+ ctx->type = type;
/* Make sure jobid is sane */
ctx->jobid = jobid & 0x7f;
if (!ctx->jobid)
ctx->jobid++;
- /* Init */
- ctx->last_donor = 255;
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Query media info */
+ if (kodak605_get_media(ctx, ctx->media)) {
+ ERROR("Can't query media\n");
+ return CUPS_BACKEND_FAILED;
+ }
+ } else {
+ int media_code = KODAK68x0_MEDIA_6TR2;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
- /* Query media info */
- if (kodak605_get_media(ctx, ctx->media)) {
- ERROR("Can't query media\n");
+ ctx->media->type = media_code;
}
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = kodak68xx_mediatypes(ctx->media->type);
+ ctx->marker.levelmax = 100; /* Ie percentage */
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void kodak605_cleanup_job(const void *vjob)
+{
+ const struct kodak605_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void kodak605_teardown(void *vctx) {
@@ -269,57 +320,59 @@ static void kodak605_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
free(ctx);
}
-static int kodak605_read_parse(void *vctx, int data_fd) {
+static int kodak605_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct kodak605_ctx *ctx = vctx;
int ret;
+ struct kodak605_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_CANCEL;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
+ memset(job, 0, sizeof(*job));
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
- if (ctx->hdr.hdr[0] != 0x01 ||
- ctx->hdr.hdr[1] != 0x40 ||
- ctx->hdr.hdr[2] != 0x0a ||
- ctx->hdr.hdr[3] != 0x00) {
+ if (job->hdr.hdr[0] != 0x01 ||
+ job->hdr.hdr[1] != 0x40 ||
+ job->hdr.hdr[2] != 0x0a ||
+ job->hdr.hdr[3] != 0x00) {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
- ctx->datalen = le16_to_cpu(ctx->hdr.rows) * le16_to_cpu(ctx->hdr.columns) * 3;
- ctx->databuf = malloc(ctx->datalen);
- if (!ctx->databuf) {
+ job->datalen = le16_to_cpu(job->hdr.rows) * le16_to_cpu(job->hdr.columns) * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
@@ -328,61 +381,36 @@ static int kodak605_read_parse(void *vctx, int data_fd) {
} while (remain);
}
- return CUPS_BACKEND_OK;
-}
-
-static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status *sts)
-{
- uint8_t cmdbuf[4];
-
- 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, sizeof(cmdbuf))))
- return ret;
-
- /* Read in the printer status */
- ret = read_data(ctx->dev, ctx->endp_up,
- (uint8_t*) sts, sizeof(*sts), &num);
- if (ret < 0)
- return ret;
-
- if (num < (int)sizeof(*sts)) {
- ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*sts));
- return CUPS_BACKEND_FAILED;
- }
+ /* Printer handles generating copies.. */
+ if (le16_to_cpu(job->hdr.copies) < copies)
+ job->hdr.copies = cpu_to_le16(copies);
- if (sts->hdr.result != RESULT_SUCCESS) {
- ERROR("Unexpected response from status query (%x)!\n", sts->hdr.result);
- return CUPS_BACKEND_FAILED;
- }
+ *vjob = job;
- return 0;
+ return CUPS_BACKEND_OK;
}
-static int kodak605_main_loop(void *vctx, int copies) {
+static int kodak605_main_loop(void *vctx, const void *vjob) {
struct kodak605_ctx *ctx = vctx;
struct kodak605_status sts;
int num, ret;
+ const struct kodak605_printjob *job = vjob;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
- /* Printer handles generating copies.. */
- if (le16_to_cpu(ctx->hdr.copies) < copies)
- ctx->hdr.copies = cpu_to_le16(copies);
+ struct kodak605_hdr hdr;
+ memcpy(&hdr, &job->hdr, sizeof(hdr));
/* 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)
+ if (ctx->media->entries[num].rows == hdr.rows &&
+ ctx->media->entries[num].cols == hdr.columns)
break;
}
if (num == ctx->media->count) {
@@ -390,22 +418,15 @@ static int kodak605_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_HOLD;
}
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", kodak68xx_mediatypes(ctx->media->type));
- ATTR("marker-types=ribbonWax\n");
-
INFO("Waiting for printer idle\n");
while(1) {
if ((ret = kodak605_get_status(ctx, &sts)))
return CUPS_BACKEND_FAILED;
- if (ctx->last_donor != sts.donor) {
- ctx->last_donor = sts.donor;
- ATTR("marker-levels=%u\n", sts.donor);
+ if (ctx->marker.levelnow != sts.donor) {
+ ctx->marker.levelnow = sts.donor;
+ dump_markers(&ctx->marker, 1, 0);
}
// XXX check for errors
@@ -430,12 +451,12 @@ static int kodak605_main_loop(void *vctx, int copies) {
}
/* Use specified jobid */
- ctx->hdr.jobid = ctx->jobid;
+ hdr.jobid = ctx->jobid;
{
INFO("Sending image header (internal id %u)\n", ctx->jobid);
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*)&ctx->hdr, sizeof(ctx->hdr))))
+ (uint8_t*)&hdr, sizeof(hdr))))
return CUPS_BACKEND_FAILED;
struct kodak605_sts_hdr resp;
@@ -453,7 +474,7 @@ static int kodak605_main_loop(void *vctx, int copies) {
INFO("Sending image data\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Image data sent\n");
@@ -464,13 +485,12 @@ static int kodak605_main_loop(void *vctx, int copies) {
if ((kodak605_get_status(ctx, &sts)) != 0)
return CUPS_BACKEND_FAILED;
+ if (ctx->marker.levelnow != sts.donor) {
+ ctx->marker.levelnow = sts.donor;
+ dump_markers(&ctx->marker, 1, 0);
+ }
// XXX check for errors
- if (ctx->last_donor != sts.donor) {
- ctx->last_donor = sts.donor;
- ATTR("marker-levels=%u\n", sts.donor);
- } // XXX check for errors ?
-
/* Wait for completion */
if (sts.b1_id == ctx->jobid && sts.b1_complete == sts.b1_total)
break;
@@ -671,21 +691,46 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int kodak605_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct kodak605_ctx *ctx = vctx;
+ struct kodak605_status sts;
+
+ /* Query printer status */
+ if (kodak605_get_status(ctx, &sts))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = sts.donor;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *kodak605_prefixes[] = {
+ "kodak605", // Family driver, do NOT nuke.
+ "kodak-605",
+ NULL,
+};
+
/* Exported */
struct dyesub_backend kodak605_backend = {
.name = "Kodak 605",
- .version = "0.27",
- .uri_prefix = "kodak605",
+ .version = "0.33",
+ .uri_prefixes = kodak605_prefixes,
.cmdline_usage = kodak605_cmdline,
.cmdline_arg = kodak605_cmdline_arg,
.init = kodak605_init,
.attach = kodak605_attach,
.teardown = kodak605_teardown,
+ .cleanup_job = kodak605_cleanup_job,
.read_parse = kodak605_read_parse,
.main_loop = kodak605_main_loop,
+ .query_markers = kodak605_query_markers,
.devices = {
- { USB_VID_KODAK, USB_PID_KODAK_605, P_KODAK_605, "Kodak"},
- { 0, 0, 0, ""}
+ { USB_VID_KODAK, USB_PID_KODAK_605, P_KODAK_605, "Kodak", "kodak-605"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_kodak6800.c b/src/cups/backend_kodak6800.c
index f535797..79d950b 100644
--- a/src/cups/backend_kodak6800.c
+++ b/src/cups/backend_kodak6800.c
@@ -1,7 +1,7 @@
/*
* Kodak 6800/6850 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@@ -22,11 +22,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -222,6 +223,13 @@ struct kodak68x0_media_readback {
#define CMDBUF_LEN 17
/* Private data structure */
+struct kodak6800_printjob {
+ struct kodak6800_hdr hdr;
+ uint8_t *databuf;
+ int datalen;
+ int copies;
+};
+
struct kodak6800_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
@@ -233,11 +241,7 @@ struct kodak6800_ctx {
struct kodak68x0_media_readback *media;
- struct kodak6800_hdr hdr;
- uint8_t *databuf;
- int datalen;
-
- uint8_t last_donor;
+ struct marker marker;
};
static const char *kodak68xx_mediatypes(int type)
@@ -276,8 +280,6 @@ static int kodak6800_do_cmd(struct kodak6800_ctx *ctx,
return 0;
}
-
-
static void kodak68x0_dump_mediainfo(struct kodak68x0_media_readback *media)
{
int i;
@@ -690,6 +692,7 @@ static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
cmdbuf[14] = 0x00;
cmdbuf[15] = 0x00;
+ respbuf[0] = 0xff;
/* Issue command and get response */
if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
respbuf, sizeof(respbuf),
@@ -1004,40 +1007,54 @@ static void *kodak6800_init(void)
ctx->media = malloc(MAX_MEDIA_LEN);
- ctx->type = P_ANY;
-
return ctx;
}
-static void kodak6800_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int kodak6800_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct kodak6800_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(&kodak6800_backend,
- desc.idVendor, desc.idProduct);
+ ctx->type = type;
/* Ensure jobid is sane */
ctx->jobid = jobid & 0x7f;
if (!ctx->jobid)
ctx->jobid++;
- /* Init */
- ctx->last_donor = 255;
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Query media info */
+ if (kodak6800_get_mediainfo(ctx, ctx->media)) {
+ ERROR("Can't query media\n");
+ return CUPS_BACKEND_FAILED;
+ }
+ } else {
+ int media_code = KODAK68x0_MEDIA_6TR2;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
- /* Query media info */
- if (kodak6800_get_mediainfo(ctx, ctx->media)) {
- ERROR("Can't query media\n");
+ ctx->media->type = media_code;
}
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = kodak68xx_mediatypes(ctx->media->type);
+ ctx->marker.levelmax = 100; /* Ie percentage */
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void kodak6800_cleanup_job(const void *vjob)
+{
+ const struct kodak6800_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void kodak6800_teardown(void *vctx) {
@@ -1046,57 +1063,59 @@ static void kodak6800_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
free(ctx);
}
-static int kodak6800_read_parse(void *vctx, int data_fd) {
+static int kodak6800_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct kodak6800_ctx *ctx = vctx;
int ret;
+ struct kodak6800_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
+ memset(job, 0, sizeof(*job));
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
- if (ctx->hdr.hdr[0] != 0x03 ||
- ctx->hdr.hdr[1] != 0x1b ||
- ctx->hdr.hdr[2] != 0x43 ||
- ctx->hdr.hdr[3] != 0x48 ||
- ctx->hdr.hdr[4] != 0x43) {
+ if (job->hdr.hdr[0] != 0x03 ||
+ job->hdr.hdr[1] != 0x1b ||
+ job->hdr.hdr[2] != 0x43 ||
+ job->hdr.hdr[3] != 0x48 ||
+ job->hdr.hdr[4] != 0x43) {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
- ctx->datalen = be16_to_cpu(ctx->hdr.rows) * be16_to_cpu(ctx->hdr.columns) * 3;
- ctx->databuf = malloc(ctx->datalen);
- if (!ctx->databuf) {
+ job->datalen = be16_to_cpu(job->hdr.rows) * be16_to_cpu(job->hdr.columns) * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
@@ -1105,29 +1124,39 @@ static int kodak6800_read_parse(void *vctx, int data_fd) {
} while (remain);
}
+ /* Fix max print count. */
+ if (copies > 9999) // XXX test against remaining media
+ copies = 9999;
+
+ /* Printer handles generating copies.. */
+ if (le16_to_cpu(job->hdr.copies) < copies)
+ job->hdr.copies = cpu_to_be16(uint16_to_packed_bcd(copies));
+
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int kodak6800_main_loop(void *vctx, int copies) {
+static int kodak6800_main_loop(void *vctx, const void *vjob) {
struct kodak6800_ctx *ctx = vctx;
struct kodak68x0_status_readback status;
int num, ret;
+ const struct kodak6800_printjob *job = vjob;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
- /* Fix max print count. */
- if (copies > 9999) // XXX test against remaining media
- copies = 9999;
-
- /* Printer handles generating copies.. */
- ctx->hdr.copies = cpu_to_be16(uint16_to_packed_bcd(copies));
+ struct kodak6800_hdr hdr;
+ memcpy(&hdr, &job->hdr, sizeof(hdr));
/* Validate against supported media list */
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 &&
+ if (ctx->media->sizes[num].height == hdr.rows &&
+ ctx->media->sizes[num].width == hdr.columns &&
ctx->media->sizes[num].code2 == 0x00) // XXX code2?
break;
}
@@ -1136,22 +1165,15 @@ static int kodak6800_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_HOLD;
}
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", kodak68xx_mediatypes(ctx->media->type));
- ATTR("marker-types=ribbonWax\n");
-
INFO("Waiting for printer idle\n");
while(1) {
if (kodak6800_get_status(ctx, &status))
return CUPS_BACKEND_FAILED;
- if (ctx->last_donor != status.donor) {
- ctx->last_donor = status.donor;
- ATTR("marker-levels=%u\n", status.donor);
+ if (ctx->marker.levelnow != status.donor) {
+ ctx->marker.levelnow = status.donor;
+ dump_markers(&ctx->marker, 1, 0);
}
if (status.status1 == STATE_STATUS1_ERROR) {
@@ -1189,20 +1211,20 @@ static int kodak6800_main_loop(void *vctx, int copies) {
return ret;
}
- ctx->hdr.jobid = ctx->jobid;
+ hdr.jobid = ctx->jobid;
#if 0
/* If we want to disable 4x6 rewind on 8x6 media.. */
// XXX not sure about this...?
- if (ctx->hdr.size == 0x00 &&
+ if (hdr.size == 0x00 &&
be16_to_cpu(ctx->media->sizes[0].width) == 0x0982) {
- ctx->hdr.size = 0x06;
- ctx->hdr.mode = 0x01;
+ hdr.size = 0x06;
+ hdr.mode = 0x01;
}
#endif
INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
- if ((ret = kodak6800_do_cmd(ctx, (uint8_t*) &ctx->hdr, sizeof(ctx->hdr),
+ if ((ret = kodak6800_do_cmd(ctx, (uint8_t*) &hdr, sizeof(hdr),
&status, sizeof(status),
&num)))
return ret;
@@ -1215,7 +1237,7 @@ static int kodak6800_main_loop(void *vctx, int copies) {
// sleep(1); // Appears to be necessary for reliability
INFO("Sending image data\n");
if ((send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)) != 0)
+ job->databuf, job->datalen)) != 0)
return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
@@ -1224,9 +1246,9 @@ static int kodak6800_main_loop(void *vctx, int copies) {
if (kodak6800_get_status(ctx, &status))
return CUPS_BACKEND_FAILED;
- if (ctx->last_donor != status.donor) {
- ctx->last_donor = status.donor;
- ATTR("marker-levels=%u\n", status.donor);
+ if (ctx->marker.levelnow != status.donor) {
+ ctx->marker.levelnow = status.donor;
+ dump_markers(&ctx->marker, 1, 0);
}
if (status.status1 == STATE_STATUS1_ERROR) {
@@ -1237,9 +1259,9 @@ static int kodak6800_main_loop(void *vctx, int copies) {
}
/* If all prints are complete, we're done! */
- if (status.b1_jobid == ctx->hdr.jobid && status.b1_complete == status.b1_total)
+ if (status.b1_jobid == hdr.jobid && status.b1_complete == status.b1_total)
break;
- if (status.b2_jobid == ctx->hdr.jobid && status.b2_complete == status.b2_total)
+ if (status.b2_jobid == hdr.jobid && status.b2_complete == status.b2_total)
break;
if (fast_return) {
@@ -1254,23 +1276,50 @@ static int kodak6800_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_OK;
}
+static int kodak6800_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct kodak6800_ctx *ctx = vctx;
+ struct kodak68x0_status_readback status;
+
+ /* Query printer status */
+ if (kodak6800_get_status(ctx, &status))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = status.donor;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *kodak6800_prefixes[] = {
+ "kodak68x0", // Family driver, do not nuke.
+ "kodak-6800", "kodak-6850",
+ // Backwards-compatibility
+ "kodak6800", "kodak6850",
+ NULL
+};
+
/* Exported */
struct dyesub_backend kodak6800_backend = {
.name = "Kodak 6800/6850",
- .version = "0.58",
- .uri_prefix = "kodak6800",
+ .version = "0.65",
+ .uri_prefixes = kodak6800_prefixes,
.cmdline_usage = kodak6800_cmdline,
.cmdline_arg = kodak6800_cmdline_arg,
.init = kodak6800_init,
.attach = kodak6800_attach,
.teardown = kodak6800_teardown,
+ .cleanup_job = kodak6800_cleanup_job,
.read_parse = kodak6800_read_parse,
.main_loop = kodak6800_main_loop,
.query_serno = kodak6800_query_serno,
+ .query_markers = kodak6800_query_markers,
.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, ""}
+ { USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak", "kodak-6800"},
+ { USB_VID_KODAK, USB_PID_KODAK_6850, P_KODAK_6850, "Kodak", "kodak-6850"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_magicard.c b/src/cups/backend_magicard.c
new file mode 100644
index 0000000..d356bba
--- /dev/null
+++ b/src/cups/backend_magicard.c
@@ -0,0 +1,1143 @@
+/*
+ * Magicard card printer family CUPS backend -- libusb-1.0 version
+ *
+ * (c) 2017-2018 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * The latest version of this program can be found at:
+ *
+ * http://git.shaftnet.org/cgit/selphy_print.git
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * [http://www.gnu.org/licenses/gpl-2.0.html]
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+
+#define BACKEND magicard_backend
+
+#include "backend_common.h"
+
+/* Exported */
+#define USB_VID_MAGICARD 0x0C1F
+#define USB_PID_MAGICARD_TANGO2E 0x1800
+#define USB_PID_MAGICARD_ENDURO 0x4800 // ??
+#define USB_PID_MAGICARD_ENDUROPLUS 0x880A // ??
+
+/* Gamma tables computed with this perl program:
+
+ my $input_bpp = 8;
+ my $output_bpp = 6;
+ my $gamma = 1/1.8; # or 1/2.2 or whatever.
+
+ my $i;
+
+ for (my $i = 0 ; $i < (2 ** $input_bpp) ; $i++) {
+ my $linear = $i / (2 ** $input_bpp);
+ my $gc = ($linear ** $gamma) * (2 ** $output_bpp);
+ $gc = int($gc);
+ print "$gc, ";
+ }
+
+*/
+
+static uint8_t gammas[2][256] = {
+ /* Gamma = 2.2 */
+ {
+ 0, 5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17,
+ 17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 23, 23, 23,
+ 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32,
+ 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 35, 36, 36,
+ 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39,
+ 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, 42,
+ 42, 42, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45,
+ 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50,
+ 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 52, 52,
+ 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54,
+ 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56,
+ 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58,
+ 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60,
+ 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63,
+ },
+ /* Gamma = 1.8 */
+ {
+ 0, 2, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12,
+ 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19,
+ 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24,
+ 24, 24, 24, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 28, 28,
+ 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32,
+ 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35,
+ 35, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38,
+ 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41,
+ 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44,
+ 44, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 47, 47, 47,
+ 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49,
+ 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 52, 52, 52,
+ 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54,
+ 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 57, 57,
+ 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59,
+ 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61,
+ 61, 61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63,
+ }
+};
+
+struct magicard_printjob {
+ uint8_t *databuf;
+ int datalen;
+
+ int hdr_len;
+ int copies;
+};
+
+/* Private data structure */
+struct magicard_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ struct marker marker;
+};
+
+struct magicard_cmd_header {
+ uint8_t guard[9]; /* 0x05 */
+ uint8_t guard2[1]; /* 0x01 */
+ uint8_t cmd[4]; /* 'REQ,' */
+ uint8_t subcmd[4]; /* '???,' */
+ uint8_t arg[4]; /* '???,' */
+ uint8_t footer[2]; /* 0x1c 0x03 */
+};
+
+struct magicard_cmd_simple_header {
+ uint8_t guard[9]; /* 0x05 */
+ uint8_t guard2[1]; /* 0x01 */
+ uint8_t cmd[]; /* '???' */
+// uint8_t footer[2]; /* 0x1c 0x03 */
+};
+
+struct magicard_resp_header {
+ uint8_t guard[1]; /* 0x01 */
+ uint8_t subcmd_arg[7]; /* '???,???' */
+ uint8_t data[0]; /* freeform resp */
+// uint8_t term[2]; /* 0x2c 0x03 terminates! */
+};
+
+struct magicard_requests {
+ char *key;
+ char *desc;
+ uint8_t type;
+};
+
+enum {
+ TYPE_UNKNOWN = 0,
+ TYPE_STRING,
+ TYPE_STRINGINT,
+ TYPE_STRINGINT_HEX,
+ TYPE_IPADDR,
+ TYPE_YESNO,
+ TYPE_MODEL,
+};
+
+/* Data definitions */
+static struct magicard_requests magicard_sta_requests[] = {
+ { "MSR", "Printer Serial Number", TYPE_STRING },
+ { "PSR", "Print Head Serial Number", TYPE_STRING },
+ { "BSR", "PCB Serial Number", TYPE_STRING },
+ { "VRS", "Firmware Version", TYPE_STRING },
+ { "FDC", "Head Density", TYPE_STRINGINT }, /* 25 per step */
+ { "FSP", "Image Start", TYPE_STRINGINT }, /* 8 steps per pixel */
+ { "FEP", "Image End", TYPE_STRINGINT }, /* 8 steps per pixel */
+ { "FSS", "Ramp Adjust", TYPE_STRINGINT },
+ { "FPP", "Head Position", TYPE_STRINGINT }, /* L-R alignment */
+ { "MDL", "Model", TYPE_MODEL }, /* 0 == Standard. Others? */
+ { "PID", "USB PID", TYPE_STRINGINT_HEX }, /* ASCII integer, but needs to be shown as hex */
+ { "VID", "USB VID", TYPE_STRINGINT_HEX }, /* ASCII integer, but needs to be shown as hex */
+ { "USN", "USB Serial Number", TYPE_STRING },
+ { "UPN", "USB Manufacturer", TYPE_STRING },
+ { "MAC", "Ethernet MAC Address", TYPE_STRING },
+ { "DYN", "Dynamic Address", TYPE_YESNO }, /* 1 == yes, 0 == no */
+ { "IPA", "IP Address", TYPE_IPADDR }, /* ASCII signed integer */
+ { "SNM", "IP Netmask", TYPE_IPADDR }, /* ASCII signed integer */
+ { "GWY", "IP Gateway", TYPE_IPADDR }, /* ASCII signed integer */
+
+ { "TCQ", "Total Cards Printed", TYPE_STRINGINT },
+ { "TCP", "Prints on Head", TYPE_STRINGINT },
+ { "TCN", "Cleaning Cycles", TYPE_STRINGINT },
+ { "CCQ", "Cards Since Last Cleaning", TYPE_STRINGINT },
+ { "TPQ", "Total Panels Printed", TYPE_STRINGINT },
+ { "CCP", "Cards between Cleaning Prompts", TYPE_STRINGINT },
+ { "CPQ", "Panels Since Last Cleaning", TYPE_STRINGINT },
+ { "DFR", "Panels Remaining", TYPE_STRINGINT }, // cook somehow?
+ { "CLP", "Cleaning Prompt", TYPE_STRING },
+
+ // CRQ: OFF ?? Cleaning overdue?
+ // CHK: checksum of fw? (8 chars, hex?)
+ // TES: ??? signed int? IP addr?
+ // RAMP: ??? hangs.
+
+ { NULL, NULL, 0 }
+};
+
+// Sensors: CAM1 CAM2 TACHO FLIP DYE BARCODE LID FRONT REAR BUTTON TEMP ON OFF
+// Languages: ENG ITA POR FRA DEU ESP SCH
+
+/* Helper functions */
+static int magicard_build_cmd(uint8_t *buf,
+ char *cmd, char *subcmd, char *arg)
+{
+ struct magicard_cmd_header *hdr = (struct magicard_cmd_header *) buf;
+
+ memset(hdr->guard, 0x05, sizeof(hdr->guard));
+ hdr->guard2[0] = 0x01;
+ memcpy(hdr->cmd, cmd, 3);
+ hdr->cmd[3] = ',';
+ memcpy(hdr->subcmd, subcmd, 3);
+ hdr->subcmd[3] = ',';
+ memcpy(hdr->arg, arg, 3);
+ hdr->arg[3] = ',';
+ hdr->footer[0] = 0x1c;
+ hdr->footer[1] = 0x03;
+
+ return sizeof(*hdr);
+}
+
+static int magicard_build_cmd_simple(uint8_t *buf,
+ char *cmd)
+{
+ struct magicard_cmd_simple_header *hdr = (struct magicard_cmd_simple_header *) buf;
+ int len = strlen(cmd);
+
+ memset(hdr->guard, 0x05, sizeof(hdr->guard));
+ hdr->guard2[0] = 0x01;
+ strncpy((char*)hdr->cmd, cmd, len);
+ hdr->cmd[len] = 0x1c;
+ hdr->cmd[len+1] = 0x03;
+
+ return (sizeof(*hdr) + len + 2);
+}
+
+
+static uint8_t * magicard_parse_resp(uint8_t *buf, uint16_t len, uint16_t *resplen)
+{
+ struct magicard_resp_header *hdr = (struct magicard_resp_header *) buf;
+
+ *resplen = len - sizeof(hdr->guard) - sizeof(hdr->subcmd_arg) - 2;
+
+ return hdr->data;
+}
+
+static int magicard_query_sensors(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ int i;
+ uint8_t buf[256];
+ char buf2[24];
+
+ for (i = 1 ; ; i++) {
+ int num = 0;
+
+ snprintf(buf2, sizeof(buf2), "SNR%d", i);
+ ret = magicard_build_cmd_simple(buf, buf2);
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret)))
+ return ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ buf, sizeof(buf), &num);
+
+ if (ret < 0)
+ return ret;
+
+ if (!memcmp(buf, "END", 3))
+ break;
+
+ buf[num] = 0;
+ INFO("%s\n", buf);
+ }
+ return 0;
+}
+
+static int magicard_selftest_card(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ uint8_t buf[256];
+
+ ret = magicard_build_cmd_simple(buf, "TST,");
+
+ ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret);
+ return ret;
+}
+
+static int magicard_reset(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ uint8_t buf[256];
+
+ ret = magicard_build_cmd_simple(buf, "RST,");
+
+ ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret);
+ return ret;
+}
+
+static int magicard_eject(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ uint8_t buf[256];
+
+ ret = magicard_build_cmd_simple(buf, "EJT,");
+
+ ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret);
+ return ret;
+}
+
+static int magicard_query_printer(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ int i;
+ uint8_t buf[256];
+ char buf2[24];
+
+ for (i = 1 ; ; i++) {
+ int num = 0;
+
+ snprintf(buf2, sizeof(buf2), "QPR%d", i);
+ ret = magicard_build_cmd_simple(buf, buf2);
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret)))
+ return ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ buf, sizeof(buf), &num);
+
+ if (ret < 0)
+ return ret;
+
+ if (!memcmp(buf, "END", 3))
+ break;
+
+ buf[num] = 0;
+ INFO("%s\n", buf);
+ }
+ return 0;
+}
+
+static int magicard_query_status(struct magicard_ctx *ctx)
+{
+ int ret = 0;
+ int i;
+ uint8_t buf[256];
+
+ for (i = 0 ; ; i++) {
+ uint16_t resplen = 0;
+ uint8_t *resp;
+ int num = 0;
+
+ if (magicard_sta_requests[i].key == NULL)
+ break;
+
+ ret = magicard_build_cmd(buf, "REQ", "STA",
+ magicard_sta_requests[i].key);
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ buf, ret)))
+ return ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ buf, sizeof(buf), &num);
+
+ if (ret < 0)
+ return ret;
+
+ resp = magicard_parse_resp(buf, num, &resplen);
+ resp[resplen] = 0;
+ switch(magicard_sta_requests[i].type) {
+ case TYPE_IPADDR: {
+ int32_t ipaddr;
+ uint8_t *addr = (uint8_t *) &ipaddr;
+ ipaddr = atoi((char*)resp);
+ INFO("%s:\t%d.%d.%d.%d\n",
+ magicard_sta_requests[i].desc,
+ addr[3], addr[2], addr[1], addr[0]);
+ break;
+ }
+ case TYPE_YESNO: {
+ int val = atoi((char*)resp);
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ val? "Yes" : "No");
+ break;
+ }
+ case TYPE_MODEL: {
+ int val = atoi((char*)resp);
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ val == 0? "Standard" : "Unknown");
+ break;
+ }
+ case TYPE_STRINGINT_HEX: {
+ int val = atoi((char*)resp);
+ INFO("%s:\t%X\n",
+ magicard_sta_requests[i].desc,
+ val);
+ break;
+ }
+ case TYPE_STRINGINT:
+ // treat differently?
+ case TYPE_STRING:
+ case TYPE_UNKNOWN:
+ default:
+ INFO("%s:\t%s\n",
+ magicard_sta_requests[i].desc,
+ resp);
+ }
+ }
+
+ return ret;
+}
+
+/* Main driver */
+static void* magicard_init(void)
+{
+ struct magicard_ctx *ctx = malloc(sizeof(struct magicard_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct magicard_ctx));
+ return ctx;
+}
+
+static int magicard_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct magicard_ctx *ctx = vctx;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+ ctx->type = type;
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00"; // XXX YMCK too!
+ ctx->marker.name = "Unknown"; // LC1/LC3/LC6/LC8
+ ctx->marker.levelmax = -1;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void magicard_cleanup_job(const void *vjob)
+{
+ const struct magicard_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
+}
+
+static void magicard_teardown(void *vctx) {
+ struct magicard_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ free(ctx);
+}
+
+static void downscale_and_extract(int gamma, uint32_t pixels,
+ uint8_t *y_i, uint8_t *m_i, uint8_t *c_i,
+ uint8_t *y_o, uint8_t *m_o, uint8_t *c_o, uint8_t *k_o)
+{
+ uint32_t i;
+
+ for (i = 0 ; i < pixels; i++)
+ {
+ uint8_t y, m, c;
+ uint8_t k = 0;
+ uint32_t j;
+ uint32_t row;
+ uint32_t col;
+ uint32_t b_offset;
+ uint8_t b_shift;
+
+ /* Downscale color planes from 8bpp -> 6bpp; */
+ if (gamma) {
+ if (gamma > 2)
+ gamma = 2;
+ gamma--;
+ y = gammas[gamma][*y_i++];
+ m = gammas[gamma][*m_i++];
+ c = gammas[gamma][*c_i++];
+ } else {
+ y = *y_i++ >> 2;
+ m = *m_i++ >> 2;
+ c = *c_i++ >> 2;
+ }
+
+ /* Extract "true black" from ymc data, if enabled */
+ if (k_o && y == 0x3f && m == 0x3f && c == 0x3f) {
+ k = 1;
+ y = m = c = 0;
+ }
+
+ /* Compute row number and offsets */
+ row = i / 672;
+ col = i - (row * 672);
+ b_offset = col / 8;
+ b_shift = 7 - (col - (b_offset * 8));
+
+ /* Now, for each row, break it down into sub-chunks */
+ for (j = 0 ; j < 6 ; j++) {
+ if (b_shift == 7) {
+ y_o[row * 504 + j * 84 + b_offset] = 0;
+ m_o[row * 504 + j * 84 + b_offset] = 0;
+ c_o[row * 504 + j * 84 + b_offset] = 0;
+ }
+ if (y & (1 << j))
+ y_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
+ if (m & (1 << j))
+ m_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
+ if (c & (1 << j))
+ c_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
+ }
+
+ /* And resin black, if enabled */
+ if (k_o) {
+ if (b_shift == 7) {
+ k_o[row * 84 + b_offset] = 0;
+ }
+ if (k)
+ k_o[row * 84 + b_offset] |= (1 << b_shift);
+ }
+ }
+}
+
+#define MAX_PRINTJOB_LEN (1016*672*4) + 1024 /* 1016*672 * 4color */
+#define INITIAL_BUF_LEN 1024
+static int magicard_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
+ struct magicard_ctx *ctx = vctx;
+ uint8_t initial_buf[INITIAL_BUF_LEN + 1];
+ uint32_t buf_offset = 0;
+ int i;
+
+ uint8_t *in_y, *in_m, *in_c;
+ uint8_t *out_y, *out_m, *out_c, *out_k;
+ uint32_t len_y = 0, len_m = 0, len_c = 0, len_k = 0;
+ int gamma = 0;
+
+ uint8_t x_gp_8bpp;
+ uint8_t x_gp_rk;
+ uint8_t k_only;
+
+ struct magicard_printjob *job = NULL;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
+
+ /* Read in the first chunk */
+ i = read(data_fd, initial_buf, INITIAL_BUF_LEN);
+ if (i < 0) {
+ magicard_cleanup_job(job);
+ return i;
+ } else if (i == 0) {
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL; /* Ie no data, we're done */
+ } else if (i < INITIAL_BUF_LEN) {
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Basic Sanity Check */
+ if (initial_buf[0] != 0x05 ||
+ initial_buf[64] != 0x01 ||
+ initial_buf[65] != 0x2c) {
+ ERROR("Unrecognized header data format @%d!\n", job->datalen);
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ initial_buf[INITIAL_BUF_LEN] = 0;
+
+ /* We can start allocating! */
+ if (job->databuf) {
+ free(job->databuf);
+ job->databuf = NULL;
+ }
+ job->datalen = 0;
+ job->databuf = malloc(MAX_PRINTJOB_LEN);
+ if (!job->databuf) {
+ ERROR("Memory allocation failure!\n");
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+
+ /* Copy over initial header */
+ memcpy(job->databuf + job->datalen, initial_buf + buf_offset, 65);
+ job->datalen += 65;
+ buf_offset += 65;
+
+ /* Start parsing headers */
+ x_gp_8bpp = x_gp_rk = k_only = job->hdr_len = 0;
+
+ char *ptr;
+ ptr = strtok((char*)initial_buf + ++buf_offset, ",\x1c");
+ while (ptr && *ptr != 0x1c) {
+ if (!strcmp("X-GP-8", ptr)) {
+ x_gp_8bpp = 1;
+ } else if (!strncmp("TDT", ptr, 3)) {
+ /* Strip out the timestamp, replace it with one from the backend */
+ } else if (!strncmp("IMF", ptr,3)) {
+ /* Strip out the image format, replace it with backend */
+// } else if (!strncmp("ESS", ptr, 3)) {
+// /* Strip out copies */
+ } else if (!strcmp("X-GP-RK", ptr)) {
+ x_gp_rk = 1;
+ } else if (!strncmp("ICC", ptr,3)) {
+ /* Gamma curve is not handled by printer,
+ strip it out and use it! */
+ gamma = atoi(ptr + 3);
+ } else if (!strncmp("SZ", ptr, 2)) {
+ if (ptr[2] == 'B') {
+ len_y = atoi(ptr + 3);
+ } else if (ptr[2] == 'G') {
+ len_m = atoi(ptr + 3);
+ } else if (ptr[2] == 'R') {
+ len_c = atoi(ptr + 3);
+ } else if (ptr[2] == 'K') {
+ len_k = atoi(ptr + 3);
+ }
+ } else {
+ /* Everything else goes in */
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",%s", ptr);
+ }
+
+ /* Keep going */
+ buf_offset += strlen(ptr) + 1;
+ /* Peek ahead to see if this is it */
+ if (initial_buf[buf_offset + 1] == 0x1c)
+ break;
+ /* Otherwise continue to the next token */
+ ptr = strtok(NULL, ",\x1c");
+ }
+
+ /* Sanity checks */
+ if (!len_y || !len_m || !len_c) {
+ ERROR("Plane lengths missing? %u/%u/%u!\n", len_y, len_m, len_c);
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (len_y != len_m || len_y != len_c) {
+ ERROR("Inconsistent data plane lengths! %u/%u/%u!\n", len_y, len_m, len_c);
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (x_gp_rk && len_k) {
+ ERROR("Data stream already has a K layer!\n");
+ magicard_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Generate a timestamp */
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",TDT%08X", (uint32_t) time(NULL));
+
+ /* Generate image format tag */
+ if (k_only == 1) {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFK");
+ } else if (x_gp_rk || len_k) {
+ /* We're adding K, so make this BGRK */
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFBGRK");
+ } else {
+ /* Just BGR */
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFBGR");
+ }
+
+ /* Insert SZB/G/R/K length descriptors */
+ if (x_gp_8bpp) {
+ if (k_only == 1) {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_c / 8);
+ } else {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZB%u", len_y * 6 / 8);
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZG%u", len_m * 6 / 8);
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZR%u", len_c * 6 / 8);
+ /* Add in a SZK length indication if requested */
+ if (x_gp_rk == 1) {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_c / 8);
+ }
+ }
+ } else {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZB%u", len_y);
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZG%u", len_m);
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZR%u", len_c);
+ /* Add in a SZK length indication if requested */
+ if (len_k) {
+ job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_k);
+ }
+ }
+
+ /* Terminate command stream */
+ job->databuf[job->datalen++] = 0x1c;
+
+ /* Let's figure out how long the image data stream is supposed to be. */
+ uint32_t remain;
+ if (k_only) {
+ remain = len_k + 3;
+ } else {
+ remain = len_y + len_m + len_c + 3 * 3;
+ if (len_k)
+ remain += len_k + 3;
+ }
+ /* Offset the stuff we already read in. */
+ remain -= INITIAL_BUF_LEN - buf_offset;
+ remain++; /* Add in a byte for the end of job marker. This is our final value. */
+
+ /* This is how much of the initial buffer is the header length. */
+ job->hdr_len = job->datalen;
+
+ if (x_gp_8bpp) {
+ uint32_t srcbuf_offset = INITIAL_BUF_LEN - buf_offset;
+ uint8_t *srcbuf = malloc(MAX_PRINTJOB_LEN);
+ if (!srcbuf) {
+ magicard_cleanup_job(job);
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+
+ memcpy(srcbuf, initial_buf + buf_offset, srcbuf_offset);
+
+ /* Finish loading the data */
+ while (remain > 0) {
+ i = read(data_fd, srcbuf + srcbuf_offset, remain);
+ if (i < 0) {
+ ERROR("Data Read Error: %d (%u) @%u)\n", i, remain, srcbuf_offset);
+ magicard_cleanup_job(job);
+ free(srcbuf);
+ return i;
+ }
+ if (i == 0) {
+ ERROR("Short read! (%d/%u)\n", i, remain);
+ magicard_cleanup_job(job);
+ free(srcbuf);
+ return CUPS_BACKEND_CANCEL;
+ }
+ srcbuf_offset += i;
+ remain -= i;
+ }
+
+ // XXX handle conversion of K-only jobs. if needed.
+
+ /* set up source pointers */
+ in_y = srcbuf;
+ in_m = in_y + len_y + 3;
+ in_c = in_m + len_m + 3;
+
+ /* Set up destination pointers */
+ out_y = job->databuf + job->datalen;
+ out_m = out_y + (len_y * 6 / 8) + 3;
+ out_c = out_m + (len_m * 6 / 8) + 3;
+ out_k = out_c + (len_c * 6 / 8) + 3;
+
+ /* Termination of each plane */
+ memcpy(out_m - 3, in_y + len_y, 3);
+ memcpy(out_c - 3, in_m + len_m, 3);
+ memcpy(out_k - 3, in_c + len_c, 3);
+
+ if (!x_gp_rk)
+ out_k = NULL;
+
+ INFO("Converting image data to printer's native format %s\n", x_gp_rk ? "and extracting K channel" : "");
+
+ downscale_and_extract(gamma, len_y, in_y, in_m, in_c,
+ out_y, out_m, out_c, out_k);
+
+ /* Pad out the length appropriately. */
+ job->datalen += ((len_c * 6 / 8) + 3) * 3;
+
+ /* If there's a K plane, compute length.. */
+ if (out_k) {
+ job->datalen += (len_c / 8);
+ job->databuf[job->datalen++] = 0x1c;
+ job->databuf[job->datalen++] = 0x4b;
+ job->databuf[job->datalen++] = 0x3a;
+ }
+
+ /* Terminate the entire stream */
+ job->databuf[job->datalen++] = 0x03;
+
+ free(srcbuf);
+ } else {
+ uint32_t srcbuf_offset = INITIAL_BUF_LEN - buf_offset;
+ memcpy(job->databuf + job->datalen, initial_buf + buf_offset, srcbuf_offset);
+ job->datalen += srcbuf_offset;
+
+ /* Finish loading the data */
+ while (remain > 0) {
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i < 0) {
+ ERROR("Data Read Error: %d (%u) @%d)\n", i, remain, job->datalen);
+ magicard_cleanup_job(job);
+ return i;
+ }
+ if (i == 0) {
+ magicard_cleanup_job(job);
+ ERROR("Short read! (%d/%u)\n", i, remain);
+ return CUPS_BACKEND_CANCEL;
+ }
+ job->datalen += i;
+ remain -= i;
+ }
+ }
+
+ *vjob = job;
+
+ return CUPS_BACKEND_OK;
+}
+
+static int magicard_main_loop(void *vctx, const void *vjob) {
+ struct magicard_ctx *ctx = vctx;
+ int ret;
+
+ const struct magicard_printjob *job = vjob;
+
+ // XXX printer handles copy generation..
+ // but it's a numeric parameter. Bleh.
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
+top:
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ job->databuf, job->hdr_len)))
+ return CUPS_BACKEND_FAILED;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ job->databuf + job->hdr_len, job->datalen - job->hdr_len)))
+ return CUPS_BACKEND_FAILED;
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void magicard_cmdline(void)
+{
+ DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -q ] # Query information\n");
+ DEBUG("\t\t[ -I ] # Query printer sensors\n");
+ DEBUG("\t\t[ -E ] # Eject card\n");
+ DEBUG("\t\t[ -T ] # Print self-test card\n");
+ DEBUG("\t\t[ -R ] # Reset printer\n");
+}
+
+static int magicard_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct magicard_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "sqEIRT")) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ case 's':
+ j = magicard_query_status(ctx);
+ break;
+ case 'q':
+ j = magicard_query_printer(ctx);
+ break;
+ case 'E':
+ j = magicard_eject(ctx);
+ break;
+ case 'I':
+ j = magicard_query_sensors(ctx);
+ break;
+ case 'R':
+ j = magicard_reset(ctx);
+ break;
+ case 'T':
+ j = magicard_selftest_card(ctx);
+ break;
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+static int magicard_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct magicard_ctx *ctx = vctx;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *magicard_prefixes[] = {
+ "magicard", // Family name
+ "magicard-tango-2e", "magicard-enduro", "magicard-enduroplus",
+ // extras
+ "magicard-rio-2e",
+ // backwards compatibility
+ "tango2e", "enduro", "enduroplus",
+ NULL
+};
+
+struct dyesub_backend magicard_backend = {
+ .name = "Magicard family",
+ .version = "0.15",
+ .uri_prefixes = magicard_prefixes,
+ .cmdline_arg = magicard_cmdline_arg,
+ .cmdline_usage = magicard_cmdline,
+ .init = magicard_init,
+ .attach = magicard_attach,
+ .teardown = magicard_teardown,
+ .cleanup_job = magicard_cleanup_job,
+ .read_parse = magicard_read_parse,
+ .main_loop = magicard_main_loop,
+ .query_markers = magicard_query_markers,
+ .devices = {
+ { USB_VID_MAGICARD, USB_PID_MAGICARD_TANGO2E, P_MAGICARD, NULL, "magicard-tango2e"},
+ { USB_VID_MAGICARD, USB_PID_MAGICARD_ENDURO, P_MAGICARD, NULL, "magicard-enduro"},
+ { USB_VID_MAGICARD, USB_PID_MAGICARD_ENDUROPLUS, P_MAGICARD, NULL, "magicard-enduroplus"},
+ { USB_VID_MAGICARD, 0xFFFF, P_MAGICARD, NULL, "magicard"},
+ { 0, 0, 0, NULL, "magicard"}
+ }
+};
+
+/* Magicard family Spool file format (Tango2e/Rio2e/AvalonE family)
+
+ This one was rather fun to figure out.
+
+ * Job starts with a sequence of 64 '0x05'
+ * Command sequence starts with 0x01
+ * Commands are textual and comma-separated.
+ * Most are passed through ignored, except for:
+ * SZB, SZG, SZR, SZK -- indicate length of respective data plane
+ * IMF -- Image format (BGR/BGRK/K)
+ * X-GP-8 -- Tells backend to convert from Gutenprint's 8bpp data
+ * X-GP-RK -- Tells backend to extract K channel from color data
+ * Command sequence ends with 0x1c
+ * Image plane data follows, in the order of the SZ# entries
+ * Plane lengths are specified by the SZ# entry.
+ * Color planes are actually Y/M/C rather than B/G/R!
+ * Each plane terminates with 0x1c __ 0x3a, where __ is 0x42, 0x47, 0x52,
+ and 0x4b for B/G/R/K respectively. Terminator is _not_ part of length.
+ * Image data is 6bpp for B/G/R and 1bpp for K, 672*1016 pixels
+ * Organized in a series of 84-byte rows.
+ * Byte data is LSB first.
+ * Each row is a single stripe of a single bit of a pixel, so
+ color data is b0b0b0b0.. b1b1b1b1.. .. b5b5b5b5.
+ * Job ends with 0x03
+
+ ** ** ** ** ** **
+
+ Firmware updates:
+
+ 0x05 (x9) 0x01 REQ,FRM###### 0x1c
+
+ Where ###### is the length of the firmware image.
+
+ Then send over 64 bytes at a time until it's done.
+
+ Then send 0x03 to mark end of job.
+
+ Follow it with:
+
+ 0x01 STA,CHK########, 0x03 (8-digit checksum?)
+
+ 0x05 (x9) 0x01 REQ,UPG, 0x1c 0x03
+
+ ** ** ** ** ** **
+
+ Known commands seen in print jobs:
+
+ BAC%s Backside format (CKO, KO, C, CO, K) -- Only used with Duplex.
+ CKI%s Custom Holokote (ON or OFF)
+ CPW%s Color power level (0-100, default 50)
+ DPX%s Duplex (ON or OFF)
+ EOI%d Card alignment end (0-100, default 50)
+ ESS%d Number of copies (1-?)
+ HGT%d Image Height (always seems to be 1016)
+ HKM%06X Holokote hole. bitwise number, each bit corresponds to an area.
+ HKT%d Holokote type (1 is "ultra secure, 2 is "interlocking rings", etc)
+ HPH%s Holopatch (ON or OFF)
+ IMF%s Image Data Format (BGR, BGRK, K)
+ KPW%s Black power level (0-100, default 50)
+ LAN%s Printer display lanaguage (ENG, ITA, POR, FRA, DEU, ESP, SCH)
+ LC%d Force media type (LC1, LC3, LC6, LC8 for YMCKO/MONO/KO/YMCKOK)
+ NCT%d,%d,%d,%d Overcoat hole
+ OPW%s Overcoat power level (0-100, default 50)
+ OVR%s Overcoat (ON or OFF)
+ PAG%d Page number (always 1, except 2 if printing duplex backside)
+ PAT%d Holopatch area (0-24)
+ REJ%s Reject faulty cards (ON or OFF)
+ SOI%d Card alignment start (0-100, default 50)
+ SLW%s Colorsure (ON or OFF)
+ SZB%d Blue data length
+ SZG%d Green data length
+ SZK%d Black data length
+ SZR%d Red data length
+ TDT%08X Driver-supplied timestamp of print job.
+ USF%s Holokote (ON or OFF)
+ VER%s Inform the printer of the driver version (seems to be ignored)
+ WID%d Image Width (always seems to be 642)
+
+ Mag-stripe encoding:
+
+ MAG%d Magstripe position (1, 2, or 3)
+ BPI%d Bits per Inch (75 or 210)
+ MPC%d Character encoding (5 or 7)
+ COE%s 'H'igh or 'L'ow coercivity
+
+ Unknown commands seen in print jobs:
+
+ DDD%s ? (only seen '50') -- Could it be K alignment?
+ KEE ?
+ NNN%s ? (Seen 'OFF')
+ NOC%d ? (Seen '1') (Seems to start a job)
+ PCT%d,%d,%d,%d ? Print area, seems fixed @ 0,0, 1025, 641)
+ RT2 ?
+ TRO%d ? (Seen '0', appears with Holokote)
+ XCO%d ? X start offset (always seems to be 0)
+ YCO%d ? Y start offset (always seems to be 0)
+
+ Unknown commands: (Seen in firmware guts)
+
+ AAA
+ AMS
+ BBB%d Numeric parameter
+ CLR
+ FBF
+ FTC
+ HFD%s String parameter
+ IPM
+ KKK
+ LBL
+ LLL
+ LRC
+ MGV%s "ON" or "OFF" but no idea
+ MMM
+ PAR
+ RDM
+ SNR
+ SSP
+
+ Unknown commands unique to Tango +L (ie w/ Laminator support)
+
+ FRN
+ LAM
+ LAM_DLY
+ LAM_SPD
+ LAM_LEN
+ LAM_END
+ LAM_STA
+ LAM_DEG
+ LAM_FLM
+ LAM_KBD
+ LAM_MOD
+
+ Commands consumed by backend:
+
+ ICC%d Gamma curve (0, 1, 2) -- off, 2.2, or 1.8 respectively.
+ X-GP-8 Raw data is 8bpp. needs to be converted.
+ X-GP-RK Extract K channel from color data.
+
+ Open questions:
+
+ * How to query/read magstripe
+ * How to set IP address (etc)
+ * How to set other parameters
+
+ "Simple Commands" (REQ,....,)
+
+ RST Reset printer
+ TST Generate self-test page
+ EJT Eject card
+
+ Other "Simple commands" referenced in Rio Pro/Enduro+ docs
+
+ DEALERSERVICE%s ON/OFF (enter/exit dealer service mode)
+ CAM Reset print head cam position
+ CHP%s UP/DOWN Feed card into smart encoder
+ CLN Cleaning cycle
+ DYE Re-init dye film
+ ENC Test encoding cycle
+ FEED%d 0/1,+ 0/1, load card into standby, >1 feed N cards.
+ FLIP Flip card in printer
+ FRN%s ON/OFF -- Film saving
+ HEAD%s UP/DOWN -- Raise or lower print head.
+ RAMP%d 0-100 Density ramp, 50 default
+ SET Saves settings into NVDATA
+ STN Re-init Holokote
+ SNS Soak cycle, test all sensors
+ SHW%s CAM, TACHO, FLIP, DYE, LID, FRONT, MID, READ, BUTTON1, BUTTON2,
+ SMART, TEMP, ON, OFF
+ LNG%d 0/1/2/3/4/5 == ENG/POR/FRE/GER/SPA/ITA
+ RUN%s CAM, FEED, DYE, MAIN, FLIPPER, FLIPROLL, FAN, PANEL, POUT, CAL, LCD,
+ OFF
+ FLM%s Y/M/C/K/O Align ribbon at corresponding panel
+ FCL Init dye calibration routine
+ FCL###### Set dye color to ###### (RGB hex)
+
+*/
diff --git a/src/cups/backend_mitsu70x.c b/src/cups/backend_mitsu70x.c
index 00547a0..154fabb 100644
--- a/src/cups/backend_mitsu70x.c
+++ b/src/cups/backend_mitsu70x.c
@@ -1,7 +1,7 @@
/*
* Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -112,7 +113,6 @@ typedef int (*send_image_dataFN)(struct BandImage *out, void *context,
#define USB_PID_MITSU_D70X 0x3B30
#define USB_PID_MITSU_K60 0x3B31
#define USB_PID_MITSU_D80 0x3B36
-#define USB_PID_MITSU_D90 0x3B60
#define USB_VID_KODAK 0x040a
#define USB_PID_KODAK305 0x404f
#define USB_VID_FUJIFILM 0x04cb
@@ -125,29 +125,47 @@ typedef int (*send_image_dataFN)(struct BandImage *out, void *context,
#define CHUNK_LEN (256*1024)
/* Private data structure */
-struct mitsu70x_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
+struct mitsu70x_printjob {
uint8_t *databuf;
int datalen;
- uint32_t matte;
+ uint8_t *spoolbuf;
+ int spoolbuflen;
- uint16_t jobid;
uint16_t rows;
uint16_t cols;
+ uint32_t planelen;
+ uint32_t matte;
+ int raw_format;
+ int copies;
- uint16_t last_donor_l;
- uint16_t last_donor_u;
- int num_decks;
+ int decks_exact[2]; /* Media is exact match */
+ int decks_ok[2]; /* Media can be used */
+
+ /* These are used only for the image processing */
+ int sharpen; /* ie mhdr.sharpen - 1 */
+ int reverse;
char *laminatefname;
char *lutfname;
char *cpcfname;
char *ecpcfname;
+};
+
+struct mitsu70x_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ uint16_t jobid;
+
+ struct marker marker[2];
+ uint8_t medias[2];
+
+ uint16_t last_l;
+ uint16_t last_u;
+ int num_decks;
void *dl_handle;
lib70x_getapiversionFN GetAPIVersion;
@@ -170,12 +188,6 @@ struct mitsu70x_ctx {
char *last_cpcfname;
char *last_ecpcfname;
- int raw_format;
- int reverse;
- int sharpen; /* ie mhdr.sharpen - 1 */
-
- uint8_t rew[2]; /* 1 for rewind ok (default!) */
-
struct BandImage output;
};
@@ -190,7 +202,9 @@ struct mitsu70x_jobstatus {
uint8_t mecha_status[2];
uint8_t temperature;
uint8_t error_status[3];
- uint8_t reserved[6];
+ uint8_t mecha_status_up[2];
+ uint8_t temperature_up;
+ uint8_t error_status_up[3];
} __attribute__((packed));
struct mitsu70x_job {
@@ -306,8 +320,7 @@ struct mitsu70x_status_deck {
uint8_t mecha_status[2];
uint8_t temperature; /* D70/D80 family only, K60 no? */
uint8_t error_status[3];
- uint8_t rsvd_a[10]; /* K60 family [1] == temperature? [3:6] == lifetime prints in BCD */
-
+ uint8_t rsvd_a[10]; /* K60 [1] == temperature? All: [3:6] == some counter in BCD. K60 [9] == ?? */
uint8_t media_brand;
uint8_t media_type;
uint8_t rsvd_b[2];
@@ -315,7 +328,8 @@ struct mitsu70x_status_deck {
uint16_t remain; /* media remaining */
uint8_t rsvd_c[2];
uint8_t lifetime_prints[4]; /* lifetime prints on deck + 10, in BCD! */
- uint16_t rsvd_e[17];
+ uint8_t rsvd_d[2]; // Unknown
+ uint16_t rsvd_e[16]; /* all 80 00 */
} __attribute__((packed));
struct mitsu70x_status_ver {
@@ -324,13 +338,15 @@ struct mitsu70x_status_ver {
} __attribute__((packed));
struct mitsu70x_printerstatus_resp {
- uint8_t hdr[4]; /* E4 56 32 31 */
+ uint8_t hdr[4]; /* E4 56 32 30 */
uint8_t memory;
uint8_t power;
uint8_t unk[20];
uint8_t sleeptime; /* In minutes, 0-60 */
uint8_t iserial; /* 0x00 for Enabled, 0x80 for Disabled */
- uint8_t unk_b[12];
+ uint8_t unk_b[5]; // [4] == 0x44 on D70x, 0x02 on D80
+ uint8_t dual_deck; /* 0x80 for dual-deck D707 */
+ uint8_t unk_c[6]; // [3] == 0x5f on D70x, 0x01 on D80. [5] == 0xbd on D70x, 0x87 on D80
int16_t model[6]; /* LE, UTF-16 */
int16_t serno[6]; /* LE, UTF-16 */
struct mitsu70x_status_ver vers[7]; // components are 'MLRTF'
@@ -340,12 +356,6 @@ struct mitsu70x_printerstatus_resp {
struct mitsu70x_status_deck upper;
} __attribute__((packed));
-#define MK60S_0105_M_CSUM 0x148C /* 1.05 316M3 1 148C */
-#define EK305_0104_M_CSUM 0x2878 /* 1.04 316F8 3 2878 */
-#define MD70X_0110_M_CSUM 0x064D /* 1.10 316V1 1 064D */
-#define MD70X_0112_M_CSUM 0x9FC3 /* 1.12 316W1 1 9FC3 */
-#define FA300_XXXX_M_CSUM 0x4431 /* ?.?? 416J2 1 4431 */
-
struct mitsu70x_memorystatus_resp {
uint8_t hdr[3]; /* E4 56 33 */
uint8_t memory;
@@ -383,9 +393,27 @@ struct mitsu70x_hdr {
uint8_t pad[447];
} __attribute__((packed));
+static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp);
+static int mitsu70x_main_loop(void *vctx, const void *vjob);
+
/* Error dumps, etc */
-static char *mitsu70x_mechastatus(uint8_t *sts)
+const char *mitsu70x_temperatures(uint8_t temp)
+{
+ switch(temp) {
+ case TEMPERATURE_NORMAL:
+ return "Normal";
+ case TEMPERATURE_PREHEAT:
+ return "Warming Up";
+ case TEMPERATURE_COOLING:
+ return "Cooling Down";
+ default:
+ break;
+ }
+ return "Unknown Temperature Status";
+}
+
+static const char *mitsu70x_mechastatus(uint8_t *sts)
{
switch(sts[0]) {
case MECHA_STATUS_INIT:
@@ -405,7 +433,7 @@ static char *mitsu70x_mechastatus(uint8_t *sts)
return "Unknown Mechanical Status";
}
-static char *mitsu70x_jobstatuses(uint8_t *sts)
+static const char *mitsu70x_jobstatuses(uint8_t *sts)
{
switch(sts[0]) {
case JOB_STATUS0_NONE:
@@ -455,7 +483,7 @@ static char *mitsu70x_jobstatuses(uint8_t *sts)
default:
return "Unknown 'End Header' status2";
}
- break;
+ break;
case JOB_STATUS1_END_PRINT:
switch(sts[2]) {
case JOB_STATUS2_END_PRINT_MEDIA:
@@ -492,7 +520,7 @@ static char *mitsu70x_jobstatuses(uint8_t *sts)
return "Unknown status0";
}
-static char *mitsu70x_errorclass(uint8_t *err)
+static const char *mitsu70x_errorclass(uint8_t *err)
{
switch(err[1]) {
case ERROR_STATUS1_PAPER:
@@ -523,7 +551,7 @@ static char *mitsu70x_errorclass(uint8_t *err)
return "Unknown error class";
}
-static char *mitsu70x_errorrecovery(uint8_t *err)
+static const char *mitsu70x_errorrecovery(uint8_t *err)
{
switch(err[1]) {
case ERROR_STATUS2_AUTO:
@@ -554,7 +582,7 @@ static char *mitsu70x_errorrecovery(uint8_t *err)
return "Unknown recovery";
}
-static char *mitsu70x_errors(uint8_t *err)
+static const char *mitsu70x_errors(uint8_t *err)
{
switch(err[0]) {
case ERROR_STATUS0_NOSTRIPBIN:
@@ -620,7 +648,7 @@ static char *mitsu70x_errors(uint8_t *err)
return "Unknown error";
}
-static const char *mitsu70x_media_types(uint8_t brand, uint8_t type)
+const char *mitsu70x_media_types(uint8_t brand, uint8_t type)
{
if (brand == 0xff && type == 0x01)
return "CK-D735 (3.5x5)";
@@ -675,12 +703,10 @@ static void *mitsu70x_init(void)
return ctx;
}
-static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int mitsu70x_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct mitsu70x_ctx *ctx = vctx;
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
ctx->jobid = jobid;
if (!ctx->jobid)
@@ -689,14 +715,9 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ ctx->type = type;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
-
- ctx->type = lookup_printer_type(&mitsu70x_backend,
- desc.idVendor, desc.idProduct);
-
- ctx->last_donor_l = ctx->last_donor_u = 65535;
+ ctx->last_l = ctx->last_u = 65535;
/* Attempt to open the library */
#if defined(WITH_DYNAMIC)
@@ -710,13 +731,13 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
ERROR("Problem resolving API Version symbol in imaging processing library, too old or not installed?\n");
DL_CLOSE(ctx->dl_handle);
ctx->dl_handle = NULL;
- return;
+ return CUPS_BACKEND_FAILED;
}
if (ctx->GetAPIVersion() != REQUIRED_LIB_APIVERSION) {
ERROR("Image processing library API version mismatch!\n");
DL_CLOSE(ctx->dl_handle);
ctx->dl_handle = NULL;
- return;
+ return CUPS_BACKEND_FAILED;
}
ctx->Get3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Get3DColorTable");
@@ -737,6 +758,7 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
ERROR("Problem resolving symbols in imaging processing library\n");
DL_CLOSE(ctx->dl_handle);
ctx->dl_handle = NULL;
+ return CUPS_BACKEND_FAILED;
} else {
DEBUG("Image processing library successfully loaded\n");
}
@@ -757,6 +779,100 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
#else
WARNING("Dynamic library support not enabled, using internal fallback code\n");
#endif
+
+ struct mitsu70x_printerstatus_resp resp;
+ int ret;
+
+ if (test_mode < TEST_MODE_NOATTACH) {
+ ret = mitsu70x_get_printerstatus(ctx, &resp);
+ if (ret) {
+ ERROR("Unable to get printer status! (%d)\n", ret);
+ return CUPS_BACKEND_FAILED;
+ }
+ } else {
+ int media_code = 0xf;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
+
+ resp.upper.mecha_status[0] = MECHA_STATUS_INIT;
+ resp.lower.mecha_status[0] = MECHA_STATUS_INIT;
+ resp.upper.capacity = cpu_to_be16(230);
+ resp.lower.capacity = cpu_to_be16(230);
+ resp.upper.remain = cpu_to_be16(200);
+ resp.lower.remain = cpu_to_be16(200);
+ resp.upper.media_brand = 0xff;
+ resp.lower.media_brand = 0xff;
+ resp.upper.media_type = media_code;
+ resp.lower.media_type = media_code;
+ resp.dual_deck = 0x80; /* Make it a dual deck */
+ }
+
+ /* Figure out if we're a D707 with two decks */
+ if (ctx->type == P_MITSU_D70X &&
+ resp.dual_deck == 0x80)
+ ctx->num_decks = 2;
+ else
+ ctx->num_decks = 1;
+
+ /* Set up markers */
+ ctx->marker[0].color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker[0].name = mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type);
+ ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
+ ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
+ ctx->medias[0] = resp.lower.media_type & 0xf;
+
+ if (ctx->num_decks == 2) {
+ ctx->marker[1].color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker[1].name = mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type);
+ ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
+ ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
+ ctx->medias[1] = resp.upper.media_type & 0xf;
+ }
+
+ /* FW sanity checking */
+ if (ctx->type == P_KODAK_305) {
+ /* Known versions:
+ v1.02: M 316E81 1433 (Add Ultrafine and matte support)
+ v1.04: M 316F83 2878 (Add 2x6 strip and support "Triton" media)
+ */
+ if (strncmp(resp.vers[0].ver, "316F83", 6) < 0)
+ WARNING("Printer FW out of date. Highly recommend upgrading EK305 to v1.04 or newer!\n");
+ } else if (ctx->type == P_MITSU_K60) {
+ /* Known versions:
+ v1.05: M 316M31 148C (Add HG media support)
+ */
+ if (strncmp(resp.vers[0].ver, "316M31", 6) < 0)
+ WARNING("Printer FW out of date. Highly recommend upgrading K60 to v1.05 or newer!\n");
+ } else if (ctx->type == P_MITSU_D70X) {
+ /* Known versions:
+ v1.10: M 316V11 064D (Add ultrafine mode, 6x6 support, 2x6 strip, and more?)
+ v1.12: M 316W11 9FC3 (??)
+ v1.13: (??)
+ */
+ if (strncmp(resp.vers[0].ver, "316W11", 6) < 0)
+ WARNING("Printer FW out of date. Highly recommend upgrading D70/D707 to v1.12 or newer!\n");
+ } else if (ctx->type == P_FUJI_ASK300) {
+ /* Known versions:
+ v?.??: M 316A21 7998 (ancient. no matte or ultrafine)
+ v?.??: M 316H21 F8EB
+ v4.20a: M 316J21 4431 (Add 2x6 strip support)
+ */
+ if (strncmp(resp.vers[0].ver, "316J21", 6) < 0)
+ WARNING("Printer FW out of date. Highly recommend upgrading ASK300 to v4.20a or newer!\n");
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void mitsu70x_cleanup_job(const void *vjob) {
+ const struct mitsu70x_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+ if (job->spoolbuf)
+ free(job->spoolbuf);
+
+ free((void*)job);
}
static void mitsu70x_teardown(void *vctx) {
@@ -765,9 +881,6 @@ static void mitsu70x_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
-
if (ctx->dl_handle) {
if (ctx->cpcdata)
ctx->DestroyCPCData(ctx->cpcdata);
@@ -783,34 +896,174 @@ static void mitsu70x_teardown(void *vctx) {
free(ctx);
}
-static int mitsu70x_read_parse(void *vctx, int data_fd) {
+#define JOB_EQUIV(__x) if (job1->__x != job2->__x) goto done
+
+static struct mitsu70x_printjob *combine_jobs(const struct mitsu70x_printjob *job1,
+ const struct mitsu70x_printjob *job2)
+{
+ struct mitsu70x_printjob *newjob = NULL;
+ uint16_t newrows;
+ uint16_t newcols;
+ uint32_t newpad, finalpad;
+ uint16_t lamoffset;
+
+ const struct mitsu70x_hdr *hdr1, *hdr2;
+ struct mitsu70x_hdr *newhdr;
+
+ /* Sanity check */
+ if (!job1 || !job2)
+ goto done;
+
+ hdr1 = (struct mitsu70x_hdr *) job1->databuf;
+ hdr2 = (struct mitsu70x_hdr *) job2->databuf;
+
+ JOB_EQUIV(rows);
+ JOB_EQUIV(cols);
+ JOB_EQUIV(matte);
+ JOB_EQUIV(sharpen);
+
+ if (hdr1->multicut || hdr2->multicut)
+ goto done;
+ if (job1->raw_format || job2->raw_format)
+ goto done;
+ if (hdr1->speed != hdr2->speed)
+ goto done;
+
+ switch (job1->rows) {
+ case 1218: /* K60, EK305 */
+ newrows = 2454;
+ newpad = 16;
+ finalpad = 0;
+ lamoffset = 0;
+ break;
+ case 1228: /* D70, ASK300, D80 */
+ newrows = 2730;
+ newpad = 38;
+ finalpad = 236;
+ lamoffset = 12;
+ break;
+ case 1076: /* EK305, K60 3.5x5" prints */
+ newrows = 2190;
+ newpad = 49;
+ finalpad = 0;
+ lamoffset = 0;
+ break;
+ default:
+ goto done;
+ }
+ newcols = job1->cols;
+ newpad *= newcols;
+ finalpad *= newcols;
+
+ /* Okay, it's kosher to proceed */
+
+ DEBUG("Combining jobs to save media\n");
+
+ newjob = malloc(sizeof(*newjob));
+ if (!newjob) {
+ ERROR("Memory allocation failure!\n");
+ goto done;
+ }
+ memcpy(newjob, job1, sizeof(*newjob));
+
+ newjob->spoolbuf = NULL;
+ newjob->rows = newrows;
+ newjob->cols = newcols;
+ newjob->planelen = (((newrows * newcols * 2) + 511) /512) * 512;
+ if (newjob->matte) {
+ newjob->matte = ((((newrows + lamoffset) * newcols * 2) + 511) / 512) * 512;
+ }
+ newjob->databuf = malloc(sizeof(*newhdr) + newjob->planelen * 3 + newjob->matte);
+ newjob->datalen = 0;
+ if (!newjob->databuf) {
+ mitsu70x_cleanup_job(newjob);
+ newjob = NULL;
+ ERROR("Memory allocation failure!\n");
+ goto done;
+ }
+ newhdr = (struct mitsu70x_hdr *) newjob->databuf;
+
+ /* Copy over header */
+ memcpy(newhdr, hdr1, sizeof(*newhdr));
+ newjob->datalen += sizeof(*newhdr);
+
+ newhdr->rows = cpu_to_be16(newrows);
+ newhdr->cols = cpu_to_be16(newcols);
+
+ if (newjob->matte) {
+ newhdr->lamrows = cpu_to_be16(newrows + lamoffset);
+ newhdr->lamcols = cpu_to_be16(newcols);
+ }
+ newhdr->multicut = 1;
+ newhdr->deck = 0; /* Let printer decide */
+
+ newjob->spoolbuf = malloc(newrows * newcols * 3);
+ newjob->spoolbuflen = 0;
+ if (!newjob->spoolbuf) {
+ mitsu70x_cleanup_job(newjob);
+ newjob = NULL;
+ ERROR("Memory allocation failure!\n");
+ goto done;
+ }
+
+ /* Fill in padding */
+ memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, finalpad * 3);
+ newjob->spoolbuflen += finalpad * 3;
+
+ /* Copy image payload */
+ memcpy(newjob->spoolbuf + newjob->spoolbuflen, job1->spoolbuf,
+ job1->spoolbuflen);
+ newjob->spoolbuflen += job1->spoolbuflen;
+
+ /* Fill in padding */
+ memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, newpad * 3);
+ newjob->spoolbuflen += newpad * 3;
+
+ /* Copy image payload */
+ memcpy(newjob->spoolbuf + newjob->spoolbuflen, job2->spoolbuf,
+ job2->spoolbuflen);
+ newjob->spoolbuflen += job2->spoolbuflen;
+
+ /* Okay, we're done. */
+
+done:
+ return newjob;
+}
+#undef JOB_EQUIV
+
+static int mitsu70x_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct mitsu70x_ctx *ctx = vctx;
int i, remain;
struct mitsu70x_hdr mhdr;
- uint32_t planelen;
+
+ struct mitsu70x_printjob *job = NULL;
+ struct dyesub_joblist *list;
+ int can_combine;
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
-
- /* Reset some state */
- ctx->matte = 0;
- ctx->rew[0] = 1;
- ctx->rew[1] = 1;
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
repeat:
/* Read in initial header */
remain = sizeof(mhdr);
while (remain > 0) {
i = read(data_fd, ((uint8_t*)&mhdr) + sizeof(mhdr) - remain, remain);
- if (i == 0)
+ if (i == 0) {
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
@@ -823,14 +1076,15 @@ repeat:
}
/* Sanity check header */
- if (mhdr.hdr[0] != 0x1b &&
- mhdr.hdr[1] != 0x5a &&
+ if (mhdr.hdr[0] != 0x1b ||
+ mhdr.hdr[1] != 0x5a ||
mhdr.hdr[2] != 0x54) {
ERROR("Unrecognized data format!\n");
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- ctx->raw_format = !mhdr.mode;
+ job->raw_format = !mhdr.mode;
/* Sanity check Matte mode */
if (!mhdr.laminate && mhdr.laminate_mode) {
@@ -849,61 +1103,61 @@ repeat:
/* Figure out the correction data table to use */
if (ctx->type == P_MITSU_D70X) {
- ctx->laminatefname = CORRTABLE_PATH "/D70MAT01.raw";
- ctx->lutfname = CORRTABLE_PATH "/CPD70L01.lut";
+ job->laminatefname = CORRTABLE_PATH "/D70MAT01.raw";
+ job->lutfname = CORRTABLE_PATH "/CPD70L01.lut";
if (mhdr.speed == 3) {
- ctx->cpcfname = CORRTABLE_PATH "/CPD70S01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPD70S01.cpc";
} else if (mhdr.speed == 4) {
- ctx->cpcfname = CORRTABLE_PATH "/CPD70U01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPD70U01.cpc";
} else {
- ctx->cpcfname = CORRTABLE_PATH "/CPD70N01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPD70N01.cpc";
}
if (mhdr.hdr[3] != 0x01) {
WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
mhdr.hdr[3] = 0x01;
}
} else if (ctx->type == P_MITSU_D80) {
- ctx->laminatefname = CORRTABLE_PATH "/D80MAT01.raw";
- ctx->lutfname = CORRTABLE_PATH "/CPD80L01.lut";
+ job->laminatefname = CORRTABLE_PATH "/D80MAT01.raw";
+ job->lutfname = CORRTABLE_PATH "/CPD80L01.lut";
if (mhdr.speed == 3) {
- ctx->cpcfname = CORRTABLE_PATH "/CPD80S01.cpc";
- ctx->ecpcfname = CORRTABLE_PATH "/CPD80E01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPD80S01.cpc";
+ job->ecpcfname = CORRTABLE_PATH "/CPD80E01.cpc";
} else if (mhdr.speed == 4) {
- ctx->cpcfname = CORRTABLE_PATH "/CPD80U01.cpc";
- ctx->ecpcfname = NULL;
+ job->cpcfname = CORRTABLE_PATH "/CPD80U01.cpc";
+ job->ecpcfname = NULL;
} else {
- ctx->cpcfname = CORRTABLE_PATH "/CPD80N01.cpc";
- ctx->ecpcfname = NULL;
+ job->cpcfname = CORRTABLE_PATH "/CPD80N01.cpc";
+ job->ecpcfname = NULL;
}
if (mhdr.hdr[3] != 0x01) {
WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
mhdr.hdr[3] = 0x01;
}
} else if (ctx->type == P_MITSU_K60) {
- ctx->laminatefname = CORRTABLE_PATH "/S60MAT02.raw";
- ctx->lutfname = CORRTABLE_PATH "/CPS60L01.lut";
+ job->laminatefname = CORRTABLE_PATH "/S60MAT02.raw";
+ job->lutfname = CORRTABLE_PATH "/CPS60L01.lut";
if (mhdr.speed == 3 || mhdr.speed == 4) {
mhdr.speed = 4; /* Ultra Fine */
- ctx->cpcfname = CORRTABLE_PATH "/CPS60T03.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPS60T03.cpc";
} else {
- ctx->cpcfname = CORRTABLE_PATH "/CPS60T01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/CPS60T01.cpc";
}
if (mhdr.hdr[3] != 0x00) {
WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
mhdr.hdr[3] = 0x00;
}
} else if (ctx->type == P_KODAK_305) {
- ctx->laminatefname = CORRTABLE_PATH "/EK305MAT.raw"; // Same as K60
- ctx->lutfname = CORRTABLE_PATH "/EK305L01.lut";
+ job->laminatefname = CORRTABLE_PATH "/EK305MAT.raw"; // Same as K60
+ job->lutfname = CORRTABLE_PATH "/EK305L01.lut";
if (mhdr.speed == 3 || mhdr.speed == 4) {
mhdr.speed = 4; /* Ultra Fine */
- ctx->cpcfname = CORRTABLE_PATH "/EK305T03.cpc";
+ job->cpcfname = CORRTABLE_PATH "/EK305T03.cpc";
} else {
- ctx->cpcfname = CORRTABLE_PATH "/EK305T01.cpc";
+ job->cpcfname = CORRTABLE_PATH "/EK305T01.cpc";
}
// XXX what about using K60 media if we read back the proper code?
if (mhdr.hdr[3] != 0x90) {
@@ -911,13 +1165,13 @@ repeat:
mhdr.hdr[3] = 0x90;
}
} else if (ctx->type == P_FUJI_ASK300) {
- ctx->laminatefname = CORRTABLE_PATH "/ASK300M2.raw"; // Same as D70
-// ctx->lutfname = CORRTABLE_PATH "/CPD70L01.lut"; // XXX guess, driver did not come with external LUT!
+ job->laminatefname = CORRTABLE_PATH "/ASK300M2.raw"; // Same as D70
+// job->lutfname = CORRTABLE_PATH "/CPD70L01.lut"; // XXX guess, driver did not come with external LUT!
if (mhdr.speed == 3 || mhdr.speed == 4) {
mhdr.speed = 3; /* Super Fine */
- ctx->cpcfname = CORRTABLE_PATH "/ASK300T3.cpc";
+ job->cpcfname = CORRTABLE_PATH "/ASK300T3.cpc";
} else {
- ctx->cpcfname = CORRTABLE_PATH "/ASK300T1.cpc";
+ job->cpcfname = CORRTABLE_PATH "/ASK300T1.cpc";
}
if (mhdr.hdr[3] != 0x80) {
WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
@@ -925,10 +1179,10 @@ repeat:
}
}
if (!mhdr.use_lut)
- ctx->lutfname = NULL;
+ job->lutfname = NULL;
- ctx->sharpen = mhdr.sharpen - 1;
- ctx->reverse = !mhdr.reversed;
+ job->sharpen = mhdr.sharpen - 1;
+ job->reverse = !mhdr.reversed;
/* Clean up header back to pristine. */
mhdr.use_lut = 0;
@@ -937,188 +1191,214 @@ repeat:
mhdr.reversed = 0;
/* Work out total printjob size */
- ctx->cols = be16_to_cpu(mhdr.cols);
- ctx->rows = be16_to_cpu(mhdr.rows);
+ job->cols = be16_to_cpu(mhdr.cols);
+ job->rows = be16_to_cpu(mhdr.rows);
- planelen = ctx->rows * ctx->cols * 2;
- planelen = (planelen + 511) / 512 * 512; /* Round to nearest 512 bytes. */
+ job->planelen = job->rows * job->cols * 2;
+ job->planelen = (job->planelen + 511) / 512 * 512; /* Round to nearest 512 bytes. */
if (!mhdr.laminate && mhdr.laminate_mode) {
i = be16_to_cpu(mhdr.lamcols) * be16_to_cpu(mhdr.lamrows) * 2;
i = (i + 511) / 512 * 512; /* Round to nearest 512 bytes. */
- ctx->matte = i;
+ job->matte = i;
}
- remain = 3 * planelen + ctx->matte;
+ remain = 3 * job->planelen + job->matte;
- ctx->datalen = 0;
- ctx->databuf = malloc(sizeof(mhdr) + remain + LAMINATE_STRIDE*2); /* Give us a bit extra */
+ job->datalen = 0;
+ job->databuf = malloc(sizeof(mhdr) + remain + LAMINATE_STRIDE*2); /* Give us a bit extra */
- if (!ctx->databuf) {
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
- memcpy(ctx->databuf + ctx->datalen, &mhdr, sizeof(mhdr));
- ctx->datalen += sizeof(mhdr);
+ memcpy(job->databuf + job->datalen, &mhdr, sizeof(mhdr));
+ job->datalen += sizeof(mhdr);
- if (ctx->raw_format) { /* RAW MODE */
+ if (job->raw_format) { /* RAW MODE */
DEBUG("Reading in %d bytes of 16bpp YMCL data\n", remain);
/* Read in the spool data */
while(remain) {
- i = read(data_fd, ctx->databuf + ctx->datalen, remain);
- if (i == 0)
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i == 0) {
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- ctx->datalen += i;
+ }
+ job->datalen += i;
remain -= i;
}
- } else { /* RAW MODE OFF */
- int spoolbuflen = 0;
- uint8_t *spoolbuf;
+ goto done;
+ }
- remain = ctx->rows * ctx->cols * 3;
- DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
+ /* Non-RAW mode! */
- spoolbuflen = 0; spoolbuf = malloc(remain);
- if (!spoolbuf) {
- ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
- }
+ remain = job->rows * job->cols * 3;
+ DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
- /* Read in the BGR data */
- while (remain) {
- i = read(data_fd, spoolbuf + spoolbuflen, remain);
- if (i == 0)
- return CUPS_BACKEND_CANCEL;
- if (i < 0)
- return CUPS_BACKEND_CANCEL;
- spoolbuflen += i;
- remain -= i;
- }
+ job->spoolbuflen = 0;
+ job->spoolbuf = malloc(remain);
+ if (!job->spoolbuf) {
+ ERROR("Memory allocation failure!\n");
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
- /* Run through basic LUT, if present and enabled */
- if (ctx->dl_handle && ctx->lutfname && !ctx->lut) { /* printer-specific, it is fixed per-job */
- DEBUG("Running print data through LUT\n");
- uint8_t *buf = malloc(LUT_LEN);
- if (!buf) {
- ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
- }
- if (ctx->Get3DColorTable(buf, ctx->lutfname)) {
- ERROR("Unable to open LUT file '%s'\n", ctx->lutfname);
- return CUPS_BACKEND_CANCEL;
- }
- ctx->lut = ctx->Load3DColorTable(buf);
- free(buf);
- if (!ctx->lut) {
- ERROR("Unable to parse LUT file '%s'!\n", ctx->lutfname);
- return CUPS_BACKEND_CANCEL;
- }
- ctx->DoColorConv(ctx->lut, spoolbuf, ctx->cols, ctx->rows, ctx->cols * 3, COLORCONV_BGR);
+ /* Read in the BGR data */
+ while (remain) {
+ i = read(data_fd, job->spoolbuf + job->spoolbuflen, remain);
+ if (i == 0) {
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
}
+ if (i < 0) {
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ job->spoolbuflen += i;
+ remain -= i;
+ }
- if (ctx->dl_handle) {
- struct BandImage input;
-
-
- /* Load in the CPC file, if needed */
- if (ctx->cpcfname && ctx->cpcfname != ctx->last_cpcfname) {
- ctx->last_cpcfname = ctx->cpcfname;
- if (ctx->cpcdata)
- ctx->DestroyCPCData(ctx->cpcdata);
- ctx->cpcdata = ctx->GetCPCData(ctx->cpcfname);
- if (!ctx->cpcdata) {
- ERROR("Unable to load CPC file '%s'\n", ctx->cpcfname);
- return CUPS_BACKEND_CANCEL;
- }
- }
-
- /* Load in the secondary CPC, if needed */
- if (ctx->ecpcfname != ctx->last_ecpcfname) {
- ctx->last_ecpcfname = ctx->ecpcfname;
- if (ctx->ecpcdata)
- ctx->DestroyCPCData(ctx->ecpcdata);
- if (ctx->ecpcfname) {
- ctx->ecpcdata = ctx->GetCPCData(ctx->ecpcfname);
- if (!ctx->ecpcdata) {
- ERROR("Unable to load CPC file '%s'\n", ctx->cpcfname);
- return CUPS_BACKEND_CANCEL;
- }
- } else {
- ctx->ecpcdata = NULL;
- }
- }
+ if (!ctx->dl_handle) {
+ // XXXFALLBACK write fallback code?
+ ERROR("!!! Image Processing Library not found, aborting!\n");
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
- /* Convert using image processing library */
- input.origin_rows = input.origin_cols = 0;
- input.rows = ctx->rows;
- input.cols = ctx->cols;
- input.imgbuf = spoolbuf;
- input.bytes_per_row = ctx->cols * 3;
-
- ctx->output.origin_rows = ctx->output.origin_cols = 0;
- ctx->output.rows = ctx->rows;
- ctx->output.cols = ctx->cols;
- ctx->output.imgbuf = ctx->databuf + ctx->datalen;
- ctx->output.bytes_per_row = ctx->cols * 3 * 2;
-
- DEBUG("Running print data through processing library\n");
- if (ctx->DoImageEffect(ctx->cpcdata, ctx->ecpcdata,
- &input, &ctx->output, ctx->sharpen, ctx->reverse, ctx->rew)) {
- ERROR("Image Processing failed, aborting!\n");
- return CUPS_BACKEND_CANCEL;
- }
- } else {
- // XXXFALLBACK write fallback code?
- ERROR("!!! Image Processing Library not found, aborting!\n");
+ /* Run through basic LUT, if present and enabled */
+ if (job->lutfname && !ctx->lut) { /* printer-specific, it is fixed per-job */
+ uint8_t *buf = malloc(LUT_LEN);
+ if (!buf) {
+ ERROR("Memory allocation failure!\n");
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ if (ctx->Get3DColorTable(buf, job->lutfname)) {
+ ERROR("Unable to open LUT file '%s'\n", job->lutfname);
+ mitsu70x_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ ctx->lut = ctx->Load3DColorTable(buf);
+ free(buf);
+ if (!ctx->lut) {
+ ERROR("Unable to parse LUT file '%s'!\n", job->lutfname);
+ mitsu70x_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
+ }
- /* Move up the pointer to after the image data */
- ctx->datalen += 3*planelen;
+ if (job->lutfname && ctx->lut) {
+ DEBUG("Running print data through LUT\n");
+ ctx->DoColorConv(ctx->lut, job->spoolbuf, job->cols, job->rows, job->cols * 3, COLORCONV_BGR);
+ }
- /* Clean up */
- free(spoolbuf);
+done:
+ list = dyesub_joblist_create(&mitsu70x_backend, ctx);
+
+ for (i = 0 ; i < ctx->num_decks ; i++) {
+ switch (ctx->medias[i]) {
+ case 0x1: // 5x3.5
+ if (job->rows == 1076)
+ job->decks_ok[i] = 1;
+ if (job->rows == 1076)
+ job->decks_exact[i] = 1;
+ break;
+ case 0x2: // 4x6
+ if (job->rows == 1218 ||
+ job->rows == 1228)
+ job->decks_ok[i] = 1;
+ if (job->rows == 1218 ||
+ job->rows == 1228)
+ job->decks_exact[i] = 1;
+ break;
+ case 0x4: // 5x7
+ if (job->rows == 1076 ||
+ job->rows == 1524 ||
+ job->rows == 2128)
+ job->decks_ok[i] = 1;
+ if (job->rows == 1524 ||
+ job->rows == 2128)
+ job->decks_exact[i] = 1;
+ break;
+ case 0x5: // 6x9
+ case 0xf: // 6x8
+ /* This is made more complicated:
+ some 6x8" jobs are 6x9" sized. Let printer
+ sort these out. It's unlikely we'll have
+ 6x8" in one deck and 6x9" in the other!
+ */
+ if (job->rows == 1218 ||
+ job->rows == 1228 ||
+ job->rows == 1820 ||
+ job->rows == 2422 ||
+ job->rows == 2564 ||
+ job->rows == 2730)
+ job->decks_ok[i] = 1;
+ if (job->rows == 2422 ||
+ job->rows == 2564 ||
+ job->rows == 2730)
+ job->decks_exact[i] = 1;
+ break;
+ default:
+ job->decks_ok[i] = 0;
+ job->decks_exact[i] = 0;
+ break;
+ }
+ }
- /* Now that we've filled everything in, read matte from file */
- if (ctx->matte) {
- int fd;
- uint32_t j;
- DEBUG("Reading %d bytes of matte data from disk (%d/%d)\n", ctx->matte, ctx->cols, LAMINATE_STRIDE);
- fd = open(ctx->laminatefname, O_RDONLY);
- if (fd < 0) {
- ERROR("Unable to open matte lamination data file '%s'\n", ctx->laminatefname);
- return CUPS_BACKEND_CANCEL;
- }
+ /* 6x4 can be combined, only on 6x8/6x9" media. */
+ can_combine = 0;
+ if (job->decks_exact[0] ||
+ job->decks_exact[1]) {
+ /* Exact media match, don't combine. */
+ } else if (job->rows == 1218 ||
+ job->rows == 1228) {
+ if (ctx->medias[0] == 0xf ||
+ ctx->medias[0] == 0x5 ||
+ ctx->medias[1] == 0xf || /* Two decks possible */
+ ctx->medias[1] == 0x5)
+ can_combine = !job->raw_format;
+ } else if (job->rows == 1076) {
+ if (ctx->type == P_KODAK_305 ||
+ ctx->type == P_MITSU_K60) {
+ if (ctx->medias[0] == 0x4) /* Only one deck */
+ can_combine = !job->raw_format;
+ }
+ }
- for (j = 0 ; j < be16_to_cpu(mhdr.lamrows) ; j++) {
- remain = LAMINATE_STRIDE * 2;
-
- /* Read one row of lamination data at a time */
- while (remain) {
- i = read(fd, ctx->databuf + ctx->datalen, remain);
- if (i < 0)
- return CUPS_BACKEND_CANCEL;
- if (i == 0) {
- /* We hit EOF, restart from beginning */
- lseek(fd, 0, SEEK_SET);
- continue;
- }
- ctx->datalen += i;
- remain -= i;
- }
- /* Back off the buffer so we "wrap" on the print row. */
- ctx->datalen -= ((LAMINATE_STRIDE - ctx->cols) * 2);
+ if (copies > 1 && can_combine) {
+ struct mitsu70x_printjob *combined;
+ combined = combine_jobs(job, job);
+ if (combined) {
+ combined->copies = job->copies / 2;
+ dyesub_joblist_addjob(list, combined);
+
+ if (job->copies & 1) {
+ job->copies = 1;
+ } else {
+ mitsu70x_cleanup_job(job);
+ job = NULL;
}
-
- /* Zero out the tail end of the buffer. */
- j = be16_to_cpu(mhdr.lamcols) * be16_to_cpu(mhdr.lamrows) * 2;
- memset(ctx->databuf + ctx->datalen, 0, ctx->matte - j);
}
}
+
+ if (job) {
+ dyesub_joblist_addjob(list, job);
+ }
+
+ /* All further work is in main loop */
+ if (test_mode >= TEST_MODE_NOPRINT)
+ dyesub_joblist_print(list);
+
+ *vjob = list;
+
return CUPS_BACKEND_OK;
}
@@ -1191,7 +1471,7 @@ static int mitsu70x_get_jobs(struct mitsu70x_ctx *ctx, struct mitsu70x_jobs *res
}
#endif
-static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, struct mitsu70x_memorystatus_resp *resp)
+static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, const struct mitsu70x_printjob *job, uint8_t mcut, struct mitsu70x_memorystatus_resp *resp)
{
uint8_t cmdbuf[CMDBUF_LEN];
@@ -1205,11 +1485,21 @@ static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, struct mitsu70x_m
cmdbuf[1] = 0x56;
cmdbuf[2] = 0x33;
cmdbuf[3] = 0x00;
- tmp = cpu_to_be16(ctx->cols);
+ tmp = cpu_to_be16(job->cols);
memcpy(cmdbuf + 4, &tmp, 2);
- tmp = cpu_to_be16(ctx->rows);
+
+ /* We have to lie about print sizes in 4x6*2 multicut modes */
+ tmp = job->rows;
+ if (tmp == 2730 && mcut == 1) {
+ if (ctx->type == P_MITSU_D70X ||
+ ctx->type == P_FUJI_ASK300) {
+ tmp = 2422;
+ }
+ }
+
+ tmp = cpu_to_be16(tmp);
memcpy(cmdbuf + 6, &tmp, 2);
- cmdbuf[8] = ctx->matte ? 0x80 : 0x00;
+ cmdbuf[8] = job->matte ? 0x80 : 0x00;
cmdbuf[9] = 0x00;
if ((ret = send_data(ctx->dev, ctx->endp_down,
@@ -1238,7 +1528,6 @@ static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, struct mitsu70x_m
return 0;
}
-
static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp)
{
uint8_t cmdbuf[CMDBUF_LEN];
@@ -1249,7 +1538,8 @@ static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x56;
cmdbuf[2] = 0x32;
- cmdbuf[3] = 0x30;
+ cmdbuf[3] = 0x30; /* or x31 or x32, for SINGLE DECK query!
+ Results will only have one deck. */
if ((ret = send_data(ctx->dev, ctx->endp_down,
cmdbuf, 4)))
return ret;
@@ -1361,23 +1651,41 @@ static int mitsu70x_set_printermode(struct mitsu70x_ctx *ctx, uint8_t enabled)
return 0;
}
#endif
-static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx)
+
+static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx, int wait)
{
int ret;
uint8_t buf[512];
+ struct mitsu70x_jobstatus jobstatus;
- memset(buf, 0, sizeof(buf));
- buf[0] = 0x1b;
- buf[1] = 0x45;
- buf[2] = 0x57; // XXX also, 0x53, 0x54 seen.
- buf[3] = 0x55;
-
- INFO("Waking up printer...\n");
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- buf, sizeof(buf))))
+top:
+ /* Query job status for jobid 0 (global) */
+ ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
+ if (ret)
return CUPS_BACKEND_FAILED;
- return 0;
+ /* Trigger a wakeup if necessary */
+ if (jobstatus.power) {
+ INFO("Waking up printer...\n");
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 0x1b;
+ buf[1] = 0x45;
+ buf[2] = 0x57; // XXX also, 0x53, 0x54 seen.
+ buf[3] = 0x55;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ buf, sizeof(buf))))
+ return CUPS_BACKEND_FAILED;
+
+ if (wait) {
+ sleep(1);
+ goto top;
+ }
+ }
+
+
+ return CUPS_BACKEND_OK;
}
static int d70_library_callback(void *context, void *buffer, uint32_t len)
@@ -1392,7 +1700,7 @@ static int d70_library_callback(void *context, void *buffer, uint32_t len)
if (chunk > CHUNK_LEN)
chunk = CHUNK_LEN;
- ret = send_data(ctx->dev, ctx->endp_down, buffer + offset, chunk);
+ ret = send_data(ctx->dev, ctx->endp_down, (uint8_t*)buffer + offset, chunk);
if (ret < 0)
break;
@@ -1403,7 +1711,7 @@ static int d70_library_callback(void *context, void *buffer, uint32_t len)
return ret;
}
-static int mitsu70x_main_loop(void *vctx, int copies)
+static int mitsu70x_main_loop(void *vctx, const void *vjob)
{
struct mitsu70x_ctx *ctx = vctx;
struct mitsu70x_jobstatus jobstatus;
@@ -1412,99 +1720,258 @@ static int mitsu70x_main_loop(void *vctx, int copies)
uint8_t last_status[4] = {0xff, 0xff, 0xff, 0xff};
int ret;
+ int copies;
+ int deck;
+
+ struct mitsu70x_printjob *job = (struct mitsu70x_printjob *) vjob; // XXX not clean.
+// const struct mitsu70x_printjob *job = vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
+ hdr = (struct mitsu70x_hdr*) job->databuf;
+
+ if (job->raw_format)
+ goto bypass;
- hdr = (struct mitsu70x_hdr*) ctx->databuf;
+ struct BandImage input;
+ uint8_t rew[2] = { 1, 1 }; /* 1 for rewind ok (default!) */
+
+ /* Load in the CPC file, if needed */
+ if (job->cpcfname && job->cpcfname != ctx->last_cpcfname) {
+ ctx->last_cpcfname = job->cpcfname;
+ if (ctx->cpcdata)
+ ctx->DestroyCPCData(ctx->cpcdata);
+ ctx->cpcdata = ctx->GetCPCData(job->cpcfname);
+ if (!ctx->cpcdata) {
+ ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
+ return CUPS_BACKEND_CANCEL;
+ }
+ }
+
+ /* Load in the secondary CPC, if needed */
+ if (job->ecpcfname != ctx->last_ecpcfname) {
+ ctx->last_ecpcfname = job->ecpcfname;
+ if (ctx->ecpcdata)
+ ctx->DestroyCPCData(ctx->ecpcdata);
+ if (job->ecpcfname) {
+ ctx->ecpcdata = ctx->GetCPCData(job->ecpcfname);
+ if (!ctx->ecpcdata) {
+ ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
+ return CUPS_BACKEND_CANCEL;
+ }
+ } else {
+ ctx->ecpcdata = NULL;
+ }
+ }
+
+ /* Convert using image processing library */
+ input.origin_rows = input.origin_cols = 0;
+ input.rows = job->rows;
+ input.cols = job->cols;
+ input.imgbuf = job->spoolbuf;
+ input.bytes_per_row = job->cols * 3;
+
+ ctx->output.origin_rows = ctx->output.origin_cols = 0;
+ ctx->output.rows = job->rows;
+ ctx->output.cols = job->cols;
+ ctx->output.imgbuf = job->databuf + job->datalen;
+ ctx->output.bytes_per_row = job->cols * 3 * 2;
+
+ DEBUG("Running print data through processing library\n");
+ if (ctx->DoImageEffect(ctx->cpcdata, ctx->ecpcdata,
+ &input, &ctx->output, job->sharpen, job->reverse, rew)) {
+ ERROR("Image Processing failed, aborting!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Twiddle rewind stuff if needed */
+ if (ctx->type != P_MITSU_D70X) {
+ hdr->rewind[0] = !rew[0];
+ hdr->rewind[1] = !rew[1];
+ DEBUG("Rewind Inhibit? %02x %02x\n", hdr->rewind[0], hdr->rewind[1]);
+ }
+
+ /* Move up the pointer to after the image data */
+ job->datalen += 3*job->planelen;
+
+ /* Clean up */
+ // XXX not really necessary.
+ free(job->spoolbuf);
+ job->spoolbuf = NULL;
+ job->spoolbuflen = 0;
+
+ /* Now that we've filled everything in, read matte from file */
+ if (job->matte) {
+ int fd;
+ uint32_t j;
+ DEBUG("Reading %u bytes of matte data from disk (%d/%d)\n", job->matte, job->cols, LAMINATE_STRIDE);
+ fd = open(job->laminatefname, O_RDONLY);
+ if (fd < 0) {
+ ERROR("Unable to open matte lamination data file '%s'\n", job->laminatefname);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ for (j = 0 ; j < be16_to_cpu(hdr->lamrows) ; j++) {
+ int remain = LAMINATE_STRIDE * 2;
+
+ /* Read one row of lamination data at a time */
+ while (remain) {
+ int i = read(fd, job->databuf + job->datalen, remain);
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ if (i == 0) {
+ /* We hit EOF, restart from beginning */
+ lseek(fd, 0, SEEK_SET);
+ continue;
+ }
+ job->datalen += i;
+ remain -= i;
+ }
+ /* Back off the buffer so we "wrap" on the print row. */
+ job->datalen -= ((LAMINATE_STRIDE - job->cols) * 2);
+ }
+ /* We're done */
+ close(fd);
+
+ /* Zero out the tail end of the buffer. */
+ j = be16_to_cpu(hdr->lamcols) * be16_to_cpu(hdr->lamrows) * 2;
+ memset(job->databuf + job->datalen, 0, job->matte - j);
+ }
+
+bypass:
+ /* Bypass */
+ if (test_mode >= TEST_MODE_NOPRINT)
+ return CUPS_BACKEND_OK;
INFO("Waiting for printer idle...\n");
+ /* Ensure printer is awake */
+ ret = mitsu70x_wakeup(ctx, 1);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
top:
/* Query job status for jobid 0 (global) */
ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
if (ret)
return CUPS_BACKEND_FAILED;
- /* Make sure we're awake! */
- if (jobstatus.power) {
- ret = mitsu70x_wakeup(ctx);
- if (ret)
- return CUPS_BACKEND_FAILED;
+ /* Figure out which deck(s) can be used.
+ This should be in the main loop due to copy retries */
- sleep(1);
- goto top;
+ /* First, try to respect requested deck */
+ if (ctx->type == P_MITSU_D70X) {
+ deck = hdr->deck; /* Respect D70 deck choice, 0 is automatic. */
+ } else {
+ deck = 1; /* All others have one deck only */
}
- /* Make sure temperature is sane */
- if (jobstatus.temperature == TEMPERATURE_COOLING) {
- INFO("Printer cooling down...\n");
- sleep(1);
- goto top;
+ /* If user requested a specific deck, go with it, if it's legal */
+ if (deck == 1 && job->decks_ok[0]) {
+ deck = 1;
+ } else if (deck == 2 && job->decks_ok[1]) {
+ deck = 2;
+ /* If we have an exact match for media, use it exclusively */
+ } else if (job->decks_exact[0] && job->decks_exact[1]) {
+ deck = 1 | 2;
+ } else if (job->decks_exact[0]) {
+ deck = 1;
+ } else if (job->decks_exact[1]) {
+ deck = 2;
+ /* Use a non-exact match only if we don't have an exact match */
+ } else if (job->decks_ok[0] && job->decks_ok[1]) {
+ deck = 1 | 2;
+ } else if (job->decks_ok[0]) {
+ deck = 1;
+ } else if (job->decks_ok[1]) {
+ deck = 2;
+ } else {
+ ERROR("Loaded media does not match job!\n");
+ return CUPS_BACKEND_CANCEL;
}
- /* See if we hit a printer error. */
- if (jobstatus.error_status[0]) {
- ERROR("%s/%s -> %s: %02x/%02x/%02x\n",
- mitsu70x_errorclass(jobstatus.error_status),
- mitsu70x_errors(jobstatus.error_status),
- mitsu70x_errorrecovery(jobstatus.error_status),
- jobstatus.error_status[0],
- jobstatus.error_status[1],
- jobstatus.error_status[2]);
- return CUPS_BACKEND_STOP;
+ if (ctx->num_decks > 1)
+ DEBUG("Deck selection mask: %d (%d %d %d/%d %d/%d) \n",
+ deck, hdr->deck, job->rows,
+ job->decks_exact[0], job->decks_exact[1],
+ job->decks_ok[0], job->decks_ok[1]);
+
+ /* Okay, we know which decks are _legal_, pick one to use */
+ if (deck & 1) {
+ if (jobstatus.temperature == TEMPERATURE_COOLING) {
+ if (ctx->num_decks == 2)
+ INFO("Lower deck cooling down...\n");
+ else
+ INFO("Printer cooling down...\n");
+ deck &= ~1;
+ } else if (jobstatus.error_status[0]) {
+ ERROR("%s/%s -> %s: %02x/%02x/%02x\n",
+ mitsu70x_errorclass(jobstatus.error_status),
+ mitsu70x_errors(jobstatus.error_status),
+ mitsu70x_errorrecovery(jobstatus.error_status),
+ jobstatus.error_status[0],
+ jobstatus.error_status[1],
+ jobstatus.error_status[2]);
+ deck &= ~1;
+ } else if (jobstatus.mecha_status[0] != MECHA_STATUS_IDLE) {
+ deck = ~1;
+ }
+ }
+ if (deck & 2) {
+ if (jobstatus.temperature_up == TEMPERATURE_COOLING) {
+ INFO("Upper deck cooling down...\n");
+ deck &= ~2;
+ } else if (jobstatus.error_status_up[0]) {
+ ERROR("UPPER: %s/%s -> %s: %02x/%02x/%02x\n",
+ mitsu70x_errorclass(jobstatus.error_status_up),
+ mitsu70x_errors(jobstatus.error_status_up),
+ mitsu70x_errorrecovery(jobstatus.error_status_up),
+ jobstatus.error_status_up[0],
+ jobstatus.error_status_up[1],
+ jobstatus.error_status_up[2]);
+ deck &= ~2;
+ } else if (jobstatus.mecha_status_up[0] != MECHA_STATUS_IDLE) {
+ deck = ~2;
+ }
}
- if (ctx->num_decks)
- goto skip_status;
-
- /* Tell CUPS about the consumables we report */
- ret = mitsu70x_get_printerstatus(ctx, &resp);
- if (ret)
- return CUPS_BACKEND_FAILED;
+ if (deck == 3) {
+ /* Both decks OK to use, pick one at random */
+ if (rand() & 1)
+ deck = 1;
+ else
+ deck = 2;
+ }
- if (resp.upper.mecha_status[0] != MECHA_STATUS_INIT)
- ctx->num_decks = 2;
- else
- ctx->num_decks = 1;
+ if (ctx->num_decks > 1)
+ DEBUG("Deck selected: %d\n", deck);
- if (ctx->type == P_MITSU_D70X &&
- ctx->num_decks == 2) {
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00,#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100,100\n");
- ATTR("marker-low-levels=10,10\n");
- ATTR("marker-names='\"%s\"','\"%s\"'\n",
- mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type),
- mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type));
- ATTR("marker-types=ribbonWax,ribbonWax\n");
- } else {
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n",
- mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type));
- ATTR("marker-types=ribbonWax\n");
- }
+ if (deck == 0) {
+ /* Halt queue if printer is entirely offline */
+ if (ctx->num_decks == 2) {
+ if (jobstatus.error_status[0] && jobstatus.error_status_up[0])
+ return CUPS_BACKEND_STOP;
+ // XXX what if we only have one legal deck, and it's unavailable? We don't want to retry indefinitely here..
+ } else {
+ if (jobstatus.error_status[0])
+ return CUPS_BACKEND_STOP;
+ }
- /* FW sanity checking */
- if (ctx->type == P_KODAK_305) {
- if (be16_to_cpu(resp.vers[0].checksum) != EK305_0104_M_CSUM)
- WARNING("Printer FW out of date. Highly recommend upgrading EK305 to v1.04!\n");
- } else if (ctx->type == P_MITSU_K60) {
- if (be16_to_cpu(resp.vers[0].checksum) != MK60S_0105_M_CSUM)
- WARNING("Printer FW out of date. Highly recommend upgrading K60 to v1.05!\n");
- } else if (ctx->type == P_MITSU_D70X) {
- if (be16_to_cpu(resp.vers[0].checksum) != MD70X_0112_M_CSUM)
- WARNING("Printer FW out of date. Highly recommend upgrading D70/D707 to v1.12!\n");
+ /* No decks available yet, retry */
+ sleep(1);
+ goto top;
}
-skip_status:
/* Perform memory status query */
{
struct mitsu70x_memorystatus_resp memory;
INFO("Checking Memory availability\n");
- ret = mitsu70x_get_memorystatus(ctx, &memory);
+ ret = mitsu70x_get_memorystatus(ctx, job, hdr->multicut, &memory);
if (ret)
return CUPS_BACKEND_FAILED;
@@ -1548,25 +2015,12 @@ skip_status:
hdr->jobid = cpu_to_be16(ctx->jobid);
/* Set deck */
- if (ctx->type == P_MITSU_D70X) {
- hdr->deck = 0; /* D70 use automatic deck selection */
- /* XXX alternatively route it based on state and media? */
- } else {
- hdr->deck = 1; /* All others only have a "lower" deck. */
- }
-
-
- /* Twiddle rewind stuff if needed */
- if (ctx->type != P_MITSU_D70X) {
- hdr->rewind[0] = !ctx->rew[0];
- hdr->rewind[1] = !ctx->rew[1];
- DEBUG("Rewind Inhibit? %02x %02x\n", hdr->rewind[0], hdr->rewind[1]);
- }
+ hdr->deck = deck;
- /* Any other fixups? */
+ /* K60 and EK305 need the mcut type 1 specified for 4x6 prints! */
if ((ctx->type == P_MITSU_K60 || ctx->type == P_KODAK_305) &&
- ctx->cols == 0x0748 &&
- ctx->rows == 0x04c2 && !hdr->multicut) {
+ job->cols == 0x0748 &&
+ job->rows == 0x04c2 && !hdr->multicut) {
hdr->multicut = 1;
}
@@ -1574,16 +2028,16 @@ skip_status:
INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf,
+ job->databuf,
sizeof(struct mitsu70x_hdr))))
return CUPS_BACKEND_FAILED;
- if (ctx->dl_handle && !ctx->raw_format) {
+ if (ctx->dl_handle && !job->raw_format) {
if (ctx->SendImageData(&ctx->output, ctx, d70_library_callback))
return CUPS_BACKEND_FAILED;
- if (ctx->matte)
- if (d70_library_callback(ctx, ctx->databuf + ctx->datalen - ctx->matte, ctx->matte))
+ if (job->matte)
+ if (d70_library_callback(ctx, job->databuf + job->datalen - job->matte, job->matte))
return CUPS_BACKEND_FAILED;
} else { // Fallback code..
/* K60 and 305 need data sent in 256K chunks, but the first
@@ -1593,10 +2047,10 @@ skip_status:
int sent = 512;
while (chunk > 0) {
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf + sent, chunk)))
+ job->databuf + sent, chunk)))
return CUPS_BACKEND_FAILED;
sent += chunk;
- chunk = ctx->datalen - sent;
+ chunk = job->datalen - sent;
if (chunk > CHUNK_LEN)
chunk = CHUNK_LEN;
}
@@ -1606,38 +2060,23 @@ skip_status:
INFO("Waiting for printer to acknowledge completion\n");
do {
- uint16_t donor_u, donor_l;
-
sleep(1);
ret = mitsu70x_get_printerstatus(ctx, &resp);
if (ret)
return CUPS_BACKEND_FAILED;
- donor_l = be16_to_cpu(resp.lower.remain) * 100 / be16_to_cpu(resp.lower.capacity);
-
- if (ctx->type == P_MITSU_D70X &&
- ctx->num_decks == 2) {
- donor_u = be16_to_cpu(resp.upper.remain) * 100 / be16_to_cpu(resp.upper.capacity);
- if (donor_l != ctx->last_donor_l ||
- donor_u != ctx->last_donor_u) {
- ctx->last_donor_l = donor_l;
- ctx->last_donor_u = donor_u;
- ATTR("marker-levels=%d,%d\n", donor_l, donor_u);
- ATTR("marker-message='\"%d native prints remaining on %s media\"','\"%d native prints remaining on %s media\"'\n",
- be16_to_cpu(resp.lower.remain),
- mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type),
- be16_to_cpu(resp.upper.remain),
- mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type));
- }
- } else {
- if (donor_l != ctx->last_donor_l) {
- ctx->last_donor_l = donor_l;
- ATTR("marker-levels=%d\n", donor_l);
- ATTR("marker-message=\"%d native prints remaining on %s media\"\n",
- be16_to_cpu(resp.lower.remain),
- mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type));
- }
+ ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
+ ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
+ if (ctx->num_decks == 2) {
+ ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
+ ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
+ }
+ if (ctx->marker[0].levelnow != ctx->last_l ||
+ ctx->marker[1].levelnow != ctx->last_u) {
+ dump_markers(ctx->marker, ctx->num_decks, 0);
+ ctx->last_l = ctx->marker[0].levelnow;
+ ctx->last_u = ctx->marker[1].levelnow;
}
/* Query job status for our used jobid */
@@ -1646,18 +2085,31 @@ skip_status:
return CUPS_BACKEND_FAILED;
/* See if we hit a printer error. */
- if (jobstatus.error_status[0]) {
- ERROR("%s/%s -> %s: %02x/%02x/%02x\n",
- mitsu70x_errorclass(jobstatus.error_status),
- mitsu70x_errors(jobstatus.error_status),
- mitsu70x_errorrecovery(jobstatus.error_status),
- jobstatus.error_status[0],
- jobstatus.error_status[1],
- jobstatus.error_status[2]);
- return CUPS_BACKEND_STOP;
+ if (deck == 0) {
+ if (jobstatus.error_status[0]) {
+ ERROR("%s/%s -> %s: %02x/%02x/%02x\n",
+ mitsu70x_errorclass(jobstatus.error_status),
+ mitsu70x_errors(jobstatus.error_status),
+ mitsu70x_errorrecovery(jobstatus.error_status),
+ jobstatus.error_status[0],
+ jobstatus.error_status[1],
+ jobstatus.error_status[2]);
+ return CUPS_BACKEND_STOP;
+ }
+ } else if (deck == 1) {
+ if (jobstatus.error_status_up[0]) {
+ ERROR("UPPER: %s/%s -> %s: %02x/%02x/%02x\n",
+ mitsu70x_errorclass(jobstatus.error_status_up),
+ mitsu70x_errors(jobstatus.error_status_up),
+ mitsu70x_errorrecovery(jobstatus.error_status_up),
+ jobstatus.error_status_up[0],
+ jobstatus.error_status_up[1],
+ jobstatus.error_status_up[2]);
+ return CUPS_BACKEND_STOP;
+ }
}
- /* Only print if it's changed */
+ /* Only print if job status is changed */
if (jobstatus.job_status[0] != last_status[0] ||
jobstatus.job_status[1] != last_status[1] ||
jobstatus.job_status[2] != last_status[2] ||
@@ -1669,6 +2121,7 @@ skip_status:
jobstatus.job_status[2],
jobstatus.job_status[3]);
+ /* Check for job completion */
if (jobstatus.job_status[0] == JOB_STATUS0_END) {
if (jobstatus.job_status[1] ||
jobstatus.job_status[2] ||
@@ -1683,7 +2136,12 @@ skip_status:
break;
}
- if (fast_return) {
+ /* On a two deck system, try to use the second deck
+ for additional copies. If we can't use it, we'll block. */
+ if (ctx->num_decks > 1 && copies > 1)
+ break;
+
+ if (fast_return && copies <= 1) { /* Copies generated by backend! */
INFO("Fast return mode enabled.\n");
break;
}
@@ -1705,7 +2163,8 @@ skip_status:
return CUPS_BACKEND_OK;
}
-static void mitsu70x_dump_printerstatus(struct mitsu70x_printerstatus_resp *resp)
+static void mitsu70x_dump_printerstatus(struct mitsu70x_ctx *ctx,
+ struct mitsu70x_printerstatus_resp *resp)
{
uint32_t i;
@@ -1738,83 +2197,102 @@ static void mitsu70x_dump_printerstatus(struct mitsu70x_printerstatus_resp *resp
}
INFO("Standby Timeout: %d minutes\n", resp->sleeptime);
INFO("iSerial Reporting: %s\n", resp->iserial ? "No" : "Yes" );
+ INFO("Power Status: %s\n", resp->power ? "Sleeping" : "Awake");
- INFO("Lower Mechanical Status: %s\n",
- mitsu70x_mechastatus(resp->lower.mecha_status));
if (resp->lower.error_status[0]) {
INFO("Lower Error Status: %s/%s -> %s\n",
mitsu70x_errorclass(resp->lower.error_status),
mitsu70x_errors(resp->lower.error_status),
mitsu70x_errorrecovery(resp->lower.error_status));
}
- INFO("Lower Media type: %s (%02x/%02x)\n",
+ INFO("Lower Temperature: %s\n", mitsu70x_temperatures(resp->lower.temperature));
+ INFO("Lower Mechanical Status: %s\n",
+ mitsu70x_mechastatus(resp->lower.mecha_status));
+ INFO("Lower Media Type: %s (%02x/%02x)\n",
mitsu70x_media_types(resp->lower.media_brand, resp->lower.media_type),
resp->lower.media_brand,
resp->lower.media_type);
- INFO("Lower Prints remaining: %03d/%03d\n",
+ INFO("Lower Prints Remaining: %03d/%03d\n",
be16_to_cpu(resp->lower.remain),
be16_to_cpu(resp->lower.capacity));
-
i = packed_bcd_to_uint32((char*)resp->lower.lifetime_prints, 4);
if (i)
i-= 10;
- INFO("Lower Lifetime prints: %u\n", i);
+ INFO("Lower Lifetime Prints: %u\n", i);
- if (resp->upper.mecha_status[0] != MECHA_STATUS_INIT) {
- INFO("Upper Mechanical Status: %s\n",
- mitsu70x_mechastatus(resp->upper.mecha_status));
+ if (ctx->num_decks == 2) {
if (resp->upper.error_status[0]) {
INFO("Upper Error Status: %s/%s -> %s\n",
mitsu70x_errorclass(resp->upper.error_status),
mitsu70x_errors(resp->upper.error_status),
mitsu70x_errorrecovery(resp->upper.error_status));
}
- INFO("Upper Media type: %s (%02x/%02x)\n",
+ INFO("Upper Temperature: %s\n", mitsu70x_temperatures(resp->upper.temperature));
+ INFO("Upper Mechanical Status: %s\n",
+ mitsu70x_mechastatus(resp->upper.mecha_status));
+ INFO("Upper Media Type: %s (%02x/%02x)\n",
mitsu70x_media_types(resp->upper.media_brand, resp->upper.media_type),
resp->upper.media_brand,
resp->upper.media_type);
- INFO("Upper Prints remaining: %03d/%03d\n",
+ INFO("Upper Prints Remaining: %03d/%03d\n",
be16_to_cpu(resp->upper.remain),
be16_to_cpu(resp->upper.capacity));
i = packed_bcd_to_uint32((char*)resp->upper.lifetime_prints, 4);
if (i)
i-= 10;
- INFO("Upper Lifetime prints: %u\n", i);
+ INFO("Upper Lifetime Prints: %u\n", i);
}
}
-static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
+static int mitsu70x_query_jobs(struct mitsu70x_ctx *ctx)
{
- struct mitsu70x_printerstatus_resp resp;
#if 0
struct mitsu70x_jobs jobs;
#endif
struct mitsu70x_jobstatus jobstatus;
-
int ret;
-top:
ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
if (ret)
- goto done;
-
- /* Make sure we're awake! */
- if (jobstatus.power) {
- ret = mitsu70x_wakeup(ctx);
- if (ret)
- return CUPS_BACKEND_FAILED;
-
- sleep(1);
- goto top;
- }
-
- ret = mitsu70x_get_printerstatus(ctx, &resp);
- if (!ret)
- mitsu70x_dump_printerstatus(&resp);
+ return CUPS_BACKEND_FAILED;
INFO("JOB00 ID : %06u\n", jobstatus.jobid);
INFO("JOB00 status : %s\n", mitsu70x_jobstatuses(jobstatus.job_status));
+ INFO("Power Status: %s\n", jobstatus.power ? "Sleeping" : "Awake");
+
+ if (ctx->num_decks == 2) {
+ INFO("Lower Deck Mechanical Status: %s\n",
+ mitsu70x_mechastatus(jobstatus.mecha_status));
+ if (jobstatus.error_status[0]) {
+ INFO("%s/%s -> %s\n",
+ mitsu70x_errorclass(jobstatus.error_status),
+ mitsu70x_errors(jobstatus.error_status),
+ mitsu70x_errorrecovery(jobstatus.error_status));
+ }
+ INFO("Lower Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
+
+ INFO("Upper Deck Mechanical Status: %s\n",
+ mitsu70x_mechastatus(jobstatus.mecha_status_up));
+ if (jobstatus.error_status_up[0]) {
+ INFO("%s/%s -> %s\n",
+ mitsu70x_errorclass(jobstatus.error_status_up),
+ mitsu70x_errors(jobstatus.error_status_up),
+ mitsu70x_errorrecovery(jobstatus.error_status_up));
+ }
+ INFO("Upper Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature_up));
+ } else {
+ INFO("Mechanical Status: %s\n",
+ mitsu70x_mechastatus(jobstatus.mecha_status));
+ if (jobstatus.error_status[0]) {
+ INFO("%s/%s -> %s\n",
+ mitsu70x_errorclass(jobstatus.error_status),
+ mitsu70x_errors(jobstatus.error_status),
+ mitsu70x_errorrecovery(jobstatus.error_status));
+ }
+ INFO("Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
+ }
+ // memory status?
#if 0
ret = mitsu70x_get_jobs(ctx, &jobs);
@@ -1827,9 +2305,21 @@ top:
INFO("JOB%02d status : %s\n", i, mitsu70x_jobstatuses(jobs.jobs[i].status));
}
}
-#endif
done:
+#endif
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
+{
+ struct mitsu70x_printerstatus_resp resp;
+ int ret;
+
+ ret = mitsu70x_get_printerstatus(ctx, &resp);
+ if (!ret)
+ mitsu70x_dump_printerstatus(ctx, &resp);
+
return ret;
}
@@ -1860,7 +2350,10 @@ static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_u
static void mitsu70x_cmdline(void)
{
- DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -s ] # Query printer status\n");
+ DEBUG("\t\t[ -j ] # Query job status\n");
+ DEBUG("\t\t[ -w ] # Wake up printer\n");
+ DEBUG("\t\t[ -W ] # Wake up printer and wait\n");
DEBUG("\t\t[ -f ] # Use fast return mode\n");
DEBUG("\t\t[ -k num ] # Set standby time (1-60 minutes, 0 disables)\n");
DEBUG("\t\t[ -x num ] # Set USB iSerialNumber Reporting (1 on, 0 off)\n");
@@ -1874,15 +2367,24 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
if (!ctx)
return -1;
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "sk:X:x:")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "jk:swWX:x:")) >= 0) {
switch(i) {
GETOPT_PROCESS_GLOBAL
+ case 'j':
+ j = mitsu70x_query_jobs(ctx);
+ break;
case 'k':
j = mitsu70x_set_sleeptime(ctx, atoi(optarg));
break;
case 's':
j = mitsu70x_query_status(ctx);
break;
+ case 'w':
+ j = mitsu70x_wakeup(ctx, 0);
+ break;
+ case 'W':
+ j = mitsu70x_wakeup(ctx, 1);
+ break;
case 'x':
j = mitsu70x_set_iserial(ctx, atoi(optarg));
break;
@@ -1899,28 +2401,73 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int mitsu70x_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct mitsu70x_ctx *ctx = vctx;
+ struct mitsu70x_printerstatus_resp resp;
+ int ret;
+
+ *markers = ctx->marker;
+ *count = ctx->num_decks;
+
+ /* Tell CUPS about the consumables we report */
+ ret = mitsu70x_get_printerstatus(ctx, &resp);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ if (resp.power) {
+ ret = mitsu70x_wakeup(ctx, 1);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+
+ ret = mitsu70x_get_printerstatus(ctx, &resp);
+ if (ret)
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
+ ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
+ if (ctx->num_decks == 2) {
+ ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
+ ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *mitsu70x_prefixes[] = {
+ "mitsu70x", // Family entry, do not nuke.
+ "mitsubishi-d70dw", "mitsubishi-d80dw", "mitsubishi-k60dw", "kodak-305", "fujifilm-ask-300"
+ // Extras
+ "mitsubishi-d707dw", "mitsubishi-k60dws",
+ // backwards compatibility
+ "mitsud80", "mitsuk60", "kodak305", "fujiask300",
+ NULL,
+};
/* Exported */
struct dyesub_backend mitsu70x_backend = {
- .name = "Mitsubishi CP-D70/D707/K60/D80",
- .version = "0.66",
- .uri_prefix = "mitsu70x",
+ .name = "Mitsubishi CP-D70 family",
+ .version = "0.88",
+ .uri_prefixes = mitsu70x_prefixes,
+ .flags = BACKEND_FLAG_JOBLIST,
.cmdline_usage = mitsu70x_cmdline,
.cmdline_arg = mitsu70x_cmdline_arg,
.init = mitsu70x_init,
.attach = mitsu70x_attach,
.teardown = mitsu70x_teardown,
+ .cleanup_job = mitsu70x_cleanup_job,
.read_parse = mitsu70x_read_parse,
.main_loop = mitsu70x_main_loop,
.query_serno = mitsu70x_query_serno,
+ .query_markers = mitsu70x_query_markers,
.devices = {
- { USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, ""},
- { USB_VID_MITSU, USB_PID_MITSU_K60, P_MITSU_K60, ""},
- { USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D80, ""},
-// { USB_VID_MITSU, USB_PID_MITSU_D90, P_MITSU_D90, ""},
- { USB_VID_KODAK, USB_PID_KODAK305, P_KODAK_305, ""},
- { USB_VID_FUJIFILM, USB_PID_FUJI_ASK300, P_FUJI_ASK300, ""},
- { 0, 0, 0, ""}
+ { USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, NULL, "mitsubishi-d70dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_K60, P_MITSU_K60, NULL, "mitsubishi-k60dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D80, NULL, "mitsubishi-d80dw"},
+ { USB_VID_KODAK, USB_PID_KODAK305, P_KODAK_305, NULL, "kodak-305"},
+ { USB_VID_FUJIFILM, USB_PID_FUJI_ASK300, P_FUJI_ASK300, NULL, "fujifilm-ask-300"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_mitsu9550.c b/src/cups/backend_mitsu9550.c
index 71b38de..ab7530a 100644
--- a/src/cups/backend_mitsu9550.c
+++ b/src/cups/backend_mitsu9550.c
@@ -1,7 +1,7 @@
/*
* Mitsubishi CP-9xxx Photo Printer Family CUPS backend
*
- * (c) 2014-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2014-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -35,6 +36,11 @@
#include <fcntl.h>
#include <signal.h>
+/* For Integration into gutenprint */
+#if defined(HAVE_CONFIG_H)
+#include <config.h>
+#endif
+
#define BACKEND mitsu9550_backend
#include "backend_common.h"
@@ -53,6 +59,20 @@
//#define USB_PID_MITSU_9810D XXXXXX
//#define USB_PID_MITSU_9820DS XXXXXX
+#ifndef CORRTABLE_PATH
+#ifdef PACKAGE_DATA_DIR
+#define CORRTABLE_PATH PACKAGE_DATA_DIR "/backend_data"
+#else
+#error "Must define CORRTABLE_PATH or PACKAGE_DATA_DIR!"
+#endif
+#endif
+
+#define MITSU_M98xx_LAMINATE_FILE CORRTABLE_PATH "/M98MATTE.raw"
+#define MITSU_M98xx_DATATABLE_FILE CORRTABLE_PATH "/M98TABLE.dat"
+#define MITSU_M98xx_LUT_FILE CORRTABLE_PATH "/M98XXL01.lut"
+#define LAMINATE_STRIDE 1868
+#define DATATABLE_SIZE 42204
+
/* Spool file structures */
/* Print parameters1 */
@@ -61,14 +81,14 @@ struct mitsu9550_hdr1 {
uint8_t unk[10]; /* 00 0a 10 00 [...] */
uint16_t cols; /* BE */
uint16_t rows; /* BE */
- uint8_t matte; /* CP9810 only. 01 for matte, 00 glossy */
+ uint8_t matte; /* CP9810/9820 only. 01 for matte, 00 glossy */
uint8_t null[31];
} __attribute__((packed));
/* Print parameters2 */
struct mitsu9550_hdr2 {
uint8_t cmd[4]; /* 1b 57 21 2e */
- uint8_t unk[24]; /* 00 80 00 22 08 03 00 [...] */
+ uint8_t unk[24]; /* 00 80 00 22 08 03 [...] */
uint16_t copies; /* BE, 1-680 */
uint8_t null[2];
uint8_t cut; /* 00 == normal, 83 == 2x6*2 */
@@ -94,34 +114,63 @@ struct mitsu9550_hdr4 {
/* Data plane header */
struct mitsu9550_plane {
uint8_t cmd[4]; /* 1b 5a 54 XX */ /* XX == 0x10 if 16bpp, 0x00 for 8bpp */
+ uint16_t col_offset; /* BE, normally 0, where we start dumping data */
uint16_t row_offset; /* BE, normally 0, where we start dumping data */
- uint16_t null; /* ??? */
uint16_t cols; /* BE */
uint16_t rows; /* BE */
} __attribute__((packed));
+/* CP98xx Tabular Data */
+struct mitsu98xx_data {
+ uint16_t GNMby[256]; // @0
+ uint16_t GNMgm[256]; // @512
+ uint16_t GNMrc[256]; // @1024
+ double GammaParams[3]; // @1536
+ uint8_t KH[2048]; // @1560
+ uint32_t unk_b[3]; // @3608
+
+ struct {
+ double unka[256]; // @0
+ double unkb[256]; // @2048
+ uint32_t unkc[10]; // @4096
+ double unkd[256]; // @4136
+ double unke[256]; // @6184 // *= sharp->coef[X]
+ uint32_t unkf[10]; // @8232
+ double unkg[256]; // @8272
+ // @10320
+ } WMAM; // @3620
+ uint8_t unc_d[4]; // @13940 @10320 (from wmam start)
+ struct {
+ uint32_t unk_a; // @13944/10324 (padding?)
+ double coef[10]; // @13948/10328 (sharpness coefficients, level 0-9)
+ uint32_t unk_b[5]; // @14028/10408
+ } sharp; // total 104, @13944/10324
+ uint8_t unk_e[20]; // @14048/10428
+ // @14068/10448
+} __attribute__((packed));
+
+struct mitsu98xx_tables {
+ struct mitsu98xx_data superfine;
+ struct mitsu98xx_data fine_std;
+ struct mitsu98xx_data fine_hg;
+} __attribute__((packed));
+
+/* Command header */
struct mitsu9550_cmd {
uint8_t cmd[4];
} __attribute__((packed));
/* Private data structure */
-struct mitsu9550_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
- int is_s;
-
+struct mitsu9550_printjob {
uint8_t *databuf;
uint32_t datalen;
uint16_t rows;
uint16_t cols;
uint32_t plane_len;
+ int is_raw;
- uint16_t last_donor;
- uint16_t last_remain;
- int marker_reported;
+ int copies;
/* Parse headers separately */
struct mitsu9550_hdr1 hdr1;
@@ -134,6 +183,21 @@ struct mitsu9550_ctx {
int hdr4_present;
};
+struct mitsu9550_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+ int is_s;
+ int is_98xx;
+
+ struct marker marker;
+
+ /* CP98xx stuff */
+ struct mitsu98xx_tables *m98xxdata;
+ struct CColorConv3D *lut;
+};
+
/* Printer data structures */
struct mitsu9550_media {
uint8_t hdr[2]; /* 24 2e */
@@ -164,12 +228,14 @@ struct mitsu9550_status {
} __attribute__((packed));
struct mitsu9550_status2 {
- uint8_t hdr[2]; /* 21 2e */
- uint8_t unk[39];
+ uint8_t hdr[2]; /* 21 2e / 24 2e on 9550/9800 */
+ uint8_t unk[40];
uint16_t remain; /* BE, media remaining */
uint8_t unkb[4]; /* 0a 00 00 01 */
} __attribute__((packed));
+static int mitsu9550_main_loop(void *vctx, const void *vjob);
+
#define CMDBUF_LEN 64
#define READBACK_LEN 128
@@ -178,41 +244,24 @@ struct mitsu9550_status2 {
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;\
/* struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf; */ \
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf; \
- uint16_t donor, remain; \
+ uint16_t donor; \
/* media */ \
ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); \
if (ret < 0) \
return CUPS_BACKEND_FAILED; \
\
- /* Tell CUPS about the consumables we report */ \
- if (!ctx->marker_reported) { \
- ctx->marker_reported = 1; \
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); \
- ATTR("marker-high-levels=100\n"); \
- ATTR("marker-low-levels=10\n"); \
- ATTR("marker-names='%s'\n", mitsu9550_media_types(media->type, ctx->is_s)); \
- ATTR("marker-types=ribbonWax\n"); \
+ donor = be16_to_cpu(media->remain); \
+ if (donor != ctx->marker.levelnow) { \
+ ctx->marker.levelnow = donor; \
+ dump_markers(&ctx->marker, 1, 0); \
} \
- \
/* Sanity-check media response */ \
if (media->remain == 0 || media->max == 0) { \
ERROR("Printer out of media!\n"); \
- ATTR("marker-levels=%d\n", 0); \
return CUPS_BACKEND_HOLD; \
} \
- remain = be16_to_cpu(media->remain); \
- donor = be16_to_cpu(media->max); \
- donor = remain/donor; \
- if (donor != ctx->last_donor) { \
- ctx->last_donor = donor; \
- ATTR("marker-levels=%u\n", donor); \
- } \
- if (remain != ctx->last_remain) { \
- ctx->last_remain = remain; \
- ATTR("marker-message=\"%u prints remaining on '%s' ribbon\"\n", remain, mitsu9550_media_types(media->type, ctx->is_s)); \
- } \
- if (validate_media(ctx->type, media->type, ctx->cols, ctx->rows)) { \
- ERROR("Incorrect media (%u) type for printjob (%ux%u)!\n", media->type, ctx->cols, ctx->rows); \
+ if (validate_media(ctx->type, media->type, job->cols, job->rows)) { \
+ ERROR("Incorrect media (%u) type for printjob (%ux%u)!\n", media->type, job->cols, job->rows); \
return CUPS_BACKEND_HOLD; \
} \
/* status2 */ \
@@ -236,6 +285,246 @@ struct mitsu9550_status2 {
} \
} while (0);
+static void mitsu98xx_dogamma(uint8_t *src, uint16_t *dest, uint8_t plane,
+ uint16_t *table, uint32_t len)
+{
+ src += plane;
+ while(len--) {
+ *dest++ = table[*src];
+ src += 3;
+ }
+ /* TODO: Eventually, when we do real processing of this data, we will need to
+ have the gamma table in native endian format and generate BE data at the end. */
+}
+
+static int mitsu98xx_fillmatte(struct mitsu9550_printjob *job)
+{
+ int fd, i;
+ uint32_t j, remain;
+
+ DEBUG("Reading %d bytes of matte data from disk (%d/%d)\n", job->cols * job->rows, job->cols, LAMINATE_STRIDE);
+ fd = open(MITSU_M98xx_LAMINATE_FILE, O_RDONLY);
+ if (fd < 0) {
+ WARNING("Unable to open matte lamination data file '%s'\n", MITSU_M98xx_LAMINATE_FILE);
+ job->hdr1.matte = 0;
+ goto done;
+ }
+
+ /* Fill in the lamination plane header */
+ struct mitsu9550_plane *matte = (struct mitsu9550_plane *)(job->databuf + job->datalen);
+ matte->cmd[0] = 0x1b;
+ matte->cmd[1] = 0x5a;
+ matte->cmd[2] = 0x54;
+ matte->cmd[3] = 0x10;
+ matte->row_offset = 0;
+ matte->col_offset = 0;
+ matte->cols = job->hdr1.cols;
+ matte->rows = job->hdr1.rows;
+ job->datalen += sizeof(struct mitsu9550_plane);
+
+ /* Read in the matte data plane */
+ for (j = 0 ; j < job->rows ; j++) {
+ remain = LAMINATE_STRIDE * 2;
+
+ /* Read one row of lamination data at a time */
+ while (remain) {
+ i = read(fd, job->databuf + job->datalen, remain);
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ if (i == 0) {
+ /* We hit EOF, restart from beginning */
+ lseek(fd, 0, SEEK_SET);
+ continue;
+ }
+ job->datalen += i;
+ remain -= i;
+ }
+ /* Back off the buffer so we "wrap" on the print row. */
+ job->datalen -= ((LAMINATE_STRIDE - job->cols) * 2);
+ }
+ /* We're done! */
+ close(fd);
+
+ /* Fill in the lamination plane footer */
+ job->databuf[job->datalen++] = 0x1b;
+ job->databuf[job->datalen++] = 0x50;
+ job->databuf[job->datalen++] = 0x56;
+ job->databuf[job->datalen++] = 0x00;
+
+done:
+ return CUPS_BACKEND_OK;
+}
+
+/*** 3D color Lookup table stuff. Taken out of lib70x ****/
+#define LUT_LEN 14739
+#define COLORCONV_RGB 0
+#define COLORCONV_BGR 1
+
+struct CColorConv3D {
+ uint8_t lut[17][17][17][3];
+};
+
+/* Load the Lookup table off of disk into *PRE-ALLOCATED* buffer */
+int CColorConv3D_Get3DColorTable(uint8_t *buf, const char *filename)
+{
+ FILE *stream;
+
+ if (!filename)
+ return 1;
+ if (!*filename)
+ return 2;
+ if (!buf)
+ return 3;
+
+ stream = fopen(filename, "rb");
+ if (!stream)
+ return 4;
+
+ fseek(stream, 0, SEEK_END);
+ if (ftell(stream) < LUT_LEN) {
+ fclose(stream);
+ return 5;
+ }
+ fseek(stream, 0, SEEK_SET);
+ fread(buf, 1, LUT_LEN, stream);
+ fclose(stream);
+
+ return 0;
+}
+
+/* Parse the on-disk LUT data into the structure.... */
+struct CColorConv3D *CColorConv3D_Load3DColorTable(const uint8_t *ptr)
+{
+ struct CColorConv3D *this;
+ this = malloc(sizeof(*this));
+ if (!this)
+ return NULL;
+
+ int i, j, k;
+
+ for (i = 0 ; i <= 16 ; i++) {
+ for (j = 0 ; j <= 16 ; j++) {
+ for (k = 0; k <= 16; k++) {
+ this->lut[k][j][i][2] = *ptr++;
+ this->lut[k][j][i][1] = *ptr++;
+ this->lut[k][j][i][0] = *ptr++;
+ }
+ }
+ }
+ return this;
+}
+void CColorConv3D_Destroy3DColorTable(struct CColorConv3D *this)
+{
+ free(this);
+}
+
+/* Transform a single pixel. */
+static void CColorConv3D_DoColorConvPixel(struct CColorConv3D *this, uint8_t *redp, uint8_t *grnp, uint8_t *blup)
+{
+ int red_h;
+ int grn_h;
+ int blu_h;
+ int grn_li;
+ int red_li;
+ int blu_li;
+ int red_l;
+ int grn_l;
+ int blu_l;
+
+ uint8_t *tab0; // @ 14743
+ uint8_t *tab1; // @ 14746
+ uint8_t *tab2; // @ 14749
+ uint8_t *tab3; // @ 14752
+ uint8_t *tab4; // @ 14755
+ uint8_t *tab5; // @ 14758
+ uint8_t *tab6; // @ 14761
+ uint8_t *tab7; // @ 14764
+
+ red_h = *redp >> 4;
+ red_l = *redp & 0xF;
+ red_li = 16 - red_l;
+
+ grn_h = *grnp >> 4;
+ grn_l = *grnp & 0xF;
+ grn_li = 16 - grn_l;
+
+ blu_h = *blup >> 4;
+ blu_l = *blup & 0xF;
+ blu_li = 16 - blu_l;
+
+// printf("%d %d %d =>", *redp, *grnp, *blup);
+
+ tab0 = this->lut[red_h+0][grn_h+0][blu_h+0];
+ tab1 = this->lut[red_h+1][grn_h+0][blu_h+0];
+ tab2 = this->lut[red_h+0][grn_h+1][blu_h+0];
+ tab3 = this->lut[red_h+1][grn_h+1][blu_h+0];
+ tab4 = this->lut[red_h+0][grn_h+0][blu_h+1];
+ tab5 = this->lut[red_h+1][grn_h+0][blu_h+1];
+ tab6 = this->lut[red_h+0][grn_h+1][blu_h+1];
+ tab7 = this->lut[red_h+1][grn_h+1][blu_h+1];
+
+#if 0
+ printf(" %d %d %d ", tab0[0], tab0[1], tab0[2]);
+ printf(" %d %d %d ", tab1[0], tab1[1], tab1[2]);
+ printf(" %d %d %d ", tab2[0], tab2[1], tab2[2]);
+ printf(" %d %d %d ", tab3[0], tab3[1], tab3[2]);
+ printf(" %d %d %d ", tab4[0], tab4[1], tab4[2]);
+ printf(" %d %d %d ", tab5[0], tab5[1], tab5[2]);
+ printf(" %d %d %d ", tab6[0], tab6[1], tab6[2]);
+ printf(" %d %d %d ", tab7[0], tab7[1], tab7[2]);
+#endif
+ *redp = (blu_li
+ * (grn_li * (red_li * tab0[0] + red_l * tab1[0])
+ + grn_l * (red_li * tab2[0] + red_l * tab3[0]))
+ + blu_l
+ * (grn_li * (red_li * tab4[0] + red_l * tab5[0])
+ + grn_l * (red_li * tab6[0] + red_l * tab7[0]))
+ + 2048) >> 12;
+ *grnp = (blu_li
+ * (grn_li * (red_li * tab0[1] + red_l * tab1[1])
+ + grn_l * (red_li * tab2[1] + red_l * tab3[1]))
+ + blu_l
+ * (grn_li * (red_li * tab4[1] + red_l * tab5[1])
+ + grn_l * (red_li * tab6[1] + red_l * tab7[1]))
+ + 2048) >> 12;
+ *blup = (blu_li
+ * (grn_li * (red_li * tab0[2] + red_l * tab1[2])
+ + grn_l * (red_li * tab2[2] + red_l * tab3[2]))
+ + blu_l
+ * (grn_li * (red_li * tab4[2] + red_l * tab5[2])
+ + grn_l * (red_li * tab6[2] + red_l * tab7[2]))
+ + 2048) >> 12;
+
+// printf("=> %d %d %d\n", *redp, *grnp, *blup);
+}
+
+/* Perform a total conversion on an entire image */
+void CColorConv3D_DoColorConv(struct CColorConv3D *this, uint8_t *data, uint16_t cols, uint16_t rows, uint32_t stride, int rgb_bgr)
+{
+ uint16_t i, j;
+
+ uint8_t *ptr;
+
+ for ( i = 0; i < rows ; i++ )
+ {
+ ptr = data;
+ for ( j = 0; cols > j; j++ )
+ {
+ if (rgb_bgr) {
+ CColorConv3D_DoColorConvPixel(this, ptr + 2, ptr + 1, ptr);
+ } else {
+ CColorConv3D_DoColorConvPixel(this, ptr, ptr + 1, ptr + 2);
+ }
+ ptr += 3;
+ }
+ data += stride;
+ }
+}
+
+/* ---- end 3D LUT ---- */
+static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int status, int status2, int media);
+static char *mitsu9550_media_types(uint8_t type, uint8_t is_s);
+
static void *mitsu9550_init(void)
{
struct mitsu9550_ctx *ctx = malloc(sizeof(struct mitsu9550_ctx));
@@ -248,32 +537,58 @@ static void *mitsu9550_init(void)
return ctx;
}
-static void mitsu9550_attach(void *vctx, struct libusb_device_handle *dev,
+static int mitsu9550_attach(void *vctx, struct libusb_device_handle *dev, int type,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct mitsu9550_ctx *ctx = vctx;
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
+ struct mitsu9550_media media;
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(&mitsu9550_backend,
- desc.idVendor, desc.idProduct);
+ ctx->type = type;
if (ctx->type == P_MITSU_9550S ||
ctx->type == P_MITSU_9800S)
ctx->is_s = 1;
- ctx->last_donor = ctx->last_remain = 65535;
+ if (ctx->type == P_MITSU_9800 ||
+ ctx->type == P_MITSU_9800S ||
+ ctx->type == P_MITSU_9810)
+ ctx->is_98xx = 1;
+
+ if (test_mode < TEST_MODE_NOATTACH) {
+ if (mitsu9550_get_status(ctx, (uint8_t*) &media, 0, 0, 1))
+ return CUPS_BACKEND_FAILED;
+ } else {
+ int media_code = 0x2;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
+
+ media.max = cpu_to_be16(400);
+ media.remain = cpu_to_be16(330);
+ media.type = media_code;
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = mitsu9550_media_types(media.type, ctx->is_s);
+ ctx->marker.levelmax = be16_to_cpu(media.max);
+ ctx->marker.levelnow = be16_to_cpu(media.remain);
+
+ return CUPS_BACKEND_OK;
}
+static void mitsu9550_cleanup_job(const void *vjob)
+{
+ const struct mitsu9550_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
+}
static void mitsu9550_teardown(void *vctx) {
struct mitsu9550_ctx *ctx = vctx;
@@ -281,86 +596,100 @@ static void mitsu9550_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
+ if (ctx->lut)
+ CColorConv3D_Destroy3DColorTable(ctx->lut);
+ if (ctx->m98xxdata)
+ free(ctx->m98xxdata);
free(ctx);
}
-static int mitsu9550_read_parse(void *vctx, int data_fd) {
+static int mitsu9550_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct mitsu9550_ctx *ctx = vctx;
uint8_t buf[sizeof(struct mitsu9550_hdr1)];
int remain, i;
uint32_t planelen = 0;
+ struct mitsu9550_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
-
- ctx->hdr1_present = 0;
- ctx->hdr2_present = 0;
- ctx->hdr3_present = 0;
- ctx->hdr4_present = 0;
+ memset(job, 0, sizeof(*job));
+ job->is_raw = 1;
top:
/* Read in initial header */
remain = sizeof(buf);
while (remain > 0) {
i = read(data_fd, buf + sizeof(buf) - remain, remain);
- if (i == 0)
+ if (i == 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
}
/* Sanity check */
if (buf[0] != 0x1b || buf[1] != 0x57 || buf[3] != 0x2e) {
- if (!ctx->hdr1_present || !ctx->hdr2_present) {
- ERROR("Unrecognized data format!\n");
+ if (!job->hdr1_present || !job->hdr2_present) {
+ ERROR("Unrecognized data format (%02x%02x%02x%02x)!\n",
+ buf[0], buf[1], buf[2], buf[3]);
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- } else if (buf[0] == 0x1b && buf[1] == 0x5a &&
+ } else if (buf[0] == 0x1b &&
+ buf[1] == 0x5a &&
buf[2] == 0x54) {
/* We're in the data portion now */
if (buf[3] == 0x10)
planelen *= 2;
+ else if (ctx->is_98xx && buf[3] == 0x80)
+ job->is_raw = 0;
goto hdr_done;
} else {
- ERROR("Unrecognized data block!\n");
+ ERROR("Unrecognized data block (%02x%02x%02x%02x)!\n",
+ buf[0], buf[1], buf[2], buf[3]);
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
}
switch(buf[2]) {
case 0x20: /* header 1 */
- memcpy(&ctx->hdr1, buf, sizeof(ctx->hdr1));
- ctx->hdr1_present = 1;
+ memcpy(&job->hdr1, buf, sizeof(job->hdr1));
+ job->hdr1_present = 1;
/* Work out printjob size */
- ctx->rows = be16_to_cpu(ctx->hdr1.rows);
- ctx->cols = be16_to_cpu(ctx->hdr1.cols);
- planelen = ctx->rows * ctx->cols;
+ job->rows = be16_to_cpu(job->hdr1.rows);
+ job->cols = be16_to_cpu(job->hdr1.cols);
+ planelen = job->rows * job->cols;
break;
case 0x21: /* header 2 */
- memcpy(&ctx->hdr2, buf, sizeof(ctx->hdr2));
- ctx->hdr2_present = 1;
+ memcpy(&job->hdr2, buf, sizeof(job->hdr2));
+ job->hdr2_present = 1;
break;
case 0x22: /* header 3 */
- memcpy(&ctx->hdr3, buf, sizeof(ctx->hdr3));
- ctx->hdr3_present = 1;
+ memcpy(&job->hdr3, buf, sizeof(job->hdr3));
+ job->hdr3_present = 1;
break;
case 0x26: /* header 4 */
- memcpy(&ctx->hdr4, buf, sizeof(ctx->hdr4));
- ctx->hdr4_present = 1;
+ memcpy(&job->hdr4, buf, sizeof(job->hdr4));
+ job->hdr4_present = 1;
break;
default:
ERROR("Unrecognized header format (%02x)!\n", buf[2]);
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -369,34 +698,74 @@ top:
hdr_done:
- /* We have three planes and the final terminator to read */
- remain = 3 * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd);
+ /* Read in CP98xx data tables if necessary */
+ if (ctx->is_98xx && !job->is_raw && !ctx->m98xxdata) {
+ int fd;
+
+ DEBUG("Reading in 98xx data from disk\n");
+ fd = open(MITSU_M98xx_DATATABLE_FILE, O_RDONLY);
+ if (fd < 0) {
+ ERROR("Unable to open 98xx data table file '%s'\n", MITSU_M98xx_DATATABLE_FILE);
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_FAILED;
+ }
+ ctx->m98xxdata = malloc(DATATABLE_SIZE);
+ if (!ctx->m98xxdata) {
+ ERROR("Memory allocation Failure!\n");
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ remain = DATATABLE_SIZE;
+ while (remain) {
+ i = read(fd, ((uint8_t*)ctx->m98xxdata) + (DATATABLE_SIZE - remain), remain);
+ if (i < 0) {
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ remain -= i;
+ }
+ close(fd);
+ }
+
+ if (job->is_raw) {
+ /* We have three planes + headers and the final terminator to read */
+ remain = 3 * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd);
+ } else {
+ /* We have one plane + header and the final terminator to read */
+ remain = planelen * 3 + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
+ }
/* Mitsu9600 windows spool uses more, smaller blocks, but plane data is the same */
if (ctx->type == P_MITSU_9600) {
remain += 128 * sizeof(struct mitsu9550_plane); /* 39 extra seen on 4x6" */
}
- /* Don't forget the matte plane! */
- if (ctx->hdr1.matte) {
- remain += planelen + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
- }
-
/* 9550S/9800S doesn't typically sent over hdr4! */
if (ctx->type == P_MITSU_9550S ||
ctx->type == P_MITSU_9800S) {
/* XXX Has to do with error policy, but not sure what.
Mitsu9550-S/9800-S will set this based on a command,
but it's not part of the standard job spool */
- ctx->hdr4_present = 0;
+ job->hdr4_present = 0;
+ }
+
+ /* Disable matte if the printer doesn't support it */
+ if (job->hdr1.matte) {
+ if (ctx->type != P_MITSU_9810) {
+ WARNING("Matte not supported on this printer, disabling\n");
+ job->hdr1.matte = 0;
+ } else if (job->is_raw) {
+ remain += planelen + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
+ }
}
/* Allocate buffer for the payload */
- ctx->datalen = 0;
- ctx->databuf = malloc(remain);
- if (!ctx->databuf) {
+ job->datalen = 0;
+ job->databuf = malloc(remain);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
/* Load up the data blocks.*/
@@ -408,7 +777,9 @@ hdr_done:
if (plane->cmd[0] != 0x1b ||
plane->cmd[1] != 0x5a ||
plane->cmd[2] != 0x54) {
- ERROR("Unexpected data read, aborting job\n");
+ ERROR("Unrecognized data read (%02x%02x%02x%02x)!\n",
+ plane->cmd[0], plane->cmd[1], plane->cmd[2], plane->cmd[3]);
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -416,20 +787,26 @@ hdr_done:
planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
if (plane->cmd[3] == 0x10)
planelen *= 2;
+ if (plane->cmd[3] == 0x80)
+ planelen *= 3;
/* Copy plane header into buffer */
- memcpy(ctx->databuf + ctx->datalen, buf, sizeof(buf));
- ctx->datalen += sizeof(buf);
+ memcpy(job->databuf + job->datalen, buf, sizeof(buf));
+ job->datalen += sizeof(buf);
planelen -= sizeof(buf) - sizeof(struct mitsu9550_plane);
/* Read in the spool data */
while(planelen > 0) {
- i = read(data_fd, ctx->databuf + ctx->datalen, planelen);
- if (i == 0)
+ i = read(data_fd, job->databuf + job->datalen, planelen);
+ if (i == 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- ctx->datalen += i;
+ }
+ job->datalen += i;
planelen -= i;
}
@@ -438,44 +815,87 @@ hdr_done:
- Job footer (4B)
*/
i = read(data_fd, buf, 4);
- if (i == 0)
+ if (i == 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
/* Is this a "job end" marker? */
- if (plane->cmd[0] != 0x1b ||
- plane->cmd[1] != 0x5a ||
- plane->cmd[2] != 0x54) {
+ if (plane->cmd[0] == 0x1b &&
+ plane->cmd[1] == 0x50 &&
+ plane->cmd[3] == 0x00) {
/* store it in the buffer */
- memcpy(ctx->databuf + ctx->datalen, buf, 4);
- ctx->datalen += 4;
+ memcpy(job->databuf + job->datalen, buf, 4);
+ job->datalen += 4;
/* Unless we have a matte plane following, we're done */
- if (!ctx->hdr1.matte)
+ if (job->hdr1.matte != 0x01)
break;
- planelen = sizeof(buf);
+ remain = sizeof(buf);
} else {
/* It's part of a block header, mark what we've read */
- planelen = sizeof(buf) - 4;
+ remain = sizeof(buf) - 4;
}
/* Read in the rest of the header */
- while (planelen > 0) {
- i = read(data_fd, buf + sizeof(buf) - planelen, planelen);
- if (i == 0)
+ while (remain > 0) {
+ i = read(data_fd, buf + sizeof(buf) - remain, remain);
+ if (i == 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsu9550_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- planelen -= i;
+ }
+ remain -= i;
}
}
- /* Disable matte if the printer doesn't support it */
- if (ctx->hdr1.matte && ctx->type != P_MITSU_9810) {
- WARNING("Matte not supported on this printer, disabling\n");
- ctx->hdr1.matte = 0;
+ /* Apply LUT */
+ if (ctx->is_98xx && !job->is_raw && job->hdr2.unkc[9]) {
+ DEBUG("Applying 3D LUT\n");
+ if (!ctx->lut) {
+ uint8_t *buf = malloc(LUT_LEN);
+ if (!buf) {
+ ERROR("Memory allocation failure!\n");
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ if (CColorConv3D_Get3DColorTable(buf, MITSU_M98xx_LUT_FILE)) {
+ ERROR("Unable to open LUT file '%s'\n", MITSU_M98xx_LUT_FILE);
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ ctx->lut = CColorConv3D_Load3DColorTable(buf);
+ free(buf);
+ if (!ctx->lut) {
+ ERROR("Unable to parse LUT\n");
+ mitsu9550_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ }
+ CColorConv3D_DoColorConv(ctx->lut, job->databuf + sizeof(struct mitsu9550_plane),
+ job->cols, job->rows, job->cols * 3, COLORCONV_BGR);
+ job->hdr2.unkc[9] = 0;
+ }
+
+ /* Update printjob header to reflect number of requested copies */
+ if (job->hdr2_present) {
+ copies = 1;
+ job->hdr2.copies = cpu_to_be16(copies);
}
+ job->copies = copies;
+
+ /* All further work is in main loop */
+ if (test_mode >= TEST_MODE_NOPRINT)
+ mitsu9550_main_loop(ctx, job);
+
+ *vjob = job;
return CUPS_BACKEND_OK;
}
@@ -740,22 +1160,120 @@ static int validate_media(int type, int media, int cols, int rows)
return 0;
}
-static int mitsu9550_main_loop(void *vctx, int copies) {
+static int mitsu9550_main_loop(void *vctx, const void *vjob) {
struct mitsu9550_ctx *ctx = vctx;
struct mitsu9550_cmd cmd;
uint8_t rdbuf[READBACK_LEN];
uint8_t *ptr;
int ret;
+#if 0
+ int copies;
+#endif
+
+// const struct mitsu9550_printjob *job = vjob;
+ struct mitsu9550_printjob *job = (struct mitsu9550_printjob*) vjob; // XXX not good.
if (!ctx)
return CUPS_BACKEND_FAILED;
-
- /* Update printjob header to reflect number of requested copies */
- ctx->hdr2.copies = cpu_to_be16(copies);
+ if (!job)
+ return CUPS_BACKEND_FAILED;
/* Okay, let's do this thing */
- ptr = ctx->databuf;
+ ptr = job->databuf;
+
+#if 0
+ /* If hdr2 is not present, we have to generate copies ourselves! */
+ if (job->hdr2_present)
+ copies = job->copies;
+ // XXX..
+#endif
+
+ /* Do the 98xx processing here */
+ if (!ctx->is_98xx || job->is_raw)
+ goto bypass;
+
+ uint8_t *newbuf;
+ uint32_t newlen = 0;
+ struct mitsu98xx_data *table;
+ int i, remain, planelen;
+
+ planelen = job->rows * job->cols * 2;
+ remain = (job->hdr1.matte ? 3 : 4) * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd);
+ newbuf = malloc(remain);
+ if (!newbuf) {
+ ERROR("Memory allocation Failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ switch (job->hdr2.mode) {
+ case 0x80:
+ table = &ctx->m98xxdata->superfine;
+ break;
+ case 0x11:
+ table = &ctx->m98xxdata->fine_hg;
+ job->hdr2.mode = 0x10;
+ break;
+ case 0x10:
+ default:
+ table = &ctx->m98xxdata->fine_std;
+ break;
+ }
+
+ DEBUG("Applying 8bpp->12bpp Gamma Correction\n");
+ /* For B/Y plane */
+ memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
+ newbuf[newlen + 3] = 0x10; /* ie 16bpp data */
+ newlen += sizeof(struct mitsu9550_plane);
+ mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
+ (uint16_t*) (newbuf + newlen),
+ 0,
+ table->GNMby,
+ planelen / 2);
+ newlen += planelen;
+
+ /* For G/M plane */
+ memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
+ newbuf[newlen + 3] = 0x10; /* ie 16bpp data */
+ newlen += sizeof(struct mitsu9550_plane);
+ mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
+ (uint16_t*) (newbuf + newlen),
+ 1,
+ table->GNMgm,
+ planelen / 2);
+ newlen += planelen;
+
+ /* For R/C plane */
+ memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
+ newbuf[newlen + 3] = 0x10; /* ie 16bpp data */
+ newlen += sizeof(struct mitsu9550_plane);
+ mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
+ (uint16_t*) (newbuf + newlen),
+ 2,
+ table->GNMrc,
+ planelen / 2);
+ newlen += planelen;
+
+ /* And finally, the job footer. */
+ memcpy(newbuf + newlen, job->databuf + sizeof(struct mitsu9550_plane) + planelen * 3, sizeof(struct mitsu9550_cmd));
+ newlen += sizeof(struct mitsu9550_cmd);
+
+ /* Clean up, and move pointer to new buffer; */
+ free(job->databuf);
+ job->databuf = newbuf;
+ job->datalen = newlen;
+ ptr = job->databuf;
+
+ /* Now handle the matte plane generation */
+ if (job->hdr1.matte) {
+ if ((i = mitsu98xx_fillmatte(job))) {
+ return i;
+ }
+ }
+
+bypass:
+ /* Bypass */
+ if (test_mode >= TEST_MODE_NOPRINT)
+ return CUPS_BACKEND_OK;
top:
if (ctx->is_s) {
@@ -809,38 +1327,28 @@ top:
/* Now it's time for the actual print job! */
- if (ctx->is_s) {
- cmd.cmd[0] = 0x1b;
- cmd.cmd[1] = 0x44;
- cmd.cmd[2] = 0;
- cmd.cmd[3] = 0;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) &cmd, 4)))
- return CUPS_BACKEND_FAILED;
- }
-
QUERY_STATUS();
/* Send printjob headers from spool data */
- if (ctx->hdr1_present)
+ if (job->hdr1_present)
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) &ctx->hdr1, sizeof(ctx->hdr1))))
+ (uint8_t*) &job->hdr1, sizeof(job->hdr1))))
return CUPS_BACKEND_FAILED;
- if (ctx->hdr2_present)
+ if (job->hdr2_present)
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) &ctx->hdr2, sizeof(ctx->hdr2))))
+ (uint8_t*) &job->hdr2, sizeof(job->hdr2))))
return CUPS_BACKEND_FAILED;
- if (ctx->hdr3_present)
+ if (job->hdr3_present)
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) &ctx->hdr3, sizeof(ctx->hdr3))))
+ (uint8_t*) &job->hdr3, sizeof(job->hdr3))))
return CUPS_BACKEND_FAILED;
- if (ctx->hdr4_present)
+ if (job->hdr4_present)
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) &ctx->hdr4, sizeof(struct mitsu9550_hdr4))))
+ (uint8_t*) &job->hdr4, sizeof(struct mitsu9550_hdr4))))
return CUPS_BACKEND_FAILED;
if (ctx->is_s) {
- /* Send "start data" command */
+ /* I think this a "clear memory' command...? */
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x5a;
cmd.cmd[2] = 0x43;
@@ -852,13 +1360,15 @@ top:
}
/* Send over plane data */
- while(1) {
+ while(ptr < (job->databuf + job->datalen)) {
struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
- uint32_t planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
+ uint32_t planelen;
if (plane->cmd[0] != 0x1b ||
plane->cmd[1] != 0x5a ||
plane->cmd[2] != 0x54)
break;
+
+ planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
if (plane->cmd[3] == 0x10)
planelen *= 2;
@@ -877,29 +1387,22 @@ top:
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
- uint16_t donor, remain;
+ uint16_t donor;
ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
if (ret < 0)
return CUPS_BACKEND_FAILED;
+ donor = be16_to_cpu(media->remain);
+ if (donor != ctx->marker.levelnow) {
+ ctx->marker.levelnow = donor;
+ dump_markers(&ctx->marker, 1, 0);
+ }
/* Sanity-check media response */
if (media->remain == 0 || media->max == 0) {
ERROR("Printer out of media!\n");
- ATTR("marker-levels=%d\n", 0);
return CUPS_BACKEND_HOLD;
}
- remain = be16_to_cpu(media->remain);
- donor = be16_to_cpu(media->max);
- donor = remain/donor;
- if (donor != ctx->last_donor) {
- ctx->last_donor = donor;
- ATTR("marker-levels=%u\n", donor);
- }
- if (remain != ctx->last_remain) {
- ctx->last_remain = remain;
- ATTR("marker-message=\"%u prints remaining on '%s' ribbon\"\n", remain, mitsu9550_media_types(media->type, ctx->is_s));
- }
ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
if (ret < 0)
return CUPS_BACKEND_FAILED;
@@ -952,7 +1455,7 @@ top:
}
/* Don't forget the 9810's matte plane */
- if (ctx->hdr1.matte) {
+ if (job->hdr1.matte) {
struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
uint32_t planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
@@ -973,7 +1476,7 @@ top:
if ((ret = send_data(ctx->dev, ctx->endp_down,
ptr, sizeof(cmd))))
return CUPS_BACKEND_FAILED;
- ptr += sizeof(cmd);
+// ptr += sizeof(cmd);
}
/* Status loop, run until printer reports completion */
@@ -981,29 +1484,22 @@ top:
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
- uint16_t donor, remain;
+ uint16_t donor;
ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
if (ret < 0)
return CUPS_BACKEND_FAILED;
+ donor = be16_to_cpu(media->remain);
+ if (donor != ctx->marker.levelnow) {
+ ctx->marker.levelnow = donor;
+ dump_markers(&ctx->marker, 1, 0);
+ }
/* Sanity-check media response */
if (media->remain == 0 || media->max == 0) {
ERROR("Printer out of media!\n");
- ATTR("marker-levels=%d\n", 0);
return CUPS_BACKEND_HOLD;
}
- remain = be16_to_cpu(media->remain);
- donor = be16_to_cpu(media->max);
- donor = remain/donor;
- if (donor != ctx->last_donor) {
- ctx->last_donor = donor;
- ATTR("marker-levels=%u\n", donor);
- }
- if (remain != ctx->last_remain) {
- ctx->last_remain = remain;
- ATTR("marker-message=\"%u prints remaining on '%s' ribbon\"\n", remain, mitsu9550_media_types(media->type, ctx->is_s));
- }
ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
if (ret < 0)
return CUPS_BACKEND_FAILED;
@@ -1156,10 +1652,21 @@ static int mitsu9550_query_serno(struct libusb_device_handle *dev, uint8_t endp_
return ret;
}
+static int mitsu9550_cancel_job(struct mitsu9550_ctx *ctx)
+{
+ int ret;
+
+ uint8_t buf[2] = { 0x1b, 0x44 };
+ ret = send_data(ctx->dev, ctx->endp_down, buf, sizeof(buf));
+
+ return ret;
+}
+
static void mitsu9550_cmdline(void)
{
DEBUG("\t\t[ -m ] # Query media\n");
DEBUG("\t\t[ -s ] # Query status\n");
+ DEBUG("\t\t[ -X ] # Cancel current job\n");
}
static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
@@ -1170,7 +1677,7 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
if (!ctx)
return -1;
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "ms")) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "msX")) >= 0) {
switch(i) {
GETOPT_PROCESS_GLOBAL
case 'm':
@@ -1181,6 +1688,9 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
if (!j)
j = mitsu9550_query_status2(ctx);
break;
+ case 'X':
+ j = mitsu9550_cancel_job(ctx);
+ break;
default:
break; /* Ignore completely */
}
@@ -1191,37 +1701,70 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int mitsu9550_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct mitsu9550_ctx *ctx = vctx;
+ struct mitsu9550_media media;
+
+ /* Query printer status */
+ if (mitsu9550_get_status(ctx, (uint8_t*) &media, 0, 0, 1))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = be16_to_cpu(media.remain);
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *mitsu9550_prefixes[] = {
+ "mitsu9xxx", // Family driver, do not nuke.
+ "mitsubishi-9000dw", "mitsubishi-9500dw",
+ "mitsubishi-9550dw", "mitsubishi-9550dw-s",
+ "mitsubishi-9600dw", // "mitsubishi-9600dw-s",
+ "mitsubishi-9800dw", "mitsubishi-9800dw-s",
+ "mitsubishi-9810dw",
+ // extras
+ "mitsubishi-9550d", "mitsubishi-9550dz", "mitsubishi-9800d", "mitsubishi-9800dz", "mitsubishi-9810d",
+ // Backwards compatibility
+ "mitsu9000", "mitsu9500", "mitsu9550", "mitsu9600", "mitsu9800", "mitsu9810",
+ NULL
+};
+
/* Exported */
struct dyesub_backend mitsu9550_backend = {
- .name = "Mitsubishi CP-9550 family",
- .version = "0.29",
- .uri_prefix = "mitsu9550",
+ .name = "Mitsubishi CP9xxx family",
+ .version = "0.41",
+ .uri_prefixes = mitsu9550_prefixes,
.cmdline_usage = mitsu9550_cmdline,
.cmdline_arg = mitsu9550_cmdline_arg,
.init = mitsu9550_init,
.attach = mitsu9550_attach,
.teardown = mitsu9550_teardown,
+ .cleanup_job = mitsu9550_cleanup_job,
.read_parse = mitsu9550_read_parse,
.main_loop = mitsu9550_main_loop,
.query_serno = mitsu9550_query_serno,
+ .query_markers = mitsu9550_query_markers,
.devices = {
- { USB_VID_MITSU, USB_PID_MITSU_9000AM, P_MITSU_9550, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9000D, P_MITSU_9550, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9500D, P_MITSU_9550, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600, ""},
-// { USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600S, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9800D, P_MITSU_9800, ""},
- { USB_VID_MITSU, USB_PID_MITSU_9800DS, P_MITSU_9800S, ""},
- { USB_VID_MITSU, USB_PID_MITSU_98__D, P_MITSU_9810, ""},
-// { USB_VID_MITSU, USB_PID_MITSU_9810D, P_MITSU_9810, ""},
-// { USB_VID_MITSU, USB_PID_MITSU_9820DS, P_MITSU_9820S, ""},
- { 0, 0, 0, ""}
+ { USB_VID_MITSU, USB_PID_MITSU_9000AM, P_MITSU_9550, NULL, "mitsubishi-9000dw"}, // XXX -am instead?
+ { USB_VID_MITSU, USB_PID_MITSU_9000D, P_MITSU_9550, NULL, "mitsubishi-9000dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_9500D, P_MITSU_9550, NULL, "mitsubishi-9500dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, NULL, "mitsubishi-9550dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, NULL, "mitsubishi-9550dw-s"},
+ { USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600, NULL, "mitsubishi-9600dw"},
+// { USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600S, NULL, "mitsubishi-9600dw-s"},
+ { USB_VID_MITSU, USB_PID_MITSU_9800D, P_MITSU_9800, NULL, "mitsubishi-9800dw"},
+ { USB_VID_MITSU, USB_PID_MITSU_9800DS, P_MITSU_9800S, NULL, "mitsubishi-9800dw-s"},
+ { USB_VID_MITSU, USB_PID_MITSU_98__D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
+// { USB_VID_MITSU, USB_PID_MITSU_9810D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
+// { USB_VID_MITSU, USB_PID_MITSU_9820DS, P_MITSU_9820S, NULL, "mitsubishi-9820dw-s"},
+ { 0, 0, 0, NULL, NULL}
}
};
-/* Mitsubish CP-9550/9600/9800/9810 spool format:
+/* Mitsubish CP-9500/9550/9600/9800/9810/9820 spool format:
Spool file consists of 3 (or 4) 50-byte headers, followed by three
image planes, each with a 12-byte header, then a 4-byte footer.
@@ -1240,12 +1783,13 @@ struct dyesub_backend mitsu9550_backend = {
1b 57 21 2e 00 80 00 22 QQ QQ 00 00 00 00 00 00 :: ZZ ZZ = num copies (>= 0x01)
00 00 00 00 00 00 00 00 00 00 00 00 ZZ ZZ 00 00 :: YY = 00/80 Fine/SuperFine (9550), 10/80 Fine/Superfine (98x0), 00 (9600)
XX 00 00 00 00 00 YY 00 00 00 00 00 00 00 00 00 :: XX = 00 normal, 83 Cut 2x6 (9550 only!)
- 00 01 :: QQ QQ = 0x0803 on 9550, 0x0801 on 98x0, 0x0003 on 9600
+ RR 01 :: QQ QQ = 0x0803 on 9550, 0x0801 on 98x0, 0x0003 on 9600, 0xa803 on 9500
+ :: RR = 01 for "use LUT" on 98xx, 0x00 otherwise. Extension to stock.
~~~ Header 3 (9550 and 9800-S only..)
- 1b 57 22 2e 00 40 00 00 00 00 00 XX 00 00 00 00 :: XX = 00 normal, 01 FineDeep
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 1b 57 22 2e 00 QQ 00 00 00 00 00 XX 00 00 00 00 :: XX = 00 normal, 01 FineDeep
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ = 0xf0 on 9500, 0x40 on the rest
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00
@@ -1253,18 +1797,18 @@ struct dyesub_backend mitsu9550_backend = {
1b 57 26 2e 00 QQ 00 00 00 00 00 SS RR 01 00 00 :: QQ = 0x70 on 9550/98x0, 0x60 on 9600 or 9800S
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: RR = 0x01 on 9550/98x0, 0x00 on 9600
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: SS = 0x01 on 9800S
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: SS = 0x01 on 9800S, 0x00 otherwise.
00 00
~~~~ Data follows:
- Format is: planar YMC16 for 98x0 (only 12 bits used)
- planar BGR for 9550DW
- planar RGB for 9550DW-S and 9600DW
+ Format is: planar YMC16 for 98x0 (but only 12 bits used, BIG endian)
+ planar RGB for all others
- 1b 5a 54 ?? RR RR 00 00 07 14 04 d8 :: 0714 == columns, 04d8 == rows
- :: RRRR == row offset for data
+ 1b 5a 54 ?? RR RR CC CC 07 14 04 d8 :: 0714 == columns, 04d8 == rows
+ :: RRRR == row offset for data, CCCC == col offset for data
:: ?? == 0x00 for 8bpp, 0x10 for 16/12bpp.
+ :: 0x80 for PACKED BGR!
Data follows immediately, no padding.
@@ -1278,12 +1822,15 @@ struct dyesub_backend mitsu9550_backend = {
~~~~ Footer:
+ 1b 50 57 00 (9500)
1b 50 46 00 (9550)
1b 50 47 00 (9550-S)
1b 50 48 00 (9600)
- 1b 50 4c 00 (98x0)
+ 1b 50 4c 00 (9800/9810)
1b 50 4e 00 (9800-S)
+ Unknown: 9600-S, 9820-S
+
~~~~ Lamination data follows (on 9810 only, if matte selected)
1b 5a 54 10 00 00 00 00 06 24 04 34
@@ -1306,7 +1853,7 @@ struct dyesub_backend mitsu9550_backend = {
-> 1b 53 c5 9d
- [[ Unknown ]]
+ [[ Unknown, query some parameter? ]]
-> 1b 4b 7f 00
<- eb 4b 8f 00 02 00 5e [[ '02' seems to be a length ]]
@@ -1331,7 +1878,7 @@ struct dyesub_backend mitsu9550_backend = {
00 00 00 00 00 00 00 00 00 00 00 00 MM MM 00 00 :: MM MM = Max prints
NN NN 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: NN NN = Remaining
- [[ unknown, 9800-only ]]
+ [[ unknown query, 9800-only ]]
-> 1b 4b 01 00
<- e4 4b 01 00 02 00 78
@@ -1350,7 +1897,7 @@ struct dyesub_backend mitsu9550_backend = {
00 00 00 00 00 00 00 00 00 00 00 QQ 00 00 00 00 :: QQ == Prints in job?
00 00 00 00 00 00 00 00 00 00 NN NN 0A 00 00 01 :: NN NN = Remaining media
- [[ Unknown ]]
+ [[ Job Cancel ]]
-> 1b 44
@@ -1388,7 +1935,7 @@ struct dyesub_backend mitsu9550_backend = {
Followed by image plane #3 (Red), XXXX * YYYY bytes
- [[ Unknown -- End Data aka START print? ]]
+ [[ Footer -- End Data aka START print? See above for other models ]]
-> 1b 50 47 00 [9550S]
-> 1b 50 4e 00 [9800S]
diff --git a/src/cups/backend_mitsud90.c b/src/cups/backend_mitsud90.c
new file mode 100644
index 0000000..9655e55
--- /dev/null
+++ b/src/cups/backend_mitsud90.c
@@ -0,0 +1,1456 @@
+/*
+ * Mitsubishi CP-D90DW Photo Printer CUPS backend
+ *
+ * (c) 2018 Solomon Peachy <pizza@shaftnet.org>
+ *
+ * The latest version of this program can be found at:
+ *
+ * http://git.shaftnet.org/cgit/selphy_print.git
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * [http://www.gnu.org/licenses/gpl-2.0.html]
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#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 mitsud90_backend
+
+#include "backend_common.h"
+
+#define USB_VID_MITSU 0x06D3
+#define USB_PID_MITSU_D90 0x3B60
+
+const char *mitsu70x_media_types(uint8_t brand, uint8_t type);
+const char *mitsu70x_temperatures(uint8_t temp);
+
+/* Printer data structures */
+#define D90_STATUS_TYPE_MODEL 0x01 // 10, null-terminated ASCII. 'CPD90D'
+#define D90_STATUS_TYPE_x02 0x02 // 1, 0x5f ?
+#define D90_STATUS_TYPE_FW_0b 0x0b // 8, 34 31 34 42 31 31 a7 de (414D11)
+#define D90_STATUS_TYPE_FW_MA 0x0c // 8, 34 31 35 41 38 31 86 bf (415A81) // MAIN FW
+#define D90_STATUS_TYPE_FW_F 0x0d // 8, 34 31 36 41 35 31 dc 8a (416A51) // FPGA FW
+#define D90_STATUS_TYPE_FW_T 0x0e // 8, 34 31 37 45 31 31 e7 e6 (417E11) // TABLE FW
+#define D90_STATUS_TYPE_FW_0f 0x0f // 8, 34 31 38 41 31 32 6c 64 (418A12)
+#define D90_STATUS_TYPE_FW_11 0x11 // 8, 34 32 31 51 31 31 74 f2 (421Q11)
+#define D90_STATUS_TYPE_FW_ME 0x13 // 8, 34 31 39 45 31 31 15 bf (419E11) // MECHA FW
+
+#define D90_STATUS_TYPE_ERROR 0x16 // 11 (see below)
+#define D90_STATUS_TYPE_MECHA 0x17 // 2 (see below)
+#define D90_STATUS_TYPE_x1e 0x1e // 1, power state or time? (x00)
+#define D90_STATUS_TYPE_TEMP 0x1f // 1 (see below)
+#define D90_STATUS_TYPE_x22 0x22 // 2, all 0
+#define D90_STATUS_TYPE_x28 0x28 // 2, all 0, seen some sort of counter?
+#define D90_STATUS_TYPE_x29 0x29 // 8, e0 07 00 00 21 e6 b3 22
+#define D90_STATUS_TYPE_MEDIA 0x2a // 10 (see below)
+#define D90_STATUS_TYPE_x2b 0x2b // 2, all 0
+#define D90_STATUS_TYPE_x2c 0x2c // 2, 00 56
+#define D90_STATUS_TYPE_x65 0x65 // 50, ac 80 00 01 bb b8 fe 48 05 13 5d 9c 00 33 00 00 00 00 00 00 00 00 00 00 00 00 02 39 00 00 00 00 03 13 00 02 10 40 00 00 00 00 00 00 05 80 00 3a 00 00
+#define D90_STATUS_TYPE_x82 0x82 // 1, 80 (iserial disabled?)
+#define D90_STATUS_TYPE_x83 0x83 // 1, 00
+#define D90_STATUS_TYPE_x84 0x84 // 1, 00
+
+//#define D90_STATUS_TYPE_x85 0x85 // 2, 00 ?? BE, wait time?
+ // combined total of 5.
+
+struct mitsud90_fw_resp_single {
+ uint8_t version[6];
+ uint16_t csum;
+} __attribute__((packed));
+
+struct mitsud90_media_resp {
+ uint8_t hdr[4]; /* e4 47 44 30 */
+ struct {
+ uint8_t brand;
+ uint8_t type;
+ uint8_t unk_a[2];
+ uint16_t capacity; /* BE */
+ uint16_t remain; /* BE */
+ uint8_t unk_b[2];
+ } __attribute__((packed)) media; /* D90_STATUS_TYPE_MEDIA */
+} __attribute__((packed));
+
+struct mitsud90_status_resp {
+ uint8_t hdr[4]; /* e4 47 44 30 */
+ /* D90_STATUS_TYPE_ERROR */
+ uint8_t code[2]; /* 00 is ok, nonzero is error */
+ uint8_t unk[9];
+ /* D90_STATUS_TYPE_MECHA */
+ uint8_t mecha[2];
+ /* D90_STATUS_TYPE_TEMP */
+ uint8_t temp;
+} __attribute__((packed));
+
+struct mitsud90_info_resp {
+ uint8_t hdr[4]; /* e4 47 44 30 */
+ uint8_t model[10];
+ uint8_t x02;
+ struct mitsud90_fw_resp_single fw_vers[7];
+ uint8_t x1e;
+ uint8_t x22[2];
+ uint8_t x28[2];
+ uint8_t x29[8];
+ uint8_t x2b[2];
+ uint8_t x2c[2];
+ uint8_t x65[50];
+ uint8_t x82;
+ uint8_t x83;
+ uint8_t x84;
+} __attribute__((packed));
+
+#define D90_MECHA_STATUS_IDLE 0x00
+#define D90_MECHA_STATUS_PRINTING 0x50
+#define D90_MECHA_STATUS_INIT 0x80
+#define D90_MECHA_STATUS_INIT_FEEDCUT 0x10
+
+#define D90_MECHA_STATUS_PRINT_FEEDING 0x10 // feeding ?
+#define D90_MECHA_STATUS_PRINT_PRE_Y 0x21 // pre Y ?
+#define D90_MECHA_STATUS_PRINT_Y 0x22 // Y ?
+#define D90_MECHA_STATUS_PRINT_PRE_M 0x23 // pre M ?
+#define D90_MECHA_STATUS_PRINT_M 0x24 // M ?
+#define D90_MECHA_STATUS_PRINT_PRE_C 0x25 // pre C ? guess!
+#define D90_MECHA_STATUS_PRINT_C 0x26 // C ?
+#define D90_MECHA_STATUS_PRINT_PRE_OC 0x27 // pre OC ? guess!
+#define D90_MECHA_STATUS_PRINT_OC 0x28 // O C?
+#define D90_MECHA_STATUS_PRINTING_x2f 0x2f // ??
+#define D90_MECHA_STATUS_PRINTING_x38 0x38 // eject ?
+
+#define D90_ERROR_STATUS_OK 0x00
+#define D90_ERROR_STATUS_OK_WARMING 0x40
+#define D90_ERROR_STATUS_OK_COOLING 0x80
+#define D90_ERROR_STATUS_RIBBON 0x21
+#define D90_ERROR_STATUS_PAPER 0x22
+#define D90_ERROR_STATUS_PAP_RIB 0x23
+#define D90_ERROR_STATUS_OPEN 0x29
+
+struct mitsud90_job_query {
+ uint8_t hdr[4]; /* 1b 47 44 31 */
+ uint16_t jobid; /* BE */
+};
+
+struct mitsud90_job_resp {
+ uint8_t hdr[4]; /* e4 47 44 31 */
+ uint8_t unk1;
+ uint8_t unk2;
+ uint16_t unk3;
+};
+
+struct mitsud90_job_hdr {
+ uint8_t hdr[6]; /* 1b 53 50 30 00 33 */
+ uint16_t cols; /* BE */
+ uint16_t rows; /* BE */
+ uint8_t unk[5]; /* 64 00 00 01 00 */
+ union {
+#if 0
+ struct {
+ uint8_t margin;
+ uint16_t position;
+ } cuts[3] __attribute__((packed));
+#endif
+ uint8_t cutzero[9];
+ } __attribute__((packed));
+ uint8_t zero[24];
+
+ uint8_t overcoat;
+ uint8_t quality;
+ uint8_t colorcorr;
+ uint8_t sharp_h;
+ uint8_t sharp_v;
+ uint8_t zero_b[5];
+ union {
+ struct {
+ uint16_t pano_on; /* 0x0001 when pano is on, */
+ uint8_t pano_tot; /* 2 or 3 */
+ uint8_t pano_pg; /* 1, 2, 3 */
+ uint16_t pano_rows; /* always 0x097c (BE), ie 2428 ie 8" print */
+ uint16_t pano_rows2; /* Always 0x30 less than pano_rows */
+ uint16_t pano_zero; /* 0x0000 */
+ uint8_t pano_unk[6]; /* 02 58 00 0c 00 06 */
+ } pano __attribute__((packed));
+ uint8_t zero_c[16];
+ };
+ uint8_t zero_d[6];
+ uint8_t zero_fill[432];
+} __attribute__((packed));
+
+struct mitsud90_plane_hdr {
+ uint8_t hdr[10]; /* 1b 5a 54 01 00 09 00 00 00 00 */
+ uint16_t cols; /* BE */
+ uint16_t rows; /* BE */
+ uint8_t zero_fill[498];
+};
+
+struct mitsud90_job_footer {
+ uint8_t hdr[4]; /* 1b 42 51 31 */
+ uint8_t pad;
+ uint8_t seconds; /* 0x05 by default (windows) */
+};
+
+struct mitsud90_memcheck {
+ uint8_t hdr[4]; /* 1b 47 44 33 */
+ uint8_t unk[2]; /* 00 33 */
+ uint16_t cols; /* BE */
+ uint16_t rows; /* BE */
+ uint8_t unk_b[4]; /* 64 00 00 01 */
+ uint8_t zero_fill[498];
+};
+
+struct mitsud90_memcheck_resp {
+ uint8_t hdr[4]; /* e4 47 44 43 */
+ uint8_t size_bad; /* 0x00 is ok */
+ uint8_t mem_bad; /* 0x00 is ok */
+};
+
+const char *mitsud90_mecha_statuses(const uint8_t *code)
+{
+ switch (code[0]) {
+ case D90_MECHA_STATUS_IDLE:
+ return "Idle";
+ case D90_MECHA_STATUS_PRINTING:
+ switch (code[1]) {
+ case D90_MECHA_STATUS_PRINT_FEEDING:
+ return "Feeding Media";
+ case D90_MECHA_STATUS_PRINT_PRE_Y:
+ case D90_MECHA_STATUS_PRINT_Y:
+ return "Printing Yellow";
+ case D90_MECHA_STATUS_PRINT_PRE_M:
+ case D90_MECHA_STATUS_PRINT_M:
+ return "Printing Magenta";
+ case D90_MECHA_STATUS_PRINT_PRE_C:
+ case D90_MECHA_STATUS_PRINT_C:
+ return "Printing Cyan";
+ case D90_MECHA_STATUS_PRINT_PRE_OC:
+ case D90_MECHA_STATUS_PRINT_OC:
+ return "Applying Overcoat";
+ case D90_MECHA_STATUS_PRINTING_x2f:
+ case D90_MECHA_STATUS_PRINTING_x38:
+ return "Ejecting Media?";
+ default:
+ return "Printing (Unknown)";
+ }
+ case D90_MECHA_STATUS_INIT:
+ if (code[1] == D90_MECHA_STATUS_INIT_FEEDCUT)
+ return "Feed & Cut paper";
+ else
+ return "Initializing";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *mitsud90_error_codes(const uint8_t *code)
+{
+ switch(code[0]) {
+ case D90_ERROR_STATUS_OK:
+ if (code[1] & D90_ERROR_STATUS_OK_WARMING)
+ return "Heating";
+ else if (code[1] & D90_ERROR_STATUS_OK_COOLING)
+ return "Cooling Down";
+ else
+ return "Idle";
+ case D90_ERROR_STATUS_RIBBON:
+ switch (code[1]) {
+ case 0x00:
+ return "Ribbon exhausted";
+ case 0x10:
+ return "Insufficient remaining ribbon";
+ case 0x20:
+ return "Ribbon Cue Timeout";
+ case 0x30:
+ return "Cannot Cue Ribbon";
+ case 0x90:
+ return "No ribbon";
+ default:
+ return "Unknown Ribbon Error";
+ }
+ case D90_ERROR_STATUS_PAPER:
+ switch (code[1]) {
+ case 0x00:
+ return "No paper";
+ case 0x02:
+ return "Paper exhausted";
+ default:
+ return "Unknown Paper Error";
+ }
+ case D90_ERROR_STATUS_PAP_RIB:
+ switch (code[1]) {
+ case 0x00:
+ return "Ribbon/Paper mismatch";
+ case 0x90:
+ return "Ribbon/Job mismatch";
+ default:
+ return "Unknown ribbon match error";
+ }
+ case 0x26:
+ return "Illegal Ribbon";
+ case 0x28:
+ return "Cut Bin Missing";
+ case D90_ERROR_STATUS_OPEN:
+ switch (code[1]) {
+ case 0x00:
+ return "Printer Open during Stop";
+ case 0x10:
+ return "Printer Open during Initialization";
+ case 0x90:
+ return "Printer Open during Printing";
+ default:
+ return "Unknown Door error";
+ }
+ case 0x2f:
+ return "Printer turned off during printing";
+ case 0x31:
+ return "Ink feed stop";
+ case 0x32:
+ return "Ink Skip 1 timeout";
+ case 0x33:
+ return "Ink Skip 2 timeout";
+ case 0x34:
+ return "Ink Sticking";
+ case 0x35:
+ return "Ink return stop";
+ case 0x36:
+ return "Ink Rewind timeout";
+ case 0x37:
+ return "Winding sensing error";
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ return "Paper Jam";
+ case 0x60:
+ if (code[1] == 0x20)
+ return "Preheat error";
+ else if (code[1] == 0x04)
+ return "Humidity sensor error";
+ else if (code[1] & 0x1f)
+ return "Thermistor error";
+ else
+ return "Unknown error";
+ case 0x61:
+ if (code[1] == 0x00)
+ return "Color Sensor Error";
+ else if (code[1] & 0x10)
+ return "Matte OP Error";
+ else
+ return "Unknown error";
+ case 0x62:
+ return "Data Transfer error";
+ case 0x63:
+ return "EEPROM error";
+ case 0x64:
+ return "Flash access error";
+ case 0x65:
+ return "FPGA configuration error";
+ case 0x66:
+ return "Power voltage Error";
+ case 0x67:
+ return "RFID access error";
+ case 0x68:
+ if (code[1] == 0x00)
+ return "Fan Lock Error";
+ else if (code[1] == 0x90)
+ return "MDA Error";
+ else
+ return "Unknown error";
+ case 0x69:
+ if (code[1] == 0x10)
+ return "DDR Error";
+ else if (code[1] == 0x00)
+ return "Firmware Error";
+ else
+ return "Unknown error";
+ case 0x70:
+ case 0x71:
+ case 0x73:
+ case 0x75:
+ return "Mechanical Error (check ribbon and power cycle)";
+ case 0x82:
+ return "USB Timeout";
+ case 0x83:
+ return "Illegal paper size";
+ case 0x84:
+ return "Illegal parameter";
+ case 0x85:
+ return "Job Cancel";
+ case 0x89:
+ return "Last Job Error";
+ default:
+ return "Unknown";
+ }
+}
+
+static void mitsud90_dump_status(struct mitsud90_status_resp *resp)
+{
+ INFO("Error Status: %s (%02x %02x) -- %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ mitsud90_error_codes(resp->code),
+ resp->code[0], resp->code[1],
+ resp->unk[0], resp->unk[1], resp->unk[2], resp->unk[3],
+ resp->unk[4], resp->unk[5], resp->unk[6], resp->unk[7],
+ resp->unk[8]);
+ INFO("Printer Status: %s (%02x %02x)\n",
+ mitsud90_mecha_statuses(resp->mecha),
+ resp->mecha[0], resp->mecha[1]);
+ INFO("Temperature Status: %s\n",
+ mitsu70x_temperatures(resp->temp));
+}
+
+/* Private data structure */
+struct mitsud90_printjob {
+ uint8_t *databuf;
+ int datalen;
+ int copies;
+};
+
+struct mitsud90_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ int type;
+
+ /* Used in parsing.. */
+ struct mitsud90_job_footer holdover;
+ int holdover_on;
+
+ struct marker marker;
+};
+
+static int mitsud90_query_media(struct mitsud90_ctx *ctx, struct mitsud90_media_resp *resp)
+{
+ uint8_t cmdbuf[8];
+ int ret, num;
+
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x47;
+ cmdbuf[2] = 0x44;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0;
+ cmdbuf[5] = 0;
+ cmdbuf[6] = 0x01; /* Number of commands */
+ cmdbuf[7] = D90_STATUS_TYPE_MEDIA;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
+ memset(resp, 0, sizeof(*resp));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) resp, sizeof(*resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(*resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
+ return 4;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_query_status(struct mitsud90_ctx *ctx, struct mitsud90_status_resp *resp)
+{
+ uint8_t cmdbuf[10];
+ int ret, num;
+
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x47;
+ cmdbuf[2] = 0x44;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0;
+ cmdbuf[5] = 0;
+ cmdbuf[6] = 0x03; /* Number of commands */
+ cmdbuf[7] = D90_STATUS_TYPE_ERROR;
+ cmdbuf[8] = D90_STATUS_TYPE_MECHA;
+ cmdbuf[9] = D90_STATUS_TYPE_TEMP;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
+ memset(resp, 0, sizeof(*resp));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) resp, sizeof(*resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(*resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
+ return 4;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+/* Generic functions */
+
+static void *mitsud90_init(void)
+{
+ struct mitsud90_ctx *ctx = malloc(sizeof(struct mitsud90_ctx));
+ if (!ctx) {
+ ERROR("Memory Allocation Failure!\n");
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(struct mitsud90_ctx));
+
+ return ctx;
+}
+
+static int mitsud90_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+{
+ struct mitsud90_ctx *ctx = vctx;
+ struct mitsud90_media_resp resp;
+
+ UNUSED(jobid);
+
+ ctx->dev = dev;
+ ctx->endp_up = endp_up;
+ ctx->endp_down = endp_down;
+ ctx->type = type;
+
+ if (test_mode < TEST_MODE_NOATTACH) {
+ if (mitsud90_query_media(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+ } else {
+ resp.media.brand = 0xff;
+ resp.media.type = 0x0f;
+ resp.media.capacity = cpu_to_be16(230);
+ resp.media.remain = cpu_to_be16(200);
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = mitsu70x_media_types(resp.media.brand, resp.media.type);
+ ctx->marker.levelmax = be16_to_cpu(resp.media.capacity);
+ ctx->marker.levelnow = be16_to_cpu(resp.media.remain);
+
+ return CUPS_BACKEND_OK;
+}
+
+static void mitsud90_cleanup_job(const void *vjob)
+{
+ const struct mitsud90_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
+}
+
+static void mitsud90_teardown(void *vctx) {
+ struct mitsud90_ctx *ctx = vctx;
+
+ if (!ctx)
+ return;
+
+ free(ctx);
+}
+
+static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
+ struct mitsud90_ctx *ctx = vctx;
+ int i, remain;
+ struct mitsud90_job_hdr *hdr;
+
+ struct mitsud90_printjob *job;;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
+
+ /* Just allocate a worst-case buffer */
+ job->datalen = 0;
+ job->databuf = malloc(sizeof(struct mitsud90_job_hdr) +
+ sizeof(struct mitsud90_plane_hdr) +
+ sizeof(struct mitsud90_job_footer) +
+ 1852*2729*3);
+ if (!job->databuf) {
+ ERROR("Memory allocation failure!\n");
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+
+ /* Make sure there's no holdover */
+ if (ctx->holdover_on) {
+ memcpy(job->databuf, &ctx->holdover, sizeof(ctx->holdover));
+ job->datalen += sizeof(ctx->holdover);
+ ctx->holdover_on = 0;
+ }
+
+ /* Read in first header. */
+ remain = sizeof(struct mitsud90_job_hdr) - job->datalen;
+ while (remain) {
+ i = read(data_fd, (job->databuf + job->datalen), remain);
+ if (i == 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (i < 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ remain -= i;
+ job->datalen += i;
+ }
+
+ /* Sanity check header */
+ hdr = (struct mitsud90_job_hdr *) job->databuf;
+ if (hdr->hdr[0] != 0x1b ||
+ hdr->hdr[1] != 0x53 ||
+ hdr->hdr[2] != 0x50 ||
+ hdr->hdr[3] != 0x30 ) {
+ ERROR("Unrecognized data format (%02x%02x%02x%02x)!\n",
+ hdr->hdr[0], hdr->hdr[1], hdr->hdr[2], hdr->hdr[3]);
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Now read in the rest */
+ remain = sizeof(struct mitsud90_plane_hdr) + be16_to_cpu(hdr->cols) * be16_to_cpu(hdr->rows) * 3;
+ while(remain) {
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i == 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (i < 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ job->datalen += i;
+ remain -= i;
+ }
+
+ /* Read in the footer. Hopefully. */
+ remain = sizeof(struct mitsud90_job_footer);
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i == 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (i < 0) {
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ /* See if this is a job footer. If it is, keep, else holdover. */
+ if (job->databuf[job->datalen + 0] != 0x1b ||
+ job->databuf[job->datalen + 1] != 0x42 ||
+ job->databuf[job->datalen + 2] != 0x51 ||
+ job->databuf[job->datalen + 3] != 0x31) {
+ memcpy(&ctx->holdover, job->databuf + job->datalen, sizeof(struct mitsud90_job_footer));
+ ctx->holdover_on = 1;
+ } else {
+ job->datalen += i;
+ ctx->holdover_on = 0;
+ }
+
+ /* Sanity check */
+ if (hdr->pano.pano_on) {
+ ERROR("Unable to handle panorama jobs yet\n");
+ mitsud90_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+
+ *vjob = job;
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_main_loop(void *vctx, const void *vjob) {
+ struct mitsud90_ctx *ctx = vctx;
+ struct mitsud90_job_hdr *hdr;
+ struct mitsud90_status_resp resp;
+ uint8_t last_status[2] = {0xff, 0xff};
+
+ int sent;
+ int ret;
+ int copies;
+
+ const struct mitsud90_printjob *job = vjob;
+
+ if (!ctx)
+ return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+ copies = job->copies;
+
+ hdr = (struct mitsud90_job_hdr*) job->databuf;
+
+ INFO("Waiting for printer idle...\n");
+
+top:
+ sent = 0;
+
+ // XXX Figure out if printer is asleep, and wake it up if necessary.
+
+ /* Query status, wait for idle or error out */
+ do {
+ if (mitsud90_query_status(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ if (resp.code[0] != D90_ERROR_STATUS_OK) {
+ ERROR("Printer reported error condition: %s (%02x %02x)\n",
+ mitsud90_error_codes(resp.code), resp.code[0], resp.code[1]);
+ return CUPS_BACKEND_STOP;
+ }
+
+ if (resp.code[1] & D90_ERROR_STATUS_OK_WARMING ||
+ resp.temp & D90_ERROR_STATUS_OK_WARMING ) {
+ INFO("Printer warming up\n");
+ sleep(1);
+ continue;
+ }
+ if (resp.code[1] & D90_ERROR_STATUS_OK_COOLING ||
+ resp.temp & D90_ERROR_STATUS_OK_COOLING) {
+ INFO("Printer cooling down\n");
+ sleep(1);
+ continue;
+ }
+
+ if (resp.mecha[0] != last_status[0] ||
+ resp.mecha[1] != last_status[1]) {
+ INFO("Printer status: %s\n",
+ mitsud90_mecha_statuses(resp.mecha));
+ last_status[0] = resp.mecha[0];
+ last_status[1] = resp.mecha[1];
+ }
+
+ if (resp.mecha[0] == D90_MECHA_STATUS_IDLE) {
+ break;
+ // we don't have to wait until idle, just
+ // until we have free buffers. Don't know how
+ // to check this though.. XXXX
+ }
+ } while(1);
+
+
+ /* Send memory check */
+ {
+ struct mitsud90_memcheck mem;
+ struct mitsud90_memcheck_resp mem_resp;
+ int num;
+
+ memcpy(&mem, hdr, sizeof(mem));
+ mem.hdr[0] = 0x1b;
+ mem.hdr[1] = 0x47;
+ mem.hdr[2] = 0x44;
+ mem.hdr[3] = 0x33;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &mem, sizeof(mem))))
+ return CUPS_BACKEND_FAILED;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*)&mem_resp, sizeof(mem_resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(mem_resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(mem_resp));
+ return 4;
+ }
+ if (mem_resp.size_bad || mem_resp.mem_bad == 0xff) {
+ ERROR("Printer reported bad print params (%02x)\n", mem_resp.size_bad);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (mem_resp.mem_bad) {
+ ERROR("Printer buffers full, retrying!\n");
+ sleep(1);
+ goto top;
+ }
+ }
+
+ /* Send header */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ job->databuf + sent, sizeof(*hdr))))
+ return CUPS_BACKEND_FAILED;
+ sent += sizeof(*hdr);
+
+ /* Send Plane header */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ job->databuf + sent, sizeof(*hdr))))
+ return CUPS_BACKEND_FAILED;
+ sent += sizeof(*hdr);
+
+ /* Send payload + footer */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ job->databuf + sent, job->datalen - sent)))
+ return CUPS_BACKEND_FAILED;
+// sent += (job->datalen - sent);
+
+ /* Wait for completion */
+ do {
+ sleep(1);
+
+ if (mitsud90_query_status(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ if (resp.code[0] != D90_ERROR_STATUS_OK) {
+ ERROR("Printer reported error condition: %s (%02x %02x)\n",
+ mitsud90_error_codes(resp.code), resp.code[0], resp.code[1]);
+ return CUPS_BACKEND_STOP;
+ }
+
+ if (resp.mecha[0] != last_status[0] ||
+ resp.mecha[1] != last_status[1]) {
+ INFO("Printer status: %s\n",
+ mitsud90_mecha_statuses(resp.mecha));
+ last_status[0] = resp.mecha[0];
+ last_status[1] = resp.mecha[1];
+ }
+
+ /* Terminate when printing complete */
+ if (resp.mecha[0] == D90_MECHA_STATUS_IDLE) {
+ break;
+ }
+
+ if (fast_return && copies <= 1) { /* Copies generated by backend? */
+ INFO("Fast return mode enabled.\n");
+ break;
+ }
+ } while(1);
+
+ /* Clean up */
+ if (terminate)
+ copies = 1;
+
+ INFO("Print complete (%d copies remaining)\n", copies - 1);
+
+ if (copies && --copies) {
+ goto top;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_query_job(struct mitsud90_ctx *ctx, uint16_t jobid,
+ struct mitsud90_job_resp *resp)
+{
+ struct mitsud90_job_query req;
+ int ret, num;
+
+ req.hdr[0] = 0x1b;
+ req.hdr[1] = 0x47;
+ req.hdr[2] = 0x44;
+ req.hdr[3] = 0x31;
+ req.jobid = cpu_to_be16(jobid);
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &req, sizeof(req))))
+ return ret;
+ memset(resp, 0, sizeof(*resp));
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) resp, sizeof(*resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(*resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
+ return 4;
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_get_jobstatus(struct mitsud90_ctx *ctx, uint16_t jobid)
+{
+ struct mitsud90_job_resp resp;
+
+ if (mitsud90_query_job(ctx, jobid, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Job Status: %04x = %02x/%02x/%04x\n",
+ jobid, resp.unk1, resp.unk2, be16_to_cpu(resp.unk3));
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_get_media(struct mitsud90_ctx *ctx)
+{
+ struct mitsud90_media_resp resp;
+
+ if (mitsud90_query_media(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ INFO("Media Type: %s (%02x/%02x)\n",
+ mitsu70x_media_types(resp.media.brand, resp.media.type),
+ resp.media.brand,
+ resp.media.type);
+ INFO("Prints Remaining: %03d/%03d\n",
+ be16_to_cpu(resp.media.remain),
+ be16_to_cpu(resp.media.capacity));
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_get_status(struct mitsud90_ctx *ctx)
+{
+ struct mitsud90_status_resp resp;
+
+ if (mitsud90_query_status(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ mitsud90_dump_status(&resp);
+
+ return CUPS_BACKEND_OK;
+}
+
+int mitsud90_get_info(struct mitsud90_ctx *ctx)
+{
+ uint8_t cmdbuf[26];
+ int ret, num;
+ struct mitsud90_info_resp resp;
+
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x47;
+ cmdbuf[2] = 0x44;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0;
+ cmdbuf[5] = 0;
+ cmdbuf[6] = 19; /* Number of commands */
+
+ cmdbuf[7] = D90_STATUS_TYPE_MODEL;
+ cmdbuf[8] = 0x02;
+ cmdbuf[9] = 0x0b;
+ cmdbuf[10] = 0x0c;
+
+ cmdbuf[11] = 0x0d;
+ cmdbuf[12] = 0x0e;
+ cmdbuf[13] = 0x0f;
+ cmdbuf[14] = 0x11;
+
+ cmdbuf[15] = 0x13;
+ cmdbuf[16] = 0x1e;
+ cmdbuf[17] = 0x22;
+ cmdbuf[18] = 0x28;
+
+ cmdbuf[19] = 0x29;
+ cmdbuf[20] = 0x2b;
+ cmdbuf[21] = 0x2c;
+ cmdbuf[22] = 0x65;
+
+ cmdbuf[23] = 0x82;
+ cmdbuf[24] = 0x83;
+ cmdbuf[25] = 0x84;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
+ memset(&resp, 0, sizeof(resp));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ (uint8_t*) &resp, sizeof(resp), &num);
+
+ if (ret < 0)
+ return ret;
+ if (num != sizeof(resp)) {
+ ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(resp));
+ return 4;
+ }
+
+ /* start dumping output */
+ memset(cmdbuf, 0, sizeof(cmdbuf));
+ memcpy(cmdbuf, resp.model, sizeof(resp.model));
+ INFO("Model: %s\n", (char*)cmdbuf);
+ for (num = 0; num < 7 ; num++) {
+ memset(cmdbuf, 0, sizeof(cmdbuf));
+ memcpy(cmdbuf, resp.fw_vers[num].version, sizeof(resp.fw_vers[num].version));
+ INFO("FW Component %02d: %s (%04x)\n",
+ num, cmdbuf, be16_to_cpu(resp.fw_vers[num].csum));
+ }
+ INFO("TYPE_02: %02x\n", resp.x02);
+ INFO("TYPE_1e: %02x\n", resp.x1e);
+ INFO("TYPE_22: %02x %02x\n", resp.x22[0], resp.x22[1]);
+ INFO("TYPE_28: %02x %02x\n", resp.x28[0], resp.x28[1]);
+ INFO("TYPE_29: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ resp.x29[0], resp.x29[1], resp.x29[2], resp.x29[3],
+ resp.x29[4], resp.x29[5], resp.x29[6], resp.x29[7]);
+ INFO("TYPE_2b: %02x %02x\n", resp.x2b[0], resp.x2b[1]);
+ INFO("TYPE_2c: %02x %02x\n", resp.x2c[0], resp.x2c[1]);
+
+ INFO("TYPE_65:");
+ for (num = 0; num < 50 ; num++) {
+ DEBUG2(" %02x", resp.x65[num]);
+ }
+ DEBUG2("\n");
+ INFO("TYPE_1e: %82x\n", resp.x82);
+ INFO("TYPE_1e: %83x\n", resp.x83);
+
+ /* XXX Dump iSerial, sleep time settings */
+ // XXX what about resume, wait time, "cut limit" ?
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_dumpall(struct mitsud90_ctx *ctx)
+{
+ int i;
+ uint8_t cmdbuf[8];
+ uint8_t buf[256];
+
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x47;
+ cmdbuf[2] = 0x44;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0;
+ cmdbuf[5] = 0;
+ cmdbuf[6] = 0x01; /* Number of commands */
+
+ for (i = 0 ; i < 256 ; i++) {
+ int num, ret;
+
+ cmdbuf[7] = i;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
+ memset(buf, 0, sizeof(buf));
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ buf, sizeof(buf), &num);
+
+ if (ret <= 0)
+ continue;
+
+ if (num > 4) {
+ DEBUG("TYPE %02x LEN: %d (%d)\n", i, num, num - 4);
+ DEBUG("<--");
+ for (ret = 0; ret < num ; ret ++) {
+ DEBUG2(" %x", buf[ret]);
+ }
+ DEBUG2("\n");
+ }
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsud90_set_iserial(struct mitsud90_ctx *ctx, uint8_t enabled)
+{
+ uint8_t cmdbuf[23];
+ int ret, num;
+
+ enabled = (enabled) ? 0: 0x80;
+
+ /* Send Parameter.. */
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x31;
+ cmdbuf[2] = 0x36;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0x41;
+ cmdbuf[5] = 0xbe;
+ cmdbuf[6] = 0x00;
+ cmdbuf[7] = 0x00;
+
+ cmdbuf[8] = 0x00;
+ cmdbuf[9] = 0x01;
+ cmdbuf[10] = 0x00;
+ cmdbuf[11] = 0x00;
+ cmdbuf[12] = 0x00;
+ cmdbuf[13] = 0x11;
+ cmdbuf[14] = 0xff;
+ cmdbuf[15] = 0xff;
+
+ cmdbuf[16] = 0xff;
+ cmdbuf[17] = 0xfe;
+ cmdbuf[18] = 0xff;
+ cmdbuf[19] = 0xff;
+ cmdbuf[20] = 0xff;
+ cmdbuf[21] = 0xfe;
+ cmdbuf[22] = enabled;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, sizeof(cmdbuf))))
+ return ret;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ cmdbuf, sizeof(cmdbuf), &num);
+
+ /* No response */
+
+ return ret;
+}
+
+static int mitsud90_set_sleeptime(struct mitsud90_ctx *ctx, uint16_t time)
+{
+ uint8_t cmdbuf[24];
+ int ret;
+
+ /* 255 minutes max, according to RE work */
+ if (time > 255)
+ time = 255;
+
+ /* Send Parameter.. */
+ cmdbuf[0] = 0x1b;
+ cmdbuf[1] = 0x31;
+ cmdbuf[2] = 0x36;
+ cmdbuf[3] = 0x30;
+ cmdbuf[4] = 0x41;
+ cmdbuf[5] = 0xbe;
+ cmdbuf[6] = 0x00;
+ cmdbuf[7] = 0x00;
+
+ cmdbuf[8] = 0x00;
+ cmdbuf[9] = 0x02;
+ cmdbuf[10] = 0x00;
+ cmdbuf[11] = 0x00;
+ cmdbuf[12] = 0x05;
+ cmdbuf[13] = 0x02;
+ cmdbuf[14] = 0xff;
+ cmdbuf[15] = 0xff;
+
+ cmdbuf[16] = 0xff;
+ cmdbuf[17] = 0xfd;
+ cmdbuf[18] = 0xff;
+ cmdbuf[19] = 0xff;
+ cmdbuf[20] = 0xfa;
+ cmdbuf[21] = 0xff;
+ cmdbuf[22] = (time >> 8) & 0xff;
+ cmdbuf[23] = time & 0xff;
+
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ cmdbuf, 4)))
+ return ret;
+
+ /* No response */
+
+ return 0;
+}
+
+static void mitsud90_cmdline(void)
+{
+ DEBUG("\t\t[ -i ] # Query printer info\n");
+ DEBUG("\t\t[ -j jobid ] # Query job status\n");
+ DEBUG("\t\t[ -k time ] # Set sleep time in minutes\n");
+ DEBUG("\t\t[ -m ] # Query printer media\n");
+ DEBUG("\t\t[ -s ] # Query printer status\n");
+ DEBUG("\t\t[ -x 0|1 ] # Enable/disable iSerial reporting\n");
+// DEBUG("\t\t[ -Z ] # Dump all parameters\n");
+}
+
+static int mitsud90_cmdline_arg(void *vctx, int argc, char **argv)
+{
+ struct mitsud90_ctx *ctx = vctx;
+ int i, j = 0;
+
+ if (!ctx)
+ return -1;
+
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "ij:k:msx:Z")) >= 0) {
+ switch(i) {
+ GETOPT_PROCESS_GLOBAL
+ case 'i':
+ j = mitsud90_get_info(ctx);
+ break;
+ case 'j':
+ j = mitsud90_get_jobstatus(ctx, atoi(optarg));
+ break;
+ case 'k':
+ j = mitsud90_set_sleeptime(ctx, atoi(optarg));
+ break;
+ case 'm':
+ j = mitsud90_get_media(ctx);
+ break;
+ case 's':
+ j = mitsud90_get_status(ctx);
+ break;
+ case 'x':
+ j = mitsud90_set_iserial(ctx, atoi(optarg));
+ break;
+ case 'Z':
+ j = mitsud90_dumpall(ctx);
+ break;
+ default:
+ break; /* Ignore completely */
+ }
+
+ if (j) return j;
+ }
+
+ return 0;
+}
+
+static int mitsud90_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct mitsud90_ctx *ctx = vctx;
+ struct mitsud90_media_resp resp;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ if (mitsud90_query_media(ctx, &resp))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = be16_to_cpu(resp.media.remain);
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *mitsud90_prefixes[] = {
+ "mitsubishi-d90dw",
+ // backwards compatibility
+ "mitsud90",
+ NULL
+};
+
+/* Exported */
+struct dyesub_backend mitsud90_backend = {
+ .name = "Mitsubishi CP-D90DW",
+ .version = "0.13",
+ .uri_prefixes = mitsud90_prefixes,
+ .cmdline_arg = mitsud90_cmdline_arg,
+ .cmdline_usage = mitsud90_cmdline,
+ .init = mitsud90_init,
+ .attach = mitsud90_attach,
+ .cleanup_job = mitsud90_cleanup_job,
+ .teardown = mitsud90_teardown,
+ .read_parse = mitsud90_read_parse,
+ .main_loop = mitsud90_main_loop,
+ .query_markers = mitsud90_query_markers,
+ .devices = {
+ { USB_VID_MITSU, USB_PID_MITSU_D90, P_MITSU_D90, NULL, "mitsubishi-d90dw"},
+ { 0, 0, 0, NULL, NULL}
+ }
+};
+
+/*
+ Mitsubishi CP-D90DW data format
+
+ All multi-byte values are BIG endian
+
+ [[HEADER 1]]
+
+ 1b 53 50 30 00 33 XX XX YY YY 64 00 00 01 00 ?? XX XX == COLS, YY XX ROWS (BE)
+ ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 <-- cut position, see below
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ QQ RR SS HH VV 00 00 00 00 00 01 00 03 II 09 7c QQ == 02 matte, 00 glossy,
+ 09 4c 00 00 02 58 00 0c 00 06 RR == 00 auto, 03 == fine, 02 == superfine.
+ SS == 00 colorcorr, 01 == none
+ HH/VV sharpening for Horiz/Vert, 0-8, 0 is off, 4 is normal
+ [pad to 512b]
+
+ normal == rows 00 00 00 00 00 00 00 00 00
+ 4x6div2 == 1226 00 02 65 01 00 00 01 00 00
+ 8x6div2 == 2488 01 04 be 00 00 00 00 00 00
+
+ guesses based on SDK docs:
+
+ 9x6div2 == 2728 01 05 36 00 00 00 00 00 00
+ 9x6div3 == 2724 00 03 90 00 07 14 00 00 00
+ 9x6div4 == 2628 00 02 97 00 05 22 00 07 ad
+
+ from [01 00 03 03] onwards, only shows in 8x20" PANORAMA prints. Assume 2" overlap.
+ II == 01 02 03 (which panel # in panorama!)
+ [02 58] == 600, aka 2" * 300dpi?
+ [09 4c] == 2380 (48 less than 8 size? (trim length on ends?)
+ [09 7c] == 2428 (ie 8" print)
+
+ (6x20 == 1852x6036)
+ (6x14 == 1852x4232)
+
+ 3*8" panels == 2428*3=7284. -6036 = 1248. /2 = 624 (0x270)
+
+ [[DATA PLANE HEADER]]
+
+ 1b 5a 54 01 00 09 00 00 00 00 XX XX YY YY 00 00
+ ...
+ [pad to 512b]
+
+ data, BGR packed, 8bpp. No padding to 512b!
+
+ [[FOOTER]]
+
+ 1b 42 51 31 00 TT ## TT == secs to wait for second print
+
+
+ ****************************************************
+
+Comms Protocol for D90:
+
+ [[ ERROR STATUS ]]
+
+-> 1b 47 44 30 00 00 01 16
+<- e4 47 44 30 00 00 00 00 00 00 00 00 00 00 00 [Normal/OK]
+<- e4 47 44 30 XX 00 00 00 00 00 00 00 00 3f 37 [Error condition]
+ XX == 29 (printer open)
+ 28 (cut bin missing)
+<- e4 47 44 30 21 90 00 00 01 00 00 00 00 3f 37 No ribbon
+
+ [[ MEDIA STATUS ]]
+
+-> 1b 47 44 30 00 00 01 2a
+<- e4 47 44 30 ff 0f 50 00 01 ae 01 9b 01 00 [Normal/OK]
+<- e4 47 44 30 ff ff ff ff ff ff ff ff ff ff [Error]
+
+ [[ MECHA STATUS ]]
+
+-> 1b 47 44 30 00 00 01 17
+<- e4 47 44 30 SS SS
+
+ [[ TEMPERATURE QUERY ]]
+
+-> 1b 47 44 30 00 00 01 1f
+<- e4 47 44 30 HH
+
+ [[ UNKNOWN QUERY ]]
+-> 1b 47 44 30 00 00 01 28
+<- e4 47 44 30 XX XX Unknown, seems to increment.
+
+ [[ JOB STATUS QUERY ?? ]]
+
+-> 1b 47 44 31 00 00 JJ JJ Jobid?
+<- e4 47 44 31 XX YY ZZ ZZ No idea.. sure.
+
+ [[ COMBINED STATUS QUERIES ]]
+
+-> 1b 47 44 30 00 00 04 16 17 1f 2a
+<- e4 47 44 30
+
+ MM NN 00 00 ZZ 00 00 00 00 QQ QQ [id 16, total 11]
+ SS SS [id 17, total 2]
+ HH [id 1f, total 1]
+ VV TT WW 00 XX XX YY YY 01 00 [id 2a, total 10]
+
+ WW == 0x50 or 0x00 (seen, no idea what it means)
+ VV == Media vendor (0xff etc)
+ TT == Media type, 0x02/0x0f etc (see mitsu70x_media_types!)
+ XX XX == Media capacity, BE
+ YY YY == Media remain, BE
+ QQ QQ == 00 00 normal, 3f 37 error
+ MM NN == MM major err (00 if no error) NN minor error.
+ ZZ == 01 seen for _some_ errors.
+ SS SS == Mecha Status (00 == ready, 50 == printing, 80+10 == feedandcut, 80 == initializing?
+ HH == Temperature state. 00 is OK, 0x40 is low, 0x80 is hot.
+ II II == ??
+ JJ JJ == ??
+
+ [[ WAKE UP PRINTER ]]
+-> 1b 45 57 55
+
+ [[ GET iSERIAL ]]
+
+-> 1b 61 36 36 41 be 00 00
+ 00 01 00 00 00 11 ff ff
+ ff fe ff ff ff ee
+<- e4 61 36 36 41 be 00 00
+ 00 01 00 00 00 11 ff ff
+ ff fe ff ff ff ee XX <- XX is 0x80 or 0x00. (0x80) ISERIAL OFF
+
+ [[ GET CUT? ]]
+
+-> 1b 61 36 36 45 ba 00 00
+ 00 01 00 00 05 07 ff ff
+ ff fe ff ff fa f8
+-> e4 61 36 36 45 ba 00 00
+ 00 01 00 00 05 07 ff ff
+ ff fe ff ff fa f8 XX <- XX is 0x80 or 0x00 (0x00) CUT ON?
+
+ [[ GET WAIT TIME ]]
+
+-> 1b 61 36 36 45 00 00 00
+ 00 01 00 00 05 05 ff ff
+ ff fe ff ff fa fb
+-> 1b 61 36 36 45 00 00 00
+ 00 01 00 00 05 05 ff ff
+ ff fe ff ff fa fb XX <- XX is time in seconds.
+
+ [[ GET RESUME? ]]
+
+-> 1b 61 36 36 45 ba 00 00
+ 00 01 00 00 05 06 ff ff
+ ff fe ff ff fa f9
+-> e4 61 36 36 45 ba 00 00
+ 00 01 00 00 05 06 ff ff
+ ff fe ff ff fa f9 XX <- XX is 0x80 or 0x00 (0x80) (OFF)
+
+ [[ GET SLEEP TIME! ]]
+
+-> 1b 61 36 36 45 ba 00 00
+ 00 02 00 00 05 02 ff ff
+ ff fd ff ff fa fd
+<- e4 61 36 36 45 00 00 00
+ 00 02 00 00 05 02 ff ff
+ ff fd ff ff fa fd XX 00 <- XX, sleep time in minutes.
+
+ [[ SET SLEEP TIME! ]]
+
+-> 1b 61 36 30 45 ba 00 00
+ 00 02 00 00 05 02 ff ff
+ ff fd ff ff fa fd XX 00 <- XX, sleep time in minutes.
+
+ [[ SET iSERIAL ]]
+
+-> 1b 61 36 30 41 be 00 00
+ 00 01 00 00 00 11 ff ff
+ ff fe ff ff ff ee XX <- XX 0x80 OFF, 0x00 ON.
+
+ [[ SANITY CHECK PRINT ARGUMENTS / MEMTEST ]]
+
+-> 1b 47 44 33 00 33 07 3c 04 ca 64 00 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 00 00 00 00 00 00 00 00
+ 00 00 00 04 04 00 00 00 00 00 00 00 00 00 00 00
+ [[ pad to 512 ]]
+
+ ... 07 3c onwards is the same as main payload header.
+
+<- e4 47 44 43 XX YY
+
+ ... possibly the same as the D70's "memorystatus"
+ XX == size ok (non-zero if bad size)
+ YY == memory ok (non-zero or 0xff if full?)
+
+ [[ SEND OVER HDRs and DATA ]]
+
+ ... Print arguments:
+
+-> 1b 53 50 30 00 33 07 3c 04 ca 64 00 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 00 00 00 00 00 00 00 00
+ 00 00 00 04 04 00 00 00 00 00 00 00 00 00 00 00
+ [[ pad to 512 ]]
+
+ ... Data transfer. Plane header:
+
+-> 1b 5a 54 01 00 09 00 00 00 00 07 3c 04 ca 00 00
+ [[ pad to 512 ]]
+
+-> [[print data]] [[ padded? ]]
+-> [[print data]]
+
+-> 1b 42 51 31 00 ZZ
+
+ ... Footer.
+ ZZ == Seconds to wait for follow-up print (0x05)
+
+
+ */
diff --git a/src/cups/backend_mitsup95d.c b/src/cups/backend_mitsup95d.c
index 44fbe0e..c4e0054 100644
--- a/src/cups/backend_mitsup95d.c
+++ b/src/cups/backend_mitsup95d.c
@@ -1,7 +1,7 @@
/*
* Mitsubishi P93D/P95D Monochrome Thermal Photo Printer CUPS backend
*
- * (c) 2016-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2016-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@@ -22,11 +22,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -48,32 +49,54 @@
#define USB_PID_MITSU_P95D 0x3b10
/* Private data structure */
-struct mitsup95d_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
-
- int type;
-
- uint8_t mem_clr[4]; // 1b 5a 43 00
- int mem_clr_present;
+struct mitsup95d_printjob {
+ uint8_t *databuf;
+ uint32_t datalen;
uint8_t hdr[2]; // 1b 51
-
uint8_t hdr1[50]; // 1b 57 20 2e ...
uint8_t hdr2[50]; // 1b 57 21 2e ...
uint8_t hdr3[50]; // 1b 57 22 2e ...
-
uint8_t hdr4[42]; // 1b 58 ...
int hdr4_len; // 36 (P95) or 42 (P93)
+
uint8_t plane[12]; // 1b 5a 74 00 ...
- uint8_t *databuf;
- uint32_t datalen;
+ uint8_t mem_clr[4]; // 1b 5a 43 00
+ int mem_clr_present;
uint8_t ftr[2];
};
+struct mitsup95d_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ int type;
+
+ struct marker marker;
+};
+
+#define QUERYRESP_SIZE_MAX 9
+
+static const char *mitsup93d_errors(uint8_t code)
+{
+ switch (code) {
+ case 0x6f: return "Door Open";
+ case 0x50: return "No Paper";
+ default: return "Unknown Error";
+ }
+}
+
+static const char *mitsup95d_errors(uint8_t code)
+{
+ switch (code & 0xf) {
+ case 3: return "Door Open";
+ case 4: return "No Paper";
+ default: return "Unknown Error";
+ }
+}
static void *mitsup95d_init(void)
{
@@ -87,24 +110,63 @@ static void *mitsup95d_init(void)
return ctx;
}
-static void mitsup95d_attach(void *vctx, struct libusb_device_handle *dev,
+static int mitsup95d_get_status(struct mitsup95d_ctx *ctx, uint8_t *resp)
+{
+ uint8_t querycmd[4] = { 0x1b, 0x72, 0x00, 0x00 };
+ int ret;
+ int num;
+
+ /* P93D is ... special. Windows switches to this halfway through
+ but it seems be okay to use it everywhere */
+ if (ctx->type == P_MITSU_P93D) {
+ querycmd[2] = 0x03;
+ }
+
+ /* Query Status to sanity-check job */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ querycmd, sizeof(querycmd))))
+ return CUPS_BACKEND_FAILED;
+ ret = read_data(ctx->dev, ctx->endp_up,
+ resp, QUERYRESP_SIZE_MAX, &num);
+
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+ if (ctx->type == P_MITSU_P95D && num != 9) {
+ return CUPS_BACKEND_FAILED;
+ } else if (ctx->type == P_MITSU_P93D && num != 8) {
+ return CUPS_BACKEND_FAILED;
+ }
+ return CUPS_BACKEND_OK;
+}
+
+static int mitsup95d_attach(void *vctx, struct libusb_device_handle *dev, int type,
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct mitsup95d_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;
+ ctx->type = type;
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
+ ctx->marker.color = "#000000"; /* Ie black! */
+ ctx->marker.name = "Unknown";
+ ctx->marker.levelmax = -1;
+ ctx->marker.levelnow = -2;
- ctx->type = lookup_printer_type(&mitsup95d_backend,
- desc.idVendor, desc.idProduct);
+ return CUPS_BACKEND_OK;
+}
+
+static void mitsup95d_cleanup_job(const void *vjob)
+{
+ const struct mitsup95d_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void mitsup95d_teardown(void *vctx) {
@@ -113,12 +175,10 @@ static void mitsup95d_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
free(ctx);
}
-static int mitsup95d_read_parse(void *vctx, int data_fd) {
+static int mitsup95d_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct mitsup95d_ctx *ctx = vctx;
uint8_t buf[2]; /* Enough to read in any header */
uint8_t tmphdr[50];
@@ -127,35 +187,45 @@ static int mitsup95d_read_parse(void *vctx, int data_fd) {
int remain;
int ptr_offset;
+ struct mitsup95d_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
- ctx->mem_clr_present = 0;
+ memset(job, 0, sizeof(*job));
+
+ job->mem_clr_present = 0;
top:
i = read(data_fd, buf, sizeof(buf));
- if (i == 0)
+ if (i == 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
if (buf[0] != 0x1b) {
ERROR("malformed data stream\n");
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
switch (buf[1]) {
case 0x50: /* Footer */
remain = 2;
- ptr = ctx->ftr;
+ ptr = job->ftr;
break;
case 0x51: /* Job Header */
remain = 2;
- ptr = ctx->hdr;
+ ptr = job->hdr;
break;
case 0x57: /* Geeneral headers */
remain = sizeof(tmphdr);
@@ -163,11 +233,11 @@ top:
break;
case 0x58: /* User Comment */
if (ctx->type == P_MITSU_P93D)
- ctx->hdr4_len = 42;
+ job->hdr4_len = 42;
else
- ctx->hdr4_len = 36;
- remain = ctx->hdr4_len;
- ptr = ctx->hdr4;
+ job->hdr4_len = 36;
+ remain = job->hdr4_len;
+ ptr = job->hdr4;
break;
case 0x5a: /* Plane header OR printer reset */
// reset memory: 1b 5a 43 ... [len 04]
@@ -178,6 +248,7 @@ top:
break;
default:
ERROR("Unrecognized command! (%02x %02x)\n", buf[0], buf[1]);
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -187,21 +258,25 @@ top:
while (remain) {
i = read(data_fd, ptr + ptr_offset, remain);
- if (i == 0)
+ if (i == 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
ptr_offset += i;
/* Handle the ambiguous 0x5a block */
if (buf[1] == 0x5a && remain == 0) {
if (tmphdr[2] == 0x74) { /* plane header */
- ptr = ctx->plane;
+ ptr = job->plane;
remain = 12 - ptr_offset; /* Finish reading */
} else if (tmphdr[2] == 0x43) { /* reset memory */
- ptr = ctx->mem_clr;
- ctx->mem_clr_present = 1;
+ ptr = job->mem_clr;
+ job->mem_clr_present = 1;
remain = 4 - ptr_offset;
}
memcpy(ptr, tmphdr, ptr_offset);
@@ -213,101 +288,96 @@ top:
if (tmphdr[3] != 46) {
ERROR("Unexpected header chunk: %02x %02x %02x %02x\n",
tmphdr[0], tmphdr[1], tmphdr[2], tmphdr[3]);
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
switch (tmphdr[2]) {
case 0x20:
- ptr = ctx->hdr1;
+ ptr = job->hdr1;
break;
case 0x21:
- ptr = ctx->hdr2;
+ ptr = job->hdr2;
break;
case 0x22:
- ptr = ctx->hdr3;
+ ptr = job->hdr3;
break;
default:
- ERROR("Unexpected header chunk: %02x %02x %02x %02x\n",
+ WARNING("Unexpected header chunk: %02x %02x %02x %02x\n",
tmphdr[0], tmphdr[1], tmphdr[2], tmphdr[3]);
}
memcpy(ptr, tmphdr, sizeof(tmphdr));
- } else if (ptr == ctx->plane) {
- uint16_t rows = ctx->plane[10] << 8 | ctx->plane[11];
- uint16_t cols = ctx->plane[8] << 8 | ctx->plane[9];
+ } else if (ptr == job->plane) {
+ uint16_t rows = job->plane[10] << 8 | job->plane[11];
+ uint16_t cols = job->plane[8] << 8 | job->plane[9];
remain = rows * cols;
/* Allocate buffer for the payload */
- ctx->datalen = 0;
- ctx->databuf = malloc(remain);
- if (!ctx->databuf) {
+ job->datalen = 0;
+ job->databuf = malloc(remain);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ mitsup95d_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
/* Read it in */
while (remain) {
- i = read(data_fd, ctx->databuf + ctx->datalen, remain);
- if (i == 0)
+ i = read(data_fd, job->databuf + job->datalen, remain);
+ if (i == 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
- if (i < 0)
+ }
+ if (i < 0) {
+ mitsup95d_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
remain -= i;
- ctx->datalen += i;
+ job->datalen += i;
}
- } else if (ptr == ctx->ftr) {
+ } else if (ptr == job->ftr) {
+
+ /* XXX Update unknown header field to match sniffs */
+ if (ctx->type == P_MITSU_P95D) {
+ if (job->hdr1[18] == 0x00)
+ job->hdr1[18] = 0x01;
+ }
+
+ /* Update printjob header to reflect number of requested copies */
+ if (job->hdr2[13] != 0xff)
+ job->hdr2[13] = copies;
+
+ *vjob = job;
return CUPS_BACKEND_OK;
}
goto top;
}
-static int mitsup95d_main_loop(void *vctx, int copies) {
+static int mitsup95d_main_loop(void *vctx, const void *vjob) {
struct mitsup95d_ctx *ctx = vctx;
- uint8_t querycmd[4] = { 0x1b, 0x72, 0x00, 0x00 };
- uint8_t queryresp[9];
-
+ uint8_t queryresp[QUERYRESP_SIZE_MAX];
int ret;
- int num;
+
+ const struct mitsup95d_printjob *job = vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
- /* P93D is ... special. Windows switches to this halfway through
- but it seems be okay to use it everywhere */
- if (ctx->type == P_MITSU_P93D) {
- querycmd[2] = 0x03;
- }
-
- /* Update printjob header to reflect number of requested copies */
- if (ctx->hdr2[13] != 0xff)
- ctx->hdr2[13] = copies;
-
- if (ctx->type == P_MITSU_P95D) {
- /* XXX Update unknown header field to match sniffs */
- if (ctx->hdr1[18] == 0x00)
- ctx->hdr1[18] = 0x01;
- }
INFO("Waiting for printer idle\n");
/* Query Status to make sure printer is idle */
do {
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- querycmd, sizeof(querycmd))))
- return CUPS_BACKEND_FAILED;
- ret = read_data(ctx->dev, ctx->endp_up,
- queryresp, sizeof(queryresp), &num);
- if (ret < 0)
- return CUPS_BACKEND_FAILED;
- if (ctx->type == P_MITSU_P95D && num != 9) {
- return CUPS_BACKEND_FAILED;
- } else if (ctx->type == P_MITSU_P93D && num != 8) {
- return CUPS_BACKEND_FAILED;
- }
+ ret = mitsup95d_get_status(ctx, queryresp);
+ if (ret)
+ return ret;
if (ctx->type == P_MITSU_P95D) {
- if (queryresp[5] & 0x40) {
- ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
+ if (queryresp[6] & 0x40) {
+ INFO("Printer Status: %s (%02x)\n", mitsup95d_errors(queryresp[6]), queryresp[6]);
return CUPS_BACKEND_STOP;
}
if (queryresp[5] == 0x00)
@@ -327,62 +397,47 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
INFO("Sending print job\n");
/* Send over Memory Clear, if present */
- if (ctx->mem_clr_present) {
+ if (job->mem_clr_present) {
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->mem_clr, sizeof(ctx->mem_clr))))
+ job->mem_clr, sizeof(job->mem_clr))))
return CUPS_BACKEND_FAILED;
}
/* Send Job Start */
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->hdr, sizeof(ctx->hdr))))
+ job->hdr, sizeof(job->hdr))))
return CUPS_BACKEND_FAILED;
/* Send over headers */
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->hdr1, sizeof(ctx->hdr1))))
+ job->hdr1, sizeof(job->hdr1))))
return CUPS_BACKEND_FAILED;
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->hdr2, sizeof(ctx->hdr2))))
+ job->hdr2, sizeof(job->hdr2))))
return CUPS_BACKEND_FAILED;
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->hdr3, sizeof(ctx->hdr3))))
+ job->hdr3, sizeof(job->hdr3))))
return CUPS_BACKEND_FAILED;
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->hdr4, ctx->hdr4_len)))
+ job->hdr4, job->hdr4_len)))
return CUPS_BACKEND_FAILED;
/* Send plane header and image data */
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->plane, sizeof(ctx->plane))))
+ job->plane, sizeof(job->plane))))
return CUPS_BACKEND_FAILED;
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
/* Query Status to sanity-check job */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- querycmd, sizeof(querycmd))))
- return CUPS_BACKEND_FAILED;
- ret = read_data(ctx->dev, ctx->endp_up,
- queryresp, sizeof(queryresp), &num);
-
- if (ret < 0)
- return CUPS_BACKEND_FAILED;
- if (ctx->type == P_MITSU_P95D && num != 9) {
- return CUPS_BACKEND_FAILED;
- } else if (ctx->type == P_MITSU_P93D && num != 8) {
- return CUPS_BACKEND_FAILED;
- }
-
- if (queryresp[5] & 0x40) {
- ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
- return CUPS_BACKEND_STOP;
- }
+ ret = mitsup95d_get_status(ctx, queryresp);
+ if (ret)
+ return ret;
if (ctx->type == P_MITSU_P95D) {
- if (queryresp[5] & 0x40) {
- ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
+ if (queryresp[6] & 0x40) {
+ INFO("Printer Status: %s (%02x)\n", mitsup95d_errors(queryresp[6]), queryresp[6]);
return CUPS_BACKEND_STOP;
}
if (queryresp[5] != 0x00) {
@@ -391,7 +446,7 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
}
} else {
if (queryresp[6] == 0x45) {
- ERROR("Printer error %02x\n", queryresp[7]);
+ INFO("Printer Status: %s (%02x)\n", mitsup93d_errors(queryresp[7]), queryresp[7]);
return CUPS_BACKEND_STOP;
}
if (queryresp[6] != 0x30) {
@@ -402,7 +457,7 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
/* Send over Footer */
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->ftr, sizeof(ctx->ftr))))
+ job->ftr, sizeof(job->ftr))))
return CUPS_BACKEND_FAILED;
INFO("Waiting for completion\n");
@@ -412,23 +467,13 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
sleep(1);
/* Query Status */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- querycmd, sizeof(querycmd))))
- return CUPS_BACKEND_FAILED;
- ret = read_data(ctx->dev, ctx->endp_up,
- queryresp, sizeof(queryresp), &num);
-
- if (ret < 0)
- return CUPS_BACKEND_FAILED;
- if (ctx->type == P_MITSU_P95D && num != 9) {
- return CUPS_BACKEND_FAILED;
- } else if (ctx->type == P_MITSU_P93D && num != 8) {
- return CUPS_BACKEND_FAILED;
- }
+ ret = mitsup95d_get_status(ctx, queryresp);
+ if (ret)
+ return ret;
if (ctx->type == P_MITSU_P95D) {
- if (queryresp[5] & 0x40) {
- ERROR("Printer error %02x\n", queryresp[5]); // XXX decode
+ if (queryresp[6] & 0x40) {
+ INFO("Printer Status: %s (%02x)\n", mitsup95d_errors(queryresp[6]), queryresp[6]);
return CUPS_BACKEND_STOP;
}
if (queryresp[5] == 0x00)
@@ -442,7 +487,7 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
}
} else {
if (queryresp[6] == 0x45) {
- ERROR("Printer error %02x\n", queryresp[7]);
+ INFO("Printer Status: %s (%02x)\n", mitsup93d_errors(queryresp[7]), queryresp[7]);
return CUPS_BACKEND_STOP;
}
if (queryresp[6] == 0x30)
@@ -460,17 +505,57 @@ static int mitsup95d_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_OK;
}
+static int mitsup95d_dump_status(struct mitsup95d_ctx *ctx)
+{
+ uint8_t queryresp[QUERYRESP_SIZE_MAX];
+ int ret;
+
+ ret = mitsup95d_get_status(ctx, queryresp);
+ if (ret)
+ return ret;
+
+ if (ctx->type == P_MITSU_P95D) {
+ if (queryresp[6] & 0x40) {
+ INFO("Printer Status: %s (%02x)\n", mitsup95d_errors(queryresp[6]), queryresp[6]);
+ } else if (queryresp[5] == 0x00) {
+ INFO("Printer Status: Idle\n");
+ } else if (queryresp[5] == 0x02 && queryresp[7] > 0) {
+ INFO("Printer Status: Printing (%d) copies remaining\n", queryresp[7]);
+ }
+ } else {
+ if (queryresp[6] == 0x45) {
+ INFO("Printer Status: %s (%02x)\n", mitsup93d_errors(queryresp[7]), queryresp[7]);
+ } else if (queryresp[6] == 0x30) {
+ INFO("Printer Status: Idle\n");
+ } else if (queryresp[6] == 0x43 && queryresp[7] > 0) {
+ INFO("Printer Status: Printing (%d) copies remaining\n", queryresp[7]);
+ }
+ }
+
+ return CUPS_BACKEND_OK;
+}
+
+static void mitsup95d_cmdline(void)
+{
+ DEBUG("\t\t[ -s ] # Query status\n");
+}
+
static int mitsup95d_cmdline_arg(void *vctx, int argc, char **argv)
{
- struct canonselphy_ctx *ctx = vctx;
+ struct mitsup95d_ctx *ctx = vctx;
int i, j = 0;
if (!ctx)
return -1;
- while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL)) >= 0) {
+ while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "s")) >= 0) {
switch(i) {
GETOPT_PROCESS_GLOBAL
+ case 's':
+ j = mitsup95d_dump_status(ctx);
+ break;
+ default:
+ break; /* Ignore completely */
}
if (j) return j;
@@ -479,21 +564,58 @@ static int mitsup95d_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int mitsup95d_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct mitsup95d_ctx *ctx = vctx;
+ uint8_t queryresp[QUERYRESP_SIZE_MAX];
+
+ if (mitsup95d_get_status(ctx, queryresp))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = -3;
+
+ if (ctx->type == P_MITSU_P95D) {
+ if (queryresp[6] & 0x40) {
+ ctx->marker.levelnow = 0;
+ }
+ } else {
+ if (queryresp[6] == 0x45) {
+ ctx->marker.levelnow = 0;
+ }
+ }
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *mitsup95d_prefixes[] = {
+ "mitsup9x", // Family driver name
+ "mitsubishi-p95d", "mitsubishi-p93d",
+ // backwards compatibility
+ "mitsup95d", "mitsup93d",
+ NULL
+};
+
/* Exported */
struct dyesub_backend mitsup95d_backend = {
.name = "Mitsubishi P93D/P95D",
- .version = "0.05",
- .uri_prefix = "mitsup95d",
+ .version = "0.11",
+ .uri_prefixes = mitsup95d_prefixes,
.cmdline_arg = mitsup95d_cmdline_arg,
+ .cmdline_usage = mitsup95d_cmdline,
.init = mitsup95d_init,
.attach = mitsup95d_attach,
.teardown = mitsup95d_teardown,
+ .cleanup_job = mitsup95d_cleanup_job,
.read_parse = mitsup95d_read_parse,
.main_loop = mitsup95d_main_loop,
+ .query_markers = mitsup95d_query_markers,
.devices = {
- { USB_VID_MITSU, USB_PID_MITSU_P93D, P_MITSU_P93D, ""},
- { USB_VID_MITSU, USB_PID_MITSU_P95D, P_MITSU_P95D, ""},
- { 0, 0, 0, ""}
+ { USB_VID_MITSU, USB_PID_MITSU_P93D, P_MITSU_P93D, NULL, "mitsubishi-p93d"},
+ { USB_VID_MITSU, USB_PID_MITSU_P95D, P_MITSU_P95D, NULL, "mitsubishi-p95d"},
+ { 0, 0, 0, NULL, NULL}
}
};
@@ -641,12 +763,14 @@ struct dyesub_backend mitsup95d_backend = {
STATUS query
-> 1b 72 00 00
- <- e4 72 00 00 04 XX 00 YY 00
+ <- e4 72 00 00 04 XX ZZ YY 00
YY == remaining copies
XX == Status?
00 == Idle
02 == Printing
+ ZZ == Error!
+ 00 == None
43 == Door open
44 == No Paper
4? == "Button"
diff --git a/src/cups/backend_shinkos1245.c b/src/cups/backend_shinkos1245.c
index 871dc32..cd0d34c 100644
--- a/src/cups/backend_shinkos1245.c
+++ b/src/cups/backend_shinkos1245.c
@@ -1,7 +1,7 @@
/*
* Shinko/Sinfonia CHC-S1245 CUPS backend -- libusb-1.0 version
*
- * (c) 2015-2017 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2015-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Low-level documentation was provided by Sinfonia, Inc. Thank you!
*
@@ -20,11 +20,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -395,12 +396,19 @@ struct shinkos1245_resp_matte {
uint8_t code;
uint8_t mode;
int8_t level;
- uint8_t reserved[3];
+ uint8_t reserved[4];
} __attribute__((packed));
#define MATTE_MODE_MATTE 0x00
/* Private data structure */
+struct shinkos1245_printjob {
+ uint8_t *databuf;
+ int datalen;
+
+ int copies;
+};
+
struct shinkos1245_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
@@ -415,8 +423,8 @@ struct shinkos1245_ctx {
int num_medias;
int media_8x12;
- uint8_t *databuf;
- int datalen;
+ struct marker marker;
+
int tonecurve;
};
@@ -497,6 +505,7 @@ static int shinkos1245_get_media(struct shinkos1245_ctx *ctx)
shinkos1245_fill_hdr(&cmd.hdr);
memset(cmd.pad, 0, sizeof(cmd.pad));
+ ctx->media_8x12 = 0;
for (i = 1 ; i <= 3 ; i++) {
cmd.cmd[0] = 0x0a | (i << 4);
@@ -512,20 +521,21 @@ static int shinkos1245_get_media(struct shinkos1245_ctx *ctx)
return -99;
}
- if (resp.count > NUM_MEDIAS)
- resp.count = NUM_MEDIAS;
-
/* Store media info */
- for (j = 0; j < resp.count ; j++) {
+ for (j = 0; j < NUM_MEDIAS && ctx->num_medias < 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 (ctx->medias[i].rows >= 3636)
+ ctx->media_8x12 = 1;
}
- if (resp.count < 5)
+ /* Once we've parsed them all.. we're done */
+ if (ctx->num_medias == resp.count)
break;
}
return ret;
@@ -566,7 +576,7 @@ static int shinkos1245_set_printerid(struct shinkos1245_ctx *ctx,
for (i = 0 ; i < (int)sizeof(cmd.data) ; i++) {
if (*id)
- cmd.data[i] = (uint8_t) *id;
+ cmd.data[i] = (uint8_t) *id++;
else
cmd.data[i] = ' ';
}
@@ -869,7 +879,8 @@ static char* shinkos1245_tonecurves(int type, int table)
}
}
-static void shinkos1245_dump_status(struct shinkos1245_resp_status *sts)
+static void shinkos1245_dump_status(struct shinkos1245_ctx *ctx,
+ struct shinkos1245_resp_status *sts)
{
char *detail;
switch (sts->print_status) {
@@ -895,8 +906,8 @@ static void shinkos1245_dump_status(struct shinkos1245_resp_status *sts)
INFO("\tLifetime : %u\n", be32_to_cpu(sts->counters.lifetime));
INFO("\tThermal Head : %u\n", be32_to_cpu(sts->counters.maint));
INFO("\tMedia : %u\n", be32_to_cpu(sts->counters.media));
+ INFO("\tRemaining : %u\n", ctx->marker.levelmax - be32_to_cpu(sts->counters.media));
INFO("\tCutter : %u\n", be32_to_cpu(sts->counters.cutter));
-
INFO("Versions:\n");
INFO("\tUSB Boot : %u\n", sts->counters.ver_boot);
INFO("\tUSB Control : %u\n", sts->counters.ver_ctrl);
@@ -934,10 +945,12 @@ static void shinkos1245_dump_status(struct shinkos1245_resp_status *sts)
}
static void shinkos1245_dump_media(struct shinkos1245_mediadesc *medias,
+ int media_8x12,
int count)
{
int i;
+ INFO("Loaded media type: %s\n", media_8x12 ? "8x12" : "8x10");
INFO("Supported print sizes: %d\n", count);
for (i = 0 ; i < count ; i++) {
@@ -945,7 +958,7 @@ static void shinkos1245_dump_media(struct shinkos1245_mediadesc *medias,
medias[i].print_type,
medias[i].columns,
medias[i].rows,
- medias[i].code, medias[i].type);
+ medias[i].type, medias[i].print_type);
}
}
@@ -1020,6 +1033,7 @@ static int get_tonecurve(struct shinkos1245_ctx *ctx, int type, int table, char
if (ret < 0)
goto done;
ptr += num;
+ remaining -= num;
}
/* Issue a tone_end */
@@ -1143,6 +1157,7 @@ static int set_tonecurve(struct shinkos1245_ctx *ctx, int type, int table, char
if (ret < 0)
goto done;
ptr += num;
+ remaining -= num;
}
/* Issue a tone_end */
@@ -1214,7 +1229,7 @@ int shinkos1245_cmdline_arg(void *vctx, int argc, char **argv)
case 'm':
j = shinkos1245_get_media(ctx);
if (!j)
- shinkos1245_dump_media(ctx->medias, ctx->num_medias);
+ shinkos1245_dump_media(ctx->medias, ctx->media_8x12, ctx->num_medias);
break;
case 'R':
j = shinkos1245_reset(ctx);
@@ -1223,7 +1238,7 @@ int shinkos1245_cmdline_arg(void *vctx, int argc, char **argv)
struct shinkos1245_resp_status sts;
j = shinkos1245_get_status(ctx, &sts);
if (!j)
- shinkos1245_dump_status(&sts);
+ shinkos1245_dump_status(ctx, &sts);
break;
}
case 'u': {
@@ -1267,29 +1282,54 @@ static void *shinkos1245_init(void)
return ctx;
}
-static void shinkos1245_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int shinkos1245_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ 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);
+ ctx->type = type;
/* Ensure jobid is sane */
ctx->jobid = jobid & 0x7f;
if (!ctx->jobid)
ctx->jobid++;
+
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Query Media */
+ if (shinkos1245_get_media(ctx))
+ return CUPS_BACKEND_FAILED;
+ if (!ctx->num_medias) {
+ ERROR("Media Query Error\n");
+ return CUPS_BACKEND_FAILED;
+ }
+ } else {
+ int media_code = 1;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
+
+ ctx->media_8x12 = media_code;
+ ctx->num_medias = 0;
+ }
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = ctx->media_8x12 ? "8x12" : "8x10";
+ ctx->marker.levelmax = ctx->media_8x12 ? 230 : 280;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
}
+static void shinkos1245_cleanup_job(const void *vjob)
+{
+ const struct shinkos1245_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
+}
static void shinkos1245_teardown(void *vctx) {
struct shinkos1245_ctx *ctx = vctx;
@@ -1297,31 +1337,43 @@ static void shinkos1245_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
-
free(ctx);
}
-static int shinkos1245_read_parse(void *vctx, int data_fd) {
+static int shinkos1245_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct shinkos1245_ctx *ctx = vctx;
int ret;
uint8_t tmpbuf[4];
+ struct shinkos1245_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
+
/* Read in then validate header */
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0)
+ if (ret < 0) {
+ shinkos1245_cleanup_job(job);
return ret;
- if (ret < 0 || ret != sizeof(ctx->hdr))
+ }
+ if (ret != sizeof(ctx->hdr)) {
+ shinkos1245_cleanup_job(job);
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");
+ shinkos1245_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -1329,6 +1381,7 @@ static int shinkos1245_read_parse(void *vctx, int data_fd) {
if(ctx->hdr.model != 1245) {
ERROR("Unrecognized printer (%u)!\n", ctx->hdr.model);
+ shinkos1245_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -1343,27 +1396,24 @@ static int shinkos1245_read_parse(void *vctx, int data_fd) {
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) {
+ job->datalen = ctx->hdr.rows * ctx->hdr.columns * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ shinkos1245_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
+ shinkos1245_cleanup_job(job);
return ret;
}
ptr += ret;
@@ -1377,6 +1427,7 @@ static int shinkos1245_read_parse(void *vctx, int data_fd) {
ERROR("Read failed (%d/%d/%d)\n",
ret, 4, 4);
perror("ERROR: Read failed");
+ shinkos1245_cleanup_job(job);
return ret;
}
if (tmpbuf[0] != 0x04 ||
@@ -1384,29 +1435,30 @@ static int shinkos1245_read_parse(void *vctx, int data_fd) {
tmpbuf[2] != 0x02 ||
tmpbuf[3] != 0x01) {
ERROR("Unrecognized footer data format!\n");
+ shinkos1245_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
+ *vjob = job;
return CUPS_BACKEND_OK;
}
-static int shinkos1245_main_loop(void *vctx, int copies) {
+static int shinkos1245_main_loop(void *vctx, const void *vjob) {
struct shinkos1245_ctx *ctx = vctx;
int i, num, last_state = -1, state = S_IDLE;
struct shinkos1245_resp_status status1, status2;
- /* Query Media information if necessary */
- if (!ctx->num_medias)
- shinkos1245_get_media(ctx);
- if (!ctx->num_medias) {
- ERROR("Media Query Error\n");
+ const struct shinkos1245_printjob *job = vjob;
+
+ if (!ctx)
return CUPS_BACKEND_FAILED;
- }
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
+ copies = job->copies;
+
/* Make sure print size is supported */
for (i = 0 ; i < ctx->num_medias ; i++) {
- if (ctx->medias[i].rows >= 3636)
- ctx->media_8x12 = 1;
-
if (ctx->hdr.media == ctx->medias[i].code &&
ctx->hdr.method == ctx->medias[i].print_type &&
ctx->hdr.rows == ctx->medias[i].rows &&
@@ -1422,13 +1474,6 @@ static int shinkos1245_main_loop(void *vctx, int copies) {
if (copies > 9999) // XXX test against remaining media?
copies = 9999;
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", ctx->media_8x12? "8x12" : "8x10");
- ATTR("marker-types=ribbonWax\n");
-
top:
if (state != last_state) {
if (dyesub_debug)
@@ -1452,14 +1497,6 @@ top:
if (status1.state.status1 == STATE_STATUS1_ERROR)
goto printer_error;
- /* Work out the remaining media percentage */
- {
- int remain = ctx->media_8x12 ? 230 : 280;
-
- remain = (remain - be32_to_cpu(status1.counters.media)) * 100 / remain;
- ATTR("marker-levels=%d\n", remain);
- }
-
last_state = state;
fflush(stderr);
@@ -1515,7 +1552,7 @@ top:
if (i < 0)
goto printer_error;
if (i > 0) {
- INFO("Can't set matte intensity when printing in progres...\n");
+ INFO("Can't set matte intensity when printing in progress...\n");
state = S_IDLE;
sleep(1);
break;
@@ -1561,7 +1598,7 @@ top:
/* Send over data */
INFO("Sending image data to printer\n");
if ((i = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
@@ -1588,11 +1625,6 @@ top:
INFO("Print complete\n");
- if (copies && --copies) {
- state = S_IDLE;
- goto top;
- }
-
return CUPS_BACKEND_OK;
printer_error:
@@ -1634,25 +1666,53 @@ static int shinkos1245_query_serno(struct libusb_device_handle *dev, uint8_t end
return CUPS_BACKEND_OK;
}
+static int shinkos1245_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct shinkos1245_ctx *ctx = vctx;
+ struct shinkos1245_resp_status status;
+
+ /* Query status */
+ if (shinkos1245_get_status(ctx, &status))
+ return CUPS_BACKEND_FAILED;
+
+ ctx->marker.levelnow = ctx->marker.levelmax - be32_to_cpu(status.counters.media);
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S1245 0x0007
+static const char *shinkos1245_prefixes[] = {
+ "shinko-chcs1245",
+ // extra
+ "sinfonia-chcs1245",
+ // backwards-compatibility
+ "shinkos1245",
+ NULL
+};
+
struct dyesub_backend shinkos1245_backend = {
- .name = "Shinko/Sinfonia CHC-S1245",
- .version = "0.13WIP",
- .uri_prefix = "shinkos1245",
+ .name = "Shinko/Sinfonia CHC-S1245/E1",
+ .version = "0.26",
+ .uri_prefixes = shinkos1245_prefixes,
.cmdline_usage = shinkos1245_cmdline,
.cmdline_arg = shinkos1245_cmdline_arg,
.init = shinkos1245_init,
.attach = shinkos1245_attach,
.teardown = shinkos1245_teardown,
+ .cleanup_job = shinkos1245_cleanup_job,
.read_parse = shinkos1245_read_parse,
.main_loop = shinkos1245_main_loop,
.query_serno = shinkos1245_query_serno,
+ .query_markers = shinkos1245_query_markers,
.devices = {
- { USB_VID_SHINKO, USB_PID_SHINKO_S1245, P_SHINKO_S1245, ""},
- { 0, 0, 0, ""}
+ { USB_VID_SHINKO, USB_PID_SHINKO_S1245, P_SHINKO_S1245, NULL, "shinko-chcs1245"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_shinkos2145.c b/src/cups/backend_shinkos2145.c
index c270d3c..749b59a 100644
--- a/src/cups/backend_shinkos2145.c
+++ b/src/cups/backend_shinkos2145.c
@@ -1,7 +1,7 @@
/*
* Shinko/Sinfonia CHC-S2145 CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Development of this backend was sponsored by:
*
@@ -22,11 +22,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -90,25 +91,6 @@ struct s2145_printjob_hdr {
uint32_t unk21;
} __attribute__((packed));
-/* Private data structure */
-struct shinkos2145_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
- uint8_t jobid;
-
- struct s2145_printjob_hdr hdr;
-
- uint8_t *databuf;
- int datalen;
-
- uint16_t last_donor;
- uint16_t last_remain;
- uint16_t media_prints;
-};
-
/* Structs for printer */
struct s2145_cmd_hdr {
uint16_t cmd;
@@ -163,7 +145,7 @@ static char *cmd_names(uint16_t v) {
default:
return "Unknown Command";
}
-};
+}
struct s2145_print_cmd {
struct s2145_cmd_hdr hdr;
@@ -802,6 +784,29 @@ struct s2145_getunique_resp {
uint8_t data[24]; /* Not necessarily all used. */
} __attribute__((packed));
+/* Private data structure */
+struct shinkos2145_printjob {
+ struct s2145_printjob_hdr hdr;
+
+ uint8_t *databuf;
+ int datalen;
+ int copies;
+};
+
+struct shinkos2145_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+
+ uint8_t jobid;
+
+ int type;
+
+ struct s2145_mediainfo_resp media;
+ struct marker marker;
+ int media_code;
+};
+
#define READBACK_LEN 128 /* Needs to be larger than largest response hdr */
#define CMDBUF_LEN sizeof(struct s2145_print_cmd)
@@ -972,27 +977,10 @@ static int get_errorlog(struct shinkos2145_ctx *ctx)
return 0;
}
-static int get_mediainfo(struct shinkos2145_ctx *ctx)
+static void dump_mediainfo(struct s2145_mediainfo_resp *resp)
{
- struct s2145_cmd_hdr cmd;
- struct s2145_mediainfo_resp *resp = (struct s2145_mediainfo_resp *) rdbuf;
- int ret, num = 0;
int i;
- cmd.cmd = cpu_to_le16(S2145_CMD_MEDIAINFO);
- cmd.len = cpu_to_le16(0);
-
- if ((ret = s2145_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 s2145_mediainfo_resp) - sizeof(struct s2145_status_hdr)))
- return -2;
-
INFO("Supported Media Information: %u entries:\n", resp->count);
for (i = 0 ; i < resp->count ; i++) {
INFO(" %02d: C 0x%02x (%s), %04ux%04u, M 0x%02x (%s), P 0x%02x (%s)\n", i,
@@ -1002,7 +990,6 @@ static int get_mediainfo(struct shinkos2145_ctx *ctx)
resp->items[i].media_type, media_types(resp->items[i].media_type),
resp->items[i].print_type, print_methods(resp->items[i].print_type));
}
- return 0;
}
static int get_user_string(struct shinkos2145_ctx *ctx)
@@ -1215,8 +1202,14 @@ static int get_tonecurve(struct shinkos2145_ctx *ctx, int type, char *fname)
/* Byteswap appropriately */
curves[i] = cpu_to_be16(le16_to_cpu(curves[i]));
}
- write(tc_fd, curves, UPDATE_SIZE * sizeof(uint16_t));
+ ret = write(tc_fd, curves, UPDATE_SIZE * sizeof(uint16_t));
+ if (ret < 0)
+ ERROR("Can't write curve file\n");
+ else
+ ret = 0;
+
close(tc_fd);
+
}
done:
@@ -1350,7 +1343,7 @@ int shinkos2145_cmdline_arg(void *vctx, int argc, char **argv)
j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
break;
case 'm':
- j = get_mediainfo(ctx);
+ dump_mediainfo(&ctx->media);
break;
case 'r':
j = reset_curve(ctx, RESET_USER_CURVE);
@@ -1394,30 +1387,73 @@ static void *shinkos2145_init(void)
return ctx;
}
-static void shinkos2145_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int shinkos2145_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ 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;
+ int i;
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);
+ ctx->type = type;
/* Ensure jobid is sane */
ctx->jobid = (jobid & 0x7f);
if (!ctx->jobid)
ctx->jobid++;
- /* Initialize donor */
- ctx->last_donor = ctx->last_remain = ctx->media_prints = 65535;
+ int media_prints = 65536;
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Query Media */
+ struct s2145_cmd_hdr cmd;
+ struct s2145_mediainfo_resp *resp = (struct s2145_mediainfo_resp *) rdbuf;
+ int num = 0;
+
+ cmd.cmd = cpu_to_le16(S2145_CMD_MEDIAINFO);
+ cmd.len = cpu_to_le16(0);
+
+ if (s2145_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+ memcpy(&ctx->media, resp, sizeof(ctx->media));
+
+ /* Figure out the media type... */
+ for (i = 0 ; i < ctx->media.count ; i++) {
+ if (print_counts(ctx->media.items[i].code) < media_prints) {
+ media_prints = print_counts(ctx->media.items[i].code);
+ ctx->media_code = ctx->media.items[i].code;
+ }
+ }
+ } else {
+ int media_code = PRINT_MEDIA_6x9;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
+
+ media_prints = 680;
+ ctx->media_code = media_code;
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = print_sizes(ctx->media_code);
+ ctx->marker.levelmax = media_prints;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void shinkos2145_cleanup_job(const void *vjob)
+{
+ const struct shinkos2145_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void shinkos2145_teardown(void *vctx) {
@@ -1426,64 +1462,66 @@ static void shinkos2145_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
-
free(ctx);
}
-static int shinkos2145_read_parse(void *vctx, int data_fd) {
+static int shinkos2145_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct shinkos2145_ctx *ctx = vctx;
int ret;
uint8_t tmpbuf[4];
+ struct shinkos2145_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies; // XXX hdr.copies
+
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->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) {
+ if (le32_to_cpu(job->hdr.len1) != 0x10 ||
+ le32_to_cpu(job->hdr.len2) != 0x64 ||
+ le32_to_cpu(job->hdr.dpi) != 300) {
ERROR("Unrecognized header data format!\n");
return CUPS_BACKEND_CANCEL;
}
- if (le32_to_cpu(ctx->hdr.model) != 2145) {
- ERROR("Unrecognized printer (%u)!\n", le32_to_cpu(ctx->hdr.model));
+ if (le32_to_cpu(job->hdr.model) != 2145) {
+ ERROR("Unrecognized printer (%u)!\n", le32_to_cpu(job->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) {
+ job->datalen = le32_to_cpu(job->hdr.rows) * le32_to_cpu(job->hdr.columns) * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
return ret;
}
@@ -1508,10 +1546,12 @@ static int shinkos2145_read_parse(void *vctx, int data_fd) {
return CUPS_BACKEND_FAILED;
}
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int shinkos2145_main_loop(void *vctx, int copies) {
+static int shinkos2145_main_loop(void *vctx, const void *vjob) {
struct shinkos2145_ctx *ctx = vctx;
int ret, num;
@@ -1523,49 +1563,22 @@ static int shinkos2145_main_loop(void *vctx, int copies) {
struct s2145_cmd_hdr *cmd = (struct s2145_cmd_hdr *) cmdbuf;;
struct s2145_print_cmd *print = (struct s2145_print_cmd *) cmdbuf;
struct s2145_status_resp *sts = (struct s2145_status_resp *) rdbuf;
- struct s2145_mediainfo_resp *media = (struct s2145_mediainfo_resp *) rdbuf;
- /* Send Media Query */
- memset(cmdbuf, 0, CMDBUF_LEN);
- cmd->cmd = cpu_to_le16(S2145_CMD_MEDIAINFO);
- cmd->len = cpu_to_le16(0);
-
- if ((ret = s2145_do_cmd(ctx,
- cmdbuf, sizeof(*cmd),
- sizeof(*media),
- &num)) < 0) {
- ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd));
- return CUPS_BACKEND_FAILED;
- }
-
- if (le16_to_cpu(media->hdr.payload_len) != (sizeof(struct s2145_mediainfo_resp) - sizeof(struct s2145_status_hdr)))
- return CUPS_BACKEND_FAILED;
+ struct shinkos2145_printjob *job = (struct shinkos2145_printjob*) vjob;
/* Validate print sizes */
- for (i = 0; i < media->count ; i++) {
- /* Figure out the media type... */
- int media_prints = print_counts(media->items[i].code);
- if (media_prints < ctx->media_prints)
- ctx->media_prints = media_prints;
-
+ for (i = 0; i < ctx->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)) &&
- media->items[i].print_type == le32_to_cpu(ctx->hdr.method))
+ if (le16_to_cpu(ctx->media.items[i].columns) == cpu_to_le16(le32_to_cpu(job->hdr.columns)) &&
+ le16_to_cpu(ctx->media.items[i].rows) == cpu_to_le16(le32_to_cpu(job->hdr.rows)) &&
+ ctx->media.items[i].print_type == le32_to_cpu(job->hdr.method))
break;
}
- if (i == media->count) {
+ if (i == ctx->media.count) {
ERROR("Incorrect media loaded for print!\n");
return CUPS_BACKEND_HOLD;
}
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='Color'\n");
- ATTR("marker-types=ribbonWax\n");
-
// XXX check copies against remaining media!
top:
@@ -1588,23 +1601,14 @@ top:
}
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- uint16_t donor, remain;
-
memcpy(rdbuf2, rdbuf, READBACK_LEN);
INFO("Printer Status: 0x%02x (%s)\n",
sts->hdr.status, status_str(sts->hdr.status));
- /* Guessimate a percentage for the remaining media */
- donor = le32_to_cpu(sts->count_ribbon_left) * 100 / ctx->media_prints;
- if (donor != ctx->last_donor) {
- ctx->last_donor = donor;
- ATTR("marker-levels=%d\n", donor);
- }
- remain = le32_to_cpu(sts->count_ribbon_left);
- if (remain != ctx->last_remain) {
- ctx->last_remain = remain;
- ATTR("marker-message=\"%d prints remaining on ribbon\"\n", remain);
+ if (ctx->marker.levelnow != (int)sts->count_ribbon_left) {
+ ctx->marker.levelnow = sts->count_ribbon_left;
+ dump_markers(&ctx->marker, 1, 0);
}
if (sts->hdr.result != RESULT_SUCCESS)
@@ -1647,12 +1651,12 @@ top:
print->hdr.len = cpu_to_le16(sizeof (*print) - sizeof(*cmd));
print->id = ctx->jobid;
- print->count = cpu_to_le16(copies);
- print->columns = cpu_to_le16(le32_to_cpu(ctx->hdr.columns));
- print->rows = cpu_to_le16(le32_to_cpu(ctx->hdr.rows));
- print->media = le32_to_cpu(ctx->hdr.media);
- print->mode = le32_to_cpu(ctx->hdr.mode);
- print->method = le32_to_cpu(ctx->hdr.method);
+ print->count = cpu_to_le16(job->copies);
+ print->columns = cpu_to_le16(le32_to_cpu(job->hdr.columns));
+ print->rows = cpu_to_le16(le32_to_cpu(job->hdr.rows));
+ print->media = le32_to_cpu(job->hdr.media);
+ print->mode = le32_to_cpu(job->hdr.mode);
+ print->method = le32_to_cpu(job->hdr.method);
if ((ret = s2145_do_cmd(ctx,
cmdbuf, sizeof(*print),
@@ -1675,7 +1679,7 @@ top:
INFO("Sending image data to printer\n");
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
@@ -1687,7 +1691,8 @@ top:
INFO("Fast return mode enabled.\n");
state = S_FINISHED;
} else if (sts->hdr.status == STATUS_READY ||
- sts->hdr.status == STATUS_FINISHED) {
+ sts->hdr.status == STATUS_FINISHED ||
+ sts->hdr.status == ERROR_PRINTER) {
state = S_FINISHED;
}
break;
@@ -1698,6 +1703,16 @@ top:
if (state != S_FINISHED)
goto top;
+ if (sts->hdr.status == ERROR_PRINTER) {
+ if(sts->hdr.error == ERROR_NONE)
+ sts->hdr.error = sts->hdr.status;
+ INFO(" Error 0x%02x (%s) 0x%02x/0x%02x (%s)\n",
+ sts->hdr.error,
+ error_str(sts->hdr.error),
+ sts->hdr.printer_major,
+ sts->hdr.printer_minor, error_codes(sts->hdr.printer_major, sts->hdr.printer_minor));
+ }
+
INFO("Print complete\n");
return CUPS_BACKEND_OK;
@@ -1747,25 +1762,63 @@ static int shinkos2145_query_serno(struct libusb_device_handle *dev, uint8_t end
return CUPS_BACKEND_OK;
}
+static int shinkos2145_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct shinkos2145_ctx *ctx = vctx;
+ struct s2145_cmd_hdr cmd;
+ struct s2145_status_resp *sts = (struct s2145_status_resp *) rdbuf;
+ int num;
+
+ /* Query Status */
+ cmd.cmd = cpu_to_le16(S2145_CMD_STATUS);
+ cmd.len = cpu_to_le16(0);
+
+ if (s2145_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*sts),
+ &num)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ctx->marker.levelnow = ctx->marker.levelmax - le32_to_cpu(sts->count_ribbon_left);
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S2145 0x000E
+static const char *shinkos2145_prefixes[] = {
+ "shinko-chcs2145",
+ // extras
+ "sinfonia-chcs2145",
+ // Backwards compatibility
+ "shinkos2145",
+ NULL
+};
+
struct dyesub_backend shinkos2145_backend = {
- .name = "Shinko/Sinfonia CHC-S2145",
- .version = "0.48",
- .uri_prefix = "shinkos2145",
+ .name = "Shinko/Sinfonia CHC-S2145/S2",
+ .version = "0.55",
+ .uri_prefixes = shinkos2145_prefixes,
.cmdline_usage = shinkos2145_cmdline,
.cmdline_arg = shinkos2145_cmdline_arg,
.init = shinkos2145_init,
.attach = shinkos2145_attach,
.teardown = shinkos2145_teardown,
+ .cleanup_job = shinkos2145_cleanup_job,
.read_parse = shinkos2145_read_parse,
.main_loop = shinkos2145_main_loop,
.query_serno = shinkos2145_query_serno,
+ .query_markers = shinkos2145_query_markers,
.devices = {
- { USB_VID_SHINKO, USB_PID_SHINKO_S2145, P_SHINKO_S2145, ""},
- { 0, 0, 0, ""}
+ { USB_VID_SHINKO, USB_PID_SHINKO_S2145, P_SHINKO_S2145, NULL, "shinko-chc2145"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_shinkos6145.c b/src/cups/backend_shinkos6145.c
index b9d782a..e795831 100644
--- a/src/cups/backend_shinkos6145.c
+++ b/src/cups/backend_shinkos6145.c
@@ -1,7 +1,7 @@
/*
* Shinko/Sinfonia CHC-S6145 CUPS backend -- libusb-1.0 version
*
- * (c) 2015-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2015-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Low-level documentation was provided by Sinfonia. Thank you!
*
@@ -20,8 +20,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
@@ -33,6 +32,8 @@
* You must still adhere to all other terms of the license to this program
* (ie GPLv2) and the license of the libS6145ImageProcess library.
*
+ * SPDX-License-Identifier: GPL-2.0+ with special exception
+ *
*/
#include <stdio.h>
@@ -259,43 +260,6 @@ struct shinkos6145_correctionparam {
uint8_t pad[3948]; // @12436, null.
} __attribute__((packed)); /* 16384 bytes */
-/* Private data structure */
-struct shinkos6145_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
- uint8_t jobid;
-
- struct s6145_printjob_hdr hdr;
-
- uint8_t image_avg[3]; /* CMY */
-
- uint8_t *databuf;
- size_t datalen;
-
- uint8_t ribbon_type;
- uint8_t input_ymc;
-
- uint16_t last_donor;
- uint16_t last_remain;
- uint16_t last_ribbon;
-
- uint8_t *eeprom;
- size_t eepromlen;
-
- void *dl_handle;
- ImageProcessingFN ImageProcessing;
- ImageAvrCalcFN ImageAvrCalc;
-
- struct shinkos6145_correctionparam *corrdata;
- size_t corrdatalen;
-};
-
-static int shinkos6145_get_imagecorr(struct shinkos6145_ctx *ctx);
-static int shinkos6145_get_eeprom(struct shinkos6145_ctx *ctx);
-
/* Structs for printer */
struct s6145_cmd_hdr {
uint16_t cmd;
@@ -1115,6 +1079,43 @@ struct s6145_imagecorr_data {
uint8_t data[16];
} __attribute__((packed));
+/* Private data structure */
+struct shinkos6145_printjob {
+ uint8_t *databuf;
+ size_t datalen;
+
+ struct s6145_printjob_hdr hdr;
+
+ int copies;
+};
+
+struct shinkos6145_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ uint8_t jobid;
+
+ uint8_t image_avg[3]; /* CMY */
+
+ struct marker marker;
+
+ struct s6145_mediainfo_resp media;
+
+ uint8_t *eeprom;
+ size_t eepromlen;
+
+ void *dl_handle;
+ ImageProcessingFN ImageProcessing;
+ ImageAvrCalcFN ImageAvrCalc;
+
+ struct shinkos6145_correctionparam *corrdata;
+ size_t corrdatalen;
+};
+
+static int shinkos6145_get_imagecorr(struct shinkos6145_ctx *ctx);
+static int shinkos6145_get_eeprom(struct shinkos6145_ctx *ctx);
static int get_param(struct shinkos6145_ctx *ctx, int target, uint32_t *param);
#define READBACK_LEN 512 /* Needs to be larger than largest response hdr */
@@ -1234,7 +1235,7 @@ static int get_status(struct shinkos6145_ctx *ctx)
INFO("Head Distance: %08u inches\n", le32_to_cpu(resp2->head_distance));
/* Query various params */
- if(ctx->type == P_SHINKO_S6145D) {
+ if (ctx->type == P_SHINKO_S6145D) {
if ((ret = get_param(ctx, PARAM_REGION_CODE, &val))) {
ERROR("Failed to execute command\n");
return ret;
@@ -1355,27 +1356,10 @@ static int get_errorlog(struct shinkos6145_ctx *ctx)
return 0;
}
-static int get_mediainfo(struct shinkos6145_ctx *ctx)
+static void dump_mediainfo(struct s6145_mediainfo_resp *resp)
{
- struct s6145_cmd_hdr cmd;
- struct s6145_mediainfo_resp *resp = (struct s6145_mediainfo_resp *) rdbuf;
- int ret, num = 0;
int i;
- cmd.cmd = cpu_to_le16(S6145_CMD_MEDIAINFO);
- cmd.len = cpu_to_le16(0);
-
- if ((ret = s6145_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 s6145_mediainfo_resp) - sizeof(struct s6145_status_hdr)))
- return -2;
-
INFO("Loaded Media Type: %s\n", print_ribbons(resp->ribbon));
INFO("Supported Print Sizes: %u entries:\n", resp->count);
for (i = 0 ; i < resp->count ; i++) {
@@ -1385,7 +1369,6 @@ static int get_mediainfo(struct shinkos6145_ctx *ctx)
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 shinkos6145_ctx *ctx, char *str)
@@ -1865,7 +1848,7 @@ int shinkos6145_cmdline_arg(void *vctx, int argc, char **argv)
j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
break;
case 'm':
- j = get_mediainfo(ctx);
+ dump_mediainfo(&ctx->media);
break;
case 'q':
j = shinkos6145_dump_eeprom(ctx, optarg);
@@ -1909,22 +1892,15 @@ static void *shinkos6145_init(void)
return ctx;
}
-static void shinkos6145_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int shinkos6145_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct shinkos6145_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(&shinkos6145_backend,
- desc.idVendor, desc.idProduct);
+ ctx->type = type;
/* Attempt to open the library */
#if defined(WITH_DYNAMIC)
@@ -1952,8 +1928,44 @@ static void shinkos6145_attach(void *vctx, struct libusb_device_handle *dev,
/* Ensure jobid is sane */
ctx->jobid = (jobid & 0x7f) + 1;
- /* Initialize donor */
- ctx->last_donor = ctx->last_remain = 65535;
+ if (test_mode < TEST_MODE_NOATTACH) {
+ /* Query Media */
+ struct s6145_mediainfo_resp *resp = (struct s6145_mediainfo_resp *) rdbuf;
+ struct s6145_cmd_hdr cmd;
+ int num;
+
+ if (s6145_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*resp),
+ &num)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+ memcpy(&ctx->media, resp, sizeof(*resp));
+ } else {
+ int media_code = RIBBON_6x8;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
+
+ ctx->media.ribbon = media_code;
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = print_ribbons(ctx->media.ribbon);
+ ctx->marker.levelmax = ribbon_sizes(ctx->media.ribbon);
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void shinkos6145_cleanup_job(const void *vjob)
+{
+ const struct shinkos6145_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void shinkos6145_teardown(void *vctx) {
@@ -1962,8 +1974,6 @@ static void shinkos6145_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
if (ctx->eeprom)
free(ctx->eeprom);
if (ctx->corrdata)
@@ -1976,7 +1986,9 @@ static void shinkos6145_teardown(void *vctx) {
free(ctx);
}
-static void lib6145_calc_avg(struct shinkos6145_ctx *ctx, uint16_t rows, uint16_t cols)
+static void lib6145_calc_avg(struct shinkos6145_ctx *ctx,
+ const struct shinkos6145_printjob *job,
+ uint16_t rows, uint16_t cols)
{
uint32_t plane, i, planelen;
planelen = rows * cols;
@@ -1985,7 +1997,7 @@ static void lib6145_calc_avg(struct shinkos6145_ctx *ctx, uint16_t rows, uint16_
uint64_t sum = 0;
for (i = 0 ; i < planelen ; i++) {
- sum += ctx->databuf[(planelen * plane) + i];
+ sum += job->databuf[(planelen * plane) + i];
}
ctx->image_avg[plane] = (sum / planelen);
}
@@ -2066,35 +2078,72 @@ static void lib6145_process_image(uint8_t *src, uint16_t *dest,
}
}
-static int shinkos6145_read_parse(void *vctx, int data_fd) {
+static int shinkos6145_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct shinkos6145_ctx *ctx = vctx;
int ret;
uint8_t tmpbuf[4];
+ uint8_t input_ymc;
+
+ struct shinkos6145_printjob *job = NULL;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies; // XXX hdr.copies?
+
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
+ shinkos6145_cleanup_job(job);
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->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) {
+#define SWAP_HDR(__x) job->hdr.__x = le32_to_cpu(job->hdr.__x)
+
+ SWAP_HDR(len1);
+ SWAP_HDR(model);
+ SWAP_HDR(media_w);
+ SWAP_HDR(len2);
+ SWAP_HDR(media);
+ SWAP_HDR(method);
+ SWAP_HDR(qual);
+ SWAP_HDR(oc_mode);
+ SWAP_HDR(columns);
+ SWAP_HDR(rows);
+ SWAP_HDR(copies);
+ SWAP_HDR(dpi);
+ SWAP_HDR(ext_flags);
+
+#undef SWAP_HDR
+
+ if (job->hdr.len1 != 0x10 ||
+ job->hdr.len2 != 0x64 ||
+ job->hdr.dpi != 300) {
ERROR("Unrecognized header data format!\n");
+ shinkos6145_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
- if (le32_to_cpu(ctx->hdr.model) != 6145) {
- ERROR("Unrecognized printer (%u)!\n", le32_to_cpu(ctx->hdr.model));
+ if (job->hdr.model != 6145) {
+ ERROR("Unrecognized printer (%u)!\n", job->hdr.model);
+ shinkos6145_cleanup_job(job);
+ return CUPS_BACKEND_CANCEL;
+ }
+ if (!job->hdr.rows || !job->hdr.columns) {
+ ERROR("Bad print job header!\n");
+ shinkos6145_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
}
@@ -2102,29 +2151,26 @@ static int shinkos6145_read_parse(void *vctx, int data_fd) {
When bit 0 is set, this tells the backend that the data is
already in planar YMC format (vs packed RGB) so we don't need
to do the conversion ourselves. Saves some processing overhead */
- ctx->input_ymc = le32_to_cpu(ctx->hdr.ext_flags) & 0x01;
-
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
- }
+ input_ymc = job->hdr.ext_flags & 0x01;
- ctx->datalen = le32_to_cpu(ctx->hdr.rows) * le32_to_cpu(ctx->hdr.columns) * 3;
- ctx->databuf = malloc(ctx->datalen);
- if (!ctx->databuf) {
+ job->datalen = job->hdr.rows * job->hdr.columns * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ shinkos6145_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%zu)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
+ shinkos6145_cleanup_job(job);
return ret;
}
ptr += ret;
@@ -2138,6 +2184,7 @@ static int shinkos6145_read_parse(void *vctx, int data_fd) {
ERROR("Read failed (%d/%d/%d)\n",
ret, 4, 4);
perror("ERROR: Read failed");
+ shinkos6145_cleanup_job(job);
return ret;
}
if (tmpbuf[0] != 0x04 ||
@@ -2145,13 +2192,45 @@ static int shinkos6145_read_parse(void *vctx, int data_fd) {
tmpbuf[2] != 0x02 ||
tmpbuf[3] != 0x01) {
ERROR("Unrecognized footer data format!\n");
+ shinkos6145_cleanup_job(job);
return CUPS_BACKEND_FAILED;
}
+ /* Convert packed RGB to planar YMC if necessary */
+ if (!input_ymc) {
+ INFO("Converting Packed RGB to Planar YMC\n");
+ int planelen = job->hdr.columns * job->hdr.rows;
+ uint8_t *databuf3 = malloc(job->datalen);
+ int i;
+ if (!databuf3) {
+ ERROR("Memory allocation failure!\n");
+ shinkos6145_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ for (i = 0 ; i < planelen ; i++) {
+ uint8_t r, g, b;
+ r = job->databuf[3*i];
+ g = job->databuf[3*i+1];
+ b = job->databuf[3*i+2];
+ databuf3[i] = 255 - b;
+ databuf3[planelen + i] = 255 - g;
+ databuf3[planelen + planelen + i] = 255 - r;
+ }
+ free(job->databuf);
+ job->databuf = databuf3;
+ }
+
+ // if (job->copies > 1 && hdr->media == 0 && hdr->method == 0)
+ // and if printer_media == 6x8 or 6x9
+ // combine 4x6 + 4x6 -> 8x6
+ // 1844x2492 = 1844x1240.. delta = 12.
+
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int shinkos6145_main_loop(void *vctx, int copies) {
+static int shinkos6145_main_loop(void *vctx, const void *vjob) {
struct shinkos6145_ctx *ctx = vctx;
int ret, num;
@@ -2167,6 +2246,11 @@ static int shinkos6145_main_loop(void *vctx, int copies) {
uint32_t cur_mode;
+ struct shinkos6145_printjob *job = (struct shinkos6145_printjob*) vjob; /* XXX stupid, we can't do this. */
+
+ if (!job)
+ return CUPS_BACKEND_FAILED;
+
/* Send Media Query */
memset(cmdbuf, 0, CMDBUF_LEN);
cmd->cmd = cpu_to_le16(S6145_CMD_MEDIAINFO);
@@ -2186,10 +2270,10 @@ static int shinkos6145_main_loop(void *vctx, int copies) {
/* 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)) &&
- media->items[i].print_method == le32_to_cpu(ctx->hdr.method) &&
- media->items[i].media_code == le32_to_cpu(ctx->hdr.media))
+ if (le16_to_cpu(media->items[i].columns) == job->hdr.columns &&
+ le16_to_cpu(media->items[i].rows) == job->hdr.rows &&
+ media->items[i].print_method == job->hdr.method &&
+ media->items[i].media_code == job->hdr.media)
break;
}
if (i == media->count) {
@@ -2197,16 +2281,6 @@ static int shinkos6145_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_HOLD;
}
- ctx->last_ribbon = media->ribbon;
-
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", print_ribbons(media->ribbon));
- ATTR("marker-types=ribbonWax\n");
- ctx->ribbon_type = media->ribbon;
-
// XXX check copies against remaining media?
/* Query printer mode */
@@ -2236,23 +2310,14 @@ top:
}
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- uint16_t donor, remain;
-
memcpy(rdbuf2, rdbuf, READBACK_LEN);
INFO("Printer Status: 0x%02x (%s)\n",
sts->hdr.status, status_str(sts->hdr.status));
- /* Guessimate a percentage for the remaining media */
- donor = le32_to_cpu(sts->count_ribbon_left) * 100 / ribbon_sizes(ctx->ribbon_type);
- if (donor != ctx->last_donor) {
- ctx->last_donor = donor;
- ATTR("marker-levels=%d\n", donor);
- }
- remain = le32_to_cpu(sts->count_ribbon_left);
- if (remain != ctx->last_remain) {
- ctx->last_remain = remain;
- ATTR("marker-message=\"%d prints remaining on '%s' ribbon\"\n", remain, print_ribbons(media->ribbon));
+ if (ctx->marker.levelnow != (int)sts->count_ribbon_left) {
+ ctx->marker.levelnow = sts->count_ribbon_left;
+ dump_markers(&ctx->marker, 1, 0);
}
if (sts->hdr.result != RESULT_SUCCESS)
@@ -2279,7 +2344,7 @@ top:
case S_PRINTER_READY_CMD: {
/* Set matte/etc */
- uint32_t oc_mode = le32_to_cpu(ctx->hdr.oc_mode);
+ uint32_t oc_mode = job->hdr.oc_mode;
uint32_t updated = 0;
if (!oc_mode) /* if nothing set, default to glossy */
@@ -2320,51 +2385,35 @@ top:
/* Set up library transform... */
uint32_t newlen = le16_to_cpu(ctx->corrdata->headDots) *
- le32_to_cpu(ctx->hdr.rows) * sizeof(uint16_t) * 4;
+ job->hdr.rows * sizeof(uint16_t) * 4;
uint16_t *databuf2 = malloc(newlen);
/* Set the size in the correctiondata */
- ctx->corrdata->width = cpu_to_le16(le32_to_cpu(ctx->hdr.columns));
- ctx->corrdata->height = cpu_to_le16(le32_to_cpu(ctx->hdr.rows));
-
- /* Convert packed RGB to planar YMC if necessary */
- if (!ctx->input_ymc) {
- int planelen = le16_to_cpu(ctx->corrdata->width) * le16_to_cpu(ctx->corrdata->height);
- uint8_t *databuf3 = malloc(ctx->datalen);
-
- for (i = 0 ; i < planelen ; i++) {
- uint8_t r, g, b;
- r = ctx->databuf[3*i];
- g = ctx->databuf[3*i+1];
- b = ctx->databuf[3*i+2];
- databuf3[i] = 255 - b;
- databuf3[planelen + i] = 255 - g;
- databuf3[planelen + planelen + i] = 255 - r;
- }
- free(ctx->databuf);
- ctx->databuf = databuf3;
- }
+ ctx->corrdata->width = cpu_to_le16(job->hdr.columns);
+ ctx->corrdata->height = cpu_to_le16(job->hdr.rows);
+
/* Perform the actual library transform */
if (ctx->dl_handle) {
INFO("Calling image processing library...\n");
- if (ctx->ImageAvrCalc(ctx->databuf, le32_to_cpu(ctx->hdr.columns), le32_to_cpu(ctx->hdr.rows), ctx->image_avg)) {
+ if (ctx->ImageAvrCalc(job->databuf, job->hdr.columns, job->hdr.rows, ctx->image_avg)) {
+ free(databuf2);
ERROR("Library returned error!\n");
return CUPS_BACKEND_FAILED;
}
- ctx->ImageProcessing(ctx->databuf, databuf2, ctx->corrdata);
+ ctx->ImageProcessing(job->databuf, databuf2, ctx->corrdata);
} else {
WARNING("Utilizing fallback internal image processing code\n");
WARNING(" *** Output quality will be poor! *** \n");
- lib6145_calc_avg(ctx, le32_to_cpu(ctx->hdr.columns), le32_to_cpu(ctx->hdr.rows));
- lib6145_process_image(ctx->databuf, databuf2, ctx->corrdata, oc_mode);
+ lib6145_calc_avg(ctx, job, job->hdr.columns, job->hdr.rows);
+ lib6145_process_image(job->databuf, databuf2, ctx->corrdata, oc_mode);
}
- free(ctx->databuf);
- ctx->databuf = (uint8_t*) databuf2;
- ctx->datalen = newlen;
+ free(job->databuf);
+ job->databuf = (uint8_t*) databuf2;
+ job->datalen = newlen;
INFO("Sending print job (internal id %u)\n", ctx->jobid);
@@ -2373,16 +2422,16 @@ top:
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->count = cpu_to_le16(job->copies);
+ print->columns = cpu_to_le16(job->hdr.columns);
+ print->rows = cpu_to_le16(job->hdr.rows);
print->image_avg = ctx->image_avg[2]; /* Cyan level */
- print->method = cpu_to_le32(ctx->hdr.method);
+ print->method = cpu_to_le32(job->hdr.method);
print->combo_wait = 0;
/* Brava21 header has a few quirks */
if(ctx->type == P_SHINKO_S6145D) {
- print->media = ctx->hdr.media;
+ print->media = job->hdr.media;
print->unk_1 = 0x01;
}
@@ -2409,7 +2458,7 @@ top:
// XXX we shouldn't send the lamination layer over if
// it's not needed. hdr->oc_mode == PRINT_MODE_NO_OC
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf, ctx->datalen)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
@@ -2481,27 +2530,65 @@ static int shinkos6145_query_serno(struct libusb_device_handle *dev, uint8_t end
return CUPS_BACKEND_OK;
}
+static int shinkos6145_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct shinkos6145_ctx *ctx = vctx;
+ struct s6145_cmd_hdr cmd;
+ struct s6145_status_resp *sts = (struct s6145_status_resp *) rdbuf;
+ int num;
+
+ /* Query Status */
+ cmd.cmd = cpu_to_le16(S6145_CMD_GETSTATUS);
+ cmd.len = cpu_to_le16(0);
+
+ if (s6145_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(*sts),
+ &num)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ctx->marker.levelnow = le32_to_cpu(sts->count_ribbon_left);
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S6145 0x0019
#define USB_PID_SHINKO_S6145D 0x001E /* Aka CIAAT Brava 21 */
+static const char *shinkos6145_prefixes[] = {
+ "sinfonia-chcs6145", "ciaat-brava-21",
+ // extras
+ "shinko-chcs6145",
+ // backwards-compatiblity
+ "shinkos6145", "brava21",
+ NULL
+};
+
struct dyesub_backend shinkos6145_backend = {
- .name = "Shinko/Sinfonia CHC-S6145",
- .version = "0.22",
- .uri_prefix = "shinkos6145",
+ .name = "Shinko/Sinfonia CHC-S6145/CS2",
+ .version = "0.30",
+ .uri_prefixes = shinkos6145_prefixes,
.cmdline_usage = shinkos6145_cmdline,
.cmdline_arg = shinkos6145_cmdline_arg,
.init = shinkos6145_init,
.attach = shinkos6145_attach,
.teardown = shinkos6145_teardown,
+ .cleanup_job = shinkos6145_cleanup_job,
.read_parse = shinkos6145_read_parse,
.main_loop = shinkos6145_main_loop,
.query_serno = shinkos6145_query_serno,
+ .query_markers = shinkos6145_query_markers,
.devices = {
- { USB_VID_SHINKO, USB_PID_SHINKO_S6145, P_SHINKO_S6145, ""},
- { USB_VID_SHINKO, USB_PID_SHINKO_S6145D, P_SHINKO_S6145D, ""},
- { 0, 0, 0, ""}
+ { USB_VID_SHINKO, USB_PID_SHINKO_S6145, P_SHINKO_S6145, NULL, "sinfonia-chcs6145"},
+ { USB_VID_SHINKO, USB_PID_SHINKO_S6145D, P_SHINKO_S6145D, NULL, "ciaat-brava-21"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_shinkos6245.c b/src/cups/backend_shinkos6245.c
index 44a2f7e..5d75e0d 100644
--- a/src/cups/backend_shinkos6245.c
+++ b/src/cups/backend_shinkos6245.c
@@ -1,7 +1,7 @@
/*
* Shinko/Sinfonia CHC-S6245 CUPS backend -- libusb-1.0 version
*
- * (c) 2015-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2015-2018 Solomon Peachy <pizza@shaftnet.org>
*
* Low-level documentation was provided by Sinfonia, Inc. Thank you!
*
@@ -20,11 +20,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -90,25 +91,6 @@ struct s6245_printjob_hdr {
uint32_t unk21;
} __attribute__((packed));
-/* Private data structure */
-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;
-
- uint16_t last_donor;
- uint16_t last_remain;
- uint8_t ribbon_code;
-};
-
/* Structs for printer */
struct s6245_cmd_hdr {
uint16_t cmd;
@@ -178,7 +160,7 @@ static char *cmd_names(uint16_t v) {
default:
return "Unknown Command";
}
-};
+}
struct s6245_print_cmd {
struct s6245_cmd_hdr hdr;
@@ -924,37 +906,50 @@ struct s6245_fwinfo_resp {
uint16_t checksum;
} __attribute__((packed));
+/* Private data structure */
+struct shinkos6245_printjob {
+ uint8_t *databuf;
+ int datalen;
+ int copies;
+ struct s6245_printjob_hdr hdr;
+};
+
+struct shinkos6245_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+
+ uint8_t jobid;
+
+ struct marker marker;
+
+ struct s6245_mediainfo_resp media;
+};
#define READBACK_LEN 512 /* Needs to be larger than largest response hdr */
#define CMDBUF_LEN sizeof(struct s6245_print_cmd)
-static uint8_t rdbuf[READBACK_LEN];
-
static int s6245_do_cmd(struct shinkos6245_ctx *ctx,
uint8_t *cmd, int cmdlen,
- int minlen, int *num)
+ int buflen,
+ int *num, struct s6245_status_hdr *resp)
{
- 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;
+ int ret;
if ((ret = send_data(dev, endp_down,
cmd, cmdlen)))
return (ret < 0) ? ret : -99;
ret = read_data(dev, endp_up,
- rdbuf, READBACK_LEN, num);
+ (uint8_t *)resp, buflen, 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,
@@ -971,8 +966,8 @@ static int s6245_do_cmd(struct shinkos6245_ctx *ctx,
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;
+ struct s6245_status_resp resp;
+ struct s6245_getextcounter_resp resp2;
int ret, num = 0;
cmd.cmd = cpu_to_le16(S6245_CMD_GETSTATUS);
@@ -980,48 +975,48 @@ static int get_status(struct shinkos6245_ctx *ctx)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 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("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));
+ 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)))
+ 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("\tMaintenance:\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("\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("\tMaintenance:\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));
+ 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 %03u @ %03u/%03u (%03u 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));
+ 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));
+ 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);
@@ -1029,17 +1024,17 @@ static int get_status(struct shinkos6245_ctx *ctx)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp2),
- &num)) < 0) {
+ sizeof(resp2),
+ &num, (void*)&resp2)) < 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)))
+ if (le16_to_cpu(resp2.hdr.payload_len) != (sizeof(struct s6245_getextcounter_resp) - sizeof(struct s6245_status_hdr)))
return 0;
- INFO("Lifetime Distance: %08u inches\n", le32_to_cpu(resp2->lifetime_distance));
- INFO("Maintenance Distance: %08u inches\n", le32_to_cpu(resp2->maint_distance));
- INFO("Head Distance: %08u inches\n", le32_to_cpu(resp2->head_distance));
+ INFO("Lifetime Distance: %08u inches\n", le32_to_cpu(resp2.lifetime_distance));
+ INFO("Maintenance Distance: %08u inches\n", le32_to_cpu(resp2.maint_distance));
+ INFO("Head Distance: %08u inches\n", le32_to_cpu(resp2.head_distance));
return 0;
}
@@ -1047,7 +1042,7 @@ static int get_status(struct shinkos6245_ctx *ctx)
static int get_fwinfo(struct shinkos6245_ctx *ctx)
{
struct s6245_fwinfo_cmd cmd;
- struct s6245_fwinfo_resp *resp = (struct s6245_fwinfo_resp *)rdbuf;
+ struct s6245_fwinfo_resp resp;
int num = 0;
int i;
@@ -1062,23 +1057,23 @@ static int get_fwinfo(struct shinkos6245_ctx *ctx)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 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)))
+ 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);
+ 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));
+ 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;
@@ -1087,7 +1082,7 @@ static int get_fwinfo(struct shinkos6245_ctx *ctx)
static int get_errorlog(struct shinkos6245_ctx *ctx)
{
struct s6245_errorlog_cmd cmd;
- struct s6245_errorlog_resp *resp = (struct s6245_errorlog_resp *) rdbuf;
+ struct s6245_errorlog_resp resp;
int num = 0;
int i = 0;
@@ -1100,50 +1095,33 @@ static int get_errorlog(struct shinkos6245_ctx *ctx)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 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)))
+ 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-%02u-%02u %02u:%02u:%02u @ %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));
+ 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: %02u/%02u Hum: %02u\n",
- resp->printer_thermistor, resp->head_thermistor, resp->printer_humidity);
- } while (++i < le16_to_cpu(resp->error_count));
+ 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)
+static void dump_mediainfo(struct s6245_mediainfo_resp *resp)
{
- 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("Loaded Media Type: %s\n", ribbon_sizes(resp->ribbon_code));
INFO("Supported Media Information: %u entries:\n", resp->count);
for (i = 0 ; i < resp->count ; i++) {
@@ -1153,13 +1131,12 @@ static int get_mediainfo(struct shinkos6245_ctx *ctx)
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;
+ struct s6245_status_hdr resp;
int ret, num = 0;
if (!str)
@@ -1172,8 +1149,8 @@ static int cancel_job(struct shinkos6245_ctx *ctx, char *str)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
return ret;
}
@@ -1184,7 +1161,7 @@ static int cancel_job(struct shinkos6245_ctx *ctx, char *str)
static int flash_led(struct shinkos6245_ctx *ctx)
{
struct s6245_cmd_hdr cmd;
- struct s6245_status_hdr *resp = (struct s6245_status_hdr *) rdbuf;
+ struct s6245_status_hdr resp;
int ret, num = 0;
cmd.cmd = cpu_to_le16(S6245_CMD_FLASHLED);
@@ -1192,8 +1169,8 @@ static int flash_led(struct shinkos6245_ctx *ctx)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
return ret;
}
@@ -1205,7 +1182,7 @@ static int flash_led(struct shinkos6245_ctx *ctx)
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;
+ struct s6245_status_hdr resp;
int ret, num = 0;
/* Set up command */
@@ -1217,8 +1194,8 @@ static int set_param(struct shinkos6245_ctx *ctx, int target, uint32_t param)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command (%d)\n", cmd_names(cmd.hdr.cmd), ret);
}
@@ -1228,7 +1205,7 @@ static int set_param(struct shinkos6245_ctx *ctx, int target, uint32_t param)
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;
+ struct s6245_status_hdr resp;
int ret, num = 0;
cmd.target = target;
@@ -1238,8 +1215,8 @@ static int reset_curve(struct shinkos6245_ctx *ctx, int target)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
return ret;
}
@@ -1249,8 +1226,8 @@ static int reset_curve(struct shinkos6245_ctx *ctx, int target)
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;
+ struct s6245_readtone_cmd cmd;
+ struct s6245_readtone_resp resp;
int ret, num = 0;
uint8_t *data;
@@ -1268,25 +1245,25 @@ static int get_tonecurve(struct shinkos6245_ctx *ctx, int type, char *fname)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
return ret;
}
- resp->total_size = le16_to_cpu(resp->total_size);
+ resp.total_size = le16_to_cpu(resp.total_size);
- data = malloc(resp->total_size * 2);
+ data = malloc(resp.total_size * 2);
if (!data) {
ERROR("Memory Allocation Failure!\n");
return -1;
}
i = 0;
- while (i < resp->total_size) {
+ while (i < resp.total_size) {
ret = read_data(ctx->dev, ctx->endp_up,
data + i,
- resp->total_size * 2 - i,
+ resp.total_size * 2 - i,
&num);
if (ret < 0)
goto done;
@@ -1294,7 +1271,7 @@ static int get_tonecurve(struct shinkos6245_ctx *ctx, int type, char *fname)
}
i = j = 0;
- while (i < resp->total_size) {
+ while (i < resp.total_size) {
memcpy(curves + j, data + i+2, data[i+1]);
j += data[i+1] / 2;
i += data[i+1] + 2;
@@ -1324,7 +1301,7 @@ done:
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;
+ struct s6245_status_hdr resp;
int ret, num = 0;
INFO("Set %s Tone Curve from '%s'\n", update_targets(target), fname);
@@ -1367,8 +1344,8 @@ static int set_tonecurve(struct shinkos6245_ctx *ctx, int target, char *fname)
if ((ret = s6245_do_cmd(ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd.hdr.cmd));
goto done;
}
@@ -1455,7 +1432,7 @@ int shinkos6245_cmdline_arg(void *vctx, int argc, char **argv)
j = set_tonecurve(ctx, TONECURVE_CURRENT, optarg);
break;
case 'm':
- j = get_mediainfo(ctx);
+ dump_mediainfo(&ctx->media);
break;
case 'r':
j = reset_curve(ctx, RESET_TONE_CURVE);
@@ -1491,30 +1468,61 @@ static void *shinkos6245_init(void)
return ctx;
}
-static void shinkos6245_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int shinkos6245_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ 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;
+
+ int num;
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);
+ ctx->type = type;
/* Ensure jobid is sane */
ctx->jobid = jobid & 0x7f;
if (!ctx->jobid)
ctx->jobid++;
- /* Initialize donor */
- ctx->last_donor = ctx->last_remain = 65535;
+ /* Query Media */
+ if (test_mode < TEST_MODE_NOATTACH) {
+ struct s6245_cmd_hdr cmd;
+ cmd.cmd = cpu_to_le16(S6245_CMD_MEDIAINFO);
+ cmd.len = cpu_to_le16(0);
+
+ if (s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(ctx->media),
+ &num, (void*)&ctx->media)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+ } else {
+ int media_code = 0x12;
+ if (getenv("MEDIA_CODE"))
+ media_code = atoi(getenv("MEDIA_CODE"));
+
+
+ ctx->media.ribbon_code = media_code;
+ }
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = ribbon_sizes(ctx->media.ribbon_code);
+ ctx->marker.levelmax = ribbon_counts(ctx->media.ribbon_code);
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
+
+static void shinkos6245_cleanup_job(const void *vjob)
+{
+ const struct shinkos6245_printjob *job = vjob;
+
+ if (job->databuf)
+ free(job->databuf);
+
+ free((void*)job);
}
static void shinkos6245_teardown(void *vctx) {
@@ -1523,64 +1531,71 @@ static void shinkos6245_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
-
free(ctx);
}
-static int shinkos6245_read_parse(void *vctx, int data_fd) {
+static int shinkos6245_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct shinkos6245_ctx *ctx = vctx;
int ret;
uint8_t tmpbuf[4];
+ struct shinkos6245_printjob *job = NULL;
+
if (!ctx)
return CUPS_BACKEND_FAILED;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
+ }
+ memset(job, 0, sizeof(*job));
+ job->copies = copies; // XXX hdr.copies
+
/* Read in then validate header */
- ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
- if (ret < 0 || ret != sizeof(ctx->hdr)) {
+ ret = read(data_fd, &job->hdr, sizeof(job->hdr));
+ if (ret < 0 || ret != sizeof(job->hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
- ret, 0, (int)sizeof(ctx->hdr));
+ ret, 0, (int)sizeof(job->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) {
+ if (le32_to_cpu(job->hdr.len1) != 0x10 ||
+ le32_to_cpu(job->hdr.len2) != 0x64 ||
+ le32_to_cpu(job->hdr.dpi) != 300) {
ERROR("Unrecognized header data format!\n");
return CUPS_BACKEND_CANCEL;
}
- if (le32_to_cpu(ctx->hdr.model) != 6245) {
- ERROR("Unrecognized printer (%u)!\n", le32_to_cpu(ctx->hdr.model));
+ if (le32_to_cpu(job->hdr.model) != 6245) {
+ ERROR("Unrecognized printer (%u)!\n", le32_to_cpu(job->hdr.model));
return CUPS_BACKEND_CANCEL;
}
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ if (job->databuf) {
+ free(job->databuf);
+ job->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) {
+ job->datalen = le32_to_cpu(job->hdr.rows) * le32_to_cpu(job->hdr.columns) * 3;
+ job->databuf = malloc(job->datalen);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_RETRY_CURRENT;
}
{
- int remain = ctx->datalen;
- uint8_t *ptr = ctx->databuf;
+ int remain = job->datalen;
+ uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
- ret, remain, ctx->datalen);
+ ret, remain, job->datalen);
perror("ERROR: Read failed");
return ret;
}
@@ -1605,23 +1620,29 @@ static int shinkos6245_read_parse(void *vctx, int data_fd) {
return CUPS_BACKEND_FAILED;
}
+ *vjob = job;
+
return CUPS_BACKEND_OK;
}
-static int shinkos6245_main_loop(void *vctx, int copies) {
+static int shinkos6245_main_loop(void *vctx, const void *vjob) {
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;
+ int copies;
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;
+ struct s6245_status_resp sts, sts2;
+ struct s6245_status_hdr resp;
+
+ struct shinkos6245_printjob *job = (struct shinkos6245_printjob*) vjob;
+
+ copies = job->copies;
/* Cap copies */
// XXX 120 for 8x10 media, 100 for 8x12 media (S6245)
@@ -1630,7 +1651,7 @@ static int shinkos6245_main_loop(void *vctx, int copies) {
copies = 120;
/* Set up mcut */
- switch (le32_to_cpu(ctx->hdr.media)) {
+ switch (le32_to_cpu(job->hdr.media)) {
case MEDIA_8x4_2:
case MEDIA_8x5_2:
case MEDIA_8x6_2:
@@ -1644,34 +1665,17 @@ static int shinkos6245_main_loop(void *vctx, int copies) {
}
// 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++) {
+ for (i = 0; i < ctx->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)))
+ if (le16_to_cpu(ctx->media.items[i].columns) == cpu_to_le16(le32_to_cpu(job->hdr.columns)) &&
+ le16_to_cpu(ctx->media.items[i].rows) == cpu_to_le16(le32_to_cpu(job->hdr.rows)))
break;
}
- if (i == media->count) {
+ if (i == ctx->media.count) {
ERROR("Incorrect media loaded for print!\n");
return CUPS_BACKEND_HOLD;
}
- ctx->ribbon_code = media->ribbon_code;
/* Send Set Time */
{
@@ -1693,21 +1697,14 @@ static int shinkos6245_main_loop(void *vctx, int copies) {
if ((ret = s6245_do_cmd(ctx,
cmdbuf, sizeof(*stime),
sizeof(struct s6245_status_hdr),
- &num)) < 0) {
+ &num, (void*)&resp)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(stime->hdr.cmd));
return CUPS_BACKEND_FAILED;
}
- if (sts->hdr.result != RESULT_SUCCESS)
+ if (resp.result != RESULT_SUCCESS)
goto printer_error;
}
- /* Tell CUPS about the consumables we report */
- ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n");
- ATTR("marker-high-levels=100\n");
- ATTR("marker-low-levels=10\n");
- ATTR("marker-names='%s'\n", ribbon_sizes(ctx->ribbon_code));
- ATTR("marker-types=ribbonWax\n");
-
// XXX check copies against remaining media!
top:
@@ -1723,35 +1720,26 @@ top:
if ((ret = s6245_do_cmd(ctx,
cmdbuf, sizeof(*cmd),
- sizeof(struct s6245_status_hdr),
- &num)) < 0) {
+ sizeof(sts),
+ &num, (void*)&sts)) < 0) {
ERROR("Failed to execute %s command\n", cmd_names(cmd->cmd));
return CUPS_BACKEND_FAILED;
}
- if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
- uint16_t donor, remain;
-
- memcpy(rdbuf2, rdbuf, READBACK_LEN);
+ if (memcmp(&sts2, &sts, sizeof(sts))) {
+ memcpy(&sts2, &sts, sizeof(sts));
INFO("Printer Status: 0x%02x (%s)\n",
- sts->hdr.status, status_str(sts->hdr.status));
+ sts.hdr.status, status_str(sts.hdr.status));
- /* Guessimate a percentage for the remaining media */
- donor = le32_to_cpu(sts->count_ribbon_left) * 100 / ribbon_counts(ctx->ribbon_code);
- if (donor != ctx->last_donor) {
- ctx->last_donor = donor;
- ATTR("marker-levels=%d\n", donor);
- }
- remain = le32_to_cpu(sts->count_ribbon_left);
- if (remain != ctx->last_remain) {
- ctx->last_remain = remain;
- ATTR("marker-message=\"%d prints remaining on '%s' ribbon\"\n", remain, ribbon_sizes(ctx->ribbon_code));
+ if (ctx->marker.levelnow != (int)sts.count_ribbon_left) {
+ ctx->marker.levelnow = sts.count_ribbon_left;
+ dump_markers(&ctx->marker, 1, 0);
}
- if (sts->hdr.result != RESULT_SUCCESS)
+ if (sts.hdr.result != RESULT_SUCCESS)
goto printer_error;
- if (sts->hdr.error == ERROR_PRINTER)
+ if (sts.hdr.error == ERROR_PRINTER)
goto printer_error;
} else if (state == last_state) {
sleep(1);
@@ -1767,8 +1755,8 @@ top:
/* make sure we're not colliding with an existing
jobid */
- while (ctx->jobid == sts->bank1_printid ||
- ctx->jobid == sts->bank2_printid) {
+ while (ctx->jobid == sts.bank1_printid ||
+ ctx->jobid == sts.bank2_printid) {
ctx->jobid++;
ctx->jobid &= 0x7f;
if (!ctx->jobid)
@@ -1776,8 +1764,8 @@ top:
}
/* If either bank is free, continue */
- if (sts->bank1_status == BANK_STATUS_FREE ||
- sts->bank2_status == BANK_STATUS_FREE)
+ if (sts.bank1_status == BANK_STATUS_FREE ||
+ sts.bank2_status == BANK_STATUS_FREE)
state = S_PRINTER_READY_CMD;
break;
@@ -1792,33 +1780,33 @@ top:
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->columns = cpu_to_le16(le32_to_cpu(job->hdr.columns));
+ print->rows = cpu_to_le16(le32_to_cpu(job->hdr.rows));
+ print->mode = le32_to_cpu(job->hdr.oc_mode);
print->method = mcut;
if ((ret = s6245_do_cmd(ctx,
cmdbuf, sizeof(*print),
- sizeof(struct s6245_status_hdr),
- &num)) < 0) {
+ sizeof(resp),
+ &num, (void*)&resp)) < 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) {
+ if (resp.result != RESULT_SUCCESS) {
+ if (resp.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));
+ } else if ((resp.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)
+ } else if (resp.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)))
+ job->databuf, job->datalen)))
return CUPS_BACKEND_FAILED;
INFO("Waiting for printer to acknowledge completion\n");
@@ -1829,7 +1817,7 @@ top:
if (fast_return) {
INFO("Fast return mode enabled.\n");
state = S_FINISHED;
- } else if (sts->hdr.status == STATUS_READY) {
+ } else if (sts.hdr.status == STATUS_READY) {
state = S_FINISHED;
}
break;
@@ -1846,19 +1834,19 @@ top:
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));
+ 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;
+ struct s6245_getserial_resp resp;
int ret, num = 0;
struct shinkos6245_ctx ctx = {
@@ -1872,42 +1860,83 @@ static int shinkos6245_query_serno(struct libusb_device_handle *dev, uint8_t end
if ((ret = s6245_do_cmd(&ctx,
(uint8_t*)&cmd, sizeof(cmd),
- sizeof(*resp) - 1,
- &num)) < 0) {
+ sizeof(resp) - 1,
+ &num, (void*)&resp)) < 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);
+ 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;
}
+static int shinkos6245_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct shinkos6245_ctx *ctx = vctx;
+ struct s6245_cmd_hdr cmd;
+ struct s6245_status_resp status;
+ int num;
+
+ /* Query Status */
+ cmd.cmd = cpu_to_le16(S6245_CMD_GETSTATUS);
+ cmd.len = cpu_to_le16(0);
+
+ if (s6245_do_cmd(ctx,
+ (uint8_t*)&cmd, sizeof(cmd),
+ sizeof(status),
+ &num, (void*)&status)) {
+ ERROR("Failed to execute %s command\n", cmd_names(cmd.cmd));
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ctx->marker.levelnow = le32_to_cpu(status.count_ribbon_left);
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
/* Exported */
#define USB_VID_SHINKO 0x10CE
#define USB_PID_SHINKO_S6245 0x001D
+#define USB_VID_HITI 0x0D16
+#define USB_PID_HITI_P910L 0x000E
+
+static const char *shinkos6245_prefixes[] = {
+ "sinfonia-chcs6245", "hiti-p910l",
+ // extras
+ "shinko-chcs6245",
+ // backwards compatibility
+ "shinkos6245", "hitip910",
+ NULL
+};
struct dyesub_backend shinkos6245_backend = {
.name = "Shinko/Sinfonia CHC-S6245",
- .version = "0.07WIP",
- .uri_prefix = "shinkos6245",
+ .version = "0.14WIP",
+ .uri_prefixes = shinkos6245_prefixes,
.cmdline_usage = shinkos6245_cmdline,
.cmdline_arg = shinkos6245_cmdline_arg,
.init = shinkos6245_init,
.attach = shinkos6245_attach,
.teardown = shinkos6245_teardown,
+ .cleanup_job = shinkos6245_cleanup_job,
.read_parse = shinkos6245_read_parse,
.main_loop = shinkos6245_main_loop,
.query_serno = shinkos6245_query_serno,
+ .query_markers = shinkos6245_query_markers,
.devices = {
- { USB_VID_SHINKO, USB_PID_SHINKO_S6245, P_SHINKO_S6245, ""},
- { 0, 0, 0, ""}
+ { USB_VID_SHINKO, USB_PID_SHINKO_S6245, P_SHINKO_S6245, NULL, "shinfonia-chcs6245"},
+ { USB_VID_HITI, USB_PID_HITI_P910L, P_SHINKO_S6245, NULL, "hiti-p910l"},
+ { 0, 0, 0, NULL, NULL}
}
};
diff --git a/src/cups/backend_sonyupdr150.c b/src/cups/backend_sonyupdr150.c
index dae8bf1..5e8ae2e 100644
--- a/src/cups/backend_sonyupdr150.c
+++ b/src/cups/backend_sonyupdr150.c
@@ -1,7 +1,7 @@
/*
* Sony UP-DR150 Photo Printer CUPS backend -- libusb-1.0 version
*
- * (c) 2013-2016 Solomon Peachy <pizza@shaftnet.org>
+ * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
@@ -18,11 +18,12 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* [http://www.gnu.org/licenses/gpl-2.0.html]
*
+ * SPDX-License-Identifier: GPL-2.0+
+ *
*/
#include <stdio.h>
@@ -39,23 +40,20 @@
#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 0x0226
-
/* Private data structure */
+struct updr150_printjob {
+ uint8_t *databuf;
+ int datalen;
+ int copies;
+};
+
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;
+ struct marker marker;
};
static void* updr150_init(void)
@@ -69,26 +67,34 @@ static void* updr150_init(void)
return ctx;
}
-static void updr150_attach(void *vctx, struct libusb_device_handle *dev,
- uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
+static int updr150_attach(void *vctx, struct libusb_device_handle *dev, int type,
+ uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
{
struct updr150_ctx *ctx = vctx;
- struct libusb_device *device;
- struct libusb_device_descriptor desc;
UNUSED(jobid);
ctx->dev = dev;
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
+ ctx->type = type;
+
+ ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
+ ctx->marker.name = "Unknown";
+ ctx->marker.levelmax = -1;
+ ctx->marker.levelnow = -2;
+
+ return CUPS_BACKEND_OK;
+}
- device = libusb_get_device(dev);
- libusb_get_device_descriptor(device, &desc);
+static void updr150_cleanup_job(const void *vjob)
+{
+ const struct updr150_printjob *job = vjob;
- ctx->type = lookup_printer_type(&updr150_backend,
- desc.idVendor, desc.idProduct);
+ if (job->databuf)
+ free(job->databuf);
- ctx->copies_offset = 0;
+ free((void*)job);
}
static void updr150_teardown(void *vctx) {
@@ -97,147 +103,164 @@ static void updr150_teardown(void *vctx) {
if (!ctx)
return;
- if (ctx->databuf)
- free(ctx->databuf);
free(ctx);
}
#define MAX_PRINTJOB_LEN 16736455
-static int updr150_read_parse(void *vctx, int data_fd) {
+static int updr150_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
struct updr150_ctx *ctx = vctx;
int len, run = 1;
+ uint32_t copies_offset = 0;
+
+ struct updr150_printjob *job = NULL;
if (!ctx)
return CUPS_BACKEND_FAILED;
- if (ctx->databuf) {
- free(ctx->databuf);
- ctx->databuf = NULL;
+ job = malloc(sizeof(*job));
+ if (!job) {
+ ERROR("Memory allocation failure!\n");
+ return CUPS_BACKEND_RETRY_CURRENT;
}
+ memset(job, 0, sizeof(*job));
+ job->copies = copies;
- ctx->datalen = 0;
- ctx->databuf = malloc(MAX_PRINTJOB_LEN);
- if (!ctx->databuf) {
+ job->datalen = 0;
+ job->databuf = malloc(MAX_PRINTJOB_LEN);
+ if (!job->databuf) {
ERROR("Memory allocation failure!\n");
- return CUPS_BACKEND_FAILED;
+ updr150_cleanup_job(job);
+ return CUPS_BACKEND_RETRY_CURRENT;
}
while(run) {
int i;
int keep = 0;
- i = read(data_fd, ctx->databuf + ctx->datalen, 4);
- if (i < 0)
+ i = read(data_fd, job->databuf + job->datalen, 4);
+ if (i < 0) {
+ updr150_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
if (i == 0)
break;
- memcpy(&len, ctx->databuf + ctx->datalen, sizeof(len));
+ memcpy(&len, job->databuf + job->datalen, sizeof(len));
len = le32_to_cpu(len);
/* Filter out chunks we don't send to the printer */
- switch (len) {
- case 0xffffff60:
- case 0xffffff6a:
- case 0xffffffeb:
- case 0xffffffec:
- case 0xffffffed:
- case 0xfffffff4:
- case 0xfffffff8:
- case 0xfffffff9:
- case 0xfffffffa:
- case 0xfffffffb:
- case 0xfffffffc:
- case 0xffffffff:
- if(dyesub_debug)
- DEBUG("Block ID '%08x' (len %d)\n", len, 0);
- len = 0;
- break;
- case 0xfffffff3:
- if(dyesub_debug)
- DEBUG("Block ID '%08x' (len %d)\n", len, 0);
- len = 0;
- if (ctx->type == P_SONY_UPDR150)
- run = 0;
- break;
- case 0xfffffff7:
- if(dyesub_debug)
- DEBUG("Block ID '%08x' (len %d)\n", len, 0);
- len = 0;
- if (ctx->type == P_SONY_UPCR10)
- run = 0;
- break;
- case 0xffffffef:
- case 0xfffffff5:
- if(dyesub_debug)
- DEBUG("Block ID '%08x' (len %d)\n", len, 4);
- len = 4;
- break;
- default:
- if (len & 0xff000000) {
- ERROR("Unknown block ID '%08x', aborting!\n", len);
- return CUPS_BACKEND_CANCEL;
- } else {
- /* Only keep these chunks */
+ if (len & 0xf0000000) {
+ switch (len) {
+ case 0xfffffff3:
+ if(dyesub_debug)
+ DEBUG("Block ID '%08x' (len %d)\n", len, 0);
+ len = 0;
+ if (ctx->type == P_SONY_UPDR150)
+ run = 0;
+ break;
+ case 0xfffffff7:
+ if(dyesub_debug)
+ DEBUG("Block ID '%08x' (len %d)\n", len, 0);
+ len = 0;
+ if (ctx->type == P_SONY_UPCR10)
+ run = 0;
+ break;
+ case 0xfffffff8: // 895
+ case 0xfffffff4: // 897
+ if(dyesub_debug)
+ DEBUG("Block ID '%08x' (len %d)\n", len, 0);
+ len = 0;
+ if (ctx->type == P_SONY_UPD89x)
+ run = 0;
+ break;
+ case 0xffffffeb:
+ case 0xffffffec:
+ case 0xffffffed:
+ case 0xffffffee:
+ case 0xffffffef:
+ case 0xfffffff5:
if(dyesub_debug)
- DEBUG("Data block (len %d)\n", len);
- keep = 1;
+ DEBUG("Block ID '%08x' (len %d)\n", len, 4);
+ len = 4;
+ break;
+ default:
+ if(dyesub_debug)
+ DEBUG("Block ID '%08x' (len %d)\n", len, 0);
+ len = 0;
+ break;
}
- break;
+ } else {
+ /* Only keep these chunks */
+ if(dyesub_debug)
+ DEBUG("Data block (len %d)\n", len);
+ keep = 1;
}
if (keep)
- ctx->datalen += sizeof(uint32_t);
+ job->datalen += sizeof(uint32_t);
/* Read in the data chunk */
while(len > 0) {
- i = read(data_fd, ctx->databuf + ctx->datalen, len);
- if (i < 0)
+ i = read(data_fd, job->databuf + job->datalen, len);
+ if (i < 0) {
+ updr150_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
if (i == 0)
break;
- if (ctx->databuf[ctx->datalen] == 0x1b &&
- ctx->databuf[ctx->datalen + 1] == 0xee) {
+ if (job->databuf[job->datalen] == 0x1b &&
+ job->databuf[job->datalen + 1] == 0xee) {
if (ctx->type == P_SONY_UPCR10)
- ctx->copies_offset = ctx->datalen + 8;
+ copies_offset = job->datalen + 8;
else
- ctx->copies_offset = ctx->datalen + 12;
+ copies_offset = job->datalen + 12;
}
if (keep)
- ctx->datalen += i;
+ job->datalen += i;
len -= i;
}
}
- if (!ctx->datalen)
+ if (!job->datalen) {
+ updr150_cleanup_job(job);
return CUPS_BACKEND_CANCEL;
+ }
+
+ /* Some models specify copies in the print job */
+ if (copies_offset) {
+ job->databuf[copies_offset] = job->copies;
+ job->copies = 1;
+ }
+
+ *vjob = job;
return CUPS_BACKEND_OK;
}
-static int updr150_main_loop(void *vctx, int copies) {
+static int updr150_main_loop(void *vctx, const void *vjob) {
struct updr150_ctx *ctx = vctx;
int i, ret;
+ int copies;
+
+ const struct updr150_printjob *job = vjob;
if (!ctx)
return CUPS_BACKEND_FAILED;
+ if (!job)
+ return CUPS_BACKEND_FAILED;
- /* Some models specify copies in the print job */
- if (ctx->copies_offset) {
- ctx->databuf[ctx->copies_offset] = copies;
- copies = 1;
- }
+ copies = job->copies;
top:
i = 0;
- while (i < ctx->datalen) {
+ while (i < job->datalen) {
uint32_t len;
- memcpy(&len, ctx->databuf + i, sizeof(len));
+ memcpy(&len, job->databuf + i, sizeof(len));
len = le32_to_cpu(len);
i += sizeof(uint32_t);
if ((ret = send_data(ctx->dev, ctx->endp_down,
- ctx->databuf + i, len)))
+ job->databuf + i, len)))
return CUPS_BACKEND_FAILED;
i += len;
@@ -275,21 +298,54 @@ static int updr150_cmdline_arg(void *vctx, int argc, char **argv)
return 0;
}
+static int updr150_query_markers(void *vctx, struct marker **markers, int *count)
+{
+ struct updr150_ctx *ctx = vctx;
+
+ *markers = &ctx->marker;
+ *count = 1;
+
+ return CUPS_BACKEND_OK;
+}
+
+static const char *sonyupdr150_prefixes[] = {
+ "sonyupdr150", // Family name.
+ "sony-updr150", "sony-updr200", "sony-upcr10",
+ // Backwards compatibility
+ "sonyupdr200", "sonyupcr10",
+// "sonyupd895", "sonyupd897", "sonyupd898",
+ NULL
+};
+
+/* Exported */
+#define USB_VID_SONY 0x054C
+#define USB_PID_SONY_UPDR150 0x01E8
+#define USB_PID_SONY_UPDR200 0x035F
+#define USB_PID_SONY_UPCR10 0x0226
+//#define USB_PID_SONY_UPD895 XXXXX // 0x7ea6?
+//#define USB_PID_SONY_UPD897 XXXXX // 0xbce7?
+//#define USB_PID_SONY_UPD898 XXXXX // 0x589a?
+
struct dyesub_backend updr150_backend = {
.name = "Sony UP-DR150/UP-DR200/UP-CR10",
- .version = "0.19",
- .uri_prefix = "sonyupdr150",
+ .version = "0.26",
+ .uri_prefixes = sonyupdr150_prefixes,
.cmdline_arg = updr150_cmdline_arg,
.init = updr150_init,
.attach = updr150_attach,
.teardown = updr150_teardown,
+ .cleanup_job = updr150_cleanup_job,
.read_parse = updr150_read_parse,
.main_loop = updr150_main_loop,
+ .query_markers = updr150_query_markers,
.devices = {
- { USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, ""},
- { USB_VID_SONY, USB_PID_SONY_UPDR200, P_SONY_UPDR150, ""},
- { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, ""},
- { 0, 0, 0, ""}
+ { USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, NULL, "sony-updr150"},
+ { USB_VID_SONY, USB_PID_SONY_UPDR200, P_SONY_UPDR150, NULL, "sony-updr200"},
+ { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, NULL, "sony-upcr10"},
+// { USB_VID_SONY, USB_PID_SONY_UPD895MD, P_SONY_UPD89x, NULL, "sonyupd895"},
+// { USB_VID_SONY, USB_PID_SONY_UPD897MD, P_SONY_UPD89x, NULL, "sonyupd897"},
+// { USB_VID_SONY, USB_PID_SONY_UPD898MD, P_SONY_UPD89x, NULL, "sonyupd898"},
+ { 0, 0, 0, NULL, NULL}
}
};
@@ -299,25 +355,18 @@ struct dyesub_backend updr150_backend = {
arguments. The purpose of the commands is unknown, but they presumably
instruct the driver to perform certain things.
- If you treat these 4 bytes as a 32-bit little-endian number, if the
- most significant four bits are bits are non-zero, the value is is to
+ If you treat these 4 bytes as a 32-bit little-endian number, if any of the
+ most significant 4 bits are non-zero, the value is is to
be interpreted as a driver command. If the most significant bits are
zero, the value signifies that the following N bytes of data should be
sent to the printer as-is.
Known driver "commands":
- 6a ff ff ff
- fc ff ff ff
- fb ff ff ff
- f4 ff ff ff
- ed ff ff ff
- f9 ff ff ff
- f8 ff ff ff
- ec ff ff ff
- eb ff ff ff
- fa ff ff ff
- f3 ff ff ff
+ eb ff ff ff ?? 00 00 00
+ ec ff ff ff ?? 00 00 00
+ ed ff ff ff ?? 00 00 00
+ ee ff ff ff ?? 00 00 00
ef ff ff ff XX 00 00 00 # XX == print size (0x01/0x02/0x03/0x04)
f5 ff ff ff YY 00 00 00 # YY == ??? (seen 0x01)
@@ -403,6 +452,117 @@ f7 ff ff ff
SH SH SH SH == Plane size, Big Endian (Rows * Cols * 3)
NN == Copies
+ **************
+
+ Sony UP-D895 spool format:
+
+ XX XX == cols, BE (fixed at 1280/0x500)
+ YY YY == rows, BE (798/0x031e,1038/0x040e,1475/0x05c3, 2484/09b4) @ 960/1280/1920/3840+4096
+ SS SS SS SS == data len (rows * cols, LE)
+ S' S' S' S' == data len (rows * cols, BE)
+ NN == copies (1 -> ??)
+ GG GG == ??? 0000/0050/011b/04aa/05aa at each resolution.
+ G' == Gamma 01 (soft), 03 (hard), 02 (normal)
+
+ 9c ff ff ff 97 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff
+
+ 14 00 00 00
+ 1b 15 00 00 00 0d 00 00 00 00 00 01 GG GG 00 00 YY YY XX XX
+ 0b 00 00 00
+ 1b ea 00 00 00 00 S' S' S' S' 00
+ SS SS SS SS
+ ...DATA... (rows * cols)
+ ff ff ff ff
+ 09 00 00 00
+ 1b ee 00 00 00 02 00 00 NN
+ 0f 00 00 00
+ 1b e5 00 00 00 08 00 00 00 00 00 00 00 00 00
+ 0c 00 00 00
+ 1b c0 00 00 00 05 00 02 00 00 01 G'
+ 11 00 00 00
+ 1b c0 00 01 00 0a 00 02 01 00 06 00 00 00 00 00 00
+ 12 00 00 00
+ 1b e1 00 00 00 0b 00 00 08 00 GG GG 00 00 YY YY XX XX
+ 07 00 00 00
+ 1b 0a 00 00 00 00 00
+ fd ff ff ff f7 ff ff ff f8 ff ff ff
+
+ **************
+
+ Sony UP-D897 spool format:
+
+ NN NN == copies (00 for printer selected)
+ XX XX == cols (fixed @ 1280)
+ YY YY == rows
+ GG == gamma -- Table 2 == 2, Table 1 == 3, Table 3 == 1, Table 4 == 4
+ DD == "dark" +- 64.
+ LL == "light" +- 64.
+ AA == "advanced" +- 32.
+ SS == Sharpness 0-14
+ ZZ ZZ ZZ ZZ == Data length (BE)
+ Z` Z` Z` Z` == Data length (LE)
+
+
+ 83 ff ff ff fc ff ff ff fb ff ff ff f5 ff ff ff f1 ff ff ff f0 ff ff ff ef ff ff ff
+
+ 07 00 00 00
+ 1b 15 00 00 00 0d 00
+ 0d 00 00 00
+ 00 00 00 00 01 00 a2 00 00 YY YY XX XX
+
+ 0b 00 00 00
+ 1b ea 00 00 00 00 ZZ ZZ ZZ ZZ 00
+
+ Z` Z` Z` Z`
+ ...DATA...
+
+ ea ff ff ff
+
+ 07 00 00 00
+ 1b ee 00 00 00 02 00
+ 02 00 00 00
+ 00 NN
+
+ ee ff ff ff 01 00 00 00
+
+ 07 00 00 00
+ 1b e5 00 00 00 08 00
+ 08 00 00 00
+ 00 00 00 00 DD LL SS AA
+
+ eb ff ff ff ?? 00 00 00 <--- 02/05 5 at #3, 2 otherwise. Sharpness?
+
+ 07 00 00 00
+ 1b c0 00 00 00 05 00
+ 05 00 00 00
+ 02 00 00 01 GG
+
+ ec ff ff ff ?? 00 00 00 <--- 01/00/02/01/01 Seen. Unknown.
+
+ 07 00 00 00
+ 1b c0 00 01 00 0a 00
+ 0a 00 00 00
+ 02 01 00 06 00 00 00 00 00 00
+
+ ed ff ff ff 00 00 00 00
+
+ 07 00 00 00
+ 1b e1 00 00 00 0b 00
+ 0b 00 00 00
+ 00 08 00 00 a2 00 00 YY YY XX XX
+
+ fa ff ff ff
+
+ 07 00 00 00
+ 1b 0a 00 00 00 00 00
+
+ fc ff ff ff
+ fd ff ff ff
+ ff ff ff ff
+
+ 07 00 00 00
+ 1b 17 00 00 00 00 00
+ f4 ff ff ff
*/
diff --git a/src/cups/blacklist b/src/cups/blacklist
index 0ca284c..157fd47 100644
--- a/src/cups/blacklist
+++ b/src/cups/blacklist
@@ -90,6 +90,9 @@
# Canon SELPHY CP1200
0x04a9 0x32b1 blacklist
+# Canon SELPHY CP1300
+0x04a9 0x32db blacklist
+
# Canon SELPHY ES1
0x04a9 0x3141 blacklist
@@ -153,6 +156,9 @@
# Mitsubishi CP-D80DW
0x06d3 0x3b36 blacklist
+# Mitsubishi CP-D90DW
+0x06d3 0x3b60 blacklist
+
# Mitsubishi CP-K60DW-S
0x06d3 0x3b31 blacklist
@@ -196,17 +202,19 @@
# DNP DS80 + Citizen CX-W + Mitsubishi CP3800
0x1343 0x0004 blacklist
-# DNP DS-RX1 + Citizen CY
+# DNP DS-RX1 + Citizen CY (Plus RX1HS and CY-02)
0x1343 0x0005 blacklist
-# Citizen CW-02
+# Citizen CW-02 / OP900II
0x1343 0x0006 blacklist
+# Citizen CX-02
+0x1343 0x000A blacklist
+
# DNP DS80D
-0x1343 0x0007 blacklist
+0x1343 0x0008 blacklist
# DNP DS620
-0x1343 0x0008 blacklist
0x1452 0x8b01 blacklist
# DNP DS820
@@ -218,3 +226,14 @@
# Fujifilm ASK-300
0x04cb 0x5006 blacklist
+# HiTi P910L
+0x0d16 0x000e blacklist
+
+# Magicard Tango 2E
+0x0c1f 0x1800 blacklist
+
+# Magicard Enduro
+0x0c1f 0x4800 blacklist
+
+# Magicard Enduro+
+0x0c1f 0x880a blacklist
diff --git a/src/cups/command.types b/src/cups/command.types
index e03f094..f8eb8b2 100644
--- a/src/cups/command.types
+++ b/src/cups/command.types
@@ -13,8 +13,7 @@
# 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.
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Define the new application/vnd.cups-command filetype...
diff --git a/src/cups/commandtoepson.c b/src/cups/commandtoepson.c
index 0582df2..7bac83c 100644
--- a/src/cups/commandtoepson.c
+++ b/src/cups/commandtoepson.c
@@ -14,8 +14,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contents:
*
diff --git a/src/cups/cups-calibrate.c b/src/cups/cups-calibrate.c
index 205157b..de0a9e1 100644
--- a/src/cups/cups-calibrate.c
+++ b/src/cups/cups-calibrate.c
@@ -16,8 +16,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contents:
*
diff --git a/src/cups/cups-genppd.c b/src/cups/cups-genppd.c
new file mode 100644
index 0000000..fde7c46
--- /dev/null
+++ b/src/cups/cups-genppd.c
@@ -0,0 +1,607 @@
+/*
+ * PPD file generation program for the CUPS drivers.
+ *
+ * Copyright 1993-2008 by Mike Sweet and Robert Krawitz.
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ *
+ * Contents:
+ *
+ * main() - Process files on the command-line...
+ * cat_ppd() - Copy the named PPD to stdout.
+ * generate_ppd() - Generate a PPD file.
+ * getlangs() - Get a list of available translations.
+ * help() - Show detailed help.
+ * is_special_option() - Determine if an option should be grouped.
+ * list_ppds() - List the available drivers.
+ * print_group_close() - Close a UI group.
+ * print_group_open() - Open a new UI group.
+ * printlangs() - Print list of available translations.
+ * printmodels() - Print a list of available models.
+ * usage() - Show program usage.
+ * write_ppd() - Write a PPD file.
+ */
+
+#include "genppd.h"
+
+static int generate_ppd(const char *prefix, int verbose,
+ const stp_printer_t *p, const char *language,
+ ppd_type_t ppd_type, int use_compression);
+static int generate_model_ppds(const char *prefix, int verbose,
+ const stp_printer_t *printer,
+ const char *language, int which_ppds,
+ int use_compression);
+static void help(void);
+static void printlangs(char** langs);
+static void printmodels(int verbose);
+static void usage(void);
+static gpFile gpopen(const char *path, const char *mode, int use_compression);
+static int gpclose(gpFile f, int use_compression);
+
+/*
+ * 'main()' - Process files on the command-line...
+ */
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ int i; /* Looping var */
+ const char *prefix; /* Directory prefix for output */
+ const char *language = NULL; /* Language */
+ const stp_printer_t *printer; /* Pointer to printer driver */
+ int verbose = 0; /* Verbose messages */
+ char **langs = NULL; /* Available translations */
+ char **models = NULL; /* Models to output, all if NULL */
+ int opt_printlangs = 0; /* Print available translations */
+ int opt_printmodels = 0;/* Print available models */
+ int which_ppds = 2; /* Simplified PPD's = 1, full = 2,
+ no color opts = 4 */
+ unsigned parallel = 1; /* Generate PPD files in parallel */
+ unsigned rotor = 0; /* Rotor for generating PPD files in parallel */
+ pid_t *subprocesses = NULL;
+ int parent = 1;
+#ifdef HAVE_LIBZ
+ int use_compression = 1;
+#else
+ int use_compression = 0;
+#endif
+ int skip_duplicate_ppds = 0;
+
+
+ /*
+ * Parse command-line args...
+ */
+
+ prefix = CUPS_MODELDIR;
+
+ for (;;)
+ {
+ if ((i = getopt(argc, argv, "23hvqc:p:l:LMVd:saNCbZzS")) == -1)
+ break;
+
+ switch (i)
+ {
+ case '2':
+ cups_ppd_ps_level = 2;
+ break;
+ case '3':
+ cups_ppd_ps_level = 3;
+ break;
+ case 'h':
+ help();
+ exit(EXIT_SUCCESS);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'q':
+ verbose = 0;
+ break;
+ case 'c':
+ fputs("ERROR: -c option no longer supported!\n", stderr);
+ break;
+ case 'p':
+ prefix = optarg;
+# ifdef DEBUG
+ fprintf(stderr, "DEBUG: prefix: %s\n", prefix);
+# endif
+ break;
+ case 'l':
+ language = optarg;
+ break;
+ case 'L':
+ opt_printlangs = 1;
+ break;
+ case 'M':
+ opt_printmodels = 1;
+ break;
+ case 'd':
+ cups_modeldir = optarg;
+ break;
+ case 's':
+ which_ppds = 1;
+ break;
+ case 'a':
+ which_ppds = 3;
+ break;
+ case 'C':
+ which_ppds |= 4;
+ break;
+ case 'N':
+ localize_numbers = !localize_numbers;
+ break;
+ case 'V':
+ printf("cups-genppd version %s, "
+ "Copyright 1993-2008 by Michael R Sweet and Robert Krawitz.\n\n",
+ VERSION);
+ printf("Default CUPS PPD PostScript Level: %d\n", cups_ppd_ps_level);
+ printf("Default PPD location (prefix): %s\n", CUPS_MODELDIR);
+ printf("Default base locale directory: %s\n\n", PACKAGE_LOCALE_DIR);
+ puts("This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License,\n"
+ "version 2, as published by the Free Software Foundation.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n");
+ exit(EXIT_SUCCESS);
+ break;
+ case 'b':
+ use_base_version = 1;
+ break;
+ case 'z':
+#ifdef HAVE_LIBZ
+ use_compression = 1;
+#endif
+ break;
+ case 'Z':
+#ifdef HAVE_LIBZ
+ use_compression = 0;
+#endif
+ break;
+ case 'S':
+ skip_duplicate_ppds = 1;
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+#ifdef HAVE_LIBZ
+ if (use_compression)
+ gpext = ".gz";
+ else
+#endif
+ gpext = "";
+ if (optind < argc) {
+ int n, numargs;
+ numargs = argc-optind;
+ models = stp_malloc((numargs+1) * sizeof(char*));
+ for (n=0; n<numargs; n++)
+ {
+ models[n] = argv[optind+n];
+ }
+ models[numargs] = (char*)NULL;
+ }
+
+/*
+ * Initialise libgutenprint
+ */
+
+ stp_init();
+
+ langs = getlangs();
+
+ /*
+ * Print lists
+ */
+
+ if (opt_printlangs)
+ {
+ printlangs(langs);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (opt_printmodels)
+ {
+ printmodels(verbose);
+ exit(EXIT_SUCCESS);
+ }
+
+ /*
+ * Write PPD files...
+ */
+
+ if (getenv("STP_PARALLEL"))
+ {
+ parallel = atoi(getenv("STP_PARALLEL"));
+ if (parallel < 1 || parallel > 256)
+ parallel = 1;
+ }
+ if (parallel > 1)
+ {
+ subprocesses = stp_malloc(sizeof(pid_t) * parallel);
+ for (rotor = 0; rotor < parallel; rotor++)
+ {
+ pid_t pid = fork();
+ if (pid == 0) /* Child */
+ {
+ parent = 0;
+ break;
+ }
+ else if (pid > 0)
+ subprocesses[rotor] = pid;
+ else
+ {
+ fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
+ return 1;
+ }
+ }
+ }
+ if (models)
+ {
+ int n;
+ for (n=0; models[n]; n++)
+ {
+ printer = stp_get_printer_by_driver(models[n]);
+ if (!printer)
+ printer = stp_get_printer_by_long_name(models[n]);
+
+ if (n % parallel == rotor && printer)
+ {
+ if (printer)
+ {
+ if (generate_model_ppds(prefix, verbose, printer, language,
+ which_ppds, use_compression))
+ return 1;
+ }
+ else
+ {
+ printf("Driver not found: %s\n", models[n]);
+ return (1);
+ }
+ }
+ }
+ stp_free(models);
+ }
+ else
+ {
+ stp_string_list_t *seen_models = NULL;
+ if (skip_duplicate_ppds)
+ seen_models = stp_string_list_create();
+
+ for (i = 0; i < stp_printer_model_count(); i++)
+ {
+ printer = stp_get_printer_by_index(i);
+ if (skip_duplicate_ppds)
+ {
+ char model_family[128];
+ (void) snprintf(model_family, 127, "%d_%s",
+ stp_printer_get_model(printer),
+ stp_printer_get_family(printer));
+ if (stp_string_list_is_present(seen_models, model_family))
+ continue;
+ else
+ stp_string_list_add_string_unsafe(seen_models, model_family,
+ model_family);
+ }
+
+ if (i % parallel == rotor && printer)
+ {
+ if (! verbose && (i % 100) == 0)
+ fputc('.',stderr);
+ if (generate_model_ppds(prefix, verbose, printer, language,
+ which_ppds, use_compression))
+ return 1;
+ }
+ }
+ if (seen_models)
+ stp_string_list_destroy(seen_models);
+ }
+ if (subprocesses)
+ {
+ pid_t pid;
+ do
+ {
+ int status;
+ pid = waitpid(-1, &status, 0);
+ if (pid > 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
+ {
+ fprintf(stderr, "failed!\n");
+ return 1;
+ }
+ } while (pid > 0);
+ stp_free(subprocesses);
+ }
+ if (parent && !verbose)
+ fprintf(stderr, " done.\n");
+
+ return (0);
+}
+
+static int
+generate_model_ppds(const char *prefix, int verbose,
+ const stp_printer_t *printer, const char *language,
+ int which_ppds, int use_compression)
+{
+ if ((which_ppds & 1) &&
+ generate_ppd(prefix, verbose, printer, language, PPD_SIMPLIFIED,
+ use_compression))
+ return (1);
+ if ((which_ppds & 2) &&
+ generate_ppd(prefix, verbose, printer, language, PPD_STANDARD,
+ use_compression))
+ return (1);
+ if ((which_ppds & 4) &&
+ generate_ppd(prefix, verbose, printer, language, PPD_NO_COLOR_OPTS,
+ use_compression))
+ return (1);
+ return 0;
+}
+
+/*
+ * 'generate_ppd()' - Generate a PPD file.
+ */
+
+static int /* O - Exit status */
+generate_ppd(
+ const char *prefix, /* I - PPD directory prefix */
+ int verbose, /* I - Verbosity level */
+ const stp_printer_t *p, /* I - Driver */
+ const char *language, /* I - Primary language */
+ ppd_type_t ppd_type, /* I - full, simplified, no color */
+ int use_compression) /* I - compress output */
+{
+ int status; /* Exit status */
+ gpFile fp; /* File to write to */
+ char filename[1024], /* Filename */
+ ppd_location[1024]; /* Installed location */
+ struct stat dir; /* Prefix dir status */
+ const char *ppd_infix;
+
+ /*
+ * Skip the PostScript drivers...
+ */
+
+ if (!strcmp(stp_printer_get_family(p), "ps") ||
+ !strcmp(stp_printer_get_family(p), "raw"))
+ return (0);
+
+ /*
+ * Make sure the destination directory exists...
+ */
+
+ if (stat(prefix, &dir) && !S_ISDIR(dir.st_mode))
+ {
+ if (mkdir(prefix, 0777))
+ {
+ printf("cups-genppd: Cannot create directory %s: %s\n",
+ prefix, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * The files will be named stp-<driver>.<major>.<minor>.ppd, for
+ * example:
+ *
+ * stp-escp2-ex.5.0.ppd
+ *
+ * or
+ *
+ * stp-escp2-ex.5.0.ppd.gz
+ */
+
+ switch (ppd_type)
+ {
+ case PPD_SIMPLIFIED:
+ ppd_infix = ".sim";
+ break;
+ case PPD_NO_COLOR_OPTS:
+ ppd_infix = ".nc";
+ break;
+ default:
+ ppd_infix = "";
+ }
+
+ snprintf(filename, sizeof(filename) - 1, "%s/stp-%s.%s%s%s%s",
+ prefix, stp_printer_get_driver(p), GUTENPRINT_RELEASE_VERSION,
+ ppd_infix, ppdext, gpext);
+
+ /*
+ * Open the PPD file...
+ */
+
+ if ((fp = gpopen(filename, "wb", use_compression)) == NULL)
+ {
+ fprintf(stderr, "cups-genppd: Unable to create file \"%s\" - %s.\n",
+ filename, strerror(errno));
+ return (2);
+ }
+
+ if (verbose)
+ fprintf(stderr, "Writing %s...\n", filename);
+
+ snprintf(ppd_location, sizeof(ppd_location), "%s%s%s/%s",
+ cups_modeldir,
+ cups_modeldir[strlen(cups_modeldir) - 1] == '/' ? "" : "/",
+ language ? language : "C",
+ basename(filename));
+
+ snprintf(filename, sizeof(filename) - 1, "stp-%s.%s%s%s",
+ stp_printer_get_driver(p), GUTENPRINT_RELEASE_VERSION,
+ ppd_infix, ppdext);
+
+ status = write_ppd(fp, p, language, ppd_location, ppd_type,
+ basename(filename), use_compression);
+
+ gpclose(fp, use_compression);
+
+ return (status);
+}
+
+
+/*
+ * 'help()' - Show detailed help.
+ */
+
+void
+help(void)
+{
+ puts("Generate Gutenprint PPD files for use with CUPS\n\n");
+ usage();
+ puts("\nExamples: LANG=de_DE cups-genppd -p ppd -c /usr/share/locale\n"
+ " cups-genppd -L -c /usr/share/locale\n"
+ " cups-genppd -M -v\n\n"
+ "Commands:\n"
+ " -h Show this help message.\n"
+ " -L List available translations (message catalogs).\n"
+ " -M List available printer models.\n"
+ " -V Show version information and defaults.\n"
+ " The default is to output PPDs.\n");
+ puts("Options:\n"
+ " -N Localize numbers.\n"
+ " -l locale Output PPDs translated with messages for locale.\n"
+ " -p prefix Output PPDs in directory prefix.\n"
+ " -d prefix Embed directory prefix in PPD file.\n"
+ " -s Generate simplified PPD files.\n"
+ " -a Generate all (simplified and full) PPD files.\n"
+ " -q Quiet mode.\n"
+ " -v Verbose mode.\n");
+ puts(
+#ifdef HAVE_LIBZ
+ " -z Compress PPD files.\n"
+ " -Z Don't compress PPD files.\n"
+#endif
+ " -S Skip PPD files with duplicate model identifiers.\n"
+ "models:\n"
+ " A list of printer models, either the driver or quoted full name.\n");
+}
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+void
+usage(void)
+{
+ puts("Usage: cups-genppd "
+ "[-l locale] [-p prefix] [-s | -a] [-q] [-v] models...\n"
+ " cups-genppd -L\n"
+ " cups-genppd -M [-v]\n"
+ " cups-genppd -h\n"
+ " cups-genppd -V\n");
+}
+
+/*
+ * 'printlangs()' - Print list of available translations.
+ */
+
+void
+printlangs(char **langs) /* I - Languages */
+{
+ if (langs)
+ {
+ int n = 0;
+ while (langs && langs[n])
+ {
+ puts(langs[n]);
+ n++;
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+
+
+/*
+ * 'printmodels()' - Print a list of available models.
+ */
+
+void
+printmodels(int verbose) /* I - Verbosity level */
+{
+ const stp_printer_t *p;
+ int i;
+
+ for (i = 0; i < stp_printer_model_count(); i++)
+ {
+ p = stp_get_printer_by_index(i);
+ if (p &&
+ strcmp(stp_printer_get_family(p), "ps") != 0 &&
+ strcmp(stp_printer_get_family(p), "raw") != 0)
+ {
+ if(verbose)
+ printf("%-20s%s\n", stp_printer_get_driver(p),
+ stp_printer_get_long_name(p));
+ else
+ printf("%s\n", stp_printer_get_driver(p));
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static gpFile
+gpopen(const char *path, const char *mode, int use_compression)
+{
+#ifdef HAVE_LIBZ
+ gpFile f = stp_malloc(sizeof(gpfile));
+ if (use_compression)
+ {
+ f->gzf = gzopen(path, mode);
+ if (!f->gzf)
+ {
+ stp_free(f);
+ return NULL;
+ }
+ return f;
+ }
+ else
+#endif
+ {
+ FILE *fl = fopen(path, mode);
+#ifdef HAVE_LIBZ
+ if (fl)
+ {
+ f->f = fl;
+ return f;
+ }
+ else
+ {
+ stp_free(f);
+ return NULL;
+ }
+#else
+ return fl;
+#endif
+ }
+}
+
+static int
+gpclose(gpFile f, int use_compression)
+{
+ int status;
+#ifdef HAVE_LIBZ
+ if (use_compression)
+ status = gzclose(f->gzf);
+ else
+ status = fclose(f->f);
+ stp_free(f);
+#else
+ status = fclose(f);
+#endif
+ return status;
+}
diff --git a/src/cups/cups-genppdupdate.in b/src/cups/cups-genppdupdate.in
index 8f0137b..1376884 100644
--- a/src/cups/cups-genppdupdate.in
+++ b/src/cups/cups-genppdupdate.in
@@ -13,8 +13,7 @@
# 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.
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
use strict;
use Getopt::Long;
@@ -44,6 +43,7 @@ our $opt_r; # Gutenprint version
our $opt_i; # Interactive
our $opt_f; # Force upgrade
our $opt_l; # Language
+our $opt_x; # Allow update across major.minor version
my $debug = 0;
my $verbose = 0; # Verbose output
@@ -213,6 +213,7 @@ sub HELP_MESSAGE($;$$$) {
print $fh " -r version Use PPD files for Gutenprint major.minor version.\n";
print $fh " -f Ignore new PPD file safety checks.\n";
print $fh " -i Prompt (interactively) for each PPD file.\n";
+ print $fh " -x Allow update across major Gutenprint releases.\n";
print $fh " -l language Language choice (Gutenprint 5.1 or below).\n";
print $fh " Choices: " . join(" ", @languages) . "\n";
print $fh " Or -loriginal to preserve original language\n";
@@ -262,6 +263,7 @@ sub parse_options () {
"p=s" => \$opt_p,
"P=s" => \$opt_P,
"v" => \$opt_v,
+ "x" => \$opt_x,
"N" => \$opt_N,
"o=s" => \$opt_o,
"r=s" => \$opt_r,
@@ -541,14 +543,28 @@ sub update_ppd ($) {
return 0;
}
- my ($ndt, $nopt, $nres, $ndef, $source_data) = get_ppd_data($source_fd, 1, 1, 1, 1, 1);
+ my ($ndt, $nopt, $nres, $ndef, $source_data, $new_fileversion) = get_ppd_data($source_fd, 1, 1, 1, 1, 1);
+ my $new_majversion = $new_fileversion;
+ $new_majversion =~ s/^([[:digit:]]+\.[[:digit:]]).*/$1/;
if (! defined $ndt) {
print "Unable to retrieve PPD file for $ppd_source_filename!\n";
close ORIG;
return 0;
}
+ # Extract the default values from the original PPD...
+
+ seek(ORIG, 0, 0);
+
+ my ($odt, $oopt, $ores, $odef, $ignore, $old_fileversion) = get_ppd_data(ORIG, 1, 0, 1, 1, 0);
+ my $old_majversion = $old_fileversion;
+ $old_majversion =~ s/^([[:digit:]]+\.[[:digit:]]).*/$1/;
+
if ($interactive) {
+ if ($old_majversion ne $new_majversion) {
+ print "WARNING: Current PPD file $ppd_source_filename has different version ($old_majversion)\n";
+ print " from new PPD file $new_ppd_filename ($new_majversion).\n";
+ }
print "Update PPD $ppd_source_filename from $new_ppd_filename [nyq]? ";
my $input = readline(*STDIN);
if ($input =~ /^q/i) {
@@ -562,17 +578,16 @@ sub update_ppd ($) {
}
}
- # Extract the default values from the original PPD...
-
- seek(ORIG, 0, 0);
-
- my ($odt, $oopt, $ores, $odef) = get_ppd_data(ORIG, 1, 0, 1, 1, 0);
-
# Close original and temporary files...
close ORIG;
if (! $server_multicat && ! close $source_fd) {
- print "Unable to retrieve new PPD file: $!\n";
+ print STDERR "Unable to retrieve new PPD file: $!\n";
+ return -1;
+ }
+
+ if (! $opt_x && !$opt_i && $old_majversion ne $new_majversion) {
+ print STDERR "Skipping $ppd_source_filename: mismatched file versions (old $old_majversion, new $new_majversion); will not update without -x!\n";
return -1;
}
@@ -668,7 +683,7 @@ sub update_ppd ($) {
print STDOUT "Would update $ppd_source_filename to $ppd_dest_filename using $new_ppd_filename\n";
}
}
- return 0;
+ return -1;
}
if (! $reset_defaults) {
@@ -877,6 +892,7 @@ sub get_ppd_data(*$$$$$) {
my ($fh, $types, $opts, $resolutions, $defaults, $data) = @_;
my (%options, %defaults, %resolution_map, %default_types);
my ($fileversion_found) = 0;
+ my ($fileversion) = "";
my $cur_opt = "";
my (@optionlist);
my ($source_data) = "";
@@ -890,7 +906,10 @@ sub get_ppd_data(*$$$$$) {
if ($resolutions || $types || $opts || $defaults || $data) {
while (<$fh>) {
last if $_ eq "*%*%EOFEOF\n";
- $fileversion_found = 1 if (/^\*FileVersion:/);
+ if (/^\*FileVersion:/) {
+ $fileversion_found = 1;
+ ($fileversion) = /^\*FileVersion:\s*"(.*)"$/;
+ }
$source_data .= $_ if ($data);
chomp;
if (($types || $opts) && m/^\*OpenUI/) {
@@ -921,6 +940,6 @@ sub get_ppd_data(*$$$$$) {
}
}
}
- return (undef, undef, undef, undef, undef) if (! $fileversion_found);
- return (\%default_types, \%options, \%resolution_map, \%defaults, $source_data);
+ return (undef, undef, undef, undef, undef, undef) if (! $fileversion_found);
+ return (\%default_types, \%options, \%resolution_map, \%defaults, $source_data, $fileversion);
}
diff --git a/src/cups/genppd.c b/src/cups/genppd.c
index 2ae4124..aa47aad 100644
--- a/src/cups/genppd.c
+++ b/src/cups/genppd.c
@@ -14,8 +14,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contents:
*
@@ -38,51 +37,22 @@
* Include necessary headers...
*/
+#include "genppd.h"
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <libgen.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <sys/wait.h>
#if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
#include <varargs.h>
#else
#include <stdarg.h>
#endif
-#ifdef CUPS_DRIVER_INTERFACE
-# ifdef HAVE_LIBZ
-# undef HAVE_LIBZ
-# endif /* HAVE_LIBZ */
-#endif /* CUPS_DRIVER_INTERFACE */
-#ifdef HAVE_LIBZ
-#include <zlib.h>
-static int use_compression = 1;
-#endif
-
-static const char *cups_modeldir = CUPS_MODELDIR;
-static const char *gpext = "";
-
-#include <cups/cups.h>
-#include <cups/raster.h>
+const char *ppdext = ".ppd";
+const char *cups_modeldir = CUPS_MODELDIR;
+const char *gpext = "";
-#include "i18n.h"
+static int use_compression;
-static int use_base_version = 0;
+int use_base_version = 0;
/*
* Some applications use the XxYdpi tags rather than the actual
@@ -96,13 +66,6 @@ static int use_base_version = 0;
#define MAXIMUM_SAFE_PPD_Y_RESOLUTION (720)
#define MAXIMUM_SAFE_PPD_X_RESOLUTION (1500)
-typedef enum
-{
- PPD_STANDARD = 0,
- PPD_SIMPLIFIED = 1,
- PPD_NO_COLOR_OPTS = 2
-} ppd_type_t;
-
/*
* Note:
*
@@ -117,8 +80,6 @@ int localize_numbers = 0;
* File handling stuff...
*/
-static const char *ppdext = ".ppd";
-
typedef struct /**** Media size values ****/
{
const char *name, /* Media size name */
@@ -166,43 +127,13 @@ const char *parameter_level_names[] =
_("Extra 5")
};
-#ifdef HAVE_LIBZ
-typedef union
-{
- gzFile gzf;
- FILE *f;
-} _gpfile;
-
-typedef _gpfile *gpFile;
-#else
-#define gpFile FILE *
-#endif
-
/*
* Local functions...
*/
-#ifdef CUPS_DRIVER_INTERFACE
-static int cat_ppd(const char *uri);
-static int list_ppds(const char *argv0);
-#else /* !CUPS_DRIVER_INTERFACE */
-static int generate_ppd(const char *prefix, int verbose,
- const stp_printer_t *p, const char *language,
- ppd_type_t ppd_type);
-static int generate_model_ppds(const char *prefix, int verbose,
- const stp_printer_t *printer,
- const char *language, int which_ppds);
-static void help(void);
-static void printlangs(char** langs);
-static void printmodels(int verbose);
-static void usage(void);
-static gpFile gpopen(const char *path, const char *mode);
-static int gpclose(gpFile f);
-#endif /* !CUPS_DRIVER_INTERFACE */
static int gpputs(gpFile f, const char *s);
static int gpprintf(gpFile f, const char *format, ...)
__attribute__((format(__printf__, 2, 3)));
-static char **getlangs(void);
static int is_special_option(const char *name);
static void print_group_close(gpFile fp, stp_parameter_class_t p_class,
stp_parameter_level_t p_level,
@@ -212,9 +143,6 @@ static void print_group_open(gpFile fp, stp_parameter_class_t p_class,
stp_parameter_level_t p_level,
const char *language,
const stp_string_list_t *po);
-static int write_ppd(gpFile fp, const stp_printer_t *p,
- const char *language, const char *ppd_location,
- ppd_type_t ppd_type, const char *filename);
/*
@@ -222,747 +150,6 @@ static int write_ppd(gpFile fp, const stp_printer_t *p,
*/
-#ifdef CUPS_DRIVER_INTERFACE
-
-/*
- * 'main()' - Process files on the command-line...
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
-{
- /*
- * Force POSIX locale, since stp_init incorrectly calls setlocale...
- */
-
- (void) setenv("LANG", "C", 1);
- (void) setenv("LC_ALL", "C", 1);
- (void) setenv("LC_NUMERIC", "C", 1);
-
- /*
- * Initialise libgutenprint
- */
-
- stp_init();
-
- /*
- * Process command-line...
- */
-
- if (argc == 2 && !strcmp(argv[1], "list"))
- return (list_ppds(argv[0]));
- else if (argc == 3 && !strcmp(argv[1], "cat"))
- return (cat_ppd(argv[2]));
- else if (argc == 2 && !strcmp(argv[1], "org.gutenprint.multicat"))
- {
- char buf[1024];
- int status = 0;
- while (fgets(buf, sizeof(buf) - 1, stdin))
- {
- size_t len = strlen(buf);
- if (len == 0)
- continue;
- if (buf[len - 1] == '\n')
- buf[len - 1] = '\0';
- status |= cat_ppd(buf);
- fputs("*%*%EOFEOF\n", stdout);
- (void) fflush(stdout);
- }
- }
- else if (argc == 2 && !strcmp(argv[1], "VERSION"))
- {
- printf("%s\n", VERSION);
- return (0);
- }
- else if (argc == 2 && !strcasecmp(argv[1], "org.gutenprint.extensions"))
- {
- printf("org.gutenprint.multicat");
- return (0);
- }
- else
- {
- fprintf(stderr, "Usage: %s list\n", argv[0]);
- fprintf(stderr, " %s cat URI\n", argv[0]);
- return (1);
- }
- return (0);
-}
-
-
-/*
- * 'cat_ppd()' - Copy the named PPD to stdout.
- */
-
-static int /* O - Exit status */
-cat_ppd(const char *uri) /* I - Driver URI */
-{
- char scheme[64], /* URI scheme */
- userpass[32], /* URI user/pass (unused) */
- hostname[32], /* URI hostname */
- resource[1024]; /* URI resource */
- int port; /* URI port (unused) */
- http_uri_status_t status; /* URI decode status */
- const stp_printer_t *p; /* Printer driver */
- const char *lang = NULL;
- char *s;
- char filename[1024], /* Filename */
- ppd_location[1024]; /* Installed location */
- const char *infix = "";
- ppd_type_t ppd_type = PPD_STANDARD;
-
- if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri,
- scheme, sizeof(scheme),
- userpass, sizeof(userpass),
- hostname, sizeof(hostname),
- &port, resource, sizeof(resource)))
- < HTTP_URI_OK)
- {
- fprintf(stderr, "ERROR: Bad ppd-name \"%s\" (%d)!\n", uri, status);
- return (1);
- }
-
- if (strcmp(scheme, "gutenprint." GUTENPRINT_RELEASE_VERSION) != 0)
- {
- fprintf(stderr, "ERROR: Gutenprint version mismatch!\n");
- return(1);
- }
-
- s = strchr(resource + 1, '/');
- if (s)
- {
- lang = s + 1;
- *s = '\0';
- }
-
- if ((p = stp_get_printer_by_driver(hostname)) == NULL)
- {
- fprintf(stderr, "ERROR: Unable to find driver \"%s\"!\n", hostname);
- return (1);
- }
-
- if (strcmp(resource + 1, "simple") == 0)
- {
- infix = ".sim";
- ppd_type = PPD_SIMPLIFIED;
- }
- else if (strcmp(resource + 1, "nocolor") == 0)
- {
- infix = ".nc";
- ppd_type = PPD_NO_COLOR_OPTS;
- }
-
- /*
- * This isn't really the right thing to do. We really shouldn't
- * be embedding filenames in automatically generated PPD files, but
- * if the user ever decides to go back from generated PPD files to
- * static PPD files we'll need to have this for genppdupdate to work.
- */
- snprintf(filename, sizeof(filename) - 1, "stp-%s.%s%s%s",
- hostname, GUTENPRINT_RELEASE_VERSION, infix, ppdext);
- snprintf(ppd_location, sizeof(ppd_location) - 1, "%s%s%s/ppd/%s%s",
- cups_modeldir,
- cups_modeldir[strlen(cups_modeldir) - 1] == '/' ? "" : "/",
- lang ? lang : "C",
- filename, gpext);
-
- return (write_ppd(stdout, p, lang, ppd_location, ppd_type, filename));
-}
-
-/*
- * 'list_ppds()' - List the available drivers.
- */
-
-static int /* O - Exit status */
-list_ppds(const char *argv0) /* I - Name of program */
-{
- const char *scheme; /* URI scheme */
- int i; /* Looping var */
- const stp_printer_t *printer; /* Pointer to printer driver */
-
- if ((scheme = strrchr(argv0, '/')) != NULL)
- scheme ++;
- else
- scheme = argv0;
-
- for (i = 0; i < stp_printer_model_count(); i++)
- if ((printer = stp_get_printer_by_index(i)) != NULL)
- {
- const char *device_id;
- if (!strcmp(stp_printer_get_family(printer), "ps") ||
- !strcmp(stp_printer_get_family(printer), "raw"))
- continue;
-
- device_id = stp_printer_get_device_id(printer);
- printf("\"%s://%s/expert\" "
- "%s "
- "\"%s\" "
- "\"%s" CUPS_PPD_NICKNAME_STRING VERSION "\" "
- "\"%s\"\n",
- scheme, stp_printer_get_driver(printer),
- "en",
- stp_printer_get_manufacturer(printer),
- stp_printer_get_long_name(printer),
- device_id ? device_id : "");
-
-#ifdef GENERATE_SIMPLIFIED_PPDS
- printf("\"%s://%s/simple\" "
- "%s "
- "\"%s\" "
- "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " Simplified\" "
- "\"%s\"\n",
- scheme, stp_printer_get_driver(printer),
- "en",
- stp_printer_get_manufacturer(printer),
- stp_printer_get_long_name(printer),
- device_id ? device_id : "");
-#endif
-
-#ifdef GENERATE_NOCOLOR_PPDS
- printf("\"%s://%s/nocolor\" "
- "%s "
- "\"%s\" "
- "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " No color options\" "
- "\"%s\"\n",
- scheme, stp_printer_get_driver(printer),
- "en",
- stp_printer_get_manufacturer(printer),
- stp_printer_get_long_name(printer),
- device_id ? device_id : "");
-#endif
- }
-
- return (0);
-}
-#endif /* CUPS_DRIVER_INTERFACE */
-
-#ifndef CUPS_DRIVER_INTERFACE
-
-/*
- * 'main()' - Process files on the command-line...
- */
-
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
-{
- int i; /* Looping var */
- const char *prefix; /* Directory prefix for output */
- const char *language = NULL; /* Language */
- const stp_printer_t *printer; /* Pointer to printer driver */
- int verbose = 0; /* Verbose messages */
- char **langs = NULL; /* Available translations */
- char **models = NULL; /* Models to output, all if NULL */
- int opt_printlangs = 0; /* Print available translations */
- int opt_printmodels = 0;/* Print available models */
- int which_ppds = 2; /* Simplified PPD's = 1, full = 2,
- no color opts = 4 */
- unsigned parallel = 1; /* Generate PPD files in parallel */
- unsigned rotor = 0; /* Rotor for generating PPD files in parallel */
- pid_t *subprocesses = NULL;
- int parent = 1;
-
- /*
- * Parse command-line args...
- */
-
- prefix = CUPS_MODELDIR;
-
- for (;;)
- {
- if ((i = getopt(argc, argv, "23hvqc:p:l:LMVd:saNCbZz")) == -1)
- break;
-
- switch (i)
- {
- case '2':
- cups_ppd_ps_level = 2;
- break;
- case '3':
- cups_ppd_ps_level = 3;
- break;
- case 'h':
- help();
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- verbose = 1;
- break;
- case 'q':
- verbose = 0;
- break;
- case 'c':
- fputs("ERROR: -c option no longer supported!\n", stderr);
- break;
- case 'p':
- prefix = optarg;
-# ifdef DEBUG
- fprintf(stderr, "DEBUG: prefix: %s\n", prefix);
-# endif
- break;
- case 'l':
- language = optarg;
- break;
- case 'L':
- opt_printlangs = 1;
- break;
- case 'M':
- opt_printmodels = 1;
- break;
- case 'd':
- cups_modeldir = optarg;
- break;
- case 's':
- which_ppds = 1;
- break;
- case 'a':
- which_ppds = 3;
- break;
- case 'C':
- which_ppds |= 4;
- break;
- case 'N':
- localize_numbers = !localize_numbers;
- break;
- case 'V':
- printf("cups-genppd version %s, "
- "Copyright 1993-2008 by Michael R Sweet and Robert Krawitz.\n\n",
- VERSION);
- printf("Default CUPS PPD PostScript Level: %d\n", cups_ppd_ps_level);
- printf("Default PPD location (prefix): %s\n", CUPS_MODELDIR);
- printf("Default base locale directory: %s\n\n", PACKAGE_LOCALE_DIR);
- puts("This program is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU General Public License,\n"
- "version 2, as published by the Free Software Foundation.\n"
- "\n"
- "This program is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU General Public License for more details.\n");
- exit(EXIT_SUCCESS);
- break;
- case 'b':
- use_base_version = 1;
- break;
- case 'z':
-#ifdef HAVE_LIBZ
- use_compression = 1;
-#endif
- break;
- case 'Z':
-#ifdef HAVE_LIBZ
- use_compression = 0;
-#endif
- break;
- default:
- usage();
- exit(EXIT_FAILURE);
- break;
- }
- }
-#ifdef HAVE_LIBZ
- if (use_compression)
- gpext = ".gz";
- else
-#endif
- gpext = "";
- if (optind < argc) {
- int n, numargs;
- numargs = argc-optind;
- models = stp_malloc((numargs+1) * sizeof(char*));
- for (n=0; n<numargs; n++)
- {
- models[n] = argv[optind+n];
- }
- models[numargs] = (char*)NULL;
- }
-
-/*
- * Initialise libgutenprint
- */
-
- stp_init();
-
- langs = getlangs();
-
- /*
- * Print lists
- */
-
- if (opt_printlangs)
- {
- printlangs(langs);
- exit(EXIT_SUCCESS);
- }
-
- if (opt_printmodels)
- {
- printmodels(verbose);
- exit(EXIT_SUCCESS);
- }
-
- /*
- * Write PPD files...
- */
-
- if (getenv("STP_PARALLEL"))
- {
- parallel = atoi(getenv("STP_PARALLEL"));
- if (parallel < 1 || parallel > 256)
- parallel = 1;
- }
- if (parallel)
- {
- subprocesses = stp_malloc(sizeof(pid_t) * parallel);
- for (rotor = 0; rotor < parallel; rotor++)
- {
- pid_t pid = fork();
- if (pid == 0) /* Child */
- {
- parent = 0;
- break;
- }
- else if (pid > 0)
- subprocesses[rotor] = pid;
- else
- {
- fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
- return 1;
- }
- }
- }
- if (models)
- {
- int n;
- for (n=0; models[n]; n++)
- {
- printer = stp_get_printer_by_driver(models[n]);
- if (!printer)
- printer = stp_get_printer_by_long_name(models[n]);
-
- if (n % parallel == rotor && printer)
- {
- if (printer)
- {
- if (generate_model_ppds(prefix, verbose, printer, language,
- which_ppds))
- return 1;
- }
- else
- {
- printf("Driver not found: %s\n", models[n]);
- return (1);
- }
- }
- }
- stp_free(models);
- }
- else
- {
- for (i = 0; i < stp_printer_model_count(); i++)
- {
- printer = stp_get_printer_by_index(i);
-
- if (i % parallel == rotor && printer)
- {
- if (! verbose && (i % 50) == 0)
- fputc('.',stderr);
- if (generate_model_ppds(prefix, verbose, printer, language,
- which_ppds))
- return 1;
- }
- }
- }
- if (subprocesses)
- {
- pid_t pid;
- do
- {
- int status;
- pid = waitpid(-1, &status, 0);
- if (pid > 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
- {
- fprintf(stderr, "failed!\n");
- return 1;
- }
- } while (pid > 0);
- stp_free(subprocesses);
- }
- if (parent && !verbose)
- fprintf(stderr, " done.\n");
-
- return (0);
-}
-
-static int
-generate_model_ppds(const char *prefix, int verbose,
- const stp_printer_t *printer, const char *language,
- int which_ppds)
-{
- if ((which_ppds & 1) &&
- generate_ppd(prefix, verbose, printer, language, PPD_SIMPLIFIED))
- return (1);
- if ((which_ppds & 2) &&
- generate_ppd(prefix, verbose, printer, language, PPD_STANDARD))
- return (1);
- if ((which_ppds & 4) &&
- generate_ppd(prefix, verbose, printer, language, PPD_NO_COLOR_OPTS))
- return (1);
- return 0;
-}
-
-/*
- * 'generate_ppd()' - Generate a PPD file.
- */
-
-static int /* O - Exit status */
-generate_ppd(
- const char *prefix, /* I - PPD directory prefix */
- int verbose, /* I - Verbosity level */
- const stp_printer_t *p, /* I - Driver */
- const char *language, /* I - Primary language */
- ppd_type_t ppd_type) /* I - full, simplified, no color */
-{
- int status; /* Exit status */
- gpFile fp; /* File to write to */
- char filename[1024], /* Filename */
- ppd_location[1024]; /* Installed location */
- struct stat dir; /* Prefix dir status */
- const char *ppd_infix;
-
- /*
- * Skip the PostScript drivers...
- */
-
- if (!strcmp(stp_printer_get_family(p), "ps") ||
- !strcmp(stp_printer_get_family(p), "raw"))
- return (0);
-
- /*
- * Make sure the destination directory exists...
- */
-
- if (stat(prefix, &dir) && !S_ISDIR(dir.st_mode))
- {
- if (mkdir(prefix, 0777))
- {
- printf("cups-genppd: Cannot create directory %s: %s\n",
- prefix, strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
-
- /*
- * The files will be named stp-<driver>.<major>.<minor>.ppd, for
- * example:
- *
- * stp-escp2-ex.5.0.ppd
- *
- * or
- *
- * stp-escp2-ex.5.0.ppd.gz
- */
-
- switch (ppd_type)
- {
- case PPD_SIMPLIFIED:
- ppd_infix = ".sim";
- break;
- case PPD_NO_COLOR_OPTS:
- ppd_infix = ".nc";
- break;
- default:
- ppd_infix = "";
- }
-
- snprintf(filename, sizeof(filename) - 1, "%s/stp-%s.%s%s%s%s",
- prefix, stp_printer_get_driver(p), GUTENPRINT_RELEASE_VERSION,
- ppd_infix, ppdext, gpext);
-
- /*
- * Open the PPD file...
- */
-
- if ((fp = gpopen(filename, "wb")) == NULL)
- {
- fprintf(stderr, "cups-genppd: Unable to create file \"%s\" - %s.\n",
- filename, strerror(errno));
- return (2);
- }
-
- if (verbose)
- fprintf(stderr, "Writing %s...\n", filename);
-
- snprintf(ppd_location, sizeof(ppd_location), "%s%s%s/%s",
- cups_modeldir,
- cups_modeldir[strlen(cups_modeldir) - 1] == '/' ? "" : "/",
- language ? language : "C",
- basename(filename));
-
- snprintf(filename, sizeof(filename) - 1, "stp-%s.%s%s%s",
- stp_printer_get_driver(p), GUTENPRINT_RELEASE_VERSION,
- ppd_infix, ppdext);
-
- status = write_ppd(fp, p, language, ppd_location, ppd_type,
- basename(filename));
-
- gpclose(fp);
-
- return (status);
-}
-
-/*
- * 'help()' - Show detailed help.
- */
-
-void
-help(void)
-{
- puts("Generate Gutenprint PPD files for use with CUPS\n\n");
- usage();
- puts("\nExamples: LANG=de_DE cups-genppd -p ppd -c /usr/share/locale\n"
- " cups-genppd -L -c /usr/share/locale\n"
- " cups-genppd -M -v\n\n"
- "Commands:\n"
- " -h Show this help message.\n"
- " -L List available translations (message catalogs).\n"
- " -M List available printer models.\n"
- " -V Show version information and defaults.\n"
- " The default is to output PPDs.\n");
- puts("Options:\n"
- " -N Localize numbers.\n"
- " -l locale Output PPDs translated with messages for locale.\n"
- " -p prefix Output PPDs in directory prefix.\n"
- " -d prefix Embed directory prefix in PPD file.\n"
- " -s Generate simplified PPD files.\n"
- " -a Generate all (simplified and full) PPD files.\n"
- " -q Quiet mode.\n"
- " -v Verbose mode.\n");
- puts(
-#ifdef HAVE_LIBZ
- " -z Compress PPD files.\n"
- " -Z Don't compress PPD files.\n"
-#endif
- "models:\n"
- " A list of printer models, either the driver or quoted full name.\n");
-}
-
-/*
- * 'usage()' - Show program usage.
- */
-
-void
-usage(void)
-{
- puts("Usage: cups-genppd "
- "[-l locale] [-p prefix] [-s | -a] [-q] [-v] models...\n"
- " cups-genppd -L\n"
- " cups-genppd -M [-v]\n"
- " cups-genppd -h\n"
- " cups-genppd -V\n");
-}
-
-/*
- * 'printlangs()' - Print list of available translations.
- */
-
-void
-printlangs(char **langs) /* I - Languages */
-{
- if (langs)
- {
- int n = 0;
- while (langs && langs[n])
- {
- puts(langs[n]);
- n++;
- }
- }
- exit(EXIT_SUCCESS);
-}
-
-
-/*
- * 'printmodels()' - Print a list of available models.
- */
-
-void
-printmodels(int verbose) /* I - Verbosity level */
-{
- const stp_printer_t *p;
- int i;
-
- for (i = 0; i < stp_printer_model_count(); i++)
- {
- p = stp_get_printer_by_index(i);
- if (p &&
- strcmp(stp_printer_get_family(p), "ps") != 0 &&
- strcmp(stp_printer_get_family(p), "raw") != 0)
- {
- if(verbose)
- printf("%-20s%s\n", stp_printer_get_driver(p),
- stp_printer_get_long_name(p));
- else
- printf("%s\n", stp_printer_get_driver(p));
- }
- }
- exit(EXIT_SUCCESS);
-}
-
-static gpFile
-gpopen(const char *path, const char *mode)
-{
-#ifdef HAVE_LIBZ
- gpFile f = stp_malloc(sizeof(_gpfile));
- if (use_compression)
- {
- f->gzf = gzopen(path, mode);
- if (!f->gzf)
- {
- stp_free(f);
- return NULL;
- }
- return f;
- }
- else
-#endif
- {
- FILE *fl = fopen(path, mode);
-#ifdef HAVE_LIBZ
- if (fl)
- {
- f->f = fl;
- return f;
- }
- else
- {
- stp_free(f);
- return NULL;
- }
-#else
- return fl;
-#endif
- }
-}
-
-static int
-gpclose(gpFile f)
-{
- int status;
-#ifdef HAVE_LIBZ
- if (use_compression)
- status = gzclose(f->gzf);
- else
- status = fclose(f->f);
- stp_free(f);
-#else
- status = fclose(f);
-#endif
- return status;
-}
-
-#endif /* !CUPS_DRIVER_INTERFACE */
-
static int
gpputs(gpFile f, const char *s)
{
@@ -1106,7 +293,8 @@ print_ppd_header(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
gpputs(fp, "*% Copyright 1993-2008 by Mike Sweet and Robert Krawitz.\n");
gpputs(fp, "*% This program is free software; you can redistribute it and/or\n");
gpputs(fp, "*% modify it under the terms of the GNU General Public License,\n");
- gpputs(fp, "*% version 2, as published by the Free Software Foundation.\n");
+ gpputs(fp, "*% either version 2, or (at your option) any later version,\n");
+ gpputs(fp, "*% as published by the Free Software Foundation.\n");
gpputs(fp, "*%\n");
gpputs(fp, "*% This program is distributed in the hope that it will be useful, but\n");
gpputs(fp, "*% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n");
@@ -1114,8 +302,7 @@ print_ppd_header(gpFile fp, ppd_type_t ppd_type, int model, const char *driver,
gpputs(fp, "*% for more details.\n");
gpputs(fp, "*%\n");
gpputs(fp, "*% You should have received a copy of the GNU General Public License\n");
- gpputs(fp, "*% along with this program; if not, write to the Free Software\n");
- gpputs(fp, "*% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
+ gpputs(fp, "*% along with this program. If not, see <https://www.gnu.org/licenses/>.\n");
gpputs(fp, "*%\n");
gpputs(fp, "*FormatVersion: \"4.3\"\n");
if (use_base_version)
@@ -1200,7 +387,29 @@ print_ppd_header_3(gpFile fp, ppd_type_t ppd_type, int model,
if (strcasecmp(manufacturer, "EPSON") == 0)
gpputs(fp, "*cupsFilter: \"application/vnd.cups-command 33 commandtoepson\"\n");
if (device_id)
- gpprintf(fp, "*1284DeviceID: \"%s\"\n", device_id);
+ {
+ if (strlen(device_id) > 200)
+ {
+ char buf[129];
+ int bytes_left = strlen(device_id);
+ int offset = 0;
+ gpputs(fp, "*1284DeviceID: \"");
+ while (bytes_left > 0)
+ {
+ memset(buf, 0, 129);
+ strncpy(buf, device_id + offset, 128);
+ gpputs(fp, buf);
+ if (bytes_left <= 128)
+ gpputs(fp, "\"");
+ gpputs(fp, "\n");
+ offset += 128;
+ bytes_left -= 128;
+ }
+ gpputs(fp, "*End\n");
+ }
+ else
+ gpprintf(fp, "*1284DeviceID: \"%s\"\n", device_id);
+ }
if (!language)
{
/*
@@ -1263,31 +472,32 @@ print_page_sizes(gpFile fp, stp_vars_t *v, int simplified,
{
const stp_papersize_t *papersize;
opt = stp_string_list_param(desc.bounds.str, i);
- papersize = stp_get_papersize_by_name(opt->name);
-
- if (!papersize)
+ if (strcmp(opt->name, "Custom") == 0)
{
- printf("Unable to lookup size %s!\n", opt->name);
+ variable_sizes = 1;
continue;
}
- if (strcmp(opt->name, "Custom") == 0)
+ papersize = stp_describe_papersize(v, opt->name);
+
+ if (!papersize)
{
- variable_sizes = 1;
+ printf("Unable to lookup size %s!\n", opt->name);
continue;
}
+
if (simplified && num_opts >= 10 &&
(!desc.deflt.str || strcmp(opt->name, desc.deflt.str) != 0) &&
(papersize->paper_unit == PAPERSIZE_ENGLISH_EXTENDED ||
papersize->paper_unit == PAPERSIZE_METRIC_EXTENDED))
continue;
+ if (papersize->width <= 0 || papersize->height <= 0)
+ continue;
+
width = papersize->width;
height = papersize->height;
- if (width <= 0 || height <= 0)
- continue;
-
stp_set_string_parameter(v, "PageSize", opt->name);
stp_get_media_size(v, &width, &height);
@@ -1978,14 +1188,15 @@ print_standard_fonts(gpFile fp)
* 'write_ppd()' - Write a PPD file.
*/
-static int /* O - Exit status */
+int /* O - Exit status */
write_ppd(
gpFile fp, /* I - File to write to */
const stp_printer_t *p, /* I - Printer driver */
const char *language, /* I - Primary language */
const char *ppd_location, /* I - Location of PPD file */
ppd_type_t ppd_type, /* I - 1 = simplified options */
- const char *filename) /* I - input filename */
+ const char *filename, /* I - input filename */
+ int compress) /* I - compress output */
{
int i, j, k, l; /* Looping vars */
int num_opts; /* Number of printer options */
@@ -2014,7 +1225,12 @@ write_ppd(
const stp_string_list_t *po = stp_i18n_load(language);
/* Message catalog */
-
+ /*
+ * This is ugly. The right thing would be to pass this through, but
+ * then all calls to gpputs, gpprintf, etc. and callers would need to
+ * have this arg.
+ */
+ use_compression = compress;
/*
* Initialize driver-specific variables...
*/
@@ -2057,8 +1273,10 @@ write_ppd(
}
stp_parameter_description_destroy(&desc);
- if (stp_check_boolean_parameter(v, "NativeCopies", STP_PARAMETER_ACTIVE))
- nativecopies = stp_get_boolean_parameter(v, "NativeCopies");
+ stp_describe_parameter(v, "NativeCopies", &desc);
+ if (desc.p_type == STP_PARAMETER_TYPE_BOOLEAN)
+ nativecopies = desc.deflt.boolean;
+ stp_parameter_description_destroy(&desc);
if (nativecopies)
gpputs(fp, "*cupsManualCopies: False\n");
@@ -2470,7 +1688,6 @@ write_ppd(
print_group_close(fp, j, k, language, po);
}
}
- stp_parameter_list_destroy(param_list);
stp_describe_parameter(v, "ImageType", &desc);
if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
{
@@ -2528,7 +1745,7 @@ write_ppd(
{
const stp_papersize_t *papersize;
opt = stp_string_list_param(desc.bounds.str, i);
- papersize = stp_get_papersize_by_name(opt->name);
+ papersize = stp_describe_papersize(v, opt->name);
if (!papersize)
continue;
@@ -2539,12 +1756,11 @@ write_ppd(
*/
if (simplified && num_opts >= 10 &&
+ (!desc.deflt.str || strcmp(opt->name, desc.deflt.str) != 0) &&
(papersize->paper_unit == PAPERSIZE_ENGLISH_EXTENDED ||
- papersize->paper_unit == PAPERSIZE_METRIC_EXTENDED))
- continue;
-
- if ((papersize->width <= 0 || papersize->height <= 0) &&
- strcmp(opt->name, "Custom") != 0)
+ papersize->paper_unit == PAPERSIZE_METRIC_EXTENDED ||
+ ((papersize->width <= 0 || papersize->height <= 0) &&
+ strcmp(opt->name, "Custom") != 0)))
continue;
gpprintf(fp, "*%s.PageSize %s/%s: \"\"\n", lang, opt->name, stp_i18n_lookup(po, opt->text));
@@ -2706,8 +1922,6 @@ write_ppd(
gpprintf(fp, "*%s.StpiShrinkOutput %s/%s: \"\"\n", lang, "Crop", _("Crop (preserve dimensions)"));
gpprintf(fp, "*%s.StpiShrinkOutput %s/%s: \"\"\n", lang, "Expand", _("Expand (use maximum page area)"));
- param_list = stp_get_parameter_list(v);
-
for (j = 0; j <= STP_PARAMETER_CLASS_OUTPUT; j++)
{
for (k = 0; k <= maximum_level; k++)
@@ -2733,7 +1947,6 @@ write_ppd(
}
}
}
- stp_parameter_list_destroy(param_list);
stp_describe_parameter(v, "ImageType", &desc);
if (desc.is_active && desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
{
@@ -2753,6 +1966,7 @@ write_ppd(
}
po = savepo;
}
+ stp_parameter_list_destroy(param_list);
if (has_quality_parameter)
stp_free(default_resolution);
stp_string_list_destroy(resolutions);
diff --git a/src/cups/genppd.h b/src/cups/genppd.h
new file mode 100644
index 0000000..3452a99
--- /dev/null
+++ b/src/cups/genppd.h
@@ -0,0 +1,91 @@
+/*
+ * PPD file generation program for the CUPS drivers.
+ *
+ * Copyright 1993-2008 by Mike Sweet and Robert Krawitz.
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ *
+ * Contents:
+ *
+ * main() - Process files on the command-line...
+ * cat_ppd() - Copy the named PPD to stdout.
+ * generate_ppd() - Generate a PPD file.
+ * getlangs() - Get a list of available translations.
+ * help() - Show detailed help.
+ * is_special_option() - Determine if an option should be grouped.
+ * list_ppds() - List the available drivers.
+ * print_group_close() - Close a UI group.
+ * print_group_open() - Open a new UI group.
+ * printlangs() - Print list of available translations.
+ * printmodels() - Print a list of available models.
+ * usage() - Show program usage.
+ * write_ppd() - Write a PPD file.
+ */
+
+#include "i18n.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libgen.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <cups/raster.h>
+
+extern char **getlangs(void);
+
+
+typedef enum
+{
+ PPD_STANDARD = 0,
+ PPD_SIMPLIFIED = 1,
+ PPD_NO_COLOR_OPTS = 2
+} ppd_type_t;
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+typedef union
+{
+#ifdef HAVE_LIBZ
+ gzFile gzf;
+#endif
+ FILE *f;
+} gpfile;
+typedef gpfile *gpFile;
+
+extern const char *ppdext;
+extern const char *cups_modeldir;
+extern const char *gpext;
+extern int cups_ppd_ps_level;
+extern int localize_numbers;
+extern int use_base_version;
+
+extern int write_ppd(gpFile fp, const stp_printer_t *p,
+ const char *language, const char *ppd_location,
+ ppd_type_t ppd_type, const char *filename,
+ int compress);
diff --git a/src/cups/gutenprint.c b/src/cups/gutenprint.c
new file mode 100644
index 0000000..6ab2194
--- /dev/null
+++ b/src/cups/gutenprint.c
@@ -0,0 +1,253 @@
+/*
+ * PPD file generation program for the CUPS drivers.
+ *
+ * Copyright 1993-2008 by Mike Sweet and Robert Krawitz.
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ *
+ * Contents:
+ *
+ * main() - Process files on the command-line...
+ * cat_ppd() - Copy the named PPD to stdout.
+ * generate_ppd() - Generate a PPD file.
+ * getlangs() - Get a list of available translations.
+ * help() - Show detailed help.
+ * is_special_option() - Determine if an option should be grouped.
+ * list_ppds() - List the available drivers.
+ * print_group_close() - Close a UI group.
+ * print_group_open() - Open a new UI group.
+ * printlangs() - Print list of available translations.
+ * printmodels() - Print a list of available models.
+ * usage() - Show program usage.
+ * write_ppd() - Write a PPD file.
+ */
+
+/*
+ * 'main()' - Process files on the command-line...
+ */
+
+#include "genppd.h"
+
+static int cat_ppd(const char *uri);
+static int list_ppds(const char *argv0);
+
+
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+{
+ /*
+ * Force POSIX locale, since stp_init incorrectly calls setlocale...
+ */
+
+ (void) setenv("LANG", "C", 1);
+ (void) setenv("LC_ALL", "C", 1);
+ (void) setenv("LC_NUMERIC", "C", 1);
+
+ /*
+ * Initialise libgutenprint
+ */
+
+ stp_init();
+
+ /*
+ * Process command-line...
+ */
+
+ if (argc == 2 && !strcmp(argv[1], "list"))
+ return (list_ppds(argv[0]));
+ else if (argc == 3 && !strcmp(argv[1], "cat"))
+ return (cat_ppd(argv[2]));
+ else if (argc == 2 && !strcmp(argv[1], "org.gutenprint.multicat"))
+ {
+ char buf[1024];
+ int status = 0;
+ while (fgets(buf, sizeof(buf) - 1, stdin))
+ {
+ size_t len = strlen(buf);
+ if (len == 0)
+ continue;
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ status |= cat_ppd(buf);
+ fputs("*%*%EOFEOF\n", stdout);
+ (void) fflush(stdout);
+ }
+ }
+ else if (argc == 2 && !strcmp(argv[1], "VERSION"))
+ {
+ printf("%s\n", VERSION);
+ return (0);
+ }
+ else if (argc == 2 && !strcasecmp(argv[1], "org.gutenprint.extensions"))
+ {
+ printf("org.gutenprint.multicat");
+ return (0);
+ }
+ else
+ {
+ fprintf(stderr, "Usage: %s list\n", argv[0]);
+ fprintf(stderr, " %s cat URI\n", argv[0]);
+ return (1);
+ }
+ return (0);
+}
+
+
+/*
+ * 'cat_ppd()' - Copy the named PPD to stdout.
+ */
+
+static int /* O - Exit status */
+cat_ppd(const char *uri) /* I - Driver URI */
+{
+ char scheme[64], /* URI scheme */
+ userpass[32], /* URI user/pass (unused) */
+ hostname[32], /* URI hostname */
+ resource[1024]; /* URI resource */
+ int port; /* URI port (unused) */
+ http_uri_status_t status; /* URI decode status */
+ const stp_printer_t *p; /* Printer driver */
+ const char *lang = NULL;
+ char *s;
+ char filename[1024], /* Filename */
+ ppd_location[1024]; /* Installed location */
+ const char *infix = "";
+ ppd_type_t ppd_type = PPD_STANDARD;
+ gpfile outFD;
+
+ if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri,
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname),
+ &port, resource, sizeof(resource)))
+ < HTTP_URI_OK)
+ {
+ fprintf(stderr, "ERROR: Bad ppd-name \"%s\" (%d)!\n", uri, status);
+ return (1);
+ }
+
+ if (strcmp(scheme, "gutenprint." GUTENPRINT_RELEASE_VERSION) != 0)
+ {
+ fprintf(stderr, "ERROR: Gutenprint version mismatch!\n");
+ return(1);
+ }
+
+ s = strchr(resource + 1, '/');
+ if (s)
+ {
+ lang = s + 1;
+ *s = '\0';
+ }
+
+ if ((p = stp_get_printer_by_driver(hostname)) == NULL)
+ {
+ fprintf(stderr, "ERROR: Unable to find driver \"%s\"!\n", hostname);
+ return (1);
+ }
+
+ if (strcmp(resource + 1, "simple") == 0)
+ {
+ infix = ".sim";
+ ppd_type = PPD_SIMPLIFIED;
+ }
+ else if (strcmp(resource + 1, "nocolor") == 0)
+ {
+ infix = ".nc";
+ ppd_type = PPD_NO_COLOR_OPTS;
+ }
+
+ /*
+ * This isn't really the right thing to do. We really shouldn't
+ * be embedding filenames in automatically generated PPD files, but
+ * if the user ever decides to go back from generated PPD files to
+ * static PPD files we'll need to have this for genppdupdate to work.
+ */
+ snprintf(filename, sizeof(filename) - 1, "stp-%s.%s%s%s",
+ hostname, GUTENPRINT_RELEASE_VERSION, infix, ppdext);
+ snprintf(ppd_location, sizeof(ppd_location) - 1, "%s%s%s/ppd/%s%s",
+ cups_modeldir,
+ cups_modeldir[strlen(cups_modeldir) - 1] == '/' ? "" : "/",
+ lang ? lang : "C",
+ filename, gpext);
+
+ outFD.f = stdout;
+ return (write_ppd(&outFD, p, lang, ppd_location, ppd_type, filename, 0));
+}
+
+/*
+ * 'list_ppds()' - List the available drivers.
+ */
+
+static int /* O - Exit status */
+list_ppds(const char *argv0) /* I - Name of program */
+{
+ const char *scheme; /* URI scheme */
+ int i; /* Looping var */
+ const stp_printer_t *printer; /* Pointer to printer driver */
+
+ if ((scheme = strrchr(argv0, '/')) != NULL)
+ scheme ++;
+ else
+ scheme = argv0;
+
+ for (i = 0; i < stp_printer_model_count(); i++)
+ if ((printer = stp_get_printer_by_index(i)) != NULL)
+ {
+ const char *device_id;
+ if (!strcmp(stp_printer_get_family(printer), "ps") ||
+ !strcmp(stp_printer_get_family(printer), "raw"))
+ continue;
+
+ device_id = stp_printer_get_device_id(printer);
+ printf("\"%s://%s/expert\" "
+ "%s "
+ "\"%s\" "
+ "\"%s" CUPS_PPD_NICKNAME_STRING VERSION "\" "
+ "\"%s\"\n",
+ scheme, stp_printer_get_driver(printer),
+ "en",
+ stp_printer_get_manufacturer(printer),
+ stp_printer_get_long_name(printer),
+ device_id ? device_id : "");
+
+#ifdef GENERATE_SIMPLIFIED_PPDS
+ printf("\"%s://%s/simple\" "
+ "%s "
+ "\"%s\" "
+ "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " Simplified\" "
+ "\"%s\"\n",
+ scheme, stp_printer_get_driver(printer),
+ "en",
+ stp_printer_get_manufacturer(printer),
+ stp_printer_get_long_name(printer),
+ device_id ? device_id : "");
+#endif
+
+#ifdef GENERATE_NOCOLOR_PPDS
+ printf("\"%s://%s/nocolor\" "
+ "%s "
+ "\"%s\" "
+ "\"%s" CUPS_PPD_NICKNAME_STRING VERSION " No color options\" "
+ "\"%s\"\n",
+ scheme, stp_printer_get_driver(printer),
+ "en",
+ stp_printer_get_manufacturer(printer),
+ stp_printer_get_long_name(printer),
+ device_id ? device_id : "");
+#endif
+ }
+
+ return (0);
+}
diff --git a/src/cups/i18n.c b/src/cups/i18n.c
index f032d13..89ff2b6 100644
--- a/src/cups/i18n.c
+++ b/src/cups/i18n.c
@@ -14,8 +14,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contents:
*
diff --git a/src/cups/i18n.h b/src/cups/i18n.h
index 222b2c3..1ab5275 100644
--- a/src/cups/i18n.h
+++ b/src/cups/i18n.h
@@ -14,8 +14,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gutenprint/gutenprint.h>
diff --git a/src/cups/min-pagesize.in b/src/cups/min-pagesize.in
new file mode 100644
index 0000000..06cd148
--- /dev/null
+++ b/src/cups/min-pagesize.in
@@ -0,0 +1,42 @@
+#!@PERL@
+
+# Find smallest page size in PPD file.
+#
+# Copyright 2018 Robert Krawitz (rlk@alum.mit.edu)
+#
+# 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, see <https://www.gnu.org/licenses/>.
+#
+# This is faster than using Gutenprint to do this; stp_init() is still
+# quite expensive for such small operations.
+
+use strict;
+
+open(PPD, $ENV{'PPD'}) || die "Can't open PPD file $ENV{'PPD'}: $!\n";
+my ($min_size_name) = "";
+my ($min_size_dim) = 0;
+while (<PPD>) {
+ if ($min_size_name ne '' && ! /^\*PaperDimension/) {
+ print "$min_size_name\n";
+ exit;
+ }
+ next if (! /^\*PaperDimension/);
+ $_ =~ /^\*PaperDimension *([^\/]+)\/[^\"]*"([0-9.]+) *([0-9.]+)/;
+ my ($pname) = $1;
+ my ($x) = $2;
+ my ($y) = $3;
+ if ($min_size_name eq "" || ($x * $y < $min_size_dim)) {
+ $min_size_name = $pname;
+ $min_size_dim = $x * $y;
+ }
+}
diff --git a/src/cups/rastertoprinter.c b/src/cups/rastertogutenprint.c
index 0fa0668..5e6e8ba 100644
--- a/src/cups/rastertoprinter.c
+++ b/src/cups/rastertogutenprint.c
@@ -14,8 +14,7 @@
* 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.
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contents:
*
@@ -111,6 +110,7 @@ typedef struct
static void cups_writefunc(void *file, const char *buf, size_t bytes);
static void cups_errfunc(void *file, const char *buf, size_t bytes);
+static void cups_dbgfunc(void *file, const char *buf, size_t bytes);
static void cancel_job(int sig);
static const char *Image_get_appname(stp_image_t *image);
static stp_image_status_t Image_get_row(stp_image_t *image,
@@ -144,8 +144,6 @@ static const char *save_file_name = NULL;
static const char *load_file_name = NULL;
#endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
-extern void stpi_vars_print_error(const stp_vars_t *v, const char *prefix);
-
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
@@ -268,7 +266,7 @@ print_debug_block(const stp_vars_t *v, const cups_image_t *cups)
fprintf(stderr, "DEBUG: Gutenprint: cupsRowFeed = %d\n", cups->header.cupsRowFeed);
fprintf(stderr, "DEBUG: Gutenprint: cupsRowStep = %d\n", cups->header.cupsRowStep);
fprintf(stderr, "DEBUG: Gutenprint: shrink page to fit %d\n", cups->shrink_to_fit);
- stpi_vars_print_error(v, "DEBUG");
+ stp_vars_print_error(v, "DEBUG");
fprintf(stderr, "DEBUG: Gutenprint: End page data\n");
}
@@ -318,7 +316,7 @@ validate_options(stp_vars_t *v, cups_image_t *cups)
if (strcmp(desc.name, "PageSize") == 0)
{
const stp_papersize_t *ps =
- stp_get_papersize_by_name(desc.deflt.str);
+ stp_describe_papersize(v, desc.deflt.str);
if (ps->width > 0)
{
if (! suppress_messages)
@@ -356,11 +354,6 @@ initialize_page(cups_image_t *cups, const stp_vars_t *default_settings,
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Initialize page\n");
- stp_set_outfunc(v, cups_writefunc);
- stp_set_errfunc(v, cups_errfunc);
- stp_set_outdata(v, stdout);
- stp_set_errdata(v, stderr);
-
if (cups->header.cupsBitsPerColor == 16)
set_string_parameter(v, "ChannelBitDepth", "16");
else
@@ -405,10 +398,10 @@ initialize_page(cups_image_t *cups, const stp_vars_t *default_settings,
set_special_parameter(v, "Quality", cups->header.cupsRowFeed - 1);
- if (cups->header.MediaClass && strlen(cups->header.MediaClass) > 0)
+ if (strlen(cups->header.MediaClass) > 0)
set_string_parameter(v, "InputSlot", cups->header.MediaClass);
- if (cups->header.MediaType && strlen(cups->header.MediaType) > 0)
+ if (strlen(cups->header.MediaType) > 0)
set_string_parameter(v, "MediaType", cups->header.MediaType);
if (! suppress_messages)
@@ -425,7 +418,7 @@ initialize_page(cups_image_t *cups, const stp_vars_t *default_settings,
stp_set_page_width(v, cups->header.PageSize[0]);
stp_set_page_height(v, cups->header.PageSize[1]);
}
- else if (stp_get_papersize_by_name(page_size_name))
+ else if (stp_describe_papersize(v, page_size_name))
{
stp_dimension_t width, height;
if (!suppress_messages)
@@ -1067,7 +1060,7 @@ load_options(const char *load_name)
fprintf(stderr, "DEBUG: Gutenprint: loading options from %s\n",
load_file_name);
if (! suppress_messages)
- stpi_vars_print_error(settings, "DEBUG");
+ stp_vars_print_error(settings, "DEBUG");
}
}
else
@@ -1132,8 +1125,15 @@ main(int argc, /* I - Number of command-line arguments */
theImage.rep = &cups;
(void) gettimeofday(&t1, NULL);
+ stp_set_global_errfunc(cups_errfunc);
+ stp_set_global_dbgfunc(cups_dbgfunc);
+ stp_set_global_errdata(stderr);
+ stp_set_global_dbgdata(stderr);
stp_init();
version_id = stp_get_version();
+ default_settings = stp_vars_create();
+ stp_set_outfunc(default_settings, cups_writefunc);
+ stp_set_outdata(default_settings, stdout);
/*
* Check for valid arguments...
@@ -1238,7 +1238,7 @@ main(int argc, /* I - Number of command-line arguments */
cupsMarkOptions(ppd, num_options, options);
size = ppdPageSize(ppd, NULL);
- if (size->name)
+ if (size)
page_size_name = stp_strdup(size->name);
if (! suppress_messages)
@@ -1299,7 +1299,6 @@ main(int argc, /* I - Number of command-line arguments */
if (! suppress_messages)
fprintf(stderr, "DEBUG: Gutenprint: Using fd %d\n", fd);
- default_settings = stp_vars_create_copy(stp_printer_get_defaults(printer));
stp_set_printer_defaults(default_settings, printer);
#ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
if (load_file_name)
@@ -1361,7 +1360,7 @@ main(int argc, /* I - Number of command-line arguments */
if (! suppress_messages)
{
fprintf(stderr, "DEBUG: Gutenprint: Interim page settings:\n");
- stpi_vars_print_error(v, "DEBUG");
+ stp_vars_print_error(v, "DEBUG");
}
stp_merge_printvars(v, stp_printer_get_defaults(printer));
@@ -1378,15 +1377,6 @@ main(int argc, /* I - Number of command-line arguments */
if (! suppress_messages)
print_debug_block(v, &cups);
print_messages_as_errors = 1;
- if (!stp_verify(v))
- {
- fprintf(stderr, "DEBUG: Gutenprint: Options failed to verify.\n");
- fprintf(stderr, "DEBUG: Gutenprint: Make sure that you are using ESP Ghostscript rather\n");
- fprintf(stderr, "DEBUG: Gutenprint: than GNU or AFPL Ghostscript with CUPS.\n");
- fprintf(stderr, "DEBUG: Gutenprint: If this is not the cause, set LogLevel to debug to identify the problem.\n");
- aborted = 1;
- break;
- }
if (!initialized_job)
{
@@ -1396,7 +1386,14 @@ main(int argc, /* I - Number of command-line arguments */
if (!stp_print(v, &theImage))
{
- aborted = 1;
+ if (Image_status != STP_IMAGE_STATUS_ABORT)
+ {
+ fprintf(stderr, "DEBUG: Gutenprint: Options failed to verify.\n");
+ fprintf(stderr, "DEBUG: Gutenprint: Make sure that you are using ESP Ghostscript rather\n");
+ fprintf(stderr, "DEBUG: Gutenprint: than GNU or AFPL Ghostscript with CUPS.\n");
+ fprintf(stderr, "DEBUG: Gutenprint: If this is not the cause, set LogLevel to debug to identify the problem.\n");
+ }
+ aborted = 1;
break;
}
print_messages_as_errors = 0;
@@ -1467,13 +1464,38 @@ cups_errfunc(void *file, const char *buf, size_t bytes)
{
if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
{
- fputs("ERROR: Gutenprint error:", prn);
+ fputs("ERROR: Gutenprint:", prn);
buf += 6;
}
else if (print_messages_as_errors)
- fputs("ERROR: Gutenprint error: ", prn);
- else
- fputs("DEBUG: Gutenprint internal: ", prn);
+ fputs("ERROR: Gutenprint: ", prn);
+ else if (strncmp(buf, "DEBUG", 5) != 0)
+ fputs("DEBUG: Gutenprint: ", prn);
+ while (next_nl < bytes)
+ {
+ if (buf[next_nl++] == '\n')
+ break;
+ }
+ fwrite(buf + where, 1, next_nl - where, prn);
+ where = next_nl;
+ }
+}
+
+static void
+cups_dbgfunc(void *file, const char *buf, size_t bytes)
+{
+ size_t next_nl = 0;
+ size_t where = 0;
+ FILE *prn = (FILE *)file;
+ while (where < bytes)
+ {
+ if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
+ {
+ fputs("ERROR: Gutenprint:", prn);
+ buf += 6;
+ }
+ else if (strncmp(buf, "DEBUG", 5) != 0)
+ fputs("DEBUG: Gutenprint: ", prn);
while (next_nl < bytes)
{
if (buf[next_nl++] == '\n')
@@ -1635,7 +1657,7 @@ Image_get_row(stp_image_t *image, /* I - Image */
new_percent = (int) (100.0 * cups->row / cups->header.cupsHeight);
if (new_percent > cups->last_percent)
{
- if (! suppress_messages)
+ if (! suppress_verbose_messages)
{
stp_i18n_printf(po, _("INFO: Printing page %d, %d%%\n"),
cups->page + 1, new_percent);
diff --git a/src/cups/test-ppds b/src/cups/test-ppds
deleted file mode 100755
index 27e5a8d..0000000
--- a/src/cups/test-ppds
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh
-
-# Test PPD conformance
-#
-# Copyright 2006-2017 Robert Krawitz (rlk@alum.mit.edu)
-#
-# 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.
-
-# Keeping this up to date with changing CUPS versions is a real headache
-
-make EXTRA_GENPPD_OPTS='-b -Z' ppd-clean ppd-global ppd-nls ppd-nonls
-
-# Most non-Macintosh systems won't have the Macintosh-specific profiles
-# installed in Macintosh-specific locations.
-#
-# 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 -I filters'
-
-ppd_count=`find ppd \( -name '*.ppd.gz' -o -name '*.ppd' \) -print | wc -l`
-
-if [ -n "$STP_PARALLEL" ] ; then
- PARALLEL="-P $STP_PARALLEL"
-fi
-
-failures="`find ppd -name '*.ppd*' -print | sort -t/ -k3 -k2 | xargs $PARALLEL cupstestppd $cupstestppdopts |grep 'FAIL$' | awk -F: '{print $1}'`"
-
-if [ -z "$failures" ] ; then
- echo "All $ppd_count PPD files pass"
- exit 0
-fi
-
-# Use this with "normal" PPD files without translated numbers.
-#echo $failures | xargs cupstestppd $cupstestppdopts 2>&1 | egrep -v 'Missing "[a-z][a-z](_[A-Z][A-Z])?" translation string for option Stp((Brightness|Contrast|Saturation), choice None|([a-zA-Z0-9]+, choice (-?[0-9]+)))!$' |egrep -v 'Missing cupsICCProfile file'
-
-# Use this with PPD files with translated numbers (genppd -N)
-# With normal globalized PPD files this will yield hundreds of megabytes
-# of errors.
-echo $failures | xargs cupstestppd -r $cupstestppdopts 2>&1 |egrep -v 'Missing cupsICCProfile file'
-
-fail_count=`echo "$failures" | wc -l`
-echo "$fail_count/$ppd_count fail"
-exit 1
diff --git a/src/cups/test-ppds.in b/src/cups/test-ppds.in
new file mode 100644
index 0000000..3664f4e
--- /dev/null
+++ b/src/cups/test-ppds.in
@@ -0,0 +1,127 @@
+#!@BASHREAL@
+
+# Test PPD conformance
+#
+# Copyright 2006-2017 Robert Krawitz (rlk@alum.mit.edu)
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+################################################################
+# TEST FOR PPD FILE COMPLIANCE
+#
+# Keeping this up to date with changing CUPS versions is a real headache.
+# This test, however, is particularly important; PPD conformance failures
+# are one of the most frequently observed problems, and a lot of apps
+# (and CUPS itself) are very sensitive -- arguably overly so -- to
+# violations of the spec.
+#
+# We can't skip the translated PPD files either; sometimes translations
+# blow out token maximum lengths.
+
+if [[ -n "$STP_TEST_LOG_PREFIX" ]] ; then
+ redir="${STP_TEST_LOG_PREFIX}${0##*/}_$$.log"
+ if [[ -n $BUILD_VERBOSE ]] ; then
+ exec > >(tee -a "$redir" >&3)
+ else
+ exec 1>>"$redir"
+ fi
+ exec 2>&1
+fi
+
+[[ -n "$STP_TEST_DEBUG" ]] && DEBUG=echo
+
+[[ -z $STP_TEST_SUITE || -z $STP_TEST_PROFILE ]] && STP_TEST_PROFILE=full
+
+PPD_DIR=ppdtest
+
+PPD_PARALLEL=200
+
+function test_full() {
+ rm -rf "$PPD_DIR"
+ echo "GENERATING PPD FILES (all):"
+ set -e
+ $DEBUG make "PPD_DIR=$PPD_DIR" EXTRA_GENPPD_OPTS='-b -Z' ppd-clean ppd-global-a ppd-nls-a ppd-nonls-a
+}
+
+function test_fast() {
+ rm -rf "$PPD_DIR"
+ echo "GENERATING PPD FILES (fast):"
+ set -e
+ $DEBUG make "PPD_DIR=$PPD_DIR" EXTRA_GENPPD_OPTS='-b -Z' ppd-clean ppd-nonls
+ if [[ -n $STP_TEST_DIST ]] ; then
+ echo "GENERATING PPD FILES (global):"
+ set -e
+ $DEBUG make "PPD_DIR=$PPD_DIR" EXTRA_GENPPD_OPTS='-b -Z -S' ppd-global
+ fi
+ PPD_PARALLEL=20
+}
+
+function test_minimal() {
+ rm -rf "$PPD_DIR"
+ echo "GENERATING PPD FILES (minimal):"
+ set -e
+ $DEBUG make "PPD_DIR=$PPD_DIR" EXTRA_GENPPD_OPTS='-b -Z -S' ppd-clean ppd-nonls
+ PPD_PARALLEL=20
+}
+
+case "$STP_TEST_PROFILE" in
+ full|fast|minimal)
+ test_$STP_TEST_PROFILE
+ ;;
+ *)
+ exit 77
+esac
+
+if [[ -n "$STP_TEST_DEBUG" ]] ; then
+ echo "Would run $0 $@"
+ exit 0
+fi
+
+ppd_count=$(find "$PPD_DIR" -name '*.ppd' -print | wc -l)
+
+# Setting a limit on the number of files per invocation improves
+# performance by about a minute by reducing the tail at the end.
+[[ -n $STP_PARALLEL ]] && PARALLEL="-P $STP_PARALLEL -L $PPD_PARALLEL"
+
+# Most non-Macintosh systems won't have the Macintosh-specific profiles
+# installed in Macintosh-specific locations.
+#
+# 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 -I filters'
+
+# This lets us report progress
+testcmd="echo -n . 1>&2; cupstestppd $cupstestppdopts "'"$@"'
+
+echo -n "TESTING PPD FILES: "
+failures="$(find $PPD_DIR -name '*.ppd*' -print | sort -t/ -k3 -k2 | xargs $PARALLEL sh -c "$testcmd" |grep 'FAIL$' | awk -F: '{print $1}')"
+
+if [[ -z "$failures" ]] ; then
+ echo "All $ppd_count PPD files pass"
+ rm -rf $PPD_DIR
+ exit 0
+fi
+
+# Use this with "normal" PPD files without translated numbers.
+#echo $failures | xargs cupstestppd $cupstestppdopts 2>&1 | egrep -v 'Missing "[a-z][a-z](_[A-Z][A-Z])?" translation string for option Stp((Brightness|Contrast|Saturation), choice None|([a-zA-Z0-9]+, choice (-?[0-9]+)))!$' |egrep -v 'Missing cupsICCProfile file'
+
+# Use this with PPD files with translated numbers (genppd -N)
+# With normal globalized PPD files this will yield hundreds of megabytes
+# of errors.
+echo $failures | xargs cupstestppd -r $cupstestppdopts 2>&1
+
+fail_count=`echo "$failures" | wc -l`
+echo "$fail_count/$ppd_count fail"
+exit 1
diff --git a/src/cups/test-rastertogutenprint.check.in b/src/cups/test-rastertogutenprint.check.in
new file mode 100644
index 0000000..cd3f38b
--- /dev/null
+++ b/src/cups/test-rastertogutenprint.check.in
@@ -0,0 +1,77 @@
+#!@BASHREAL@
+
+# Harness for rastertogutenprint tester.
+#
+# Copyright 2007-2017 Robert Krawitz (rlk@alum.mit.edu)
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+if [[ -n "$STP_TEST_LOG_PREFIX" ]] ; then
+ redir="${STP_TEST_LOG_PREFIX}${0##*/}_$$.log"
+ if [[ -n $BUILD_VERBOSE ]] ; then
+ exec > >(tee -a "$redir" >&3)
+ else
+ exec 1>>"$redir"
+ fi
+ exec 2>&1
+fi
+
+STP_TEST_PROFILE=${STP_TEST_PROFILE:-full}
+
+set -e
+
+declare FASTOPT="-o StpDitherAlgorithm=VeryFast -l -N -o ColorCorrection=Raw"
+declare MIN_PRINTERS="@MINIMAL_PRINTERS_TO_TEST@"
+
+function runit() {
+ echo "================================================================"
+ echo "$@"
+ [[ -z $STP_TEST_DEBUG ]] && "$@"
+}
+
+function test_minimal() {
+ runit ./test-rastertogutenprint -s $FASTOPT -p 1 \
+ $MIN_PRINTERS
+}
+
+function test_fast() {
+ runit ./test-rastertogutenprint -S -s $FASTOPT -p 2
+}
+
+function test_full() {
+ runit ./test-rastertogutenprint -l -p 2 $FASTOPT
+ runit ./test-rastertogutenprint -S -s -X
+}
+
+function test_valgrind_minimal() {
+ runit ./test-rastertogutenprint -v -v -s $FASTOPT -p 1 \
+ $MIN_PRINTERS
+}
+
+function test_valgrind_fast() {
+ test_valgrind_minimal
+}
+
+function test_valgrind() {
+ runit ./test-rastertogutenprint -v -v -S -s $FASTOPT -p 2
+}
+
+case "$STP_TEST_PROFILE" in
+ full|fast|valgrind|valgrind_minimal|valgrind_fast|minimal)
+ test_$STP_TEST_PROFILE
+ ;;
+ *)
+ exit 77
+ ;;
+esac
diff --git a/src/cups/test-rastertogutenprint.in b/src/cups/test-rastertogutenprint.in
index 75d4102..410814d 100755..100644
--- a/src/cups/test-rastertogutenprint.in
+++ b/src/cups/test-rastertogutenprint.in
@@ -1,4 +1,4 @@
-#!@SHELL@
+#!@BASH@
# Driver for rastertogutenprint tester.
#
@@ -15,142 +15,175 @@
# 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.
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
retval=0
-if [ -z "$srcdir" -o "$srcdir" = "." ] ; then
- sdir=`pwd`
-elif [ -n "`echo $srcdir |grep '^/'`" ] ; then
+if [[ -z $srcdir || $srcdir = . ]] ; then
+ sdir=$(pwd)
+elif [[ $srcdir =~ ^/ ]] ; then
sdir="$srcdir"
else
- sdir="`pwd`/$srcdir"
+ sdir="$(pwd)/$srcdir"
fi
-if [ -z "$STP_DATA_PATH" ] ; then
- STP_DATA_PATH="$sdir/../xml"
- export STP_DATA_PATH
-fi
+export STP_DATA_PATH=${STP_DATA_PATH:-"$sdir/../xml"}
+export STP_MODULE_PATH=${STP_MODULE_PATH:-"$sdir/../main:$sdir/../main/.libs"}
+
+declare single=0
+declare verbose=0
+declare valgrind=0
+declare make_ppds=1
+declare skip_simplified=0
+declare postscript=0
+declare use_explicit_quality=0
+declare extra_genppd_opts=-Z
+declare use_smallest_pagesize=0
+declare cupsargs=''
+declare printers_to_test=''
-if [ -z "$STP_MODULE_PATH" ] ; then
- STP_MODULE_PATH="$sdir/../main:$sdir/../main/.libs"
- export STP_MODULE_PATH
+if [ -n "$STP_TEST_DEBUG" ] ; then
+ echo "Would run with single=$single skip_simplified=$skip_simplified extra_genppd_opts=$extra_genppd_opts cupsargs=$cupsargs use_explicit_quality=$use_explicit_quality valopts=$valopts valgrind=$valgrind"
+ exit 0
fi
-single=''
-all_models=''
-verbose=''
-valgrind=0
-make_ppds=1
-md5dir=''
-outdir=''
-cupsargs=''
-postscript=''
-npages=3
-jobs=${STP_PARALLEL:-1}
-enable_static='@ENABLE_STATIC@'
-enable_shared='@ENABLE_SHARED@'
-
-if [ -r "$sdir/../../src/cups/gutenprint-users-manual.pdf" ] ; then
+declare family=$STP_TEST_FAMILY
+declare all_models=''
+declare md5dir=''
+declare outdir=''
+declare qualarg=''
+declare npages=3
+declare jobs=${STP_PARALLEL:-1}
+declare -A all_models=
+
+if [[ -r $sdir/../../src/cups/gutenprint-users-manual.pdf ]] ; then
testfile="$sdir/../../src/cups/gutenprint-users-manual.pdf"
else
testfile="$sdir/../../doc/gutenprint-users-manual.pdf"
fi
+quality_presets=(FastEconomy Economy Draft Standard High Photo HighPhoto UltraPhoto Best)
+
usage() {
- echo "Usage: test-rastertogutenprint [-s] [-v|--valgrind]"
- exit 0;
+ cat <<'EOF'
+Usage: test-rastertogutenprint [options] [PPD files...]
+ Options:
+ -s Run only one PPD file with a given model ID/family
+ -v Use valgrind
+ -c Use cachegrind
+ -g Use GDB attach in valgrind
+ -V Verbose output
+ -n Don't build PPD files prior to run
+ -O dir Save output in specified directory
+ -o opt Set option on CUPS command line
+ -m dir Save MD5 checksums in specified directory
+ -p pages Specify page range of input document to use
+ -P Use PostScript rather than PDF input
+ -t jobs Run jobs in parallel (alternatively, use STP_PARALLEL)
+ -f family Run printers only in the particular family
+ -S Skip simplified PPD files
+ -l Use lowest available quality setting
+ -L Use highest available quality setting
+ -X Don't use explicit quality setting
+ -N Use the smallest available page size
+EOF
+exit 0;
}
-set_args() {
- while true ; do
- case "$1" in
- -s) single=1 ;;
- -h*|--h*) usage ;;
- -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 ;;
- -n|--no-make-ppds) make_ppds='' ;;
- -O|--output) shift; outdir="$1" ;;
- -o|--option) shift; cupsargs="$cupsargs $1" ;;
- -m|--md5dir) shift; md5dir="$1" ;;
- -p|--pages) shift; npages="$1" ;;
- -P|--postscript) shift; postscript=1 ;;
- -t|--parallel) shift; jobs="$1" ;;
- --) shift; args="$@"; return ;;
- *) return ;;
- esac
- shift
- done
-}
+while getopts "hvcgsVnO:m:o:p:St:lLXf:N" opt ; do
+ case "$opt" in
+ h*) usage ;;
+ v) valgrind=$((valgrind + 1)) ;;
+ c) valgrind=4 ;;
+ g) valopts='--vgdb=yes --error-exitcode=1' ;;
+ s) single=1 ;;
+ V) verbose=$((verbose+1)) ;;
+ n) make_ppds='' ;;
+ O) outdir="$OPTARG"; mkdir -p "$outdir" ;;
+ o) cupsargs="$cupsargs $OPTARG" ;;
+ m) md5dir="$OPTARG"; mkdir -p "$md5dir" ;;
+ p) npages="$OPTARG" ;;
+ P) postscript=1 ;;
+ t) jobs="$OPTARG" ;;
+ f) family="$OPTARG" ;;
+ S) skip_simplified=1 ;;
+ X) use_explicit_quality=0 ;;
+ l) use_explicit_quality=1 ;;
+ L) use_explicit_quality=2 ;;
+ N) use_smallest_pagesize=1 ;;
+ \?) usage ;;
+ *) echo "Unknown argument $opt"; usage ;;
+ esac
+done
-set_args `getopt hvcgsVnO:m:o:p: "$@"`
+case "$valgrind" in
+ 4)
+ valopts='--tool=callgrind --dump-instr=yes --trace-jump=yes --error-exitcode=1'
+ ;;
+ '')
+ ;;
+ *)
+ valopts='--tool=memcheck --error-exitcode=1'
+ ;;
+esac
-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
-if [ -n "$md5dir" -a ! -d "$md5dir" ] ; then
- mkdir -p "$md5dir"
-fi
+shift $((OPTIND - 1))
version="@GUTENPRINT_RELEASE_VERSION@";
-cupsdir="/usr/lib/cups/filter"
-if [ -x "$cupsdir/pstoraster" -o -x "$cupsdir/gstoraster" -o -x "$cupsdir/cgpdftoraster" ] ; then
- pages="24-`expr 24 + $npages - 1`"
- if [ -n "$postscript" ] ; then
- pages="page-ranges=$pages"
- fi
-else
- pages=''
-fi
+rgp="./rastertogutenprint.$version"
+cupsdir="$(cups-config --serverbin)/filter"
+cgpdftoraster="$cupsdir/cgpdftoraster"
+gstoraster="$cupsdir/gstoraster"
+imagetoraster="$cupsdir/imagetoraster"
+pdftops="$cupsdir/pdftops"
+pstops="$cupsdir/pstops"
+pstoraster="$cupsdir/pstoraster"
-if [ ! -x "$cupsdir/cgpdftoraster" -a ! -x "$cupsdir/pdftops" -a ! -x "$cupsdir/gstoraster" ] ; then
+if [[ ! -x $cgpdftoraster && ! -x $pdftops && ! -x $gstoraster ]] ; then
echo 'CUPS does not appear to be installed, skipping test'
exit 0
fi
+if [[ -x $pstoraster || -x $gstoraster || -x $cgpdftoraster ]] ; then
+ pages="24-$((24 + $npages - 1))"
+ (( $postscript > 0 )) && pages="page-ranges=$pages"
+else
+ pages=''
+fi
+
cleanup() {
- if [ -f "$tfile" ] ; then
- rm -f $tfile
- fi
+ [[ -n $tfile ]] && rm -f "$tfile"
exit 1
}
-pdfjam="`which pdfjam`"
-if [ -z "$pdfjam" ] ; then
- postscript=1
-fi
-
-if [ -n "$postscript" ] ; then
- pdftops="`type -p pdftops`"
+pdfjam=$(type -p pdfjam)
+[[ -n $pdfjam ]] && postscript=1
- if [ ! -n "$pdftops" -o ! -x "$pdftops" ] ; then
- pdftops="`whence pdftops`"
- fi
+if (( $postscript > 0 )) ; then
+ pdftops=$(type -p pdftops)
- if [ -n "$pdftops" -a ! -x "$cupsdir/cgpdftoraster" ] ; then
- tfile=`mktemp`
+ if [[ -n $pdftops && ! -x $cgpdftoraster ]] ; then
+ tfile=$(mktemp)
trap cleanup 1 2 3 6 14 15 30
- "$pdftops" -f 24 -l `expr 24 + $npages - 1` "$testfile" $tfile
+ "$pdftops" -f 24 -l $((24 + $npages - 1)) "$testfile" $tfile
fi
else
- tfile=`mktemp`
+ tfile=$(mktemp)
trap cleanup 1 2 3 6 14 15 30
"$pdfjam" -q "$testfile" "$pages" -o $tfile
fi
-if [ -z "$verbose" ] ; then
- STP_SUPPRESS_MESSAGES=1
- export STP_SUPPRESS_MESSAGES
-fi
+case "$verbose" in
+ 1)
+ export STP_SUPPRESS_VERBOSE_MESSAGES=1
+ ;;
+ 0|'')
+ export STP_SUPPRESS_MESSAGES=1
+ export STP_SUPPRESS_VERBOSE_MESSAGES=1
+ ;;
+ *)
+ ;;
+esac
# Note that using CUPS arguments may trigger valgrind memory leaks in
# CUPS.
@@ -159,70 +192,54 @@ fi
#cupsargs='PageSize=w324h495 Resolution=180dpi'
#cupsargs='PageSize=A8'
-run_rastertogp() {
- case "$valgrind" in
- 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
- if [ $? -ne 0 ] ; then
- retval=1
- fi
- exit $retval
-}
-
get_ppds() {
- args="$@"
- if [ -n "$args" ] ; then
- for f in "$@" ; do
- if [ -r "$f" ] ; then
+ if [[ -n $@ || -n $printers_to_test ]] ; then
+ for f in "$@" $printers_to_test ; do
+ if [[ -r $f ]] ; then
echo $f
- elif [ -r "ppd/C/$f" ] ; then
+ elif [[ -r ppd/C/$f ]] ; then
echo "ppd/C/$f"
- elif [ -f "ppd/C/${f}.ppd" ] ; then
+ elif [[ -f ppd/C/${f}.ppd ]] ; then
echo "ppd/C/${f}.ppd"
- elif [ -f "ppd/C/${f}.ppd.gz" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.gz ]] ; then
echo "ppd/C/${f}.ppd.gz"
- elif [ -f "ppd/C/${f}.ppd.GZ" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.GZ ]] ; then
echo "ppd/C/${f}.ppd.GZ"
- elif [ -f "ppd/C/${f}.ppd.bz2" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.bz2 ]] ; then
echo "ppd/C/${f}.ppd.bz2"
- elif [ -f "ppd/C/${f}.ppd.BZ2" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.BZ2 ]] ; then
echo "ppd/C/${f}.ppd.BZ2"
- elif [ -f "ppd/C/${f}.ppd.z" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.z ]] ; then
echo "ppd/C/${f}.ppd.z"
- elif [ -f "ppd/C/${f}.ppd.Z" ] ; then
+ elif [[ -f ppd/C/${f}.ppd.Z ]] ; then
echo "ppd/C/${f}.ppd.Z"
- elif [ -f "ppd/C/stp-${f}.ppd" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd ]] ; then
echo "ppd/C/stp-${f}.ppd"
- elif [ -f "ppd/C/stp-${f}.ppd.gz" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.gz ]] ; then
echo "ppd/C/stp-${f}.ppd.gz"
- elif [ -f "ppd/C/stp-${f}.ppd.GZ" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.GZ ]] ; then
echo "ppd/C/stp-${f}.ppd.GZ"
- elif [ -f "ppd/C/stp-${f}.ppd.bz2" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.bz2 ]] ; then
echo "ppd/C/stp-${f}.ppd.bz2"
- elif [ -f "ppd/C/stp-${f}.ppd.BZ2" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.BZ2 ]] ; then
echo "ppd/C/stp-${f}.ppd.BZ2"
- elif [ -f "ppd/C/stp-${f}.ppd.z" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.z ]] ; then
echo "ppd/C/stp-${f}.ppd.z"
- elif [ -f "ppd/C/stp-${f}.ppd.Z" ] ; then
+ elif [[ -f ppd/C/stp-${f}.ppd.Z ]] ; then
echo "ppd/C/stp-${f}.ppd.Z"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.gz" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.gz ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.gz"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.GZ" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.GZ ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.GZ"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.bz2" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.bz2 ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.bz2"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.BZ2" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.BZ2 ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.BZ2"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.z" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.z ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.z"
- elif [ -f "ppd/C/stp-${f}.${version}.ppd.Z" ] ; then
+ elif [[ -f ppd/C/stp-${f}.${version}.ppd.Z ]] ; then
echo "ppd/C/stp-${f}.${version}.ppd.Z"
fi
done
@@ -231,48 +248,156 @@ get_ppds() {
fi
}
-if [ -n "$make_ppds" -o ! -d ppd/C ] ; then
- rm -rf ppd/C # Clean out any leftover simplified PPDs
- make ppd-nonls-a # that double the time for the test
+if [[ -n $make_ppds || ! -d ppd/C ]] ; then
+ rm -rf ppd/C
## not all systems can work with gzipped PPDs
- find ppd/C -name '*.ppd.gz' | xargs gunzip -f
+ if [[ $skip_simplified == 1 ]] ; then
+ EXTRA_GENPPD_OPTS="$extra_genppd_opts" make ppd-nonls
+ else
+ EXTRA_GENPPD_OPTS="$extra_genppd_opts" make ppd-nonls-a
+ fi
fi
-do_output() {
- if [ -n "`echo "$PPD" |grep '\.gz$'`" ] ; then
- driver=`gunzip -c "$PPD" | grep '^\*StpDriverName:' |awk '{print $2}' | sed 's/"//g'`
+find_page_size() {
+ ppd=$1
+ (( $use_smallest_pagesize == 0 )) && return;
+ driver=$(grep '^\*StpDriverName' "$ppd" | sed -e 's/^[^"]*"//' -e 's/"//g')
+ pagesize=$(./min-pagesize "$driver")
+ [[ -n "$pagesize" ]] && echo "PageSize=$pagesize"
+}
+
+find_resolution() {
+ ppd=$1
+ resolutions=$(grep "^\\*Resolution " "$ppd" |sed -e 's,/.*,,' -e 's/.* //')
+ [[ -z "$resolutions" ]] && return
+ low_resolution=9999999999
+ low_resolution_name=''
+ high_resolution=0
+ high_resolution_name=''
+ for r in $resolutions ; do
+ res=$(sed -e 's/dpi//' -e 's/x/ \\\* /' -e 's/^\([0-9]*\)$/\1 \\\* \1/' <<< $r)
+ resnum=$(eval "expr $res")
+ if (( $resnum > $high_resolution )) ; then
+ high_resolution=$resnum
+ high_resolution_name=$r
+ fi
+ if (( $resnum < $low_resolution )) ; then
+ low_resolution=$resnum
+ low_resolution_name=$r
+ fi
+ done
+ if (( $use_explicit_quality == 1 )) ; then
+ echo "Resolution=$low_resolution_name"
+ elif (( $use_explicit_quality == 2 )) ; then
+ echo "Resolution=$high_resolution_name"
+ fi
+
+}
+
+find_quality_preset() {
+ ppd=$1
+ if (( $use_explicit_quality == 1 )) ; then
+ for q in ${quality_presets[@]} ; do
+ if grep -q "^\\*StpQuality $q" "$ppd" ; then
+ echo "StpQuality=$q"
+ return
+ fi
+ done
+ elif (( "$use_explicit_quality" == 2 )) ; then
+ best_quality=''
+ for q in ${quality_presets[@]} ; do
+ grep -q "^\\*StpQuality $q" "$ppd" && best_quality=$q
+ done
+ [[ -n $best_quality ]] && echo "StpQuality=$best_quality"
+ fi
+}
+
+find_quality() {
+ ppd=$1
+ if [[ ! -r $ppd ]] ; then
+ echo "Can't find $ppd!" 1>&2
+ exit 1;
+ fi
+ (( "$use_explicit_quality" == 0 )) && return
+ if grep -q '\*Resolution' "$ppd" ; then
+ find_resolution $ppd
else
- driver=`grep '^\*StpDriverName:' "$PPD" |awk '{print $2}' | sed 's/"//g'`
+ find_quality_preset $ppd
fi
- if [ -n "$outdir" ] ; then
+}
+
+xgrep() {
+ pat=$1
+ file=$2
+ if [[ $file == *.gz ]] ; then
+ egrep -m1 $pat $file
+ else
+ zgrep $pat $file
+ fi
+}
+
+runcmd() {
+ qualarg=$(find_quality "$PPD")
+ sizearg=$(find_page_size "$PPD")
+ a='1 1 1 1'
+ qarg="$qualarg $sizearg $cupsargs"
+ if [[ -x $cgpdftoraster ]] ; then
+ # cgpdftoraster doesn't like arguments. How rude.
+ $cgpdftoraster $a "" < "$tfile"
+ elif [[ -f $tfile && -x $gstoraster ]] ; then
+ $gstoraster $a "$qarg" < "$tfile"
+ elif [[ -f $tfile ]] ; then
+ $pstops $a $"qarg" < "$tfile"
+ elif [[ -x $pstoraster ]] ; then
+ $pdftops $a "$qarg" < "$tfile" | $pstops $a "$pages$qarg" | $pstoraster
+ elif [[ -x $gstoraster ]] ; then
+ $pdftops $a "$qarg" < "$tfile" | $gstoraster $a "$pages$qarg"
+ else
+ $imagetoraster $a "$qarg" < calibrate.ppm
+ fi
+}
+
+do_output() {
+ driver=$(xgrep '^\*StpDriverName:' "$PPD" |awk '{print $2}' | sed 's/"//g')
+ if [[ -n $outdir ]] ; then
cat > "$outdir/$driver.prn"
- if [ -n "$md5dir" ] ; then
- (cd "$outdir"; cat "$driver.prn") | md5sum | sed "s/-/\*$driver/" > "$md5dir/$driver.md5"
+ if [[ -n $md5dir ]] ; then
+ md5sum < "$outdir/$driver.prn" | sed "s/-/\*$driver/" > "$md5dir/$driver.md5"
fi
- elif [ -n "$md5dir" ] ; then
+ elif [[ -n $md5dir ]] ; then
cat | md5sum | sed "s/-/\*$driver/" > "$md5dir/$driver.md5"
else
- cat > /dev/null
+ cat >/dev/null
fi
}
+run_rastertogp() {
+ qualarg=$(find_quality "$PPD")
+ sizearg=$(find_page_size "$PPD")
+ vg="libtool --mode=execute valgrind $valopts --log-fd=3"
+ vg1="$vg --num-callers=50 --leak-check=yes --error-limit=no --error-exitcode=1"
+ rgpc="$rgp 1 1 1 1"
+ qarg="$qualarg $sizearg $cupsargs"
+ case "$valgrind" in
+ 1) $vg1 -q $rgpc ;;
+ 2) $vg1 --leak-resolution=high $rgpc "$qarg" ;;
+ 3) $vg1 --leak-resolution=high --show-reachable=yes $rgpc "$qarg";;
+ 4) $vg $rgpc "$qarg" ;;
+ 5) cat ;;
+ 6) cat > /dev/null ;;
+ *) $rgp 1 1 1 1 "$qarg"
+ esac
+}
+
runme() {
f="$1"
- p=$(echo -n "`basename $f |sed -e 's/stp-//' -e 's/@GUTENPRINT_RELEASE_VERSION@.ppd.*$//'`... ")
- PPD=$f
- export PPD
- if [ -x "$cupsdir/cgpdftoraster" ] ; then
- output="$p `($cupsdir/cgpdftoraster 1 1 1 1 "" < "$tfile" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
- elif [ -f "$tfile" -a -x "$cupsdir/gstoraster" ] ; then
- output="$p `($cupsdir/gstoraster 1 1 1 1 \"$cupsargs\" < "$tfile" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
- elif [ -f "$tfile" ] ; then
- output="$p `($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="$p `($cupsdir/pdftops 1 1 1 1 \"$cupsargs\" < "$tfile" 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="$p `($cupsdir/pdftops 1 1 1 1 \"$cupsargs\" < "$tfile" 2>/dev/null | $cupsdir/gstoraster 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
+ p=${f#*stp-}
+ p=${p/${version}./}
+ export PPD=$f
+ if [[ -n $outdir || -n $md5dir ]] ; then
+ output="${p%.ppd*}...$( (runcmd 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2)"
else
- output="$p `($cupsdir/imagetoraster 1 1 1 1 \"$cupsargs\" < calibrate.ppm 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2`"
+ output="${p%.ppd*}...$( (runcmd 2>/dev/null | run_rastertogp >/dev/null) 2>&1 3>&2)"
fi
return $?
}
@@ -280,65 +405,79 @@ runme() {
runall() {
jobs="${1:-1}"
rotor="${2:-0}"
- shift
- shift
+ shift 2
retval=0
jobno=0
for f in "$@" ; do
- skip=''
- if [ $((jobno % jobs)) -eq $rotor ] ; then
+ if (( $jobno == $rotor )) ; then
runme "$f"
- if [ $? -ne 0 ] ; then
- retval=1
- fi
+ (( $? != 0 )) && retval=1
echo "$output"
- echo "$output" |grep ERROR
- if [ $? -eq 0 ] ; then
- retval=1
- fi
+ grep -q 'ERROR:' <<< "$output" && retval=1
fi
- jobno=$((jobno+1))
+ jobno=$((($jobno+1) % $jobs))
done
return $retval
}
+get_models() {
+ re='\*StpDriverModelFamily: '
+ if (( ${#all_models[*]} <= 1 )) ; then
+ declare -a models=($(xargs grep -m1 -H "^$re" <<< $@ | sed "s/:$re/=/"))
+ for m in ${models[@]} ; do
+ model=${m#*=}
+ file=${m%%=*}
+ all_models[$file]=$model
+ done
+ fi
+}
+
retval=0
-if [ -d ppd/C ] ; then
- files=$(get_ppds $args)
- if [ -n "$single" ] ; then
- all_models=""
- nondup_files=""
- for f in $files ; do
- if [ "$(basename $f .gz)" = "$(basename $f)" ] ; then
- model=$(grep '^.StpDriverModelFamily' $f | awk '{print $2}')
- else
- model=$(gunzip -c $f | grep '^.StpDriverModelFamily' | awk '{print $2}')
- fi
- skip=0
- for m in $all_models ; do
- if [ "$model" = "$m" ] ; then
- skip=1
- break
- fi
- done
- if [ "$skip" -eq 0 ] ; then
- all_models="$model $all_models"
- nondup_files="$nondup_files $f"
+if [[ -d ppd/C ]] ; then
+ declare -a files=($(get_ppds "$@"))
+ declare -A models
+ declare -a nfiles
+ if (( $skip_simplified > 0 )) ; then
+ for f in ${files[@]} ; do
+ [[ $f != *.sim.ppd* ]] && nfiles+=($f)
+ done
+ files=(${nfiles[@]})
+ fi
+ if [[ -n $family ]] ; then
+ get_models ${files[@]}
+ nfiles=()
+ for f in ${files[@]} ; do
+ [[ ${all_models[$f]} =~ $family ]] && nfiles+=($f)
+ done
+ files=(${nfiles[@]})
+ fi
+ if (( $single != 0 )) ; then
+ declare -A seen_models
+ nfiles=()
+ get_models ${files[@]}
+ for f in ${files[@]} ; do
+ model=${all_models[$f]}
+ [[ $f == *.sim.ppd ]] && model="${model}_sim"
+ if [[ -z ${seen_models[$model]} ]] ; then
+ nfiles+=($f)
+ seen_models[$model]=1
fi
done
- files=$nondup_files
+ files=(${nfiles[@]})
fi
- for i in $(seq 0 $(($jobs-1))) ; do
- runall $jobs $i $files &
+ (( ${#files[@]} < $jobs )) && jobs=${#files[@]}
+ declare -a subproc=($(seq 0 $((jobs-1))))
+ # Fire 'em off in the background...
+ for i in ${subproc[@]} ; do
+ runall $jobs $i ${files[@]} &
done
- for i in $(seq 0 $(($jobs-1))) ; do
+ # And wait for them to complete.
+ for i in ${subproc[@]} ; do
wait -n
- if [ "$?" -gt 0 ] ; then
- retval=1
- fi
+ (( $? != 0 )) && retval=1
done
fi
-if [ -f "$tfile" ] ; then
- rm -f $tfile
-fi
+
+[[ -n $tfile ]] && rm -f "$tfile"
+(( $retval == 0 )) && rm -rf ppd/C && rmdir ppd
exit $retval