1 /*
2  *   Mitsubishi CP-9xxx Photo Printer Family CUPS backend
3  *
4  *   (c) 2014-2019 Solomon Peachy <pizza@shaftnet.org>
5  *
6  *   The latest version of this program can be found at:
7  *
8  *     http://git.shaftnet.org/cgit/selphy_print.git
9  *
10  *   This program is free software; you can redistribute it and/or modify it
11  *   under the terms of the GNU General Public License as published by the Free
12  *   Software Foundation; either version 2 of the License, or (at your option)
13  *   any later version.
14  *
15  *   This program is distributed in the hope that it will be useful, but
16  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  *   for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
22  *
23  *          [http://www.gnu.org/licenses/gpl-2.0.html]
24  *
25  *   SPDX-License-Identifier: GPL-2.0+
26  *
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 
39 /* For Integration into gutenprint */
40 #if defined(HAVE_CONFIG_H)
41 #include <config.h>
42 #endif
43 
44 #define BACKEND mitsu9550_backend
45 
46 
47 #if defined(USE_DLOPEN)
48 #define WITH_DYNAMIC
49 #include <dlfcn.h>
50 #define DL_INIT() do {} while(0)
51 #define DL_OPEN(__x) dlopen(__x, RTLD_NOW)
52 #define DL_SYM(__x, __y) dlsym(__x, __y)
53 #define DL_CLOSE(__x) dlclose(__x)
54 #define DL_EXIT() do {} while(0)
55 #elif defined(USE_LTDL)
56 #define WITH_DYNAMIC
57 #include <ltdl.h>
58 #define DL_INIT() lt_dlinit()
59 #define DL_OPEN(__x) lt_dlopen(__x)
60 #define DL_SYM(__x, __y) lt_dlsym(__x, __y)
61 #define DL_CLOSE(__x) do {} while(0)
62 #define DL_EXIT() lt_dlexit()
63 #else
64 #define DL_INIT()     do {} while(0)
65 #define DL_CLOSE(__x) do {} while(0)
66 #define DL_EXIT()     do {} while(0)
67 #warning "No dynamic loading support!"
68 #endif
69 
70 #include "backend_common.h"
71 
72 // #include "lib70x/libMitsuD70ImageReProcess.h"
73 
74 #ifndef LUT_LEN
75 #define COLORCONV_RGB 0
76 #define COLORCONV_BGR 1
77 
78 #define LUT_LEN 14739
79 struct BandImage {
80 	   void  *imgbuf;
81 	 int32_t bytes_per_row;
82 	uint16_t origin_cols;
83 	uint16_t origin_rows;
84 	uint16_t cols;
85 	uint16_t rows;
86 };
87 #endif
88 
89 #define REQUIRED_LIB_APIVERSION 4
90 
91 /* Image processing library function prototypes */
92 #define LIB_NAME_RE "libMitsuD70ImageReProcess.so" // Reimplemented library
93 
94 typedef int (*lib70x_getapiversionFN)(void);
95 typedef int (*Get3DColorTableFN)(uint8_t *buf, const char *filename);
96 typedef struct CColorConv3D *(*Load3DColorTableFN)(const uint8_t *ptr);
97 typedef void (*Destroy3DColorTableFN)(struct CColorConv3D *this);
98 typedef void (*DoColorConvFN)(struct CColorConv3D *this, uint8_t *data, uint16_t cols, uint16_t rows, uint32_t bytes_per_row, int rgb_bgr);
99 
100 #ifndef CORRTABLE_PATH
101 #ifdef PACKAGE_DATA_DIR
102 #define CORRTABLE_PATH PACKAGE_DATA_DIR "/backend_data"
103 #else
104 #error "Must define CORRTABLE_PATH or PACKAGE_DATA_DIR!"
105 #endif
106 #endif
107 
108 #define MITSU_M98xx_LAMINATE_FILE CORRTABLE_PATH "/M98MATTE.raw"
109 #define MITSU_M98xx_DATATABLE_FILE CORRTABLE_PATH "/M98TABLE.dat"
110 #define MITSU_M98xx_LUT_FILE       CORRTABLE_PATH "/M98XXL01.lut"
111 #define LAMINATE_STRIDE 1868
112 #define DATATABLE_SIZE  42204
113 
114 /* USB VIDs and PIDs */
115 
116 #define USB_VID_MITSU        0x06D3
117 #define USB_PID_MITSU_9500D  0x0393
118 #define USB_PID_MITSU_9000D  0x0394
119 #define USB_PID_MITSU_9000AM 0x0395
120 #define USB_PID_MITSU_9550D  0x03A1
121 #define USB_PID_MITSU_9550DS 0x03A5  // or DZ/DZS/DZU
122 #define USB_PID_MITSU_9600D  0x03A9
123 //#define USB_PID_MITSU_9600DS  XXXXXX
124 #define USB_PID_MITSU_9800D  0x03AD
125 #define USB_PID_MITSU_9800DS 0x03AE
126 #define USB_PID_MITSU_98__D  0x3B21
127 //#define USB_PID_MITSU_9810D   XXXXXX
128 //#define USB_PID_MITSU_9820DS  XXXXXX
129 
130 /* Spool file structures */
131 
132 /* Print parameters1 */
133 struct mitsu9550_hdr1 {
134 	uint8_t  cmd[4];  /* 1b 57 20 2e */
135 	uint8_t  unk[10]; /* 00 0a 10 00 [...] */
136 	uint16_t cols;    /* BE */
137 	uint16_t rows;    /* BE */
138 	uint8_t  matte;   /* CP9810/9820 only. 01 for matte, 00 glossy */
139 	uint8_t  null[31];
140 } __attribute__((packed));
141 
142 /* Print parameters2 */
143 struct mitsu9550_hdr2 {
144 	uint8_t  cmd[4];   /* 1b 57 21 2e */
145 	uint8_t  unk[24];  /* 00 80 00 22 08 03 [...] */
146 	uint16_t copies;   /* BE, 1-680 */
147 	uint8_t  null[2];
148 	uint8_t  cut;      /* 00 == normal, 83 == 2x6*2 */
149 	uint8_t  unkb[5];
150 	uint8_t  mode;     /* 00 == fine, 80 == superfine */
151 	uint8_t  unkc[11]; /* 00 [...] 00 01 */
152 } __attribute__((packed));
153 
154 /* Fine Deep selection (9550 only) */
155 struct mitsu9550_hdr3 {
156 	uint8_t  cmd[4];   /* 1b 57 22 2e */
157 	uint8_t  unk[7];   /* 00 40 00 [...] */
158 	uint8_t  mode2;    /* 00 == normal, 01 == finedeep */
159 	uint8_t  null[38];
160 } __attribute__((packed));
161 
162 /* Error policy? */
163 struct mitsu9550_hdr4 {
164 	uint8_t  cmd[4];   /* 1b 57 26 2e */
165 	uint8_t  unk[46];  /* 00 70 00 00 00 00 00 00 01 01 00 [...] */
166 } __attribute__((packed));
167 
168 /* Data plane header */
169 struct mitsu9550_plane {
170 	uint8_t  cmd[4];     /* 1b 5a 54 XX */  /* XX == 0x10 if 16bpp, 0x00 for 8bpp */
171 	uint16_t col_offset; /* BE, normally 0, where we start dumping data */
172 	uint16_t row_offset; /* BE, normally 0, where we start dumping data */
173 	uint16_t cols;       /* BE */
174 	uint16_t rows;       /* BE */
175 } __attribute__((packed));
176 
177 /* CP98xx Tabular Data, as stored in data file! */
178 struct mitsu98xx_data {
179 	/* @    0 */	uint16_t GNMby[256];     /* BGR Order uncertain */
180 	/* @  512 */	uint16_t GNMgm[256];
181 	/* @ 1024 */    uint16_t GNMrc[256];
182 	/* @ 1536 */    uint16_t unk_sharp[20];  /* Actual format is: u16, u16[9], u16, u16[9] */
183 	/* @ 1576 */    double   GammaAdj[3];    /* Assumed to be same order as tables (BGR?) */
184 	/* @ 1600 */	struct {
185 		/* @    0 */	double   unka[256];
186 		/* @ 2048 */	double   unkb[256];
187 		/* @ 4096 */	uint32_t unkc[10];
188 		/* @ 4136 */	double   unkd[256];
189 		/* @ 6184 */	double   unke[256]; // *= sharp->coef[X]
190 		/* @ 8232 */	uint32_t unkf[10];
191 		/* @ 8272 */	double   unkg[256];
192 		/* @10320 */
193 			} WMAM;
194 	/* @11920 */	double   sharp_coef[11]; /* 0 is off, 1-10 are the levels.  Default is 5. [4 in settings] */
195 	/* @12008 */	uint32_t unk_kh[3];
196 	/* @12020 */	uint8_t  KH[2048];
197 	/* @14068 */
198 } __attribute__((packed));
199 
200 struct mitsu98xx_tables {
201 	struct mitsu98xx_data superfine;
202 	struct mitsu98xx_data fine_std;
203 	struct mitsu98xx_data fine_hg;
204 } __attribute__((packed));
205 
206 /* Command header */
207 struct mitsu9550_cmd {
208 	uint8_t cmd[4];
209 } __attribute__((packed));
210 
211 /* Private data structure */
212 struct mitsu9550_printjob {
213 	uint8_t *databuf;
214 	uint32_t datalen;
215 
216 	uint16_t rows;
217 	uint16_t cols;
218 	uint32_t plane_len;
219 	int is_raw;
220 
221 	int copies;
222 
223 	/* Parse headers separately */
224 	struct mitsu9550_hdr1 hdr1;
225 	int hdr1_present;
226 	struct mitsu9550_hdr2 hdr2;
227 	int hdr2_present;
228 	struct mitsu9550_hdr3 hdr3;
229 	int hdr3_present;
230 	struct mitsu9550_hdr4 hdr4;
231 	int hdr4_present;
232 };
233 
234 struct mitsu9550_ctx {
235 	struct libusb_device_handle *dev;
236 	uint8_t endp_up;
237 	uint8_t endp_down;
238 	int type;
239 	int is_s;
240 	int is_98xx;
241 
242 	struct marker marker;
243 
244 	/* CP98xx stuff */
245 	void *dl_handle;
246 	lib70x_getapiversionFN GetAPIVersion;
247 	Get3DColorTableFN Get3DColorTable;
248 	Load3DColorTableFN Load3DColorTable;
249 	Destroy3DColorTableFN Destroy3DColorTable;
250 	DoColorConvFN DoColorConv;
251 
252 	struct CColorConv3D *lut;
253 	struct mitsu98xx_tables *m98xxdata;
254 };
255 
256 /* Printer data structures */
257 struct mitsu9550_media {
258 	uint8_t  hdr[2];  /* 24 2e */
259 	uint8_t  unk[12];
260 	uint8_t  type;
261 	uint8_t  unka[13];
262 	uint16_t max;  /* BE, prints per media */
263 	uint8_t  unkb[2];
264 	uint16_t remain; /* BE, prints remaining */
265 	uint8_t  unkc[14];
266 } __attribute__((packed));
267 
268 struct mitsu9550_status {
269 	uint8_t  hdr[2]; /* 30 2e */
270 	uint8_t  null[4];
271 	uint8_t  sts1; // MM
272 	uint8_t  nullb[1];
273 	uint16_t copies; // BE, NN
274 	uint8_t  sts2; // ZZ  (9600 only?)
275 	uint8_t  nullc[5];
276 	uint8_t  sts3; // QQ
277 	uint8_t  sts4; // RR
278 	uint8_t  sts5; // SS
279 	uint8_t  nulld[25];
280 	uint8_t  sts6; // TT
281 	uint8_t  sts7; // UU
282 	uint8_t  nulle[2];
283 } __attribute__((packed));
284 
285 struct mitsu9550_status2 {
286 	uint8_t  hdr[2]; /* 21 2e / 24 2e  on 9550/9800 */
287 	uint8_t  unk[40];
288 	uint16_t remain; /* BE, media remaining */
289 	uint8_t  unkb[4]; /* 0a 00 00 01 */
290 } __attribute__((packed));
291 
292 static int mitsu9550_main_loop(void *vctx, const void *vjob);
293 
294 #define CMDBUF_LEN   64
295 #define READBACK_LEN 128
296 
297 #define QUERY_STATUS()	\
298 	do {\
299 		struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;\
300 		/* struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf; */ \
301 		struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf; \
302 		uint16_t donor; \
303 		/* media */ \
304 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); \
305 		if (ret < 0) \
306 			return CUPS_BACKEND_FAILED; \
307 		\
308 		donor = be16_to_cpu(media->remain); \
309 		if (donor != ctx->marker.levelnow) { \
310 			ctx->marker.levelnow = donor; \
311 			dump_markers(&ctx->marker, 1, 0); \
312 		} \
313 		/* Sanity-check media response */ \
314 		if (media->remain == 0 || media->max == 0) { \
315 			ERROR("Printer out of media!\n"); \
316 			return CUPS_BACKEND_HOLD; \
317 		} \
318 		if (validate_media(ctx->type, media->type, job->cols, job->rows)) { \
319 			ERROR("Incorrect media (%u) type for printjob (%ux%u)!\n", media->type, job->cols, job->rows); \
320 			return CUPS_BACKEND_HOLD; \
321 		} \
322 		/* status2 */ \
323 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); \
324 		if (ret < 0) \
325 			return CUPS_BACKEND_FAILED; \
326 		/* status */ \
327 		ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); \
328 		if (ret < 0) \
329 			return CUPS_BACKEND_FAILED; \
330 		\
331 		/* Make sure we're idle */ \
332 		if (sts->sts5 != 0) {  /* Printer ready for another job */ \
333 			sleep(1); \
334 			goto top; \
335 		} \
336 		/* Check for known errors */ \
337 		if (sts->sts2 != 0) {  \
338 			ERROR("Printer cover open!\n");	\
339 			return CUPS_BACKEND_STOP; \
340 		} \
341 	} while (0);
342 
mitsu98xx_dogamma(uint8_t * src,uint16_t * dest,uint8_t plane,uint16_t * table,uint32_t len)343 static void mitsu98xx_dogamma(uint8_t *src, uint16_t *dest, uint8_t plane,
344 			      uint16_t *table, uint32_t len)
345 {
346 	src += plane;
347 	while(len--) {
348 		*dest++ = cpu_to_be16(table[*src]);
349 		src += 3;
350 	}
351 }
352 
mitsu98xx_fillmatte(struct mitsu9550_printjob * job)353 static int mitsu98xx_fillmatte(struct mitsu9550_printjob *job)
354 {
355 	int fd, i;
356 	uint32_t j, remain;
357 
358 	DEBUG("Reading %d bytes of matte data from disk (%d/%d)\n", job->cols * job->rows * 2, job->cols, LAMINATE_STRIDE);
359 	fd = open(MITSU_M98xx_LAMINATE_FILE, O_RDONLY);
360 	if (fd < 0) {
361 		WARNING("Unable to open matte lamination data file '%s'\n", MITSU_M98xx_LAMINATE_FILE);
362 		job->hdr1.matte = 0;
363 		goto done;
364 	}
365 
366 	/* Fill in the lamination plane header */
367 	struct mitsu9550_plane *matte = (struct mitsu9550_plane *)(job->databuf + job->datalen);
368 	matte->cmd[0] = 0x1b;
369 	matte->cmd[1] = 0x5a;
370 	matte->cmd[2] = 0x54;
371 	matte->cmd[3] = 0x10;
372 	matte->row_offset = 0;
373 	matte->col_offset = 0;
374 	matte->cols = cpu_to_be16(job->hdr1.cols);
375 	matte->rows = cpu_to_be16(job->hdr1.rows);
376 	job->datalen += sizeof(struct mitsu9550_plane);
377 
378 	/* Read in the matte data plane */
379 	for (j = 0 ; j < job->rows ; j++) {
380 		remain = LAMINATE_STRIDE * 2;
381 
382 		/* Read one row of lamination data at a time */
383 		while (remain) {
384 			i = read(fd, job->databuf + job->datalen, remain);
385 			if (i < 0)
386 				return CUPS_BACKEND_CANCEL;
387 			if (i == 0) {
388 				/* We hit EOF, restart from beginning */
389 				lseek(fd, 0, SEEK_SET);
390 				continue;
391 			}
392 			job->datalen += i;
393 			remain -= i;
394 		}
395 		/* Back off the buffer so we "wrap" on the print row. */
396 		job->datalen -= ((LAMINATE_STRIDE - job->cols) * 2);
397 	}
398 	/* We're done! */
399 	close(fd);
400 
401 	/* Fill in the lamination plane footer */
402 	job->databuf[job->datalen++] = 0x1b;
403 	job->databuf[job->datalen++] = 0x50;
404 	job->databuf[job->datalen++] = 0x56;
405 	job->databuf[job->datalen++] = 0x00;
406 
407 done:
408 	return CUPS_BACKEND_OK;
409 }
410 
411 #ifndef LUT_LEN
412 #define LUT_LEN 14739
413 #define COLORCONV_RGB 0
414 #define COLORCONV_BGR 1
415 #endif
416 
417 static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int status, int status2, int media);
418 static char *mitsu9550_media_types(uint8_t type, uint8_t is_s);
419 
mitsu9550_init(void)420 static void *mitsu9550_init(void)
421 {
422 	struct mitsu9550_ctx *ctx = malloc(sizeof(struct mitsu9550_ctx));
423 	if (!ctx) {
424 		ERROR("Memory Allocation Failure!\n");
425 		return NULL;
426 	}
427 	memset(ctx, 0, sizeof(struct mitsu9550_ctx));
428 
429 	DL_INIT();
430 
431 	return ctx;
432 }
433 
mitsu9550_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)434 static int mitsu9550_attach(void *vctx, struct libusb_device_handle *dev, int type,
435 			    uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
436 {
437 	struct mitsu9550_ctx *ctx = vctx;
438 	struct mitsu9550_media media;
439 
440 	UNUSED(jobid);
441 
442 	ctx->dev = dev;
443 	ctx->endp_up = endp_up;
444 	ctx->endp_down = endp_down;
445 	ctx->type = type;
446 
447 	if (ctx->type == P_MITSU_9550S ||
448 	    ctx->type == P_MITSU_9800S)
449 		ctx->is_s = 1;
450 
451 	if (ctx->type == P_MITSU_9800 ||
452 	    ctx->type == P_MITSU_9800S ||
453 	    ctx->type == P_MITSU_9810)
454 		ctx->is_98xx = 1;
455 
456 	/* Attempt to open the library */
457 #if defined(WITH_DYNAMIC)
458 	if (!ctx->is_98xx) goto skip;
459 
460 	DEBUG("Attempting to load image processing library\n");
461 	ctx->dl_handle = DL_OPEN(LIB_NAME_RE);
462 	if (!ctx->dl_handle)
463 		WARNING("Image processing library not found, using internal fallback code\n");
464 	if (ctx->dl_handle) {
465 		ctx->GetAPIVersion = DL_SYM(ctx->dl_handle, "lib70x_getapiversion");
466 		if (!ctx->GetAPIVersion) {
467 			ERROR("Problem resolving API Version symbol in imaging processing library, too old or not installed?\n");
468 			DL_CLOSE(ctx->dl_handle);
469 			ctx->dl_handle = NULL;
470 			return CUPS_BACKEND_FAILED;
471 		}
472 		if (ctx->GetAPIVersion() != REQUIRED_LIB_APIVERSION) {
473 			ERROR("Image processing library API version mismatch!\n");
474 			DL_CLOSE(ctx->dl_handle);
475 			ctx->dl_handle = NULL;
476 			return CUPS_BACKEND_FAILED;
477 		}
478 
479 		ctx->Get3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Get3DColorTable");
480 		ctx->Load3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Load3DColorTable");
481 		ctx->Destroy3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Destroy3DColorTable");
482 		ctx->DoColorConv = DL_SYM(ctx->dl_handle, "CColorConv3D_DoColorConv");
483 		if (!ctx->Get3DColorTable || !ctx->Load3DColorTable ||
484 		    !ctx->Destroy3DColorTable || !ctx->DoColorConv ) {
485 			ERROR("Problem resolving symbols in imaging processing library\n");
486 			DL_CLOSE(ctx->dl_handle);
487 			ctx->dl_handle = NULL;
488 			return CUPS_BACKEND_FAILED;
489 		} else {
490 			DEBUG("Image processing library successfully loaded\n");
491 		}
492 	}
493 skip:
494 #endif
495 
496 	if (test_mode < TEST_MODE_NOATTACH) {
497 		if (mitsu9550_get_status(ctx, (uint8_t*) &media, 0, 0, 1))
498 			return CUPS_BACKEND_FAILED;
499 	} else {
500 		int media_code = 0x2;
501 		if (getenv("MEDIA_CODE"))
502 			media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
503 
504 		media.max = cpu_to_be16(400);
505 		media.remain = cpu_to_be16(330);
506 		media.type = media_code;
507 	}
508 
509 	ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
510 	ctx->marker.name = mitsu9550_media_types(media.type, ctx->is_s);
511 	ctx->marker.levelmax = be16_to_cpu(media.max);
512 	ctx->marker.levelnow = be16_to_cpu(media.remain);
513 
514 	return CUPS_BACKEND_OK;
515 }
516 
mitsu9550_cleanup_job(const void * vjob)517 static void mitsu9550_cleanup_job(const void *vjob)
518 {
519 	const struct mitsu9550_printjob *job = vjob;
520 
521 	if (job->databuf)
522 		free(job->databuf);
523 
524 	free((void*)job);
525 }
526 
mitsu9550_teardown(void * vctx)527 static void mitsu9550_teardown(void *vctx) {
528 	struct mitsu9550_ctx *ctx = vctx;
529 
530 	if (!ctx)
531 		return;
532 
533 	if (ctx->dl_handle) {
534 		if (ctx->lut)
535 			ctx->Destroy3DColorTable(ctx->lut);
536 		if (ctx->m98xxdata)
537 			free(ctx->m98xxdata);
538 		DL_CLOSE(ctx->dl_handle);
539 	}
540 
541 	free(ctx);
542 }
543 
mitsu9550_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)544 static int mitsu9550_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
545 	struct mitsu9550_ctx *ctx = vctx;
546 	uint8_t buf[sizeof(struct mitsu9550_hdr1)];
547 	int remain, i;
548 	uint32_t planelen = 0;
549 
550 	struct mitsu9550_printjob *job = NULL;
551 
552 	if (!ctx)
553 		return CUPS_BACKEND_FAILED;
554 
555 	job = malloc(sizeof(*job));
556 	if (!job) {
557 		ERROR("Memory allocation failure!\n");
558 		return CUPS_BACKEND_RETRY_CURRENT;
559 	}
560 	memset(job, 0, sizeof(*job));
561 	job->is_raw = 1;
562 
563 top:
564 	/* Read in initial header */
565 	remain = sizeof(buf);
566 	while (remain > 0) {
567 		i = read(data_fd, buf + sizeof(buf) - remain, remain);
568 		if (i == 0) {
569 			mitsu9550_cleanup_job(job);
570 			return CUPS_BACKEND_CANCEL;
571 		}
572 		if (i < 0) {
573 			mitsu9550_cleanup_job(job);
574 			return CUPS_BACKEND_CANCEL;
575 		}
576 		remain -= i;
577 	}
578 
579 	/* Sanity check */
580 	if (buf[0] != 0x1b || buf[1] != 0x57 || buf[3] != 0x2e) {
581 		if (!job->hdr1_present || !job->hdr2_present) {
582 			ERROR("Unrecognized data format (%02x%02x%02x%02x)!\n",
583 			      buf[0], buf[1], buf[2], buf[3]);
584 			mitsu9550_cleanup_job(job);
585 			return CUPS_BACKEND_CANCEL;
586 		} else if (buf[0] == 0x1b &&
587 			   buf[1] == 0x5a &&
588 			   buf[2] == 0x54) {
589 
590 			/* We're in the data portion now */
591 			if (buf[3] == 0x10)
592 				planelen *= 2;
593 			else if (ctx->is_98xx && buf[3] == 0x80)
594 				job->is_raw = 0;
595 
596 			goto hdr_done;
597 		} else {
598 			ERROR("Unrecognized data block (%02x%02x%02x%02x)!\n",
599 			      buf[0], buf[1], buf[2], buf[3]);
600 			mitsu9550_cleanup_job(job);
601 			return CUPS_BACKEND_CANCEL;
602 		}
603 	}
604 
605 	switch(buf[2]) {
606 	case 0x20: /* header 1 */
607 		memcpy(&job->hdr1, buf, sizeof(job->hdr1));
608 		job->hdr1_present = 1;
609 
610 		/* Work out printjob size */
611 		job->rows = be16_to_cpu(job->hdr1.rows);
612 		job->cols = be16_to_cpu(job->hdr1.cols);
613 		planelen = job->rows * job->cols;
614 
615 		break;
616 	case 0x21: /* header 2 */
617 		memcpy(&job->hdr2, buf, sizeof(job->hdr2));
618 		job->hdr2_present = 1;
619 		break;
620 	case 0x22: /* header 3 */
621 		memcpy(&job->hdr3, buf, sizeof(job->hdr3));
622 		job->hdr3_present = 1;
623 		break;
624 	case 0x26: /* header 4 */
625 		memcpy(&job->hdr4, buf, sizeof(job->hdr4));
626 		job->hdr4_present = 1;
627 		break;
628 	default:
629 		ERROR("Unrecognized header format (%02x)!\n", buf[2]);
630 		mitsu9550_cleanup_job(job);
631 		return CUPS_BACKEND_CANCEL;
632 	}
633 
634 	/* Read in the next chunk */
635 	goto top;
636 
637 hdr_done:
638 
639 	/* Read in CP98xx data tables if necessary */
640 	if (ctx->is_98xx && !job->is_raw && !ctx->m98xxdata) {
641 		int ret;
642 		ctx->m98xxdata = malloc(DATATABLE_SIZE);
643 		if (!ctx->m98xxdata) {
644 			ERROR("Memory allocation Failure!\n");
645 			mitsu9550_cleanup_job(job);
646 			return CUPS_BACKEND_RETRY_CURRENT;
647 		}
648 
649 		DEBUG("Reading in 98xx data from disk\n");
650 		if ((ret = dyesub_read_file(MITSU_M98xx_DATATABLE_FILE, ctx->m98xxdata, DATATABLE_SIZE, NULL))) {
651 			ERROR("Unable to read 98xx data table file '%s'\n", MITSU_M98xx_DATATABLE_FILE);
652 			free(ctx->m98xxdata);
653 			return ret;
654 		}
655 
656 		/* Byteswap data table to native endianness, if necessary */
657 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
658 		int j;
659 		struct mitsu98xx_data *ptr = &ctx->m98xxdata->superfine;
660 		for (j = 0 ; j < 3 ; j++) {
661 			for (i = 3 ; i < 3 ; i++) {
662 				ptr->GammaAdj[i] = be64_to_cpu(ptr->GammaAdj[i]);
663 				ptr->unk_kh[i] = be32_to_cpu(ptr->unk_kh[i]);
664 			}
665 			for (i = 0 ; i < 10 ; i++) {
666 				ptr->WMAM.unkc[i] = be32_to_cpu(ptr->WMAM.unkc[i]);
667 				ptr->WMAM.unkf[i] = be32_to_cpu(ptr->WMAM.unkf[i]);
668 			}
669 			for (i = 0 ; i < 11 ; i++) {
670 				ptr->sharp_coef[i] = be64_to_cpu(ptr->sharp_coef[i]);
671 			}
672 			for (i = 0 ; i < 20 ; i++) {
673 				ptr->unk_sharp[i] = be16_to_cpu(ptr->unk_sharp[i]);
674 			}
675 			for (i = 0 ; i < 256 ; i++) {
676 				ptr->WMAM.unka[i] = be64_to_cpu(ptr->WMAM.unka[i]);
677 				ptr->WMAM.unkb[i] = be64_to_cpu(ptr->WMAM.unkb[i]);
678 				ptr->WMAM.unkd[i] = be64_to_cpu(ptr->WMAM.unkd[i]);
679 				ptr->WMAM.unke[i] = be64_to_cpu(ptr->WMAM.unke[i]);
680 				ptr->WMAM.unkg[i] = be64_to_cpu(ptr->WMAM.unkg[i]);
681 
682 				ptr->GNMby[i] = be16_to_cpu(ptr->GNMby[i]);
683 				ptr->GNMgm[i] = be16_to_cpu(ptr->GNMgm[i]);
684 				ptr->GNMrc[i] = be16_to_cpu(ptr->GNMrc[i]);
685 
686 			}
687 			// XXX TODO: KH[2048]
688 			ptr++;
689 		}
690 #endif
691 	}
692 
693 	if (job->is_raw) {
694 		/* We have three planes + headers and the final terminator to read */
695 		remain = 3 * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd);
696 	} else {
697 		/* We have one plane + header and the final terminator to read */
698 		remain = planelen * 3 + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
699 	}
700 
701 	/* Mitsu9600 windows spool uses more, smaller blocks, but plane data is the same */
702 	if (ctx->type == P_MITSU_9600) {
703 		remain += 128 * sizeof(struct mitsu9550_plane); /* 39 extra seen on 4x6" */
704 	}
705 
706 	/* 9550S/9800S doesn't typically sent over hdr4! */
707 	if (ctx->type == P_MITSU_9550S ||
708 	    ctx->type == P_MITSU_9800S) {
709 		/* XXX Has to do with error policy, but not sure what.
710 		   Mitsu9550-S/9800-S will set this based on a command,
711 		   but it's not part of the standard job spool */
712 		job->hdr4_present = 0;
713 	}
714 
715 	/* Disable matte if the printer doesn't support it */
716 	if (job->hdr1.matte) {
717 		if (ctx->type != P_MITSU_9810) {
718 			WARNING("Matte not supported on this printer, disabling\n");
719 			job->hdr1.matte = 0;
720 		} else if (job->is_raw) {
721 			remain += planelen + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
722 		}
723 	}
724 
725 	/* Allocate buffer for the payload */
726 	job->datalen = 0;
727 	job->databuf = malloc(remain);
728 	if (!job->databuf) {
729 		ERROR("Memory allocation failure!\n");
730 		mitsu9550_cleanup_job(job);
731 		return CUPS_BACKEND_RETRY_CURRENT;
732 	}
733 
734 	/* Load up the data blocks.*/
735 	while(1) {
736 		/* Note that 'buf' needs to be already filled here! */
737 		struct mitsu9550_plane *plane = (struct mitsu9550_plane *)buf;
738 
739 		/* Sanity check header... */
740 		if (plane->cmd[0] != 0x1b ||
741 		    plane->cmd[1] != 0x5a ||
742 		    plane->cmd[2] != 0x54) {
743 			ERROR("Unrecognized data read (%02x%02x%02x%02x)!\n",
744 			      plane->cmd[0], plane->cmd[1], plane->cmd[2], plane->cmd[3]);
745 			mitsu9550_cleanup_job(job);
746 			return CUPS_BACKEND_CANCEL;
747 		}
748 
749 		/* Work out the length of this block */
750 		planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
751 		if (plane->cmd[3] == 0x10)
752 			planelen *= 2;
753 		if (plane->cmd[3] == 0x80)
754 			planelen *= 3;
755 
756 		/* Copy plane header into buffer */
757 		memcpy(job->databuf + job->datalen, buf, sizeof(buf));
758 		job->datalen += sizeof(buf);
759 		planelen -= sizeof(buf) - sizeof(struct mitsu9550_plane);
760 
761 		/* Read in the spool data */
762 		while(planelen > 0) {
763 			i = read(data_fd, job->databuf + job->datalen, planelen);
764 			if (i == 0) {
765 				mitsu9550_cleanup_job(job);
766 				return CUPS_BACKEND_CANCEL;
767 			}
768 			if (i < 0) {
769 				mitsu9550_cleanup_job(job);
770 				return CUPS_BACKEND_CANCEL;
771 			}
772 			job->datalen += i;
773 			planelen -= i;
774 		}
775 
776 		/* Try to read in the next chunk.  It will be one of:
777 		    - Additional block header (12B)
778 		    - Job footer (4B)
779 		*/
780 		i = read(data_fd, buf, 4);
781 		if (i == 0) {
782 			mitsu9550_cleanup_job(job);
783 			return CUPS_BACKEND_CANCEL;
784 		}
785 		if (i < 0) {
786 			mitsu9550_cleanup_job(job);
787 			return CUPS_BACKEND_CANCEL;
788 		}
789 
790 		/* Is this a "job end" marker? */
791 		if (plane->cmd[0] == 0x1b &&
792 		    plane->cmd[1] == 0x50 &&
793 		    plane->cmd[3] == 0x00) {
794 			/* store it in the buffer */
795 			memcpy(job->databuf + job->datalen, buf, 4);
796 			job->datalen += 4;
797 
798 			/* Unless we have a raw matte plane following,
799 			   we're done */
800 			if (job->hdr1.matte != 0x01 ||
801 			    !job->is_raw)
802 				break;
803 			remain = sizeof(buf);
804 		} else {
805 			/* It's part of a block header, mark what we've read */
806 			remain = sizeof(buf) - 4;
807 		}
808 
809 		/* Read in the rest of the header */
810 		while (remain > 0) {
811 			i = read(data_fd, buf + sizeof(buf) - remain, remain);
812 			if (i == 0) {
813 				mitsu9550_cleanup_job(job);
814 				return CUPS_BACKEND_CANCEL;
815 			}
816 			if (i < 0) {
817 				mitsu9550_cleanup_job(job);
818 				return CUPS_BACKEND_CANCEL;
819 			}
820 			remain -= i;
821 		}
822 	}
823 
824 	/* Apply LUT, if job calls for it.. */
825 	if (ctx->is_98xx && !job->is_raw && job->hdr2.unkc[9]) {
826 
827 		if (!ctx->dl_handle) {
828 			// XXXFALLBACK write fallback code?
829 			ERROR("!!! Image Processing Library not found, aborting!\n");
830 			mitsu9550_cleanup_job(job);
831 			return CUPS_BACKEND_CANCEL;
832 		}
833 
834 		if (!ctx->lut) {
835 			uint8_t *lbuf = malloc(LUT_LEN);
836 			if (!lbuf) {
837 				ERROR("Memory allocation failure!\n");
838 				mitsu9550_cleanup_job(job);
839 				return CUPS_BACKEND_RETRY_CURRENT;
840 			}
841 			if (ctx->Get3DColorTable(lbuf, MITSU_M98xx_LUT_FILE)) {
842 				ERROR("Unable to open LUT file '%s'\n", MITSU_M98xx_LUT_FILE);
843 				mitsu9550_cleanup_job(job);
844 				return CUPS_BACKEND_CANCEL;
845 			}
846 			ctx->lut = ctx->Load3DColorTable(lbuf);
847 			free(lbuf);
848 			if (!ctx->lut) {
849 				ERROR("Unable to parse LUT\n");
850 				mitsu9550_cleanup_job(job);
851 				return CUPS_BACKEND_CANCEL;
852 			}
853 		}
854 
855 		DEBUG("Running print data through 3D LUT\n");
856 		ctx->DoColorConv(ctx->lut, job->databuf + sizeof(struct mitsu9550_plane),
857 				 job->cols, job->rows, job->cols * 3, COLORCONV_BGR);
858 		job->hdr2.unkc[9] = 0;
859 	}
860 
861 	/* Update printjob header to reflect number of requested copies */
862 	if (job->hdr2_present) {
863 		copies = 1;
864 		job->hdr2.copies = cpu_to_be16(copies);
865 	}
866 	job->copies = copies;
867 
868 	/* All further work is in main loop */
869 	if (test_mode >= TEST_MODE_NOPRINT)
870 		mitsu9550_main_loop(ctx, job);
871 
872 	*vjob = job;
873 
874 	return CUPS_BACKEND_OK;
875 }
876 
mitsu9550_get_status(struct mitsu9550_ctx * ctx,uint8_t * resp,int status,int status2,int media)877 static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int status, int status2, int media)
878 {
879 	struct mitsu9550_cmd cmd;
880 	int num, ret;
881 
882 	/* Send Printer Query */
883 	cmd.cmd[0] = 0x1b;
884 	cmd.cmd[1] = 0x56;
885 	if (status)
886 		cmd.cmd[2] = 0x30;
887 	else if (status2)
888 		cmd.cmd[2] = 0x21;
889 	else if (media)
890 		cmd.cmd[2] = 0x24;
891 	cmd.cmd[3] = 0x00;
892 	if ((ret = send_data(ctx->dev, ctx->endp_down,
893 			     (uint8_t*) &cmd, sizeof(cmd))))
894 		return ret;
895 	ret = read_data(ctx->dev, ctx->endp_up,
896 			resp, sizeof(struct mitsu9550_status), &num);
897 
898 	if (ret < 0)
899 		return ret;
900 	if (num != sizeof(struct mitsu9550_status)) {
901 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(struct mitsu9550_status));
902 		return 4;
903 	}
904 
905 	return 0;
906 }
907 
mitsu9550_media_types(uint8_t type,uint8_t is_s)908 static char *mitsu9550_media_types(uint8_t type, uint8_t is_s)
909 {
910 	if (is_s) {
911 		switch (type & 0xf) { /* values can be 0x0? or 0x4? */
912 		case 0x02:
913 			return "CK9015 (4x6)";
914 		case 0x04:
915 			return "CK9318 (5x7)";
916 		case 0x05:
917 			return "CK9523 (6x9)";
918 		default:
919 			return "Unknown";
920 		}
921 		return NULL;
922 	}
923 
924 	switch (type & 0xf) { /* values can be 0x0? or 0x4? */
925 	case 0x01:
926 		return "CK9035 (3.5x5)";
927 	case 0x02:
928 		return "CK9046 (4x6)";
929 	case 0x03:
930 		return "CK9046PST (4x6)";
931 	case 0x04:
932 		return "CK9057 (5x7)";
933 	case 0x05:
934 		return "CK9069 (6x9)";
935 	case 0x06:
936 		return "CK9068 (6x8)";
937 	default:
938 		return "Unknown";
939 	}
940 	return NULL;
941 }
942 
validate_media(int type,int media,int cols,int rows)943 static int validate_media(int type, int media, int cols, int rows)
944 {
945 	switch(type) {
946 	case P_MITSU_9550:
947 		switch(media & 0xf) {
948 		case 0x01: /* 3.5x5 */
949 			if (cols != 1812 && rows != 1240)
950 				return 1;
951 			break;
952 		case 0x02: /* 4x6 */
953 		case 0x03: /* 4x6 postcard */
954 			if (cols != 2152)
955 				return 1;
956 			if (rows != 1416 && rows != 1184 && rows != 1240)
957 				return 1;
958 			break;
959 		case 0x04: /* 5x7 */
960 			if (cols != 1812)
961 				return 1;
962 			if (rows != 1240 && rows != 2452)
963 				return 1;
964 			break;
965 		case 0x05: /* 6x9 */
966 			if (cols != 2152)
967 				return 1;
968 			if (rows != 1416 && rows != 2792 &&
969 			    rows != 2956 && rows != 3146)
970 				return 1;
971 			break;
972 		case 0x06: /* V (6x8??) */
973 			if (cols != 2152)
974 				return 1;
975 			if (rows != 1416 && rows != 2792)
976 				return 1;
977 			break;
978 		default: /* Unknown */
979 			WARNING("Unknown media type %02x\n", media);
980 			break;
981 		}
982 		break;
983 	case P_MITSU_9550S:
984 		switch(media & 0xf) {
985 		case 0x02: /* 4x6 */
986 		case 0x03: /* 4x6 postcard */
987 			if (cols != 2152)
988 				return 1;
989 			if (rows != 1416 && rows != 1184 && rows != 1240)
990 				return 1;
991 			break;
992 		case 0x04: /* 5x7 */
993 			if (cols != 1812 && rows != 2452)
994 				return 1;
995 			break;
996 		case 0x05: /* 6x9 */
997 			if (cols != 2152)
998 				return 1;
999 			if (rows != 1416 && rows != 2792 &&
1000 			    rows != 2956 && rows != 3146)
1001 				return 1;
1002 			break;
1003 		case 0x06: /* V (6x8??) */
1004 			if (cols != 2152)
1005 				return 1;
1006 			if (rows != 1416 && rows != 2792)
1007 				return 1;
1008 			break;
1009 		default: /* Unknown */
1010 			WARNING("Unknown media type %02x\n", media);
1011 			break;
1012 		}
1013 		break;
1014 	case P_MITSU_9600: // XXX 9600S doesn't support 5" media at all!
1015 		switch(media & 0xf) {
1016 		case 0x01: /* 3.5x5 */
1017 			if (cols == 1572) {
1018 				if (rows == 1076)
1019 					break;
1020 			} else if (cols == 3144) {
1021 				if (rows == 2152)
1022 					break;
1023 			}
1024 			return 1;
1025 		case 0x02: /* 4x6 */
1026 		case 0x03: /* 4x6 postcard */
1027 			if (cols == 1868) {
1028 				if (rows == 1228)
1029 					break;
1030 			} else if (cols == 3736) {
1031 				if (rows == 2458)
1032 					break;
1033 			}
1034 			return 1;
1035 		case 0x04: /* 5x7 */
1036 			if (cols == 1572) {
1037 				if (rows == 1076 || rows == 2128)
1038 					break;
1039 			} else if (cols == 3144) {
1040 				if (rows == 2152 || rows == 4256)
1041 					break;
1042 			}
1043 			return 1;
1044 		case 0x05: /* 6x9 */
1045 			if (cols == 1868) {
1046 				if (rows == 1228 || rows == 2442 || rows == 2564 || rows == 2730)
1047 					break;
1048 			} else if (cols == 3736) {
1049 				if (rows == 2458 || rows == 4846 || rows == 5130 || rows == 5462)
1050 					break;
1051 			}
1052 			return 1;
1053 		case 0x06: /* V (6x8??) */
1054 			if (cols == 1868) {
1055 				if (rows == 1228 || rows == 2442)
1056 					break;
1057 			} else if (cols == 3736) {
1058 				if (rows == 2458 || rows == 4846)
1059 					break;
1060 			}
1061 			return 1;
1062 		default: /* Unknown */
1063 			WARNING("Unknown media type %02x\n", media);
1064 			break;
1065 		}
1066 		break;
1067 	case P_MITSU_9800:
1068 	case P_MITSU_9810: // XXX and don't forget the 9820S
1069 		switch(media & 0xf) {
1070 		case 0x01: /* 3.5x5 */
1071 			if (cols != 1572 && rows != 1076)
1072 				return 1;
1073 			break;
1074 		case 0x02: /* 4x6 */
1075 		case 0x03: /* 4x6 postcard */
1076 			if (cols != 1868 && rows != 1228)
1077 				return 1;
1078 			break;
1079 		case 0x04: /* 5x7 */
1080 			if (cols != 1572 && rows != 2128)
1081 				return 1;
1082 			break;
1083 		case 0x05: /* 6x9 */
1084 			if (cols != 1868)
1085 				return 1;
1086 			if (rows != 1228 && rows != 2442 &&
1087 			    rows != 2564 && rows != 2730)
1088 				return 1;
1089 			break;
1090 		case 0x06: /* V (6x8??) */
1091 			if (cols != 1868)
1092 				return 1;
1093 			if (rows != 1228 && rows != 2442)
1094 				return 1;
1095 			break;
1096 		default: /* Unknown */
1097 			WARNING("Unknown media type %02x\n", media);
1098 			break;
1099 		}
1100 		break;
1101 	case P_MITSU_9800S:
1102 		switch(media & 0xf) {
1103 		case 0x02: /* 4x6 */
1104 		case 0x03: /* 4x6 postcard */
1105 			if (cols != 1868 && rows != 1228)
1106 				return 1;
1107 			break;
1108 		case 0x04: /* 5x7 */
1109 			if (cols != 1572 && rows != 2128)
1110 				return 1;
1111 			break;
1112 		case 0x05: /* 6x9 */
1113 			if (cols != 1868)
1114 				return 1;
1115 			if (rows != 1228 && rows != 2442 &&
1116 			    rows != 2564 && rows != 2730)
1117 				return 1;
1118 			break;
1119 		case 0x06: /* V (6x8??) */
1120 			if (cols != 1868)
1121 				return 1;
1122 			if (rows != 1228 && rows != 2442)
1123 				return 1;
1124 			break;
1125 		default: /* Unknown */
1126 			WARNING("Unknown media type %02x\n", media);
1127 			break;
1128 		}
1129 		break;
1130 	default:
1131 		WARNING("Unknown printer type %d\n", type);
1132 		break;
1133 	}
1134 	return 0;
1135 }
1136 
mitsu9550_main_loop(void * vctx,const void * vjob)1137 static int mitsu9550_main_loop(void *vctx, const void *vjob) {
1138 	struct mitsu9550_ctx *ctx = vctx;
1139 	struct mitsu9550_cmd cmd;
1140 	uint8_t rdbuf[READBACK_LEN];
1141 	uint8_t *ptr;
1142 
1143 	int ret;
1144 #if 0
1145 	int copies;
1146 #endif
1147 
1148 //	const struct mitsu9550_printjob *job = vjob;
1149 	struct mitsu9550_printjob *job = (struct mitsu9550_printjob*) vjob; // XXX not good.
1150 
1151 	if (!ctx)
1152 		return CUPS_BACKEND_FAILED;
1153 	if (!job)
1154 		return CUPS_BACKEND_FAILED;
1155 
1156 	/* Okay, let's do this thing */
1157 	ptr = job->databuf;
1158 
1159 #if 0
1160 	/* If hdr2 is not present, we have to generate copies ourselves! */
1161 	if (job->hdr2_present)
1162 		copies = job->copies;
1163 	// XXX..
1164 #endif
1165 
1166 	/* Do the 98xx processing here */
1167 	if (!ctx->is_98xx || job->is_raw)
1168 		goto bypass;
1169 
1170 	uint8_t *newbuf;
1171 	uint32_t newlen = 0;
1172 	struct mitsu98xx_data *table;
1173 	int i, remain, planelen;
1174 
1175 	planelen = job->rows * job->cols * 2;
1176 	remain = (job->hdr1.matte ? 4 : 3) * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd) * (job->hdr1.matte? 2 : 1) + LAMINATE_STRIDE * 2;
1177 	newbuf = malloc(remain);
1178 	if (!newbuf) {
1179 		ERROR("Memory allocation Failure!\n");
1180 		return CUPS_BACKEND_RETRY_CURRENT;
1181 	}
1182 	switch (job->hdr2.mode) {
1183 	case 0x80:
1184 		table = &ctx->m98xxdata->superfine;
1185 		break;
1186 	case 0x11:
1187 		table = &ctx->m98xxdata->fine_hg;
1188 		job->hdr2.mode = 0x10;
1189 		break;
1190 	case 0x10:
1191 	default:
1192 		table = &ctx->m98xxdata->fine_std;
1193 		break;
1194 	}
1195 
1196 	DEBUG("Applying 8bpp->12bpp Gamma Correction\n");
1197 	/* For B/Y plane */
1198 	memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
1199 	newbuf[newlen + 3] = 0x10;  /* ie 16bpp data */
1200 	newlen += sizeof(struct mitsu9550_plane);
1201 	mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
1202 			  (uint16_t*) (newbuf + newlen),
1203 			  0,
1204 			  table->GNMby,
1205 			  planelen / 2);
1206 	newlen += planelen;
1207 
1208 	/* For G/M plane */
1209 	memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
1210 	newbuf[newlen + 3] = 0x10;  /* ie 16bpp data */
1211 	newlen += sizeof(struct mitsu9550_plane);
1212 	mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
1213 			  (uint16_t*) (newbuf + newlen),
1214 			  1,
1215 			  table->GNMgm,
1216 			  planelen / 2);
1217 	newlen += planelen;
1218 
1219 	/* For R/C plane */
1220 	memcpy(newbuf + newlen, job->databuf, sizeof(struct mitsu9550_plane));
1221 	newbuf[newlen + 3] = 0x10;  /* ie 16bpp data */
1222 	newlen += sizeof(struct mitsu9550_plane);
1223 	mitsu98xx_dogamma(job->databuf + sizeof(struct mitsu9550_plane),
1224 			  (uint16_t*) (newbuf + newlen),
1225 			  2,
1226 			  table->GNMrc,
1227 			  planelen / 2);
1228 	newlen += planelen;
1229 
1230 	/* And finally, the job footer. */
1231 	memcpy(newbuf + newlen, job->databuf + sizeof(struct mitsu9550_plane) + planelen/2 * 3, sizeof(struct mitsu9550_cmd));
1232 	newlen += sizeof(struct mitsu9550_cmd);
1233 
1234 	/* Clean up, and move pointer to new buffer; */
1235 	free(job->databuf);
1236 	job->databuf = newbuf;
1237 	job->datalen = newlen;
1238 	ptr = job->databuf;
1239 
1240 	/* Now handle the matte plane generation */
1241 	if (job->hdr1.matte) {
1242 		if ((i = mitsu98xx_fillmatte(job))) {
1243 			return i;
1244 		}
1245 	}
1246 
1247 bypass:
1248 	/* Bypass */
1249 	if (test_mode >= TEST_MODE_NOPRINT)
1250 		return CUPS_BACKEND_OK;
1251 
1252 top:
1253 	if (ctx->is_s) {
1254 		int num;
1255 
1256 		/* Send "unknown 1" command */
1257 		cmd.cmd[0] = 0x1b;
1258 		cmd.cmd[1] = 0x53;
1259 		cmd.cmd[2] = 0xc5;
1260 		cmd.cmd[3] = 0x9d;
1261 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1262 				     (uint8_t*) &cmd, sizeof(cmd))))
1263 			return CUPS_BACKEND_FAILED;
1264 
1265 		/* Send "unknown 2" command */
1266 		cmd.cmd[0] = 0x1b;
1267 		cmd.cmd[1] = 0x4b;
1268 		cmd.cmd[2] = 0x7f;
1269 		cmd.cmd[3] = 0x00;
1270 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1271 				     (uint8_t*) &cmd, sizeof(cmd))))
1272 			return CUPS_BACKEND_FAILED;
1273 
1274 		ret = read_data(ctx->dev, ctx->endp_up,
1275 				rdbuf, READBACK_LEN, &num);
1276 		if (ret < 0)
1277 			return CUPS_BACKEND_FAILED;
1278 		// seen so far: eb 4b 7f 00  02 00 5e
1279 	}
1280 
1281 	if (ctx->type == P_MITSU_9800S) {
1282 		int num;
1283 
1284 		/* Send "unknown 3" command */
1285 		cmd.cmd[0] = 0x1b;
1286 		cmd.cmd[1] = 0x4b;
1287 		cmd.cmd[2] = 0x01;
1288 		cmd.cmd[3] = 0x00;
1289 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1290 				     (uint8_t*) &cmd, sizeof(cmd))))
1291 			return CUPS_BACKEND_FAILED;
1292 
1293 		ret = read_data(ctx->dev, ctx->endp_up,
1294 				rdbuf, READBACK_LEN, &num);
1295 		if (ret < 0)
1296 			return CUPS_BACKEND_FAILED;
1297 		// seen so far: e4 4b 01 00 02 00 78
1298 	}
1299 
1300 	QUERY_STATUS();
1301 
1302 	/* Now it's time for the actual print job! */
1303 
1304 	QUERY_STATUS();
1305 
1306 	/* Send printjob headers from spool data */
1307 	if (job->hdr1_present)
1308 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1309 				     (uint8_t*) &job->hdr1, sizeof(job->hdr1))))
1310 			return CUPS_BACKEND_FAILED;
1311 	if (job->hdr2_present)
1312 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1313 				     (uint8_t*) &job->hdr2, sizeof(job->hdr2))))
1314 			return CUPS_BACKEND_FAILED;
1315 	if (job->hdr3_present)
1316 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1317 				     (uint8_t*) &job->hdr3, sizeof(job->hdr3))))
1318 			return CUPS_BACKEND_FAILED;
1319 	if (job->hdr4_present)
1320 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1321 				     (uint8_t*) &job->hdr4, sizeof(struct mitsu9550_hdr4))))
1322 			return CUPS_BACKEND_FAILED;
1323 
1324 	if (ctx->is_s) {
1325 		/* I think this a "clear memory' command...? */
1326 		cmd.cmd[0] = 0x1b;
1327 		cmd.cmd[1] = 0x5a;
1328 		cmd.cmd[2] = 0x43;
1329 		cmd.cmd[3] = 0x00;
1330 
1331 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1332 				     (uint8_t*) &cmd, sizeof(cmd))))
1333 			return CUPS_BACKEND_FAILED;
1334 	}
1335 
1336 	/* Send over plane data */
1337 	while(ptr < (job->databuf + job->datalen)) {
1338 		struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
1339 		if (plane->cmd[0] != 0x1b ||
1340 		    plane->cmd[1] != 0x5a ||
1341 		    plane->cmd[2] != 0x54)
1342 			break;
1343 
1344 		planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
1345 		if (plane->cmd[3] == 0x10)
1346 			planelen *= 2;
1347 
1348 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1349 				     (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
1350 			return CUPS_BACKEND_FAILED;
1351 		ptr += sizeof(struct mitsu9550_plane);
1352 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1353 				     (uint8_t*) ptr, planelen)))
1354 			return CUPS_BACKEND_FAILED;
1355 		ptr += planelen;
1356 	}
1357 
1358 	/* Query statuses */
1359 	{
1360 		struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
1361 //		struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
1362 		struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
1363 		uint16_t donor;
1364 
1365 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
1366 		if (ret < 0)
1367 			return CUPS_BACKEND_FAILED;
1368 
1369 		donor = be16_to_cpu(media->remain);
1370 		if (donor != ctx->marker.levelnow) {
1371 			ctx->marker.levelnow = donor;
1372 			dump_markers(&ctx->marker, 1, 0);
1373 		}
1374 		/* Sanity-check media response */
1375 		if (media->remain == 0 || media->max == 0) {
1376 			ERROR("Printer out of media!\n");
1377 			return CUPS_BACKEND_HOLD;
1378 		}
1379 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
1380 		if (ret < 0)
1381 			return CUPS_BACKEND_FAILED;
1382 
1383 		ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
1384 		if (ret < 0)
1385 			return CUPS_BACKEND_FAILED;
1386 
1387 		/* Make sure we're ready to proceed */
1388 		if (sts->sts5 != 0) {
1389 			ERROR("Unexpected response (sts5 %02x)\n", sts->sts5);
1390 			return CUPS_BACKEND_FAILED;
1391 		}
1392 		if (!(sts->sts3 & 0xc0)) {
1393 			ERROR("Unexpected response (sts3 %02x)\n", sts->sts3);
1394 			return CUPS_BACKEND_FAILED;
1395 		}
1396 		/* Check for known errors */
1397 		if (sts->sts2 != 0) {
1398 			ERROR("Printer cover open!\n");
1399 			return CUPS_BACKEND_STOP;
1400 		}
1401 	}
1402 
1403 	/* Send "end data" command */
1404 	if (ctx->type == P_MITSU_9550S) {
1405 		/* Override spool, which may be wrong */
1406 		cmd.cmd[0] = 0x1b;
1407 		cmd.cmd[1] = 0x50;
1408 		cmd.cmd[2] = 0x47;
1409 		cmd.cmd[3] = 0x00;
1410 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1411 				     (uint8_t*) &cmd, sizeof(cmd))))
1412 			return CUPS_BACKEND_FAILED;
1413 	} else if (ctx->type == P_MITSU_9800S) {
1414 		/* Override spool, which may be wrong */
1415 		cmd.cmd[0] = 0x1b;
1416 		cmd.cmd[1] = 0x50;
1417 		cmd.cmd[2] = 0x4e;
1418 		cmd.cmd[3] = 0x00;
1419 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1420 				     (uint8_t*) &cmd, sizeof(cmd))))
1421 			return CUPS_BACKEND_FAILED;
1422 	} else {
1423 		/* Send from spool file */
1424 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1425 				     ptr, sizeof(cmd))))
1426 			return CUPS_BACKEND_FAILED;
1427 		ptr += sizeof(cmd);
1428 	}
1429 
1430 	/* Don't forget the 9810's matte plane */
1431 	if (job->hdr1.matte) {
1432 		struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
1433 		planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
1434 
1435 		if (plane->cmd[3] == 0x10)
1436 			planelen *= 2;
1437 
1438 		// XXX include a status loop here too?
1439 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1440 				     (uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
1441 			return CUPS_BACKEND_FAILED;
1442 		ptr += sizeof(struct mitsu9550_plane);
1443 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1444 				     (uint8_t*) ptr, planelen)))
1445 			return CUPS_BACKEND_FAILED;
1446 		ptr += planelen;
1447 
1448 		/* Send "lamination end data" command from spool file */
1449 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1450 				     ptr, sizeof(cmd))))
1451 			return CUPS_BACKEND_FAILED;
1452 //		ptr += sizeof(cmd);
1453 	}
1454 
1455 	/* Status loop, run until printer reports completion */
1456 	while(1) {
1457 		struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
1458 //		struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
1459 		struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
1460 		uint16_t donor;
1461 
1462 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 0, 1); // media
1463 		if (ret < 0)
1464 			return CUPS_BACKEND_FAILED;
1465 
1466 		donor = be16_to_cpu(media->remain);
1467 		if (donor != ctx->marker.levelnow) {
1468 			ctx->marker.levelnow = donor;
1469 			dump_markers(&ctx->marker, 1, 0);
1470 		}
1471 		/* Sanity-check media response */
1472 		if (media->remain == 0 || media->max == 0) {
1473 			ERROR("Printer out of media!\n");
1474 			return CUPS_BACKEND_HOLD;
1475 		}
1476 		ret = mitsu9550_get_status(ctx, rdbuf, 0, 1, 0); // status2
1477 		if (ret < 0)
1478 			return CUPS_BACKEND_FAILED;
1479 
1480 		ret = mitsu9550_get_status(ctx, rdbuf, 1, 0, 0); // status
1481 		if (ret < 0)
1482 			return CUPS_BACKEND_FAILED;
1483 
1484 		INFO("%03d copies remaining\n", be16_to_cpu(sts->copies));
1485 
1486 		if (!sts->sts1) /* If printer transitions to idle */
1487 			break;
1488 
1489 		if (fast_return && !be16_to_cpu(sts->copies)) { /* No remaining prints */
1490                         INFO("Fast return mode enabled.\n");
1491 			break;
1492                 }
1493 
1494 		if (fast_return && !sts->sts5) { /* Ready for another job */
1495 			INFO("Fast return mode enabled.\n");
1496 			break;
1497 		}
1498 		/* Check for known errors */
1499 		if (sts->sts2 != 0) {
1500 			ERROR("Printer cover open!\n");
1501 			return CUPS_BACKEND_STOP;
1502 		}
1503 		sleep(1);
1504 	}
1505 
1506 	INFO("Print complete\n");
1507 
1508 	return CUPS_BACKEND_OK;
1509 }
1510 
mitsu9550_dump_media(struct mitsu9550_media * resp,int is_s)1511 static void mitsu9550_dump_media(struct mitsu9550_media *resp, int is_s)
1512 {
1513 	INFO("Media type       : %02x (%s)\n",
1514 	     resp->type, mitsu9550_media_types(resp->type, is_s));
1515 	INFO("Media remaining  : %03d/%03d\n",
1516 	     be16_to_cpu(resp->remain), be16_to_cpu(resp->max));
1517 }
1518 
mitsu9550_dump_status(struct mitsu9550_status * resp)1519 static void mitsu9550_dump_status(struct mitsu9550_status *resp)
1520 {
1521 	INFO("Printer status    : %02x (%s)\n",
1522 	     resp->sts1, resp->sts1 ? "Printing": "Idle");
1523 	INFO("Pages remaining   : %03d\n",
1524 	     be16_to_cpu(resp->copies));
1525 	INFO("Other status      : %02x %02x %02x %02x  %02x %02x\n",
1526 	     resp->sts2, resp->sts3, resp->sts4,
1527 	     resp->sts5, resp->sts6, resp->sts7);
1528 }
1529 
mitsu9550_dump_status2(struct mitsu9550_status2 * resp)1530 static void mitsu9550_dump_status2(struct mitsu9550_status2 *resp)
1531 {
1532 	INFO("Prints remaining on media : %03d\n",
1533 	     be16_to_cpu(resp->remain));
1534 }
1535 
mitsu9550_query_media(struct mitsu9550_ctx * ctx)1536 static int mitsu9550_query_media(struct mitsu9550_ctx *ctx)
1537 {
1538 	struct mitsu9550_media resp;
1539 	int ret;
1540 
1541 	ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 0, 0, 1);
1542 
1543 	if (!ret)
1544 		mitsu9550_dump_media(&resp, ctx->is_s);
1545 
1546 	return ret;
1547 }
1548 
mitsu9550_query_status(struct mitsu9550_ctx * ctx)1549 static int mitsu9550_query_status(struct mitsu9550_ctx *ctx)
1550 {
1551 	struct mitsu9550_status resp;
1552 	int ret;
1553 
1554 	ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 1, 0, 0);
1555 
1556 	if (!ret)
1557 		mitsu9550_dump_status(&resp);
1558 
1559 	return ret;
1560 }
1561 
mitsu9550_query_status2(struct mitsu9550_ctx * ctx)1562 static int mitsu9550_query_status2(struct mitsu9550_ctx *ctx)
1563 {
1564 	struct mitsu9550_status2 resp;
1565 	int ret;
1566 
1567 	ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, 0, 1, 0);
1568 
1569 	if (!ret)
1570 		mitsu9550_dump_status2(&resp);
1571 
1572 	return ret;
1573 }
1574 
mitsu9550_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)1575 static int mitsu9550_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
1576 {
1577 	struct mitsu9550_cmd cmd;
1578 	uint8_t rdbuf[READBACK_LEN];
1579 	uint8_t *ptr;
1580 	int ret, num, i;
1581 
1582 	cmd.cmd[0] = 0x1b;
1583 	cmd.cmd[1] = 0x72;
1584 	cmd.cmd[2] = 0x6e;
1585 	cmd.cmd[3] = 0x00;
1586 
1587 	if ((ret = send_data(dev, endp_down,
1588                              (uint8_t*) &cmd, sizeof(cmd))))
1589                 return (ret < 0) ? ret : CUPS_BACKEND_FAILED;
1590 
1591 	ret = read_data(dev, endp_up,
1592 			rdbuf, READBACK_LEN, &num);
1593 
1594 	if (ret < 0)
1595 		return CUPS_BACKEND_FAILED;
1596 
1597 	if ((unsigned int)num < sizeof(cmd) + 1) /* Short read */
1598 		return CUPS_BACKEND_FAILED;
1599 
1600 	if (rdbuf[0] != 0xe4 ||
1601 	    rdbuf[1] != 0x72 ||
1602 	    rdbuf[2] != 0x6e ||
1603 	    rdbuf[3] != 0x00) /* Bad response */
1604 		return CUPS_BACKEND_FAILED;
1605 
1606 	/* If response is truncated, handle it */
1607 	num -= (sizeof(cmd) + 1);
1608 	if ((unsigned int) num != rdbuf[4])
1609 		WARNING("Short serno read! (%d vs %u)\r\n",
1610 			num, rdbuf[4]);
1611 
1612 	/* model and serial number are encoded as 16-bit unicode,
1613 	   little endian, separated by spaces. */
1614 	i = num;
1615 	ptr = rdbuf + 5;
1616 	while (i > 0 && buf_len > 1) {
1617 		if (*ptr != 0x20)
1618 			*buf++ = *ptr;
1619 		buf_len--;
1620 		ptr += 2;
1621 		i -= 2;
1622 	}
1623 	*buf = 0; /* Null-terminate the returned string */
1624 
1625 	return ret;
1626 }
1627 
mitsu9550_cancel_job(struct mitsu9550_ctx * ctx)1628 static int mitsu9550_cancel_job(struct mitsu9550_ctx *ctx)
1629 {
1630 	int ret;
1631 
1632 	uint8_t buf[2] = { 0x1b, 0x44 };
1633 	ret = send_data(ctx->dev, ctx->endp_down, buf, sizeof(buf));
1634 
1635 	return ret;
1636 }
1637 
mitsu9550_cmdline(void)1638 static void mitsu9550_cmdline(void)
1639 {
1640 	DEBUG("\t\t[ -m ]           # Query media\n");
1641 	DEBUG("\t\t[ -s ]           # Query status\n");
1642 	DEBUG("\t\t[ -X ]           # Cancel current job\n");
1643 }
1644 
mitsu9550_cmdline_arg(void * vctx,int argc,char ** argv)1645 static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
1646 {
1647 	struct mitsu9550_ctx *ctx = vctx;
1648 	int i, j = 0;
1649 
1650 	if (!ctx)
1651 		return -1;
1652 
1653 	while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "msX")) >= 0) {
1654 		switch(i) {
1655 		GETOPT_PROCESS_GLOBAL
1656 		case 'm':
1657 			j = mitsu9550_query_media(ctx);
1658 			break;
1659 		case 's':
1660 			j = mitsu9550_query_status(ctx);
1661 			if (!j)
1662 				j = mitsu9550_query_status2(ctx);
1663 			break;
1664 		case 'X':
1665 			j = mitsu9550_cancel_job(ctx);
1666 			break;
1667 		default:
1668 			break;  /* Ignore completely */
1669 		}
1670 
1671 		if (j) return j;
1672 	}
1673 
1674 	return 0;
1675 }
1676 
mitsu9550_query_markers(void * vctx,struct marker ** markers,int * count)1677 static int mitsu9550_query_markers(void *vctx, struct marker **markers, int *count)
1678 {
1679 	struct mitsu9550_ctx *ctx = vctx;
1680 	struct mitsu9550_media media;
1681 
1682 	/* Query printer status */
1683 	if (mitsu9550_get_status(ctx, (uint8_t*) &media, 0, 0, 1))
1684 		return CUPS_BACKEND_FAILED;
1685 
1686 	ctx->marker.levelnow = be16_to_cpu(media.remain);
1687 
1688 	*markers = &ctx->marker;
1689 	*count = 1;
1690 
1691 	return CUPS_BACKEND_OK;
1692 }
1693 
1694 static const char *mitsu9550_prefixes[] = {
1695 	"mitsu9xxx", // Family driver, do not nuke.
1696 	"mitsubishi-9000dw", "mitsubishi-9500dw",
1697 	"mitsubishi-9550dw", "mitsubishi-9550dw-s",
1698 	"mitsubishi-9600dw", // "mitsubishi-9600dw-s",
1699 	"mitsubishi-9800dw", "mitsubishi-9800dw-s",
1700 	"mitsubishi-9810dw",
1701 	// extras
1702 	"mitsubishi-9550d", "mitsubishi-9550dz", "mitsubishi-9800d", "mitsubishi-9800dz", "mitsubishi-9810d",
1703 	// Backwards compatibility
1704 	"mitsu9000", "mitsu9500", "mitsu9550", "mitsu9600", "mitsu9800", "mitsu9810",
1705 	NULL
1706 };
1707 
1708 /* Exported */
1709 struct dyesub_backend mitsu9550_backend = {
1710 	.name = "Mitsubishi CP9xxx family",
1711 	.version = "0.47",
1712 	.uri_prefixes = mitsu9550_prefixes,
1713 	.cmdline_usage = mitsu9550_cmdline,
1714 	.cmdline_arg = mitsu9550_cmdline_arg,
1715 	.init = mitsu9550_init,
1716 	.attach = mitsu9550_attach,
1717 	.teardown = mitsu9550_teardown,
1718 	.cleanup_job = mitsu9550_cleanup_job,
1719 	.read_parse = mitsu9550_read_parse,
1720 	.main_loop = mitsu9550_main_loop,
1721 	.query_serno = mitsu9550_query_serno,
1722 	.query_markers = mitsu9550_query_markers,
1723 	.devices = {
1724 		{ USB_VID_MITSU, USB_PID_MITSU_9000AM, P_MITSU_9550, NULL, "mitsubishi-9000dw"}, // XXX -am instead?
1725 		{ USB_VID_MITSU, USB_PID_MITSU_9000D, P_MITSU_9550, NULL, "mitsubishi-9000dw"},
1726 		{ USB_VID_MITSU, USB_PID_MITSU_9500D, P_MITSU_9550, NULL, "mitsubishi-9500dw"},
1727 		{ USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, NULL, "mitsubishi-9550dw"},
1728 		{ USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, NULL, "mitsubishi-9550dw-s"},
1729 		{ USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600, NULL, "mitsubishi-9600dw"},
1730 //	{ USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600S, NULL, "mitsubishi-9600dw-s"},
1731 		{ USB_VID_MITSU, USB_PID_MITSU_9800D, P_MITSU_9800, NULL, "mitsubishi-9800dw"},
1732 		{ USB_VID_MITSU, USB_PID_MITSU_9800DS, P_MITSU_9800S, NULL, "mitsubishi-9800dw-s"},
1733 		{ USB_VID_MITSU, USB_PID_MITSU_98__D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
1734 //	{ USB_VID_MITSU, USB_PID_MITSU_9810D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
1735 //	{ USB_VID_MITSU, USB_PID_MITSU_9820DS, P_MITSU_9820S, NULL, "mitsubishi-9820dw-s"},
1736 		{ 0, 0, 0, NULL, NULL}
1737 	}
1738 };
1739 
1740 /* Mitsubish CP-9500/9550/9600/9800/9810/9820 spool format:
1741 
1742    Spool file consists of 3 (or 4) 50-byte headers, followed by three
1743    image planes, each with a 12-byte header, then a 4-byte footer.
1744 
1745    All multi-byte numbers are big endian.
1746 
1747    ~~~ Header 1
1748 
1749    1b 57 20 2e 00 QQ QQ 00  00 00 00 00 00 00 XX XX :: XX XX == columns
1750    YY YY 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: YY YY == rows
1751    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: QQ == 0x0a90 on 9810, 0x0a10 on all others.
1752    00 00
1753 
1754    ~~~ Header 2
1755 
1756    1b 57 21 2e 00 80 00 22  QQ QQ 00 00 00 00 00 00 :: ZZ ZZ = num copies (>= 0x01)
1757    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)
1758    XX 00 00 00 00 00 YY 00  00 00 00 00 00 00 00 00 :: XX = 00 normal, 83 Cut 2x6 (9550 only!)
1759    RR 01                                            :: QQ QQ = 0x0803 on 9550, 0x0801 on 98x0, 0x0003 on 9600, 0xa803 on 9500
1760                                                     :: RR = 01 for "use LUT" on 98xx, 0x00 otherwise.  Extension to stock.
1761 
1762    ~~~ Header 3 (9550 and 9800-S only..)
1763 
1764    1b 57 22 2e 00 QQ 00 00  00 00 00 XX 00 00 00 00 :: XX = 00 normal, 01 FineDeep
1765    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: QQ = 0xf0 on 9500, 0x40 on the rest
1766    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1767    00 00
1768 
1769    ~~~ Header 4 (all but 9550-S and 9800-S, involves error policy?)
1770 
1771    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
1772    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: RR = 0x01 on 9550/98x0, 0x00 on 9600
1773    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: SS = 0x01 on 9800S, 0x00 otherwise.
1774    00 00
1775 
1776   ~~~~ Data follows:
1777 
1778    Format is:  planar YMC16 for 98x0 (but only 12 bits used, BIG endian)
1779                planar RGB for all others
1780 
1781    1b 5a 54 ?? RR RR CC CC  07 14 04 d8  :: 0714 == columns, 04d8 == rows
1782                                          :: RRRR == row offset for data, CCCC == col offset for data
1783 		                         :: ?? == 0x00 for 8bpp, 0x10 for 16/12bpp.
1784 					 ::    0x80 for PACKED BGR!
1785 
1786    Data follows immediately, no padding.
1787 
1788    1b 5a 54 00 00 00 00 00  07 14 04 d8  :: Another plane.
1789 
1790    Data follows immediately, no padding.
1791 
1792    1b 5a 54 00 00 00 00 00  07 14 04 d8  :: Another plane.
1793 
1794    Data follows immediately, no padding.
1795 
1796   ~~~~ Footer:
1797 
1798    1b 50 57 00  (9500)
1799    1b 50 46 00  (9550)
1800    1b 50 47 00  (9550-S)
1801    1b 50 48 00  (9600)
1802    1b 50 4c 00  (9800/9810)
1803    1b 50 4e 00  (9800-S)
1804 
1805    Unknown: 9600-S, 9820-S
1806 
1807   ~~~~ Lamination data follows (on 9810 only, if matte selected)
1808 
1809    1b 5a 54 10 00 00  00 00 06 24 04 34
1810 
1811    Data follows immediately, no padding.
1812 
1813    1b 50 56 00  (Lamination footer)
1814 
1815   ~~~~ QUESTIONS:
1816 
1817    * Lamination control?
1818    * Other 9550 multi-cut modes (on 6x9 media: 4x6*2, 4.4x6*2, 3x6*3, 2x6*4)
1819    * 9600/98x0 multi-cut modes?
1820 
1821  ***********************************************************************
1822 
1823  * Mitsubishi ** CP-9550DW-S/9800DW-S ** Communications Protocol:
1824 
1825   [[ Unknown ]]
1826 
1827  -> 1b 53 c5 9d
1828 
1829   [[ Unknown, query some parameter? ]]
1830 
1831  -> 1b 4b 7f 00
1832  <- eb 4b 8f 00 02 00 5e  [[ '02' seems to be a length ]]
1833 
1834   [[ Unknown ]]
1835 
1836  -> 1b 53 00 00
1837 
1838   Query Model & Serial number
1839 
1840  -> 1b 72 6e 00
1841  <- e4 82 6e 00 LL 39 00 35  00 35 00 30 00 5a 00 20
1842     00 41 00 32 00 30 00 30  00 36 00 37 00
1843 
1844      'LL' is length.  Data is returned in 16-bit unicode, LE.
1845      Contents are model ('9550Z'), then space, then serialnum ('A20067')
1846 
1847   Media Query
1848 
1849  -> 1b 56 24 00
1850  <- 24 2e 00 00 00 00 00 00  00 00 00 00 00 00 TT 00 :: TT = Type
1851     00 00 00 00 00 00 00 00  00 00 00 00 MM MM 00 00 :: MM MM = Max prints
1852     NN NN 00 00 00 00 00 00  00 00 00 00 00 00 00 00 :: NN NN = Remaining
1853 
1854   [[ unknown query, 9800-only ]]
1855 
1856  -> 1b 4b 01 00
1857  <- e4 4b 01 00 02 00 78
1858 
1859   Status Query
1860 
1861  -> 1b 56 30 00
1862  -> 30 2e 00 00 00 00 MM 00  NN NN ZZ 00 00 00 00 00 :: MM, NN, ZZ
1863     QQ RR SS 00 00 00 00 00  00 00 00 00 00 00 00 00 :: QQ, RR, SS
1864     00 00 00 00 00 00 00 00  00 00 00 00 TT UU 00 00 :: TT, UU
1865 
1866   Status Query B (not sure what to call this)
1867 
1868  -> 1b 56 21 00
1869  <- 21 2e 00 80 00 22 a8 0b  00 00 00 00 00 00 00 00
1870     00 00 00 00 00 00 00 00  00 00 00 QQ 00 00 00 00 :: QQ == Prints in job?
1871     00 00 00 00 00 00 00 00  00 00 NN NN 0A 00 00 01 :: NN NN = Remaining media
1872 
1873   [[ Job Cancel ]]
1874 
1875  -> 1b 44
1876 
1877   [[ Header 1 -- See above ]]
1878 
1879  -> 1b 57 20 2e ....
1880 
1881   [[ Header 2 -- See above ]]
1882 
1883  -> 1b 57 21 2e ....
1884 
1885   [[ Header 3 -- See above ]]
1886 
1887  -> 1b 57 22 2e ....
1888 
1889   [[ Unknown -- Start Data ? ]]
1890 
1891  -> 1b 5a 43 00
1892 
1893   [[ Plane header #1 (Blue) ]]
1894 
1895  -> 1b 5a 54 00 00 00 00 00  XX XX YY YY :: XX XX == Columns, YY YY == Rows
1896 
1897     Followed by image plane #1 (Blue), XXXX * YYYY bytes
1898 
1899   [[ Plane header #2 (Green) ]]
1900 
1901  -> 1b 5a 54 00 00 00 00 00  XX XX YY YY :: XX XX == Columns, YY YY == Rows
1902 
1903     Followed by image plane #2 (Green), XXXX * YYYY bytes
1904 
1905   [[ Plane header #3 (Red) ]]
1906 
1907  -> 1b 5a 54 00 00 00 00 00  XX XX YY YY :: XX XX == Columns, YY YY == Rows
1908 
1909     Followed by image plane #3 (Red), XXXX * YYYY bytes
1910 
1911   [[ Footer -- End Data aka START print?  See above for other models ]]
1912 
1913  -> 1b 50 47 00  [9550S]
1914  -> 1b 50 4e 00  [9800S]
1915 
1916   [[ At this point, loop status/status b/media queries until printer idle ]]
1917 
1918     MM, QQ RR SS, TT UU
1919 
1920  <- 00  3e 00 00  8a 44  :: Idle.
1921     00  7e 00 00  8a 44  :: Plane data submitted, pre "end data" cmd
1922     00  7e 40 01  8a 44  :: "end data" sent
1923     30  7e 40 01  8a 44
1924     38  7e 40 01  8a 44
1925     59  7e 40 01  8a 44
1926     59  7e 40 00  8a 44
1927     4d  7e 40 00  8a 44
1928      [...]
1929     43  7e 40 00  82 44
1930      [...]
1931     50  7e 40 00  80 44
1932      [...]
1933     31  7e 40 00  7d 44
1934      [...]
1935     00  3e 00 00  80 44  :: Idle.
1936 
1937   Also seen:
1938 
1939     00  3e 00 00  96 4b  :: Idle
1940     00  be 00 00  96 4b  :: Data submitted, pre "start"
1941     00  be 80 01  96 4b  :: print start sent
1942     30  be 80 01  96 4c
1943      [...]
1944     30  be 80 01  89 4b
1945     38  be 80 01  8a 4b
1946     59  be 80 01  8b 4b
1947      [...]
1948     4d  be 80 01  89 4b
1949      [...]
1950     43  be 80 01  89 4b
1951      [...]
1952     50  be 80 01  82 4b
1953      [...]
1954     31  be 80 01  80 4b
1955      [...]
1956 
1957   Seen on 9600DW
1958 
1959     ZZ == 08  Door open
1960 
1961  Working theory of interpreting the status flags:
1962 
1963   MM :: 00 is idle, else mechanical printer state.
1964   NN :: Remaining prints in job, or 0x00 0x00 when idle.
1965   QQ :: ?? 0x3e + 0x40 or 0x80 (see below)
1966   RR :: ?? 0x00 is idle, 0x40 or 0x80 is "printing"?
1967   SS :: ?? 0x00 means "ready for another print" but 0x01 is "busy"
1968   TT :: ?? seen values between 0x7c through 0x96)
1969   UU :: ?? seen values between 0x43 and 0x4c -- temperature?
1970 
1971   ***
1972 
1973    Other printer commands seen:
1974 
1975   [[ Set error policy ?? aka "header 4" ]]
1976 
1977  -> 1b 57 26 2e 00 QQ 00 00  00 00 00 00 RR SS 00 00 :: QQ/RR/SS 00 00 00 [9550S]
1978     00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ::          20 01 00 [9550S w/ ignore failures on]
1979     00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ::          70 01 01 [9550]
1980     00 00
1981 
1982  */
1983