summaryrefslogtreecommitdiff
path: root/src/cups
diff options
context:
space:
mode:
authorDidier Raboud <odyx@debian.org>2016-11-01 18:45:10 +0100
committerDidier Raboud <odyx@debian.org>2016-11-01 18:45:10 +0100
commit54a135b87201e48d4da4894a61b81a8c6fe46d26 (patch)
tree74b42137b1e3eb634c01cb593469dddc727cd124 /src/cups
parentd69d392d8c45cdcc93e58f0e1bdbb2b66d6b9566 (diff)
New upstream version 5.2.12~pre4
Diffstat (limited to 'src/cups')
-rw-r--r--src/cups/backend_common.h4
-rw-r--r--src/cups/backend_dnpds40.c35
-rw-r--r--src/cups/backend_mitsu70x.c522
-rw-r--r--src/cups/backend_mitsu9550.c821
-rw-r--r--src/cups/backend_shinkos1245.c23
-rw-r--r--src/cups/blacklist6
-rwxr-xr-xsrc/cups/test-rastertogutenprint.in12
7 files changed, 957 insertions, 466 deletions
diff --git a/src/cups/backend_common.h b/src/cups/backend_common.h
index d088aaa..2462058 100644
--- a/src/cups/backend_common.h
+++ b/src/cups/backend_common.h
@@ -112,6 +112,10 @@ enum {
P_MITSU_K60,
P_MITSU_9550,
P_MITSU_9550S,
+ P_MITSU_9600,
+ P_MITSU_9800,
+ P_MITSU_9800S,
+ P_MITSU_9810,
P_DNP_DS40,
P_DNP_DS80,
P_DNP_DS80D,
diff --git a/src/cups/backend_dnpds40.c b/src/cups/backend_dnpds40.c
index 4a08d36..41eec62 100644
--- a/src/cups/backend_dnpds40.c
+++ b/src/cups/backend_dnpds40.c
@@ -715,6 +715,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
break;
default:
ctx->media_count_new = 999; // non-zero
+ break;
}
break;
case P_DNP_DSRX1:
@@ -727,6 +728,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
break;
default:
ctx->media_count_new = 999; // non-zero
+ break;
}
break;
case P_DNP_DS80:
@@ -740,6 +742,7 @@ static void dnpds40_attach(void *vctx, struct libusb_device_handle *dev,
break;
default:
ctx->media_count_new = 999; // non-zero
+ break;
}
break;
default:
@@ -1279,11 +1282,13 @@ top:
count = atoi((char*)resp+4);
free(resp);
- /* Old-sk00l models report one less than they should */
- if (!ctx->correct_count)
- count++;
+ if (count) {
+ /* Old-sk00l models report one less than they should */
+ if (!ctx->correct_count)
+ count++;
- count -= ctx->mediaoffset;
+ count -= ctx->mediaoffset;
+ }
if (ctx->media_count_new) {
ATTR("marker-levels=%d\n", count * 100 / ctx->media_count_new);
@@ -1421,11 +1426,13 @@ top:
count = atoi((char*)resp+4);
free(resp);
- /* Old-sk00l models report one less than they should */
- if (!ctx->correct_count)
- count++;
+ if (count) {
+ /* Old-sk00l models report one less than they should */
+ if (!ctx->correct_count)
+ count++;
- count -= ctx->mediaoffset;
+ count -= ctx->mediaoffset;
+ }
if (ctx->media_count_new) {
ATTR("marker-levels=%d\n", count * 100 / ctx->media_count_new);
@@ -1841,11 +1848,13 @@ static int dnpds40_get_status(struct dnpds40_ctx *ctx)
count = atoi((char*)resp+4);
free(resp);
- /* Old-sk00l models report one less than they should */
- if (!ctx->correct_count)
- count++;
+ if (count) {
+ /* Old-sk00l models report one less than they should */
+ if (!ctx->correct_count)
+ count++;
- count -= ctx->mediaoffset;
+ count -= ctx->mediaoffset;
+ }
INFO("Native Prints Remaining on Media: %d\n", count);
if (ctx->supports_rewind) {
@@ -2223,7 +2232,7 @@ static int dnpds40_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend dnpds40_backend = {
.name = "DNP DS40/DS80/DSRX1/DS620",
- .version = "0.88",
+ .version = "0.89",
.uri_prefix = "dnpds40",
.cmdline_usage = dnpds40_cmdline,
.cmdline_arg = dnpds40_cmdline_arg,
diff --git a/src/cups/backend_mitsu70x.c b/src/cups/backend_mitsu70x.c
index 9a94a32..16099ba 100644
--- a/src/cups/backend_mitsu70x.c
+++ b/src/cups/backend_mitsu70x.c
@@ -35,10 +35,76 @@
#include <fcntl.h>
#include <signal.h>
+/* For Integration into gutenprint */
+#if defined(HAVE_CONFIG_H)
+#include <config.h>
+#endif
+
+#if defined(USE_DLOPEN)
+#define WITH_DYNAMIC
+#include <dlfcn.h>
+#define DL_INIT() do {} while(0)
+#define DL_OPEN(__x) dlopen(__x, RTLD_NOW)
+#define DL_SYM(__x, __y) dlsym(__x, __y)
+#define DL_CLOSE(__x) dlclose(__x)
+#define DL_EXIT() do {} while(0)
+#elif defined(USE_LTDL)
+#define WITH_DYNAMIC
+#include <ltdl.h>
+#define DL_INIT() lt_dlinit()
+#define DL_OPEN(__x) lt_dlopen(__x)
+#define DL_SYM(__x, __y) lt_dlsym(__x, __y)
+#define DL_CLOSE(__x) do {} while(0)
+#define DL_EXIT() lt_dlexit()
+#else
+#define DL_INIT() do {} while(0)
+#define DL_CLOSE(__x) do {} while(0)
+#define DL_EXIT() do {} while(0)
+#warning "No dynamic loading support!"
+#endif
+
#define BACKEND mitsu70x_backend
#include "backend_common.h"
+// #include "lib70x/libMitsuD70ImageReProcess.h"
+
+#ifndef LUT_LEN
+#define COLORCONV_RGB 0
+#define COLORCONV_BGR 1
+
+#define LUT_LEN 14739
+struct BandImage {
+ void *imgbuf;
+ int32_t bytes_per_row;
+ uint16_t origin_cols;
+ uint16_t origin_rows;
+ uint16_t cols;
+ uint16_t rows;
+};
+#endif
+
+/* Image processing library function prototypes */
+#define LIB_NAME_RE "libMitsuD70ImageReProcess.so" // Reimplemented library
+
+typedef int (*Get3DColorTableFN)(uint8_t *buf, const char *filename);
+typedef struct CColorConv3D *(*Load3DColorTableFN)(const uint8_t *ptr);
+typedef void (*Destroy3DColorTableFN)(struct CColorConv3D *this);
+typedef void (*DoColorConvFN)(struct CColorConv3D *this, uint8_t *data, uint16_t cols, uint16_t rows, uint32_t bytes_per_row, int rgb_bgr);
+typedef struct CPCData *(*get_CPCDataFN)(const char *filename);
+typedef void (*destroy_CPCDataFN)(struct CPCData *data);
+typedef int (*do_image_effectFN)(struct CPCData *cpc, struct BandImage *input, struct BandImage *output, int sharpen, uint8_t rew[2]);
+typedef int (*send_image_dataFN)(struct BandImage *out, void *context,
+ int (*callback_fn)(void *context, void *buffer, uint32_t len));
+
+#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 USB_VID_MITSU 0x06D3
#define USB_PID_MITSU_D70X 0x3B30
#define USB_PID_MITSU_K60 0x3B31
@@ -48,15 +114,8 @@
//#define USB_VID_FUJIFILM XXXXXX
//#define USB_PID_FUJI_ASK300 XXXXXX
-//#define ENABLE_CORRTABLES
-
-#ifndef CORRTABLE_PATH
-#define CORRTABLE_PATH "D70"
-#endif
-
-#ifdef ENABLE_CORRTABLES
-#include "D70/Mitsu_D70.c"
-#endif
+/* Width of the laminate data file */
+#define LAMINATE_STRIDE 1864
/* Private data stucture */
struct mitsu70x_ctx {
@@ -80,18 +139,31 @@ struct mitsu70x_ctx {
int supports_jobs_query;
-#ifdef ENABLE_CORRTABLES
char *laminatefname;
char *lutfname;
char *cpcfname;
- struct CColorConv3D lut;
- struct CPCData cpcdata;
+ void *dl_handle;
+ Get3DColorTableFN Get3DColorTable;
+ Load3DColorTableFN Load3DColorTable;
+ Destroy3DColorTableFN Destroy3DColorTable;
+ DoColorConvFN DoColorConv;
+ get_CPCDataFN GetCPCData;
+ destroy_CPCDataFN DestroyCPCData;
+ do_image_effectFN DoImageEffect;
+ send_image_dataFN SendImageData;
+
+ struct CColorConv3D *lut;
+ struct CPCData *cpcdata;
char *last_cpcfname;
int raw_format;
-#endif
+ int sharpen; /* ie mhdr.sharpen - 1 */
+
+ uint8_t rew[2]; /* 1 for rewind ok (default!) */
+
+ struct BandImage output;
};
/* Printer data structures */
@@ -257,10 +329,13 @@ struct mitsu70x_memorystatus_resp {
uint8_t rsvd;
} __attribute__((packed));
+// XXX also seen commands 0x67, 0x72, 0x54, 0x6e
+
struct mitsu70x_hdr {
- uint8_t hdr[4]; /* 1b 5a 54 XX */
+ uint8_t hdr[4]; /* 1b 5a 54 XX */ // XXX also, seen 1b 5a 43!
uint16_t jobid;
- uint8_t zero0[10];
+ uint8_t rewind[2]; /* XXX K60/EK305/D80 only, 0 normally, 1 for "skip" ??? */
+ uint8_t zero0[8];
uint16_t cols;
uint16_t rows;
@@ -272,11 +347,12 @@ struct mitsu70x_hdr {
uint8_t deck; /* 0 = default, 1 = lower, 2 = upper */
uint8_t zero2[7];
uint8_t laminate; /* 00 == on, 01 == off */
- uint8_t laminate_mode;
+ uint8_t laminate_mode; /* 00 == glossy, 02 == matte */
uint8_t zero3[6];
uint8_t multicut;
- uint8_t zero4[13];
+ uint8_t zero4[12];
+ uint8_t sharpen; /* 0-9. 5 is "normal", 0 is "off" */
uint8_t mode; /* 0 for cooked YMC planar, 1 for packed BGR */
uint8_t use_lut; /* in BGR mode, 0 disables, 1 enables */
@@ -536,6 +612,8 @@ static void *mitsu70x_init(void)
}
memset(ctx, 0, sizeof(struct mitsu70x_ctx));
+ DL_INIT();
+
return ctx;
}
@@ -567,6 +645,36 @@ static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev,
ctx->supports_jobs_query = 0;
else
ctx->supports_jobs_query = 1;
+
+ /* Attempt to open the library */
+#if defined(WITH_DYNAMIC)
+ INFO("Attempting to load image processing library\n");
+ ctx->dl_handle = DL_OPEN(LIB_NAME_RE);
+ if (!ctx->dl_handle)
+ WARNING("Image processing library not found, using internal fallback code\n");
+ if (ctx->dl_handle) {
+ ctx->Get3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Get3DColorTable");
+ ctx->Load3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Load3DColorTable");
+ ctx->Destroy3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Destroy3DColorTable");
+ ctx->DoColorConv = DL_SYM(ctx->dl_handle, "CColorConv3D_DoColorConv");
+ ctx->GetCPCData = DL_SYM(ctx->dl_handle, "get_CPCData");
+ ctx->DestroyCPCData = DL_SYM(ctx->dl_handle, "destroy_CPCData");
+ ctx->DoImageEffect = DL_SYM(ctx->dl_handle, "do_image_effect");
+ ctx->SendImageData = DL_SYM(ctx->dl_handle, "send_image_data");
+ if (!ctx->Get3DColorTable || !ctx->Load3DColorTable ||
+ !ctx->Destroy3DColorTable || !ctx->DoColorConv ||
+ !ctx->GetCPCData || !ctx->DestroyCPCData ||
+ !ctx->DoImageEffect || !ctx->SendImageData) {
+ WARNING("Problem resolving symbols in imaging processing library\n");
+ DL_CLOSE(ctx->dl_handle);
+ ctx->dl_handle = NULL;
+ } else {
+ INFO("Image processing library successfully loaded\n");
+ }
+ }
+#else
+ WARNING("Dynamic library support not enabled, using internal fallback code\n");
+#endif
}
static void mitsu70x_teardown(void *vctx) {
@@ -578,6 +686,16 @@ static void mitsu70x_teardown(void *vctx) {
if (ctx->databuf)
free(ctx->databuf);
+ if (ctx->dl_handle) {
+ if (ctx->cpcdata)
+ ctx->DestroyCPCData(ctx->cpcdata);
+ if (ctx->lut)
+ ctx->Destroy3DColorTable(ctx->lut);
+ DL_CLOSE(ctx->dl_handle);
+ }
+
+ DL_EXIT();
+
free(ctx);
}
@@ -596,6 +714,8 @@ static int mitsu70x_read_parse(void *vctx, int data_fd) {
}
ctx->matte = 0;
+ ctx->rew[0] = 1;
+ ctx->rew[1] = 1;
repeat:
/* Read in initial header */
@@ -625,7 +745,6 @@ repeat:
return CUPS_BACKEND_CANCEL;
}
-#ifdef ENABLE_CORRTABLES
ctx->raw_format = !mhdr.mode;
/* Figure out the correction data table to use */
@@ -640,6 +759,10 @@ repeat:
} else {
ctx->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";
@@ -652,6 +775,10 @@ repeat:
ctx->cpcfname = CORRTABLE_PATH "/CPD80N01.cpc";
}
// XXX what about CPD80**E**01?
+ 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";
@@ -662,6 +789,10 @@ repeat:
} else {
ctx->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";
@@ -672,7 +803,11 @@ repeat:
} else {
ctx->cpcfname = CORRTABLE_PATH "/EK305T01.cpc";
}
-
+ // XXX what about using K60 media if we read back the proper code?
+ if (mhdr.hdr[3] != 0x90) {
+ WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
+ 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!
@@ -682,14 +817,20 @@ repeat:
} else {
ctx->cpcfname = CORRTABLE_PATH "/ASK300T1.cpc";
}
+ if (mhdr.hdr[3] != 0x01) {
+ WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
+ mhdr.hdr[3] = 0x01;
+ }
}
if (!mhdr.use_lut)
ctx->lutfname = NULL;
+ ctx->sharpen = mhdr.sharpen - 1;
+
/* Clean up header back to pristine. */
mhdr.use_lut = 0;
mhdr.mode = 0;
-#endif
+ mhdr.sharpen = 0;
/* Work out total printjob size */
ctx->cols = be16_to_cpu(mhdr.cols);
@@ -707,7 +848,8 @@ repeat:
remain = 3 * planelen + ctx->matte;
ctx->datalen = 0;
- ctx->databuf = malloc(sizeof(mhdr) + remain);
+ ctx->databuf = malloc(sizeof(mhdr) + remain + LAMINATE_STRIDE*2); /* Give us a bit extra */
+
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_FAILED;
@@ -716,9 +858,7 @@ repeat:
memcpy(ctx->databuf + ctx->datalen, &mhdr, sizeof(mhdr));
ctx->datalen += sizeof(mhdr);
-#ifdef ENABLE_CORRTABLES
if (ctx->raw_format) { /* RAW MODE */
-#endif
DEBUG("Reading in %d bytes of 16bpp YMCL data\n", remain);
/* Read in the spool data */
@@ -731,7 +871,6 @@ repeat:
ctx->datalen += i;
remain -= i;
}
-#ifdef ENABLE_CORRTABLES
} else { /* RAW MODE OFF */
int spoolbuflen = 0;
uint8_t *spoolbuf;
@@ -757,90 +896,109 @@ repeat:
}
/* Run through basic LUT, if present and enabled */
- if (ctx->lutfname) {
+ 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 (CColorConv3D_Get3DColorTable(buf, ctx->lutfname)) {
+ if (ctx->Get3DColorTable(buf, ctx->lutfname)) {
ERROR("Unable to open LUT file '%s'\n", ctx->lutfname);
return CUPS_BACKEND_CANCEL;
}
- CColorConv3D_Load3DColorTable(&ctx->lut, buf);
+ ctx->lut = ctx->Load3DColorTable(buf);
free(buf);
- CColorConv3D_DoColorConv(&ctx->lut, spoolbuf, ctx->cols, ctx->rows, ctx->cols * 3, 1);
- // XXX proprietary lib also does gamma+contrast+brightness
+ 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);
}
/* Load in the CPC file, if needed! */
- if (ctx->cpcfname && ctx->cpcfname != ctx->last_cpcfname) {
- ctx->last_cpcfname = ctx->cpcfname;
- if (load_CPCData(&ctx->cpcdata, ctx->cpcfname)) {
- ERROR("Unable to load CPC file '%s'\n", ctx->cpcfname);
- return CUPS_BACKEND_CANCEL;
+ if (ctx->dl_handle) {
+ struct BandImage input;
+
+ 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;
+ }
}
- }
- // XXX INSERT ALGORITHM HERE...
+ /* Convert using image processing library */
- // XXX optionally CreateInkCorrectGammaTable(...)
+ 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;
- /* Convert to YMC using corrtables (aka CImageEffect70::DoGamma) */
- {
- uint32_t r, c;
- uint32_t in = 0, out = 0;
+ 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;
- uint16_t *offset_y = (uint16_t*)(ctx->databuf + ctx->datalen);
- uint16_t *offset_m = offset_y + planelen/2;
- uint16_t *offset_c = offset_m + planelen/2;
-// uint16_t *offset_l = offset_c + planelen/2;
- DEBUG("Running print data through BGR->YMC table (crude)\n");
- for(r = 0 ; r < ctx->rows; r++) {
- for (c = 0 ; c < ctx->cols ; c++) {
- offset_y[out] = cpu_to_be16(ctx->cpcdata.GNMby[spoolbuf[in]]);
- offset_m[out] = cpu_to_be16(ctx->cpcdata.GNMgm[spoolbuf[in + 1]]);
- offset_c[out] = cpu_to_be16(ctx->cpcdata.GNMrc[spoolbuf[in + 2]]);
- in += 3;
- out++;
- }
+ DEBUG("Running print data through processing library\n");
+ if (ctx->DoImageEffect(ctx->cpcdata, &input, &ctx->output, ctx->sharpen, 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");
+ return CUPS_BACKEND_CANCEL;
}
- // XXX then call CImageEffect70::DoConv(...) to do the final corrections..
- /* Move up the pointer */
+ /* Move up the pointer to after the image data */
ctx->datalen += 3*planelen;
/* Clean up */
free(spoolbuf);
- /* Now that we've filled everything in, read latte from file */
+ /* Now that we've filled everything in, read matte from file */
if (ctx->matte) {
int fd;
- DEBUG("Reading %d bytes of matte data from disk\n", ctx->matte);
+ 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;
}
- remain = ctx->matte;
- while (remain) {
- i = read(fd, ctx->databuf + ctx->datalen, remain);
- if (i == 0) {
- /* We hit EOF, restart from beginning */
- lseek(fd, 0, SEEK_SET);
- continue;
+
+ 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;
}
- if (i < 0)
- return CUPS_BACKEND_CANCEL;
- ctx->datalen += i;
- remain -= i;
+ /* Back off the buffer so we "wrap" on the print row. */
+ ctx->datalen -= ((LAMINATE_STRIDE - ctx->cols) * 2);
}
+
+ /* 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);
}
}
-#endif
return CUPS_BACKEND_OK;
}
@@ -1014,7 +1172,7 @@ static int mitsu70x_set_sleeptime(struct mitsu70x_ctx *ctx, uint8_t time)
memset(cmdbuf, 0, 4);
cmdbuf[0] = 0x1b;
cmdbuf[1] = 0x53;
- cmdbuf[2] = 0x53;
+ cmdbuf[2] = 0x53; // XXX also, 0x4e and 0x50 are other params.
cmdbuf[3] = time;
if ((ret = send_data(ctx->dev, ctx->endp_down,
@@ -1032,7 +1190,7 @@ static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx)
memset(buf, 0, sizeof(buf));
buf[0] = 0x1b;
buf[1] = 0x45;
- buf[2] = 0x57;
+ buf[2] = 0x57; // XXX also, 0x53, 0x54 seen.
buf[3] = 0x55;
INFO("Waking up printer...\n");
@@ -1043,6 +1201,13 @@ static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx)
return 0;
}
+static int d70_library_callback(void *context, void *buffer, uint32_t len)
+{
+ struct mitsu70x_ctx *ctx = context;
+
+ return send_data(ctx->dev, ctx->endp_down, buffer, len);
+}
+
static int mitsu70x_main_loop(void *vctx, int copies)
{
struct mitsu70x_ctx *ctx = vctx;
@@ -1175,23 +1340,34 @@ skip_status:
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];
+ }
+
/* Matte operation requires Ultrafine/superfine */
if (ctx->matte) {
if (ctx->type != P_MITSU_D70X) {
- hdr->speed = 0x04; /* Force UltraFine */
+ if (hdr->speed != 0x03 && hdr->speed != 0x04) {
+ WARNING("Forcing Ultrafine mode for matte printing!\n");
+ hdr->speed = 0x04; /* Force UltraFine */
+ }
} else {
- hdr->speed = 0x03; /* Force SuperFine */
+ if (hdr->speed != 0x03) {
+ hdr->speed = 0x03; /* Force SuperFine */
+ WARNING("Forcing Ultrafine mode for matte printing!\n");
+ }
}
}
/* Any other fixups? */
-#if 1 // XXX is this actually needed?
if ((ctx->type == P_MITSU_K60 || ctx->type == P_KODAK_305) &&
ctx->cols == 0x0748 &&
- ctx->rows == 0x04c2) {
- hdr->multicut = 1; // XXX only if print count even?
+ ctx->rows == 0x04c2 && !hdr->multicut) {
+ hdr->multicut = 1;
}
-#endif
/* We're clear to send data over! */
INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
@@ -1201,11 +1377,17 @@ skip_status:
sizeof(struct mitsu70x_hdr))))
return CUPS_BACKEND_FAILED;
- {
- /* K60 and 305 need data sent in 256K chunks, but the first
- chunk needs to subtract the length of the 512-byte header */
+ if (ctx->dl_handle && !ctx->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))
+ return CUPS_BACKEND_FAILED;
+ } else { // Fallback code..
+ /* K60 and 305 need data sent in 256K chunks, but the first
+ chunk needs to subtract the length of the 512-byte header */
- // XXX is this special case actually needed?
int chunk = 256*1024 - sizeof(struct mitsu70x_hdr);
int sent = 512;
while (chunk > 0) {
@@ -1217,7 +1399,7 @@ skip_status:
if (chunk > 256*1024)
chunk = 256*1024;
}
- }
+ }
/* Then wait for completion, if so desired.. */
INFO("Waiting for printer to acknowledge completion\n");
@@ -1277,9 +1459,9 @@ skip_status:
jobstatus.job_status[2] ||
jobstatus.job_status[3]) {
ERROR("Abnormal exit: %02x/%02x/%02x\n",
- jobstatus.error_status[0],
- jobstatus.error_status[1],
- jobstatus.error_status[2]);
+ jobstatus.job_status[1],
+ jobstatus.job_status[2],
+ jobstatus.job_status[3]);
return CUPS_BACKEND_STOP;
}
/* Job complete */
@@ -1476,7 +1658,7 @@ static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend mitsu70x_backend = {
.name = "Mitsubishi CP-D70/D707/K60/D80",
- .version = "0.43WIP",
+ .version = "0.51",
.uri_prefix = "mitsu70x",
.cmdline_usage = mitsu70x_cmdline,
.cmdline_arg = mitsu70x_cmdline_arg,
@@ -1496,7 +1678,8 @@ struct dyesub_backend mitsu70x_backend = {
}
};
-/* Mitsubish CP-D70DW/CP-D707DW/CP-K60DW-S/CP-D80DW/Kodak 305 data format
+/* Mitsubish CP-D70DW/D707DW/K60DW-S/D80DW, Kodak 305, Fuji ASK-300
+ data format:
Spool file consists of two headers followed by three image planes
and an optional lamination data plane. All blocks are rounded up to
@@ -1504,30 +1687,32 @@ struct dyesub_backend mitsu70x_backend = {
All multi-byte numbers are big endian, ie MSB first.
- Header 1: (Init) (AKA Wake Up)
+ Header 1: (AKA Wake Up)
1b 45 57 55 00 00 00 00 00 00 00 00 00 00 00 00
(padded by NULLs to a 512-byte boundary)
- Header 2: (Header)
+ Header 2: (Print Header)
- 1b 5a 54 PP JJ JJ 00 00 00 00 00 00 00 00 00 00
+ 1b 5a 54 PP JJ JJ RR RR 00 00 00 00 00 00 00 00
XX XX YY YY QQ QQ ZZ ZZ SS 00 00 00 00 00 00 00
- UU 00 00 00 00 00 00 00 00 TT 00 00 00 00 00 00
+ UU 00 00 00 00 00 00 00 LL TT 00 00 00 00 00 00
RR 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
(padded by NULLs to a 512-byte boundary)
- PP == 0x01 on D70x/D80, 0x02 on K60, 0x90 on K305
+ PP == 0x01 on D70x/D80/ASK300, 0x00 on K60, 0x90 on K305
JJ JJ == Job ID, can leave at 00 00
XX XX == columns
YY YY == rows
QQ QQ == lamination columns (equal to XX XX)
- ZZ ZZ == lamination rows (YY YY + 12)
+ ZZ ZZ == lamination rows (YY YY + 12 on D70x/D80/ASK300, YY YY on others)
+ RR RR == "rewind inhibit", 01 01 enabled, normally 00 00
SS == Print mode: 00 = Fine, 03 = SuperFine (D70x/D80 only), 04 = UltraFine
(Matte requires Superfine or Ultrafine)
UU == 00 = Auto, 01 = Lower Deck (required for !D70x), 02 = Upper Deck
- TT == lamination: 00 glossy, 02 matte.
+ LL == lamination enable, 00 == on, 01 == off
+ TT == lamination mode: 00 glossy, 02 matte.
RR == 00 (normal), 01 = (Double-cut 4x6), 05 = (double-cut 2x6)
Data planes:
@@ -1536,151 +1721,4 @@ struct dyesub_backend mitsu70x_backend = {
Lamination plane: (only present if QQ and ZZ are nonzero)
16-byte data, rounded up to 512-byte block (QQ * ZZ * 2 bytes)
- ********************************************************************
-
- Command format:
-
- -> 1b 56 32 30
- <- [256 byte payload]
-
- PRINTER STATUS
-
- e4 56 32 30 00 00 00 00 00 00 00 00 00 00 00 00 .V20............
- 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 00 ................
- 44 80 00 00 5f 00 00 3d 43 00 50 00 44 00 37 00 D..._..=C.P.D.7.
- 30 00 44 00 30 00 30 00 31 00 31 00 31 00 37 00 0.D.0.0.1.1.1.7.
- 33 31 36 54 31 33 21 a3 33 31 35 42 31 32 f5 e5 316T13!.315B12..
- 33 31 39 42 31 31 a3 fb 33 31 38 45 31 32 50 0d 319B11..318E12P.
- 33 31 37 41 32 32 a3 82 44 55 4d 4d 59 40 00 00 317A22..DUMMY@..
- 44 55 4d 4d 59 40 00 00 00 00 00 00 00 00 00 00 DUMMY@..........
-
- LOWER DECK STATUS
-
- 00 00 00 00 00 00 02 04 3f 00 00 04 96 00 00 00 MM MM: media capacity
- ff 0f 01 00 MM MM NN NN 00 00 00 00 05 28 75 80 NN NN: prints remaining
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
-
- alt (some sort of error state)
-
- 00 00 00 0a 05 05 01 d5 38 00 00 00 14 00 00 00
- ff ff ff ff ff ff ff ff ff ff 00 00 00 27 72 80
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
-
- UPPER DECK STATUS (if present)
-
- XX XX 00 00 00 00 01 ee 3d 00 00 06 39 00 00 00 MM MM: media capacity
- ff 02 00 00 MM MM NN NN 00 00 00 00 06 67 78 00 NN NN: prints remaining
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 XX XX: 0x80 00 if no deck
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
-
- alt (no deck present)
-
- 80 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00
- ff ff ff ff ff ff ff ff ff ff 00 00 00 00 80 00
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
- 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00
-
- -> 1b 56 31 30 00 00
- <- [26 byte payload]
-
- CP-D707DW:
-
- e4 56 31 30 00 00 00 XX YY ZZ 00 00 TT 00 00 00
- 00 00 00 00 WW 00 00 00 00 00
-
- XX/YY/ZZ and WW/TT are unknown. Observed values:
-
- 00 00 00 00/00
- 40 80 a0 80/0f
- 80 80 a0
- 40 80 90
- 40 80 00
-
- also seen:
-
- e4 56 31 30 00 00 00 00 00 00 00 00 0f 00 00 00
- 00 0a 05 05 80 00 00 00 00 00
-
- e4 56 31 30 00 00 00 40 80 90 10 00 0f 00 00 00
- 00 0a 05 05 80 00 00 00 00 00
-
- e4 56 31 30 00 00 00 00 40 80 00 00 00 ff 40 00
- 00 00 00 00 80 00 00 00 00 00
-
- print just submitted:
-
- e4 56 31 30 00 00 00 00 40 20 00 00 00 8c 00 00
- 00 00 00 00 80 00 00 00 00 00
-
- prints running...
-
- e4 56 31 30 00 00 00 00 40 20 00 00 00 cf 00 20
- 00 00 00 00 80 00 00 00 00 00
-
- CP-K60DW-S:
-
- e4 56 31 30 00 00 00 XX YY 00 00 00 0f 00 00 00
- 00 00 00 00 80 00 00 00 00 00
-
- XX/YY are unknown, observed values:
-
- 40/80
- 00/00
-
- Memory status query:
-
- -> 1b 56 33 00 XX XX YY YY UU 00
-
- XX XX == columns
- YY YY == rows
- UU == 0x00 glossy, 0x80 matte
-
- <- [ 6 byte payload ]
-
- e4 56 33 00 00 00
- e4 56 33 00 00 01
- e4 56 33 ff 01 01
-
- |--- Size check, 00 ok, 01 fail
- |------ Memory check, 00 ok, 01 fail, ff bad size
-
- ** ** ** ** ** **
-
- The windows drivers seem to send the id and status queries before
- and in between each of the chunks sent to the printer. There doesn't
- appear to be any particular intelligence in the protocol, but it didn't
- work when the raw dump was submitted as-is.
-
- ** ** ** ** ** **
-
-Various deck status dumps:
-
-0080 00 00 00 00 00 00 01 d2 39 00 00 00 07 00 00 00 ........9.......
-0090 61 8f 00 00 01 40 01 36 00 00 00 00 00 17 79 80 a....@.6......y.
-
-0080 00 00 00 00 00 00 01 c6 39 00 00 00 08 00 00 00 ........9.......
-0090 61 8f 00 00 01 40 01 35 00 00 00 00 00 18 79 80 a....@.5......y.
-
-0080 00 00 00 00 00 00 02 19 50 00 00 00 19 00 00 01 ........P.......
-0090 6c 8f 00 00 01 40 01 22 00 00 00 00 00 27 83 80 l....@.".....'..
-
-0080 00 00 00 00 00 00 02 00 3e 00 00 04 96 00 00 00 ........>.......
-0090 ff 0f 01 00 00 c8 00 52 00 00 00 00 05 28 75 80 .......R.....(u.
-
-00c0 00 00 00 00 00 00 01 f3 3d 00 00 06 39 00 00 00 ........=...9...
-00d0 ff 02 00 00 01 90 00 c3 00 00 00 00 06 67 78 00 .............gx.
-
-0080 00 00 00 00 00 00 01 d0 38 00 00 03 70 00 00 00 ........8...p...
-0090 ff 02 00 00 01 90 00 1e 01 00 00 00 03 83 72 80 ..............r.
-
-0080 00 00 00 00 00 00 01 d6 39 00 00 00 20 00 00 00 ........9... ...
-0090 ff 02 00 00 01 90 01 7c 01 00 00 00 00 33 72 80 .......|.....3r.
-
- 00 00 00 0a 05 05 01 d5 38 00 00 00 14 00 00 00
- ff ff ff ff ff ff ff ff ff ff 00 00 00 27 72 80 ?? Error ??
-
- 80 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00
- ff ff ff ff ff ff ff ff ff ff 00 00 00 00 80 00 NO DECK PRESENT
*/
diff --git a/src/cups/backend_mitsu9550.c b/src/cups/backend_mitsu9550.c
index 862f5f0..1599e9f 100644
--- a/src/cups/backend_mitsu9550.c
+++ b/src/cups/backend_mitsu9550.c
@@ -1,5 +1,5 @@
/*
- * Mitsubishi CP-9550DW[-S] Photo Printer CUPS backend
+ * Mitsubishi CP-9xxx Photo Printer Family CUPS backend
*
* (c) 2014-2016 Solomon Peachy <pizza@shaftnet.org>
*
@@ -40,38 +40,30 @@
#include "backend_common.h"
#define USB_VID_MITSU 0x06D3
+#define USB_PID_MITSU_9000D 0x0393
+#define USB_PID_MITSU_9500D 0x0394
#define USB_PID_MITSU_9550D 0x03A1
#define USB_PID_MITSU_9550DS 0x03A5 // or DZ/DZS/DZU
-
-/* Private data stucture */
-struct mitsu9550_ctx {
- struct libusb_device_handle *dev;
- uint8_t endp_up;
- uint8_t endp_down;
- int type;
-
- uint8_t *databuf;
- int datalen;
-
- int is_s_variant;
-
- uint16_t rows;
- uint16_t cols;
-
- uint16_t last_donor;
- uint16_t last_remain;
- int marker_reported;
-};
+#define USB_PID_MITSU_9600D 0x03A9
+//#define USB_PID_MITSU_9600DS XXXXXX
+//#define USB_PID_MITSU_9800D XXXXXX
+#define USB_PID_MITSU_9800DS 0x03AE
+//#define USB_PID_MITSU_9810D XXXXXX
+//#define USB_PID_MITSU_9820DS XXXXXX
/* Spool file structures */
+
+/* Print parameters1 */
struct mitsu9550_hdr1 {
uint8_t cmd[4]; /* 1b 57 20 2e */
- uint8_t unk[10];
+ uint8_t unk[10]; /* 00 0a 10 00 [...] */
uint16_t cols; /* BE */
uint16_t rows; /* BE */
- uint8_t null[32];
+ uint8_t matte; /* CP9810 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 [...] */
@@ -79,10 +71,11 @@ struct mitsu9550_hdr2 {
uint8_t null[2];
uint8_t cut; /* 00 == normal, 83 == 2x6*2 */
uint8_t unkb[5];
- uint8_t mode; /* 00 == normal, 80 == fine */
+ uint8_t mode; /* 00 == fine, 80 == superfine */
uint8_t unkc[11]; /* 00 [...] 00 01 */
} __attribute__((packed));
+/* Fine Deep selection (9550 only) */
struct mitsu9550_hdr3 {
uint8_t cmd[4]; /* 1b 57 22 2e */
uint8_t unk[7]; /* 00 40 00 [...] */
@@ -90,23 +83,55 @@ struct mitsu9550_hdr3 {
uint8_t null[38];
} __attribute__((packed));
+/* Error policy? */
struct mitsu9550_hdr4 {
uint8_t cmd[4]; /* 1b 57 26 2e */
uint8_t unk[46]; /* 00 70 00 00 00 00 00 00 01 01 00 [...] */
} __attribute__((packed));
+/* Data plane header */
struct mitsu9550_plane {
- uint8_t cmd[4]; /* 1b 5a 54 00 */
- uint8_t null[2];
- uint16_t rem_rows; /* BE, normally 0 */
- uint16_t columns; /* BE */
- uint16_t rows; /* BE */
+ uint8_t cmd[4]; /* 1b 5a 54 XX */ /* XX == 0x10 if 16bpp, 0x00 for 8bpp */
+ 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));
struct mitsu9550_cmd {
uint8_t cmd[4];
} __attribute__((packed));
+/* Private data stucture */
+struct mitsu9550_ctx {
+ struct libusb_device_handle *dev;
+ uint8_t endp_up;
+ uint8_t endp_down;
+ int type;
+ int is_s;
+
+ uint8_t *databuf;
+ uint32_t datalen;
+
+ uint16_t rows;
+ uint16_t cols;
+ uint32_t plane_len;
+
+ uint16_t last_donor;
+ uint16_t last_remain;
+ int marker_reported;
+
+ /* Parse headers separately */
+ struct mitsu9550_hdr1 hdr1;
+ int hdr1_present;
+ struct mitsu9550_hdr2 hdr2;
+ int hdr2_present;
+ struct mitsu9550_hdr3 hdr3;
+ int hdr3_present;
+ struct mitsu9550_hdr4 hdr4;
+ int hdr4_present;
+};
+
/* Printer data structures */
struct mitsu9550_media {
uint8_t hdr[2]; /* 24 2e */
@@ -162,7 +187,7 @@ struct mitsu9550_status2 {
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)); \
+ ATTR("marker-names='%s'\n", mitsu9550_media_types(media->type, ctx->is_s)); \
ATTR("marker-types=ribbonWax\n"); \
} \
\
@@ -172,17 +197,18 @@ struct mitsu9550_status2 {
ATTR("marker-levels=%d\n", 0); \
return CUPS_BACKEND_HOLD; \
} \
- donor = be16_to_cpu(media->remain)/be16_to_cpu(media->max); \
+ 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); \
} \
- remain = be16_to_cpu(media->remain); \
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)); \
+ ATTR("marker-message=\"%u prints remaining on '%s' ribbon\"\n", remain, mitsu9550_media_types(media->type, ctx->is_s)); \
} \
- if (validate_media(media->type, ctx->cols, ctx->rows)) { \
+ 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); \
return CUPS_BACKEND_HOLD; \
} \
@@ -233,6 +259,10 @@ static void mitsu9550_attach(void *vctx, struct libusb_device_handle *dev,
ctx->type = lookup_printer_type(&mitsu9550_backend,
desc.idVendor, desc.idProduct);
+ if (ctx->type == P_MITSU_9550S ||
+ ctx->type == P_MITSU_9800S)
+ ctx->is_s = 1;
+
ctx->last_donor = ctx->last_remain = 65535;
}
@@ -250,9 +280,9 @@ static void mitsu9550_teardown(void *vctx) {
static int mitsu9550_read_parse(void *vctx, int data_fd) {
struct mitsu9550_ctx *ctx = vctx;
- struct mitsu9550_hdr1 hdr;
-
+ uint8_t buf[sizeof(struct mitsu9550_hdr1)];
int remain, i;
+ uint32_t planelen = 0;
if (!ctx)
return CUPS_BACKEND_FAILED;
@@ -262,10 +292,16 @@ static int mitsu9550_read_parse(void *vctx, int data_fd) {
ctx->databuf = NULL;
}
+ ctx->hdr1_present = 0;
+ ctx->hdr2_present = 0;
+ ctx->hdr3_present = 0;
+ ctx->hdr4_present = 0;
+
+top:
/* Read in initial header */
- remain = sizeof(hdr);
+ remain = sizeof(buf);
while (remain > 0) {
- i = read(data_fd, ((uint8_t*)&hdr) + sizeof(hdr) - remain, remain);
+ i = read(data_fd, buf + sizeof(buf) - remain, remain);
if (i == 0)
return CUPS_BACKEND_CANCEL;
if (i < 0)
@@ -274,41 +310,163 @@ static int mitsu9550_read_parse(void *vctx, int data_fd) {
}
/* Sanity check */
- if (hdr.cmd[0] != 0x1b ||
- hdr.cmd[1] != 0x57 ||
- hdr.cmd[2] != 0x20 ||
- hdr.cmd[3] != 0x2e) {
- ERROR("Unrecognized data format!\n");
+ if (buf[0] != 0x1b || buf[1] != 0x57 || buf[3] != 0x2e) {
+ if (!ctx->hdr1_present || !ctx->hdr2_present) {
+ ERROR("Unrecognized data format!\n");
+ return CUPS_BACKEND_CANCEL;
+ } else if (buf[0] == 0x1b && buf[1] == 0x5a &&
+ buf[2] == 0x54) {
+
+ /* We're in the data portion now */
+ if (buf[3] == 0x10)
+ planelen *= 2;
+
+ goto hdr_done;
+ } else {
+ ERROR("Unrecognized data block!\n");
+ return CUPS_BACKEND_CANCEL;
+ }
+ }
+
+ switch(buf[2]) {
+ case 0x20: /* header 1 */
+ memcpy(&ctx->hdr1, buf, sizeof(ctx->hdr1));
+ ctx->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;
+
+ break;
+ case 0x21: /* header 2 */
+ memcpy(&ctx->hdr2, buf, sizeof(ctx->hdr2));
+ ctx->hdr2_present = 1;
+ break;
+ case 0x22: /* header 3 */
+ memcpy(&ctx->hdr3, buf, sizeof(ctx->hdr3));
+ ctx->hdr3_present = 1;
+ break;
+ case 0x26: /* header 4 */
+ memcpy(&ctx->hdr4, buf, sizeof(ctx->hdr4));
+ ctx->hdr4_present = 1;
+ break;
+ default:
+ ERROR("Unrecognized header format (%02x)!\n", buf[2]);
return CUPS_BACKEND_CANCEL;
}
- /* Work out printjob size */
- ctx->rows = be16_to_cpu(hdr.rows);
- ctx->cols = be16_to_cpu(hdr.cols);
+ /* Read in the next chunk */
+ goto top;
+
+hdr_done:
+
+ /* We have three planes and the final terminator to read */
+ remain = 3 * (planelen + 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);
+ }
- remain = ctx->rows * ctx->cols + sizeof(struct mitsu9550_plane);
- remain *= 3;
- remain += sizeof(struct mitsu9550_hdr2) + sizeof(struct mitsu9550_hdr3)+ sizeof(struct mitsu9550_hdr4) + sizeof(struct mitsu9550_cmd);
+ /* 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;
+ }
- /* Allocate buffer */
- ctx->databuf = malloc(remain + sizeof(struct mitsu9550_hdr1));
+ /* Allocate buffer for the payload */
+ ctx->datalen = 0;
+ ctx->databuf = malloc(remain);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_FAILED;
}
- memcpy(ctx->databuf, &hdr, sizeof(struct mitsu9550_hdr1));
- ctx->datalen = sizeof(struct mitsu9550_hdr1);
+ /* Load up the data blocks.*/
+ while(1) {
+ /* Note that 'buf' needs to be already filled here! */
+ struct mitsu9550_plane *plane = (struct mitsu9550_plane *)buf;
+
+ /* Sanity check header... */
+ if (plane->cmd[0] != 0x1b ||
+ plane->cmd[1] != 0x5a ||
+ plane->cmd[2] != 0x54) {
+ ERROR("Unexpected data read, aborting job\n");
+ return CUPS_BACKEND_CANCEL;
+ }
- /* Read in the spool data */
- while(remain) {
- i = read(data_fd, ctx->databuf + ctx->datalen, remain);
+ /* Work out the length of this block */
+ planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
+ if (plane->cmd[3] == 0x10)
+ planelen *= 2;
+
+ /* Copy plane header into buffer */
+ memcpy(ctx->databuf + ctx->datalen, buf, sizeof(buf));
+ ctx->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)
+ return CUPS_BACKEND_CANCEL;
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ ctx->datalen += i;
+ planelen -= i;
+ }
+
+ /* Try to read in the next chunk. It will be one of:
+ - Additional block header (12B)
+ - Job footer (4B)
+ */
+ i = read(data_fd, buf, 4);
if (i == 0)
return CUPS_BACKEND_CANCEL;
if (i < 0)
return CUPS_BACKEND_CANCEL;
- ctx->datalen += i;
- remain -= i;
+
+ /* Is this a "job end" marker? */
+ if (plane->cmd[0] != 0x1b ||
+ plane->cmd[1] != 0x5a ||
+ plane->cmd[2] != 0x54) {
+ /* store it in the buffer */
+ memcpy(ctx->databuf + ctx->datalen, buf, 4);
+ ctx->datalen += 4;
+
+ /* Unless we have a matte plane following, we're done */
+ if (!ctx->hdr1.matte)
+ break;
+ planelen = sizeof(buf);
+ } else {
+ /* It's part of a block header, mark what we've read */
+ planelen = 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)
+ return CUPS_BACKEND_CANCEL;
+ if (i < 0)
+ return CUPS_BACKEND_CANCEL;
+ planelen -= 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;
}
return CUPS_BACKEND_OK;
@@ -345,8 +503,22 @@ static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int st
return 0;
}
-static char *mitsu9550_media_types(uint8_t type)
+static char *mitsu9550_media_types(uint8_t type, uint8_t is_s)
{
+ if (is_s) {
+ switch (type & 0xf) { /* values can be 0x0? or 0x4? */
+ case 0x02:
+ return "CK9015 (4x6)";
+ case 0x04:
+ return "CK9318 (5x7)";
+ case 0x05:
+ return "CK9523 (6x9)";
+ default:
+ return "Unknown";
+ }
+ return NULL;
+ }
+
switch (type & 0xf) { /* values can be 0x0? or 0x4? */
case 0x01:
return "CK9035 (3.5x5)";
@@ -366,40 +538,195 @@ static char *mitsu9550_media_types(uint8_t type)
return NULL;
}
-static int validate_media(int type, int cols, int rows) {
+static int validate_media(int type, int media, int cols, int rows)
+{
switch(type) {
- case 0x01: /* 3.5x5 */
- if (cols != 1812 && rows != 1240)
- return 1;
+ case P_MITSU_9550:
+ switch(media & 0xf) {
+ case 0x01: /* 3.5x5 */
+ if (cols != 1812 && rows != 1240)
+ return 1;
+ break;
+ case 0x02: /* 4x6 */
+ case 0x03: /* 4x6 postcard */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 1184 && rows != 1240)
+ return 1;
+ break;
+ case 0x04: /* 5x7 */
+ if (cols != 1812)
+ return 1;
+ if (rows != 1240 && rows != 2452)
+ return 1;
+ break;
+ case 0x05: /* 6x9 */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 2792 &&
+ rows != 2956 && rows != 3146)
+ return 1;
+ break;
+ case 0x06: /* V (6x8??) */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 2792)
+ return 1;
+ break;
+ default: /* Unknown */
+ WARNING("Unknown media type %02x\n", media);
+ break;
+ }
break;
- case 0x02: /* 4x6 */
- case 0x03: /* 4x6 postcard */
- if (cols != 2152)
- return 1;
- if (rows != 1416 && rows != 1184 &&
- rows != 1240)
- return 1;
+ case P_MITSU_9550S:
+ switch(media & 0xf) {
+ case 0x02: /* 4x6 */
+ case 0x03: /* 4x6 postcard */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 1184 && rows != 1240)
+ return 1;
+ break;
+ case 0x04: /* 5x7 */
+ if (cols != 1812 && rows != 2452)
+ return 1;
+ break;
+ case 0x05: /* 6x9 */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 2792 &&
+ rows != 2956 && rows != 3146)
+ return 1;
+ break;
+ case 0x06: /* V (6x8??) */
+ if (cols != 2152)
+ return 1;
+ if (rows != 1416 && rows != 2792)
+ return 1;
+ break;
+ default: /* Unknown */
+ WARNING("Unknown media type %02x\n", media);
+ break;
+ }
break;
- case 0x04: /* 5x7 */
- if (cols != 1812)
+ case P_MITSU_9600: // XXX 9600S doesn't support 5" media at all!
+ switch(media & 0xf) {
+ case 0x01: /* 3.5x5 */
+ if (cols == 1572) {
+ if (rows == 1076)
+ break;
+ } else if (cols == 3144) {
+ if (rows == 2152)
+ break;
+ }
return 1;
- if (rows != 1240 && rows != 2452)
+ case 0x02: /* 4x6 */
+ case 0x03: /* 4x6 postcard */
+ if (cols == 1868) {
+ if (rows == 1228)
+ break;
+ } else if (cols == 3736) {
+ if (rows == 2458)
+ break;
+ }
return 1;
- break;
- case 0x05: /* 6x9 */
- if (cols != 2152)
+ case 0x04: /* 5x7 */
+ if (cols == 1572) {
+ if (rows == 1076 || rows == 2128)
+ break;
+ } else if (cols == 3144) {
+ if (rows == 2152 || rows == 4256)
+ break;
+ }
return 1;
- if (rows != 1416 && rows != 2792 &&
- rows != 2956 && rows != 3146)
+ case 0x05: /* 6x9 */
+ if (cols == 1868) {
+ if (rows == 1228 || rows == 2442 || rows == 2564 || rows == 2730)
+ break;
+ } else if (cols == 3736) {
+ if (rows == 2458 || rows == 4846 || rows == 5130 || rows == 5462)
+ break;
+ }
return 1;
- break;
- case 0x06: /* V (6x8??) */
- if (cols != 2152)
- return 1;
- if (rows != 1416 && rows != 2792)
+ case 0x06: /* V (6x8??) */
+ if (cols == 1868) {
+ if (rows == 1228 || rows == 2442)
+ break;
+ } else if (cols == 3736) {
+ if (rows == 2458 || rows == 4846)
+ break;
+ }
return 1;
+ default: /* Unknown */
+ WARNING("Unknown media type %02x\n", media);
+ break;
+ }
break;
- default: /* Unknown */
+ case P_MITSU_9800:
+ case P_MITSU_9810: // XXX and don't forget the 9820S
+ switch(media & 0xf) {
+ case 0x01: /* 3.5x5 */
+ if (cols != 1572 && rows != 1076)
+ return 1;
+ break;
+ case 0x02: /* 4x6 */
+ case 0x03: /* 4x6 postcard */
+ if (cols != 1868 && rows != 1228)
+ return 1;
+ break;
+ case 0x04: /* 5x7 */
+ if (cols != 1572 && rows != 2128)
+ return 1;
+ break;
+ case 0x05: /* 6x9 */
+ if (cols != 1868)
+ return 1;
+ if (rows != 1228 && rows != 2442 &&
+ rows != 2564 && rows != 2730)
+ return 1;
+ break;
+ case 0x06: /* V (6x8??) */
+ if (cols != 1868)
+ return 1;
+ if (rows != 1228 && rows != 2442)
+ return 1;
+ break;
+ default: /* Unknown */
+ WARNING("Unknown media type %02x\n", media);
+ break;
+ }
+ break;
+ case P_MITSU_9800S:
+ switch(media & 0xf) {
+ case 0x02: /* 4x6 */
+ case 0x03: /* 4x6 postcard */
+ if (cols != 1868 && rows != 1228)
+ return 1;
+ break;
+ case 0x04: /* 5x7 */
+ if (cols != 1572 && rows != 2128)
+ return 1;
+ break;
+ case 0x05: /* 6x9 */
+ if (cols != 1868)
+ return 1;
+ if (rows != 1228 && rows != 2442 &&
+ rows != 2564 && rows != 2730)
+ return 1;
+ break;
+ case 0x06: /* V (6x8??) */
+ if (cols != 1868)
+ return 1;
+ if (rows != 1228 && rows != 2442)
+ return 1;
+ break;
+ default: /* Unknown */
+ WARNING("Unknown media type %02x\n", media);
+ break;
+ }
+ break;
+ default:
+ WARNING("Unknown printer type %d\n", type);
break;
}
return 0;
@@ -407,7 +734,6 @@ static int validate_media(int type, int cols, int rows) {
static int mitsu9550_main_loop(void *vctx, int copies) {
struct mitsu9550_ctx *ctx = vctx;
- struct mitsu9550_hdr2 *hdr2;
struct mitsu9550_cmd cmd;
uint8_t rdbuf[READBACK_LEN];
uint8_t *ptr;
@@ -418,13 +744,13 @@ static int mitsu9550_main_loop(void *vctx, int copies) {
return CUPS_BACKEND_FAILED;
/* Update printjob header to reflect number of requested copies */
- hdr2 = (struct mitsu9550_hdr2 *) (ctx->databuf + sizeof(struct mitsu9550_hdr1));
- hdr2->copies = cpu_to_be16(copies);
+ ctx->hdr2.copies = cpu_to_be16(copies);
+ /* Okay, let's do this thing */
ptr = ctx->databuf;
top:
- if (ctx->type == P_MITSU_9550S) {
+ if (ctx->is_s) {
int num;
/* Send "unknown 1" command */
@@ -452,11 +778,30 @@ top:
// seen so far: eb 4b 7f 00 02 00 5e
}
+ if (ctx->type == P_MITSU_9800S) {
+ int num;
+
+ /* Send "unknown 3" command */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x4b;
+ cmd.cmd[2] = 0x01;
+ cmd.cmd[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+
+ ret = read_data(ctx->dev, ctx->endp_up,
+ rdbuf, READBACK_LEN, &num);
+ if (ret < 0)
+ return CUPS_BACKEND_FAILED;
+ // seen so far: e4 4b 01 00 02 00 78
+ }
+
QUERY_STATUS();
/* Now it's time for the actual print job! */
- if (ctx->type == P_MITSU_9550S) {
+ if (ctx->is_s) {
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x44;
cmd.cmd[2] = 0;
@@ -469,27 +814,24 @@ top:
QUERY_STATUS();
/* Send printjob headers from spool data */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_hdr1))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_hdr1);
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_hdr2))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_hdr2);
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_hdr3))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_hdr3);
- if (ctx->type != P_MITSU_9550S) {
- // XXX need to investigate what hdr4 is about
+ if (ctx->hdr1_present)
if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_hdr4))))
+ (uint8_t*) &ctx->hdr1, sizeof(ctx->hdr1))))
+ return CUPS_BACKEND_FAILED;
+ if (ctx->hdr2_present)
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &ctx->hdr2, sizeof(ctx->hdr2))))
+ return CUPS_BACKEND_FAILED;
+ if (ctx->hdr3_present)
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &ctx->hdr3, sizeof(ctx->hdr3))))
+ return CUPS_BACKEND_FAILED;
+ if (ctx->hdr4_present)
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &ctx->hdr4, sizeof(struct mitsu9550_hdr4))))
return CUPS_BACKEND_FAILED;
- }
- ptr += sizeof(struct mitsu9550_hdr4);
- if (ctx->type == P_MITSU_9550S) {
+ if (ctx->is_s) {
/* Send "start data" command */
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x5a;
@@ -500,34 +842,27 @@ top:
(uint8_t*) &cmd, sizeof(cmd))))
return CUPS_BACKEND_FAILED;
}
- /* Send plane data */
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_plane);
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, ctx->rows * ctx->cols)))
- return CUPS_BACKEND_FAILED;
- ptr += ctx->rows * ctx->cols;
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_plane);
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, ctx->rows * ctx->cols)))
- return CUPS_BACKEND_FAILED;
- ptr += ctx->rows * ctx->cols;
-
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
- return CUPS_BACKEND_FAILED;
- ptr += sizeof(struct mitsu9550_plane);
- if ((ret = send_data(ctx->dev, ctx->endp_down,
- (uint8_t*) ptr, ctx->rows * ctx->cols)))
- return CUPS_BACKEND_FAILED;
- ptr += ctx->rows * ctx->cols;
+ /* Send over plane data */
+ while(1) {
+ struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
+ uint32_t planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
+ if (plane->cmd[0] != 0x1b ||
+ plane->cmd[1] != 0x5a ||
+ plane->cmd[2] != 0x54)
+ break;
+ if (plane->cmd[3] == 0x10)
+ planelen *= 2;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_plane);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, planelen)))
+ return CUPS_BACKEND_FAILED;
+ ptr += planelen;
+ }
/* Query statuses */
{
@@ -546,17 +881,17 @@ top:
ATTR("marker-levels=%d\n", 0);
return CUPS_BACKEND_HOLD;
}
- donor = be16_to_cpu(media->remain)/be16_to_cpu(media->max);
+ 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=%d\n", donor);
+ ATTR("marker-levels=%u\n", donor);
}
- remain = be16_to_cpu(media->remain);
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));
+ 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;
@@ -575,18 +910,53 @@ top:
return CUPS_BACKEND_FAILED;
}
}
-
+
+ /* Send "end data" command */
if (ctx->type == P_MITSU_9550S) {
- /* Send "end data" command */
+ /* Override spool, which may be wrong */
cmd.cmd[0] = 0x1b;
cmd.cmd[1] = 0x50;
cmd.cmd[2] = 0x47;
- cmd.cmd[3] = 0x00;
+ cmd.cmd[3] = 0x00;
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) &cmd, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+ } else if (ctx->type == P_MITSU_9800S) {
+ /* Override spool, which may be wrong */
+ cmd.cmd[0] = 0x1b;
+ cmd.cmd[1] = 0x50;
+ cmd.cmd[2] = 0x4e;
+ cmd.cmd[3] = 0x00;
if ((ret = send_data(ctx->dev, ctx->endp_down,
(uint8_t*) &cmd, sizeof(cmd))))
return CUPS_BACKEND_FAILED;
} else {
- /* Send "end data" command from spool file */
+ /* Send from spool file */
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ ptr, sizeof(cmd))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(cmd);
+ }
+
+ /* Don't forget the 9810's matte plane */
+ if (ctx->hdr1.matte) {
+ struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
+ uint32_t planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
+
+ if (plane->cmd[3] == 0x10)
+ planelen *= 2;
+
+ // XXX include a status loop here too?
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
+ return CUPS_BACKEND_FAILED;
+ ptr += sizeof(struct mitsu9550_plane);
+ if ((ret = send_data(ctx->dev, ctx->endp_down,
+ (uint8_t*) ptr, planelen)))
+ return CUPS_BACKEND_FAILED;
+ ptr += planelen;
+
+ /* Send "lamination end data" command from spool file */
if ((ret = send_data(ctx->dev, ctx->endp_down,
ptr, sizeof(cmd))))
return CUPS_BACKEND_FAILED;
@@ -610,17 +980,17 @@ top:
ATTR("marker-levels=%d\n", 0);
return CUPS_BACKEND_HOLD;
}
- donor = be16_to_cpu(media->remain)/be16_to_cpu(media->max);
+ 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=%d\n", donor);
+ ATTR("marker-levels=%u\n", donor);
}
- remain = be16_to_cpu(media->remain);
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));
+ 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;
@@ -652,10 +1022,10 @@ top:
return CUPS_BACKEND_OK;
}
-static void mitsu9550_dump_media(struct mitsu9550_media *resp)
+static void mitsu9550_dump_media(struct mitsu9550_media *resp, int is_s)
{
INFO("Media type : %02x (%s)\n",
- resp->type, mitsu9550_media_types(resp->type));
+ resp->type, mitsu9550_media_types(resp->type, is_s));
INFO("Media remaining : %03d/%03d\n",
be16_to_cpu(resp->remain), be16_to_cpu(resp->max));
}
@@ -678,7 +1048,7 @@ static int mitsu9550_query_media(struct mitsu9550_ctx *ctx)
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 0, 0, 1);
if (!ret)
- mitsu9550_dump_media(&resp);
+ mitsu9550_dump_media(&resp, ctx->is_s);
return ret;
}
@@ -784,8 +1154,8 @@ static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
/* Exported */
struct dyesub_backend mitsu9550_backend = {
- .name = "Mitsubishi CP-9550DW-S",
- .version = "0.17",
+ .name = "Mitsubishi CP-9550 family",
+ .version = "0.27",
.uri_prefix = "mitsu9550",
.cmdline_usage = mitsu9550_cmdline,
.cmdline_arg = mitsu9550_cmdline_arg,
@@ -796,45 +1166,64 @@ struct dyesub_backend mitsu9550_backend = {
.main_loop = mitsu9550_main_loop,
.query_serno = mitsu9550_query_serno,
.devices = {
+ { 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_9810D, P_MITSU_9810, ""},
+// { USB_VID_MITSU, USB_PID_MITSU_9820DS, P_MITSU_9820S, ""},
{ 0, 0, 0, ""}
}
};
-/* Mitsubish CP-9550D/DW spool data format
+/* Mitsubish CP-9550/9600/9800/9810 spool format:
- Spool file consists of four 50-byte headers, followed by three image
- planes (BGR, each with a 12-byte header), and a 4-byte footer.
+ 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.
All multi-byte numbers are big endian.
- ~~~ Printer Init: 4x 50-byte blocks:
+ ~~~ Header 1
- 1b 57 20 2e 00 0a 10 00 00 00 00 00 00 00 07 14 :: 0714 = 1812 = X res
- 04 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 04d8 = 1240 = Y res
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 1b 57 20 2e 00 QQ QQ 00 00 00 00 00 00 00 XX XX :: XX XX == columns
+ YY YY 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: YY YY == rows
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ == 0x0a90 on 9810, 0x0a10 on all others.
00 00
- 1b 57 21 2e 00 80 00 22 08 03 00 00 00 00 00 00 :: ZZ = num copies (>= 0x01)
- 00 00 00 00 00 00 00 00 00 00 00 00 ZZ ZZ 00 00 :: YY 00 = normal, 80 = Fine
- XX 00 00 00 00 00 YY 00 00 00 00 00 00 00 00 00 :: XX 00 = normal, 83 = Cut 2x6
- 00 01
+ ~~~ Header 2
- 1b 57 22 2e 00 40 00 00 00 00 00 XX 00 00 00 00 :: 00 = normal, 01 = FineDeep
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 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
+
+ ~~~ 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
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00
- 1b 57 26 2e 00 70 00 00 00 00 00 00 01 01 00 00
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ ~~~ Header 4 (all but 9550-S and 9800-S, involves error policy?)
+
+ 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
- ~~~~ Data follows: Data is 8-bit BGR.
+ ~~~~ Data follows:
+
+ Format is: planar YMC16 for 98x0 (only 12 bits used)
+ planar BGR for 9550DW
+ planar RGB for 9550DW-S and 9600DW
- 1b 5a 54 00 00 00 00 00 07 14 04 d8 :: 0714 == row len, 04d8 == rows
- ^^ ^^ :: 0000 == remaining rows
+ 1b 5a 54 ?? RR RR 00 00 07 14 04 d8 :: 0714 == columns, 04d8 == rows
+ :: RRRR == row offset for data
+ :: ?? == 0x00 for 8bpp, 0x10 for 16/12bpp.
Data follows immediately, no padding.
@@ -848,16 +1237,29 @@ struct dyesub_backend mitsu9550_backend = {
~~~~ Footer:
- 1b 50 46 00
+ 1b 50 46 00 (9550)
+ 1b 50 47 00 (9550-S)
+ 1b 50 48 00 (9600)
+ 1b 50 4c 00 (98x0)
+ 1b 50 4e 00 (9800-S)
+
+ ~~~~ Lamination data follows (on 9810 only, if matte selected)
+
+ 1b 5a 54 10 00 00 00 00 06 24 04 34
+
+ Data follows immediately, no padding.
+
+ 1b 50 56 00 (Lamination footer)
~~~~ QUESTIONS:
* Lamination control?
- * Other multi-cut modes (on 6x9 media: 4x6*2, 4.4x6*2, 3x6*3, 2x6*4)
+ * Other 9550 multi-cut modes (on 6x9 media: 4x6*2, 4.4x6*2, 3x6*3, 2x6*4)
+ * 9600/98x0 multi-cut modes?
***********************************************************************
- * Mitsubishi ** CP-9550DW-S ** Communications Protocol:
+ * Mitsubishi ** CP-9550DW-S/9800DW-S ** Communications Protocol:
[[ Unknown ]]
@@ -888,6 +1290,11 @@ 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 ]]
+
+ -> 1b 4b 01 00
+ <- e4 4b 01 00 02 00 78
+
Status Query
-> 1b 56 30 00
@@ -942,49 +1349,57 @@ struct dyesub_backend mitsu9550_backend = {
[[ Unknown -- End Data aka START print? ]]
- -> 1b 50 47 00
+ -> 1b 50 47 00 [9550S]
+ -> 1b 50 4e 00 [9800S]
[[ At this point, loop status/status b/media queries until printer idle ]]
- MM, NN, QQ RR SS, TT UU
+ MM, QQ RR SS, TT UU
- <- 00 00 3e 00 00 8a 44 :: Idle.
- 00 00 7e 00 00 8a 44 :: Plane data submitted, pre "end data" cmd
- 00 00 7e 40 01 8a 44 :: "end data" sent
- 30 01 7e 40 01 8a 44
- 38 01 7e 40 01 8a 44
- 59 01 7e 40 01 8a 44
- 59 01 7e 40 00 8a 44
- 4d 01 7e 40 00 8a 44
+ <- 00 3e 00 00 8a 44 :: Idle.
+ 00 7e 00 00 8a 44 :: Plane data submitted, pre "end data" cmd
+ 00 7e 40 01 8a 44 :: "end data" sent
+ 30 7e 40 01 8a 44
+ 38 7e 40 01 8a 44
+ 59 7e 40 01 8a 44
+ 59 7e 40 00 8a 44
+ 4d 7e 40 00 8a 44
[...]
- 43 01 7e 40 00 82 44
+ 43 7e 40 00 82 44
[...]
- 50 01 7e 40 00 80 44
+ 50 7e 40 00 80 44
[...]
- 31 01 7e 40 00 7d 44
+ 31 7e 40 00 7d 44
[...]
- 00 00 3e 00 00 80 44 :: Idle.
+ 00 3e 00 00 80 44 :: Idle.
Also seen:
- 00 00 3e 00 00 96 4b :: Idle
- 00 00 be 00 00 96 4b :: Data submitted, pre "start"
- 00 00 be 80 01 96 4b :: print start sent
- 30 00 be 80 01 96 4c
+ 00 3e 00 00 96 4b :: Idle
+ 00 be 00 00 96 4b :: Data submitted, pre "start"
+ 00 be 80 01 96 4b :: print start sent
+ 30 be 80 01 96 4c
[...]
- 30 03 be 80 01 89 4b
- 38 03 be 80 01 8a 4b
- 59 03 be 80 01 8b 4b
+ 30 be 80 01 89 4b
+ 38 be 80 01 8a 4b
+ 59 be 80 01 8b 4b
[...]
- 4d 03 be 80 01 89 4b
+ 4d be 80 01 89 4b
[...]
- 43 03 be 80 01 89 4b
+ 43 be 80 01 89 4b
[...]
- 50 03 be 80 01 82 4b
+ 50 be 80 01 82 4b
[...]
- 31 03 be 80 01 80 4b
+ 31 be 80 01 80 4b
[...]
+ Seen on 9600DW
+
+ ?? 3e 00 00 8a 44 :: scrap bin?
+ ?? 3e 00 00 8a 45 :: No scrap bin | no paper?
+ ?? 3e 00 00 8a 46 :: no ribbon
+ ?? 3e 00 00 8a 47 :: Cover open
+
Working theory of interpreting the status flags:
MM :: 00 is idle, else mechanical printer state.
@@ -993,7 +1408,7 @@ struct dyesub_backend mitsu9550_backend = {
RR :: ?? 0x00 is idle, 0x40 or 0x80 is "printing"?
SS :: ?? 0x00 means "ready for another print" but 0x01 is "busy"
TT :: ?? seen values between 0x7c through 0x96)
- UU :: ?? seen values between 0x44 and 0x4c
+ UU :: ?? seen values between 0x43 and 0x4c -- temperature?
***
@@ -1001,9 +1416,9 @@ struct dyesub_backend mitsu9550_backend = {
[[ Set error policy ?? aka "header 4" ]]
- -> 1b 57 26 2e 00 QQ 00 00 00 00 00 00 RR SS 00 00 :: QQ/RR 00 00 00 [9550S]
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 20 01 00 [9550S w/ ignore failures on]
- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 70 01 01 [9550]
+ -> 1b 57 26 2e 00 QQ 00 00 00 00 00 00 RR SS 00 00 :: QQ/RR/SS 00 00 00 [9550S]
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 20 01 00 [9550S w/ ignore failures on]
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 70 01 01 [9550]
00 00
*/
diff --git a/src/cups/backend_shinkos1245.c b/src/cups/backend_shinkos1245.c
index b375cba..a2bbdd2 100644
--- a/src/cups/backend_shinkos1245.c
+++ b/src/cups/backend_shinkos1245.c
@@ -412,6 +412,7 @@ struct shinkos1245_ctx {
struct shinkos1245_mediadesc medias[15];
int num_medias;
+ int media_8x12;
uint8_t *databuf;
int datalen;
@@ -1402,6 +1403,9 @@ static int shinkos1245_main_loop(void *vctx, int 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 &&
@@ -1417,6 +1421,13 @@ 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)
@@ -1440,6 +1451,14 @@ 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);
@@ -1620,7 +1639,7 @@ static int shinkos1245_query_serno(struct libusb_device_handle *dev, uint8_t end
struct dyesub_backend shinkos1245_backend = {
.name = "Shinko/Sinfonia CHC-S1245",
- .version = "0.09WIP",
+ .version = "0.10WIP",
.uri_prefix = "shinkos1245",
.cmdline_usage = shinkos1245_cmdline,
.cmdline_arg = shinkos1245_cmdline_arg,
@@ -1645,7 +1664,7 @@ struct dyesub_backend shinkos1245_backend = {
10 00 00 00 MM MM 00 00 00 00 00 00 01 00 00 00 MM == Model (ie 1245d)
64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == Media Size (0x10 fixed)
MM 00 00 00 PP 00 00 00 00 00 00 00 ZZ ZZ ZZ ZZ MM = Print Method (aka cut control), PP = Default/Glossy/Matte (0x01/0x03/0x05), ZZ == matte intensity (0x7fffffff for glossy, else 0x00000000 +- 25 for matte)
- VV 00 00 00 WW WW 00 00 HH HH 00 00 XX 00 00 00 VV == dust; 0x00 default, 0x01 off, 0x02 on, XX == Copies
+ VV 00 00 00 WW WW 00 00 HH HH 00 00 XX XX 00 00 VV == dust; 0x00 default, 0x01 off, 0x02 on, XX == Copies
00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI, ie 300.
00 00 00 00 ce ff ff ff 00 00 00 00 00 00 00 00
diff --git a/src/cups/blacklist b/src/cups/blacklist
index 573145e..650dd04 100644
--- a/src/cups/blacklist
+++ b/src/cups/blacklist
@@ -147,6 +147,12 @@
# Mitsubishi CP-9550DZ/DW-S
0x06d3 0x03a5 blacklist
+# Mitsubishi CP-9600D/DW
+0x06d3 0x03a9 blacklist
+
+# Mitsubishi CP-9800DW-S
+0x06d3 0x03ae blacklist
+
# Citizen CW-01
0x1343 0x0002 blacklist
diff --git a/src/cups/test-rastertogutenprint.in b/src/cups/test-rastertogutenprint.in
index a8bb6d8..f3f1464 100755
--- a/src/cups/test-rastertogutenprint.in
+++ b/src/cups/test-rastertogutenprint.in
@@ -256,17 +256,17 @@ if [ -d ppd/C ] ; then
PPD=$f
export PPD
if [ -x "$cupsdir/cgpdftoraster" ] ; then
- output="`($cupsdir/cgpdftoraster 1 1 1 1 $pages < "$testfile" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
+ output="`($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="`($cupsdir/gstoraster 1 1 1 1 \"$cupsargs\" < "$testfile" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
+ output="`($cupsdir/gstoraster 1 1 1 1 \"$cupsargs\" < "$tfile" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -f "$tfile" ] ; then
- output="`($cupsdir/pstops 1 1 1 1 \"$cupsargs\" < "$testfile" 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
+ output="`($cupsdir/pstops 1 1 1 1 \"$cupsargs\" < "$tfile" 2>/dev/null | $cupsdir/pstoraster 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
elif [ -x "$cupsdir/pstoraster" ] ; then
- output="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < "$testfile" 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 `"
+ output="`($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="`($cupsdir/pdftops 1 1 1 1 \"$pages$cupsargs\" < "$testfile" 2>/dev/null | $cupsdir/gstoraster 1 1 1 1 \"$pages$cupsargs\" 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2 `"
+ output="`($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 `"
else
- output="`($cupsdir/imagetoraster 1 1 1 1 \"$pages$cupsargs\" < calibrate.ppm 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2`"
+ output="`($cupsdir/imagetoraster 1 1 1 1 \"$cupsargs\" < calibrate.ppm 2>/dev/null | run_rastertogp | do_output) 2>&1 3>&2`"
fi
if [ $? -ne 0 ] ; then
retval=1