1 /*
2  *   Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version
3  *
4  *   (c) 2013-2018 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 #if defined(USE_DLOPEN)
45 #define WITH_DYNAMIC
46 #include <dlfcn.h>
47 #define DL_INIT() do {} while(0)
48 #define DL_OPEN(__x) dlopen(__x, RTLD_NOW)
49 #define DL_SYM(__x, __y) dlsym(__x, __y)
50 #define DL_CLOSE(__x) dlclose(__x)
51 #define DL_EXIT() do {} while(0)
52 #elif defined(USE_LTDL)
53 #define WITH_DYNAMIC
54 #include <ltdl.h>
55 #define DL_INIT() lt_dlinit()
56 #define DL_OPEN(__x) lt_dlopen(__x)
57 #define DL_SYM(__x, __y) lt_dlsym(__x, __y)
58 #define DL_CLOSE(__x) do {} while(0)
59 #define DL_EXIT() lt_dlexit()
60 #else
61 #define DL_INIT()     do {} while(0)
62 #define DL_CLOSE(__x) do {} while(0)
63 #define DL_EXIT()     do {} while(0)
64 #warning "No dynamic loading support!"
65 #endif
66 
67 #define BACKEND mitsu70x_backend
68 
69 #include "backend_common.h"
70 
71 // #include "lib70x/libMitsuD70ImageReProcess.h"
72 
73 #ifndef LUT_LEN
74 #define COLORCONV_RGB 0
75 #define COLORCONV_BGR 1
76 
77 #define LUT_LEN 14739
78 struct BandImage {
79 	   void  *imgbuf;
80 	 int32_t bytes_per_row;
81 	uint16_t origin_cols;
82 	uint16_t origin_rows;
83 	uint16_t cols;
84 	uint16_t rows;
85 };
86 #endif
87 
88 #define REQUIRED_LIB_APIVERSION 4
89 
90 /* Image processing library function prototypes */
91 #define LIB_NAME_RE "libMitsuD70ImageReProcess.so" // Reimplemented library
92 
93 typedef int (*lib70x_getapiversionFN)(void);
94 typedef int (*Get3DColorTableFN)(uint8_t *buf, const char *filename);
95 typedef struct CColorConv3D *(*Load3DColorTableFN)(const uint8_t *ptr);
96 typedef void (*Destroy3DColorTableFN)(struct CColorConv3D *this);
97 typedef void (*DoColorConvFN)(struct CColorConv3D *this, uint8_t *data, uint16_t cols, uint16_t rows, uint32_t bytes_per_row, int rgb_bgr);
98 typedef struct CPCData *(*get_CPCDataFN)(const char *filename);
99 typedef void (*destroy_CPCDataFN)(struct CPCData *data);
100 typedef int (*do_image_effectFN)(struct CPCData *cpc, struct CPCData *ecpc, struct BandImage *input, struct BandImage *output, int sharpen, int reverse, uint8_t rew[2]);
101 typedef int (*send_image_dataFN)(struct BandImage *out, void *context,
102 			       int (*callback_fn)(void *context, void *buffer, uint32_t len));
103 
104 #ifndef CORRTABLE_PATH
105 #ifdef PACKAGE_DATA_DIR
106 #define CORRTABLE_PATH PACKAGE_DATA_DIR "/backend_data"
107 #else
108 #error "Must define CORRTABLE_PATH or PACKAGE_DATA_DIR!"
109 #endif
110 #endif
111 
112 #define USB_VID_MITSU       0x06D3
113 #define USB_PID_MITSU_D70X  0x3B30
114 #define USB_PID_MITSU_K60   0x3B31
115 #define USB_PID_MITSU_D80   0x3B36
116 #define USB_VID_KODAK       0x040a
117 #define USB_PID_KODAK305    0x404f
118 #define USB_VID_FUJIFILM    0x04cb
119 #define USB_PID_FUJI_ASK300 0x5006
120 
121 /* Width of the laminate data file */
122 #define LAMINATE_STRIDE 1864
123 
124 /* Max size of data chunk sent over */
125 #define CHUNK_LEN (256*1024)
126 
127 /* Private data structure */
128 struct mitsu70x_printjob {
129 	uint8_t *databuf;
130 	int datalen;
131 
132 	uint8_t *spoolbuf;
133 	int spoolbuflen;
134 
135 	uint16_t rows;
136 	uint16_t cols;
137 	uint32_t planelen;
138 	uint32_t matte;
139 	int raw_format;
140 	int copies;
141 
142 	int decks_exact[2];	 /* Media is exact match */
143 	int decks_ok[2];         /* Media can be used */
144 
145 	/* These are used only for the image processing */
146 	int sharpen; /* ie mhdr.sharpen - 1 */
147 	int reverse;
148 
149 	char *laminatefname;
150 	char *lutfname;
151 	char *cpcfname;
152 	char *ecpcfname;
153 };
154 
155 struct mitsu70x_ctx {
156 	struct libusb_device_handle *dev;
157 	uint8_t endp_up;
158 	uint8_t endp_down;
159 	int type;
160 
161 	uint16_t jobid;
162 
163 	struct marker marker[2];
164 	uint8_t medias[2];
165 
166 	uint16_t last_l;
167 	uint16_t last_u;
168 	int num_decks;
169 
170 	void *dl_handle;
171 	lib70x_getapiversionFN GetAPIVersion;
172 	Get3DColorTableFN Get3DColorTable;
173 	Load3DColorTableFN Load3DColorTable;
174 	Destroy3DColorTableFN Destroy3DColorTable;
175 	DoColorConvFN DoColorConv;
176 	get_CPCDataFN GetCPCData;
177 	destroy_CPCDataFN DestroyCPCData;
178 	do_image_effectFN DoImageEffect60;
179 	do_image_effectFN DoImageEffect70;
180 	do_image_effectFN DoImageEffect80;
181 	do_image_effectFN DoImageEffect;
182 	send_image_dataFN SendImageData;
183 
184 	struct CColorConv3D *lut;
185 	struct CPCData *cpcdata;
186 	struct CPCData *ecpcdata;
187 
188 	char *last_cpcfname;
189 	char *last_ecpcfname;
190 
191 	struct BandImage output;
192 };
193 
194 /* Printer data structures */
195 struct mitsu70x_jobstatus {
196 	uint8_t  hdr[4]; /* E4 56 31 30 */
197 	uint16_t jobid;  /* BE */
198 	uint16_t mecha_no; /* BE */
199 	uint8_t  job_status[4];
200 	uint8_t  memory;
201 	uint8_t  power;
202 	uint8_t  mecha_status[2];
203 	uint8_t  temperature;
204 	uint8_t  error_status[3];
205 	uint8_t  mecha_status_up[2];
206 	uint8_t  temperature_up;
207 	uint8_t  error_status_up[3];
208 } __attribute__((packed));
209 
210 struct mitsu70x_job {
211 	uint16_t id; /* BE */
212 	uint8_t status[4];
213 } __attribute__((packed));
214 
215 #define NUM_JOBS 170
216 
217 struct mitsu70x_jobs {
218 	uint8_t  hdr[4]; /* E4 56 31 31 */
219 	struct mitsu70x_job jobs[NUM_JOBS];
220 } __attribute__((packed));
221 
222 #define TEMPERATURE_NORMAL  0x00
223 #define TEMPERATURE_PREHEAT 0x40
224 #define TEMPERATURE_COOLING 0x80
225 
226 #define MECHA_STATUS_INIT   0x80
227 #define MECHA_STATUS_FEED   0x50
228 #define MECHA_STATUS_LOAD   0x40
229 #define MECHA_STATUS_LOAD2  0x30
230 #define MECHA_STATUS_PRINT  0x20
231 #define MECHA_STATUS_IDLE   0x00
232 
233 #define JOB_STATUS0_NONE    0x00
234 #define JOB_STATUS0_DATA    0x10
235 #define JOB_STATUS0_QUEUE   0x20
236 #define JOB_STATUS0_PRINT   0x50
237 #define JOB_STATUS0_ASSIGN  0x70 // XXX undefined.
238 #define JOB_STATUS0_END     0x80
239 
240 #define JOB_STATUS1_PRINT_MEDIALOAD  0x10
241 #define JOB_STATUS1_PRINT_PRE_Y      0x20
242 #define JOB_STATUS1_PRINT_Y          0x30
243 #define JOB_STATUS1_PRINT_PRE_M      0x40
244 #define JOB_STATUS1_PRINT_M          0x50
245 #define JOB_STATUS1_PRINT_PRE_C      0x60
246 #define JOB_STATUS1_PRINT_C          0x70
247 #define JOB_STATUS1_PRINT_PRE_OC     0x80
248 #define JOB_STATUS1_PRINT_OC         0x90
249 #define JOB_STATUS1_PRINT_EJECT      0xA0
250 
251 #define JOB_STATUS1_END_OK           0x00
252 #define JOB_STATUS1_END_MECHA        0x10 // 0x10...0x7f
253 #define JOB_STATUS1_END_HEADER       0x80
254 #define JOB_STATUS1_END_PRINT        0x90
255 #define JOB_STATUS1_END_INTERRUPT    0xA0
256 
257 #define JOB_STATUS2_END_HEADER_ERROR 0x00
258 #define JOB_STATUS2_END_HEADER_MEMORY 0x10
259 #define JOB_STATUS2_END_PRINT_MEDIA   0x00
260 #define JOB_STATUS2_END_PRINT_PREVERR 0x10
261 #define JOB_STATUS2_END_INT_TIMEOUT  0x00
262 #define JOB_STATUS2_END_INT_CANCEL   0x10
263 #define JOB_STATUS2_END_INT_DISCON   0x20
264 
265 /* Error codes */
266 #define ERROR_STATUS0_NOSTRIPBIN     0x01
267 #define ERROR_STATUS0_NORIBBON       0x02
268 #define ERROR_STATUS0_NOPAPER        0x03
269 #define ERROR_STATUS0_MEDIAMISMATCH  0x04
270 #define ERROR_STATUS0_RIBBONCNTEND   0x05
271 #define ERROR_STATUS0_BADRIBBON      0x06
272 #define ERROR_STATUS0_BADJOBPARAM    0x07
273 #define ERROR_STATUS0_PAPEREND       0x08
274 #define ERROR_STATUS0_RIBBONEND      0x09
275 #define ERROR_STATUS0_DOOROPEN_IDLE  0x0A
276 #define ERROR_STATUS0_DOOROPEN_PRNT  0x0B
277 #define ERROR_STATUS0_POWEROFF       0x0C // Powered off during printing..?
278 #define ERROR_STATUS0_NOMCOP         0x0D
279 #define ERROR_STATUS0_RIBBONSKIP1    0x0E
280 #define ERROR_STATUS0_RIBBONSKIP2    0x0F
281 #define ERROR_STATUS0_RIBBONJAM      0x10
282 #define ERROR_STATUS0_RIBBON_OTHER   0x11 // 0x11->0x1F
283 #define ERROR_STATUS0_PAPER_JAM      0x20 // 0x20->0x2F
284 #define ERROR_STATUS0_MECHANICAL     0x30 // 0x30->0x39
285 #define ERROR_STATUS0_RFID           0x3A
286 #define ERROR_STATUS0_FLASH          0x3B
287 #define ERROR_STATUS0_EEPROM         0x3C
288 #define ERROR_STATUS0_PREHEAT        0x3D
289 #define ERROR_STATUS0_MDASTATE       0x3E
290 #define ERROR_STATUS0_PSUFANLOCKED   0x3F
291 #define ERROR_STATUS0_OTHERS         0x40 // 0x40..?
292 
293 /* Error classifications */
294 #define ERROR_STATUS1_PAPER          0x01
295 #define ERROR_STATUS1_RIBBON         0x02
296 #define ERROR_STATUS1_SETTING        0x03
297 #define ERROR_STATUS1_OPEN           0x05
298 #define ERROR_STATUS1_NOSTRIPBIN     0x06
299 #define ERROR_STATUS1_PAPERJAM       0x07
300 #define ERROR_STATUS1_RIBBONSYS      0x08
301 #define ERROR_STATUS1_MECHANICAL     0x09
302 #define ERROR_STATUS1_ELECTRICAL     0x0A
303 #define ERROR_STATUS1_FIRMWARE       0x0E
304 #define ERROR_STATUS1_OTHER          0x0F
305 
306 /* Error recovery conditions */
307 #define ERROR_STATUS2_AUTO           0x00
308 #define ERROR_STATUS2_RELOAD_PAPER   0x01
309 #define ERROR_STATUS2_RELOAD_RIBBON  0x02
310 #define ERROR_STATUS2_CHANGE_BOTH    0x03
311 #define ERROR_STATUS2_CHANGE_ONE     0x04
312 #define ERROR_STATUS2_CLOSEUNIT      0x05
313 #define ERROR_STATUS2_ATTACHSTRIPBIN 0x06
314 #define ERROR_STATUS2_CLEARJAM       0x07
315 #define ERROR_STATUS2_CHECKRIBBON    0x08
316 #define ERROR_STATUS2_OPENCLOSEUNIT  0x0A
317 #define ERROR_STATUS2_POWEROFF       0x0F
318 
319 struct mitsu70x_status_deck {
320 	uint8_t  mecha_status[2];
321 	uint8_t  temperature;   /* D70/D80 family only, K60 no? */
322 	uint8_t  error_status[3];
323 	uint8_t  rsvd_a[10];    /* K60 [1] == temperature? All: [3:6] == some counter in BCD. K60 [9] == ?? */
324 	uint8_t  media_brand;
325 	uint8_t  media_type;
326 	uint8_t  rsvd_b[2];
327 	int16_t  capacity; /* media capacity */
328 	int16_t  remain;   /* media remaining */
329 	uint8_t  rsvd_c[2];
330 	uint8_t  lifetime_prints[4]; /* lifetime prints on deck + 10, in BCD! */
331 	uint8_t  rsvd_d[2]; // Unknown
332 	uint16_t rsvd_e[16]; /* all 80 00 */
333 } __attribute__((packed));
334 
335 struct mitsu70x_status_ver {
336 	char     ver[6];
337 	uint16_t checksum; /* Presumably BE */
338 } __attribute__((packed));
339 
340 struct mitsu70x_printerstatus_resp {
341 	uint8_t  hdr[4];  /* E4 56 32 30 */
342 	uint8_t  memory;
343 	uint8_t  power;
344 	uint8_t  unk[20];
345 	uint8_t  sleeptime; /* In minutes, 0-60 */
346 	uint8_t  iserial; /* 0x00 for Enabled, 0x80 for Disabled */
347 	uint8_t  unk_b[5]; // [4] == 0x44 on D70x, 0x02 on D80
348 	uint8_t  dual_deck;  /* 0x80 for dual-deck D707 */
349 	uint8_t  unk_c[6]; // [3] == 0x5f on D70x, 0x01 on D80.  [5] == 0xbd on D70x, 0x87 on D80
350 	int16_t  model[6]; /* LE, UTF-16 */
351 	int16_t  serno[6]; /* LE, UTF-16 */
352 	struct mitsu70x_status_ver vers[7]; // components are 'MLRTF'
353 	uint8_t  null[2];
354 	uint8_t  user_serno[6];  /* XXX Supposedly, don't know how to set it */
355 	struct mitsu70x_status_deck lower;
356 	struct mitsu70x_status_deck upper;
357 } __attribute__((packed));
358 
359 struct mitsu70x_memorystatus_resp {
360 	uint8_t  hdr[3]; /* E4 56 33 */
361 	uint8_t  memory;
362 	uint8_t  size;
363 	uint8_t  rsvd;
364 } __attribute__((packed));
365 
366 // XXX also seen commands 0x67, 0x72, 0x54, 0x6e
367 
368 struct mitsu70x_hdr {
369 	uint8_t  hdr[4]; /* 1b 5a 54 XX */  // XXX also, seen 1b 5a 43!
370 	uint16_t jobid;
371 	uint8_t  rewind[2];  /* K60/EK305/D80 only */
372 	uint8_t  zero0[8];
373 
374 	uint16_t cols;
375 	uint16_t rows;
376 	uint16_t lamcols;
377 	uint16_t lamrows;
378 	uint8_t  speed;
379 	uint8_t  zero1[7];
380 
381 	uint8_t  deck; /* 0 = default, 1 = lower, 2 = upper -- Non-D70/D707 is always '1' */
382 	uint8_t  zero2[7];
383 	uint8_t  laminate; /* 00 == on, 01 == off */
384 	uint8_t  laminate_mode; /* 00 == glossy, 02 == matte */
385 	uint8_t  zero3[6];
386 
387 	uint8_t  multicut;
388 	uint8_t  zero4[12]; /* NOTE:  everything past this point is an extension */
389 	uint8_t  sharpen;  /* 0-9.  5 is "normal", 0 is "off" */
390 	uint8_t  mode;     /* 0 for cooked YMC planar, 1 for packed BGR */
391 	uint8_t  use_lut;  /* in BGR mode, 0 disables, 1 enables */
392 	uint8_t  reversed; /* 1 tells the backend the row data is correct */
393 	uint8_t  pad[447];
394 } __attribute__((packed));
395 
396 static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp);
397 static int mitsu70x_main_loop(void *vctx, const void *vjob);
398 
399 /* Error dumps, etc */
400 
mitsu70x_temperatures(uint8_t temp)401 const char *mitsu70x_temperatures(uint8_t temp)
402 {
403 	switch(temp) {
404 	case TEMPERATURE_NORMAL:
405 		return "Normal";
406 	case TEMPERATURE_PREHEAT:
407 		return "Warming Up";
408 	case TEMPERATURE_COOLING:
409 		return "Cooling Down";
410 	default:
411 		break;
412 	}
413 	return "Unknown Temperature Status";
414 }
415 
mitsu70x_mechastatus(uint8_t * sts)416 static const char *mitsu70x_mechastatus(uint8_t *sts)
417 {
418 	switch(sts[0]) {
419 	case MECHA_STATUS_INIT:
420 		return "Initializing";
421 	case MECHA_STATUS_FEED:
422 		return "Paper Feeding/Cutting";
423 	case MECHA_STATUS_LOAD:
424 	case MECHA_STATUS_LOAD2:
425 		return "Media Loading";
426 	case MECHA_STATUS_PRINT:
427 		return "Printing";
428 	case MECHA_STATUS_IDLE:
429 		return "Idle";
430 	default:
431 		break;
432 	}
433 	return "Unknown Mechanical Status";
434 }
435 
mitsu70x_jobstatuses(uint8_t * sts)436 static const char *mitsu70x_jobstatuses(uint8_t *sts)
437 {
438 	switch(sts[0]) {
439 	case JOB_STATUS0_NONE:
440 		return "No Job";
441 	case JOB_STATUS0_DATA:
442 		return "Data transfer";
443 	case JOB_STATUS0_QUEUE:
444 		return "Queued for printing";
445 	case JOB_STATUS0_PRINT:
446 		switch(sts[1]) {
447 		case JOB_STATUS1_PRINT_MEDIALOAD:
448 			return "Media loading";
449 		case JOB_STATUS1_PRINT_PRE_Y:
450 			return "Waiting to print yellow plane";
451 		case JOB_STATUS1_PRINT_Y:
452 			return "Printing yellow plane";
453 		case JOB_STATUS1_PRINT_PRE_M:
454 			return "Waiting to print magenta plane";
455 		case JOB_STATUS1_PRINT_M:
456 			return "Printing magenta plane";
457 		case JOB_STATUS1_PRINT_PRE_C:
458 			return "Waiting to print cyan plane";
459 		case JOB_STATUS1_PRINT_C:
460 			return "Printing cyan plane";
461 		case JOB_STATUS1_PRINT_PRE_OC:
462 			return "Waiting to laminate page";
463 		case JOB_STATUS1_PRINT_OC:
464 			return "Laminating page";
465 		case JOB_STATUS1_PRINT_EJECT:
466 			return "Ejecting page";
467 		default:
468 			return "Unknown 'Print' status1";
469 		}
470 		break;
471 	case JOB_STATUS0_ASSIGN:
472 		return "Unknown 'Assignment' status1";
473 	case JOB_STATUS0_END:
474 		switch(sts[1]) {
475 		case JOB_STATUS1_END_OK:
476 			return "Normal End";
477 		case JOB_STATUS1_END_HEADER:
478 			switch(sts[2]) {
479 			case JOB_STATUS2_END_HEADER_ERROR:
480 				return "Incorrect Header data (bad print size?)";
481 			case JOB_STATUS2_END_HEADER_MEMORY:
482 				return "Insufficient printer memory";
483 			default:
484 				return "Unknown 'End Header' status2";
485 			}
486 			break;
487 		case JOB_STATUS1_END_PRINT:
488 			switch(sts[2]) {
489 			case JOB_STATUS2_END_PRINT_MEDIA:
490 				return "Incorrect mediasize";
491 			case JOB_STATUS2_END_PRINT_PREVERR:
492 				return "Previous job terminated abnormally";
493 			default:
494 				return "Unknown 'End Print' status2";
495 			}
496 			break;
497 		case JOB_STATUS1_END_INTERRUPT:
498 			switch(sts[2]) {
499 			case JOB_STATUS2_END_INT_TIMEOUT:
500 				return "Timeout";
501 			case JOB_STATUS2_END_INT_CANCEL:
502 				return "Job cancelled";
503 			case JOB_STATUS2_END_INT_DISCON:
504 				return "Printer disconnected";
505 			default:
506 				return "Unknown 'End Print' status2";
507 			}
508 			break;
509 		default:
510 			if (sts[1] >= 0x10 && sts[1] <= 0x7f)
511 				return "Mechanical Error";
512 			else
513 				return "Unknown 'End' status1";
514 		}
515 		break;
516 	default:
517 		break;
518 	}
519 
520 	return "Unknown status0";
521 }
522 
mitsu70x_errorclass(uint8_t * err)523 static const char *mitsu70x_errorclass(uint8_t *err)
524 {
525 	switch(err[1]) {
526 	case ERROR_STATUS1_PAPER:
527 		return "Paper";
528 	case ERROR_STATUS1_RIBBON:
529 		return "Ribbon";
530 	case ERROR_STATUS1_SETTING:
531 		return "Job settings";
532 	case ERROR_STATUS1_OPEN:
533 		return "Cover open";
534 	case ERROR_STATUS1_NOSTRIPBIN:
535 		return "No cut bin";
536 	case ERROR_STATUS1_PAPERJAM:
537 		return "Paper jam";
538 	case ERROR_STATUS1_RIBBONSYS:
539 		return "Ribbon system";
540 	case ERROR_STATUS1_MECHANICAL:
541 		return "Mechanical";
542 	case ERROR_STATUS1_ELECTRICAL:
543 		return "Electrical";
544 	case ERROR_STATUS1_FIRMWARE:
545 		return "Firmware";
546 	case ERROR_STATUS1_OTHER:
547 		return "Other";
548 	default:
549 		break;
550 	}
551 	return "Unknown error class";
552 }
553 
mitsu70x_errorrecovery(uint8_t * err)554 static const char *mitsu70x_errorrecovery(uint8_t *err)
555 {
556 	switch(err[1]) {
557 	case ERROR_STATUS2_AUTO:
558 		return "Automatic recovery";
559 	case ERROR_STATUS2_RELOAD_PAPER:
560 		return "Reload or change paper";
561 	case ERROR_STATUS2_RELOAD_RIBBON:
562 		return "Reload or change ribbon";
563 	case ERROR_STATUS2_CHANGE_BOTH:
564 		return "Change paper and ribbon";
565 	case ERROR_STATUS2_CHANGE_ONE:
566 		return "Change paper or ribbon";
567 	case ERROR_STATUS2_CLOSEUNIT:
568 		return "Close printer";
569 	case ERROR_STATUS2_ATTACHSTRIPBIN:
570 		return "Attach Strip Bin";
571 	case ERROR_STATUS2_CLEARJAM:
572 		return "Remove and reload paper";
573 	case ERROR_STATUS2_CHECKRIBBON:
574 		return "Check ribbon and reload paper";
575 	case ERROR_STATUS2_OPENCLOSEUNIT:
576 		return "Open then close printer";
577 	case ERROR_STATUS2_POWEROFF:
578 		return "Power-cycle printer";
579 	default:
580 		break;
581 	}
582 	return "Unknown recovery";
583 }
584 
mitsu70x_errors(uint8_t * err)585 static const char *mitsu70x_errors(uint8_t *err)
586 {
587 	switch(err[0]) {
588 	case ERROR_STATUS0_NOSTRIPBIN:
589 		return "Strip bin not attached";
590 	case ERROR_STATUS0_NORIBBON:
591 		return "No ribbon detected";
592 	case ERROR_STATUS0_NOPAPER:
593 		return "No paper loaded";
594 	case ERROR_STATUS0_MEDIAMISMATCH:
595 		return "Ribbon/Paper mismatch";
596 	case ERROR_STATUS0_RIBBONCNTEND:
597 		return "Ribbon count end";
598 	case ERROR_STATUS0_BADRIBBON:
599 		return "Illegal Ribbon";
600 	case ERROR_STATUS0_BADJOBPARAM:
601 		return "Job does not match loaded media";
602 	case ERROR_STATUS0_PAPEREND:
603 		return "End of paper detected";
604 	case ERROR_STATUS0_RIBBONEND:
605 		return "End of ribbon detected";
606 	case ERROR_STATUS0_DOOROPEN_IDLE:
607 	case ERROR_STATUS0_DOOROPEN_PRNT:
608 		return "Printer door open";
609 	case ERROR_STATUS0_POWEROFF:
610 		return "Printer powered off"; // nonsense..
611 	case ERROR_STATUS0_RIBBONSKIP1:
612 	case ERROR_STATUS0_RIBBONSKIP2:
613 		return "Ribbon skipped";
614 	case ERROR_STATUS0_RIBBONJAM:
615 		return "Ribbon stuck to paper";
616 	case ERROR_STATUS0_RFID:
617 		return "RFID read error";
618 	case ERROR_STATUS0_FLASH:
619 		return "FLASH read error";
620 	case ERROR_STATUS0_EEPROM:
621 		return "EEPROM read error";
622 	case ERROR_STATUS0_PREHEAT:
623 		return "Preheating unit time out";
624 	case ERROR_STATUS0_MDASTATE:
625 		return "Unknown MDA state";
626 	case ERROR_STATUS0_PSUFANLOCKED:
627 		return "Power supply fan locked up";
628 	default:
629 		break;
630 	}
631 
632 	if (err[0] >= ERROR_STATUS0_RIBBON_OTHER &&
633 	    err[0] < ERROR_STATUS0_PAPER_JAM) {
634 		return "Unknown ribbon error";
635 		// XXX use err[1]/err[2] codes?
636 	}
637 	if (err[0] >= ERROR_STATUS0_PAPER_JAM &&
638 	    err[0] < ERROR_STATUS0_MECHANICAL) {
639 		return "Paper jam";
640 		// XXX use err[1]/err[2] codes?
641 	}
642 	if (err[0] >= ERROR_STATUS0_MECHANICAL &&
643 	    err[0] < ERROR_STATUS0_RFID) {
644 		return "Unknown mechanical error";
645 		// XXX use err[1]/err[2] codes?
646 	}
647 
648 	return "Unknown error";
649 }
650 
mitsu70x_media_types(uint8_t brand,uint8_t type)651 const char *mitsu70x_media_types(uint8_t brand, uint8_t type)
652 {
653 	if (brand == 0xff && type == 0x01)
654 		return "CK-D735 (3.5x5)";
655 	else if (brand == 0xff && type == 0x02)
656 		return "CK-D746 (4x6)";
657 	else if (brand == 0xff && type == 0x04)
658 		return "CK-D757 (5x7)";
659 	else if (brand == 0xff && type == 0x05)
660 		return "CK-D769 (6x9)";
661 	else if (brand == 0xff && type == 0x0f)
662 		return "CK-D768/CK-D868 (6x8)";
663 	else if (brand == 0x6c && type == 0x84)
664 		return "Kodak 5R (5x7)";
665 	else if (brand == 0x6c && type == 0x8f)
666 		return "Kodak 6R (6x8)";
667 	else if (brand == 0x61 && type == 0x84)
668 		return "CK-K57R (5x7)";
669 	else if (brand == 0x61 && type == 0x8f)
670 		return "CK-K76R (6x8)";
671 	else if (brand == 0x7a && type == 0x01)
672 		return "RL-CF900 (3.5x5)";
673 	else if (brand == 0x7a && type == 0x02)
674 		return "RK-CF800/4R (4x6)";
675 	else if (brand == 0x7a && type == 0x04)
676 		return "R2L-CF460/5R (5x7)";
677 	else if (brand == 0x7a && type == 0x0f)
678 		return "R68-CF400/6R (6x8)";
679 	else
680 		return "Unknown";
681 
682 // Also CK-D715, CK-D718, CK-D720, CK-D723 (4x6,5x8,6x8,6x9) for D70-S model
683 //      CK-D746-U for D70-U model
684 //      CK-D820 (6x8) for D80-S model
685 // D90 can use _all_ of these types except for the -U!
686 
687 }
688 
689 #define CMDBUF_LEN 512
690 #define READBACK_LEN 256
691 
mitsu70x_init(void)692 static void *mitsu70x_init(void)
693 {
694 	struct mitsu70x_ctx *ctx = malloc(sizeof(struct mitsu70x_ctx));
695 	if (!ctx) {
696 		ERROR("Memory Allocation Failure!\n");
697 		return NULL;
698 	}
699 	memset(ctx, 0, sizeof(struct mitsu70x_ctx));
700 
701 	DL_INIT();
702 
703 	return ctx;
704 }
705 
mitsu70x_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)706 static int mitsu70x_attach(void *vctx, struct libusb_device_handle *dev, int type,
707 			   uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
708 {
709 	struct mitsu70x_ctx *ctx = vctx;
710 
711 	ctx->jobid = jobid;
712 	if (!ctx->jobid)
713 		jobid++;
714 
715 	ctx->dev = dev;
716 	ctx->endp_up = endp_up;
717 	ctx->endp_down = endp_down;
718 	ctx->type = type;
719 
720 	ctx->last_l = ctx->last_u = 65535;
721 
722 	/* Attempt to open the library */
723 #if defined(WITH_DYNAMIC)
724 	DEBUG("Attempting to load image processing library\n");
725 	ctx->dl_handle = DL_OPEN(LIB_NAME_RE);
726 	if (!ctx->dl_handle)
727 		WARNING("Image processing library not found, using internal fallback code\n");
728 	if (ctx->dl_handle) {
729 		ctx->GetAPIVersion = DL_SYM(ctx->dl_handle, "lib70x_getapiversion");
730 		if (!ctx->GetAPIVersion) {
731 			ERROR("Problem resolving API Version symbol in imaging processing library, too old or not installed?\n");
732 			DL_CLOSE(ctx->dl_handle);
733 			ctx->dl_handle = NULL;
734 			return CUPS_BACKEND_FAILED;
735 		}
736 		if (ctx->GetAPIVersion() != REQUIRED_LIB_APIVERSION) {
737 			ERROR("Image processing library API version mismatch!\n");
738 			DL_CLOSE(ctx->dl_handle);
739 			ctx->dl_handle = NULL;
740 			return CUPS_BACKEND_FAILED;
741 		}
742 
743 		ctx->Get3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Get3DColorTable");
744 		ctx->Load3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Load3DColorTable");
745 		ctx->Destroy3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Destroy3DColorTable");
746 		ctx->DoColorConv = DL_SYM(ctx->dl_handle, "CColorConv3D_DoColorConv");
747 		ctx->GetCPCData = DL_SYM(ctx->dl_handle, "get_CPCData");
748 		ctx->DestroyCPCData = DL_SYM(ctx->dl_handle, "destroy_CPCData");
749 		ctx->DoImageEffect60 = DL_SYM(ctx->dl_handle, "do_image_effect60");
750 		ctx->DoImageEffect70 = DL_SYM(ctx->dl_handle, "do_image_effect70");
751 		ctx->DoImageEffect80 = DL_SYM(ctx->dl_handle, "do_image_effect80");
752 		ctx->SendImageData = DL_SYM(ctx->dl_handle, "send_image_data");
753 		if (!ctx->Get3DColorTable || !ctx->Load3DColorTable ||
754 		    !ctx->Destroy3DColorTable || !ctx->DoColorConv ||
755 		    !ctx->GetCPCData || !ctx->DestroyCPCData ||
756 		    !ctx->DoImageEffect60 || !ctx->DoImageEffect70 ||
757 		    !ctx->DoImageEffect80 || !ctx->SendImageData) {
758 			ERROR("Problem resolving symbols in imaging processing library\n");
759 			DL_CLOSE(ctx->dl_handle);
760 			ctx->dl_handle = NULL;
761 			return CUPS_BACKEND_FAILED;
762 		} else {
763 			DEBUG("Image processing library successfully loaded\n");
764 		}
765 	}
766 
767 	switch (ctx->type) {
768 	case P_MITSU_D80:
769 		ctx->DoImageEffect = ctx->DoImageEffect80;
770 		break;
771 	case P_MITSU_K60:
772 	case P_KODAK_305:
773 		ctx->DoImageEffect = ctx->DoImageEffect60;
774 		break;
775 	default:
776 		ctx->DoImageEffect = ctx->DoImageEffect70;
777 		break;
778 	}
779 #else
780 	WARNING("Dynamic library support not enabled, using internal fallback code\n");
781 #endif
782 
783 	struct mitsu70x_printerstatus_resp resp;
784 	int ret;
785 
786 	if (test_mode < TEST_MODE_NOATTACH) {
787 		ret = mitsu70x_get_printerstatus(ctx, &resp);
788 		if (ret) {
789 			ERROR("Unable to get printer status! (%d)\n", ret);
790 			return CUPS_BACKEND_FAILED;
791 		}
792 	} else {
793 		int media_code = 0xf;
794 		if (getenv("MEDIA_CODE"))
795 			media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
796 
797 		resp.upper.mecha_status[0] = MECHA_STATUS_INIT;
798 		resp.lower.mecha_status[0] = MECHA_STATUS_INIT;
799 		resp.upper.capacity = cpu_to_be16(230);
800 		resp.lower.capacity = cpu_to_be16(230);
801 		resp.upper.remain = cpu_to_be16(200);
802 		resp.lower.remain = cpu_to_be16(200);
803 		resp.upper.media_brand = 0xff;
804 		resp.lower.media_brand = 0xff;
805 		resp.upper.media_type = media_code;
806 		resp.lower.media_type = media_code;
807 		resp.dual_deck = 0x80;  /* Make it a dual deck */
808 		resp.vers[0].ver[0] = 0;
809 	}
810 
811 	/* Figure out if we're a D707 with two decks */
812 	if (ctx->type == P_MITSU_D70X &&
813 	    resp.dual_deck == 0x80)
814 		ctx->num_decks = 2;
815 	else
816 		ctx->num_decks = 1;
817 
818 	/* Set up markers */
819 	ctx->marker[0].color = "#00FFFF#FF00FF#FFFF00";
820 	ctx->marker[0].name = mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type);
821 	ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
822 	ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
823 	ctx->medias[0] = resp.lower.media_type & 0xf;
824 
825 	if (ctx->num_decks == 2) {
826 		ctx->marker[1].color = "#00FFFF#FF00FF#FFFF00";
827 		ctx->marker[1].name = mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type);
828 		ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
829 		ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
830 		ctx->medias[1] = resp.upper.media_type & 0xf;
831 	}
832 
833 	/* FW sanity checking */
834 	if (ctx->type == P_KODAK_305) {
835 		/* Known versions:
836 		   v1.02: M 316E81 1433   (Add Ultrafine and matte support)
837 		   v1.04: M 316F83 2878   (Add 2x6 strip and support new "Triton" media)
838 		   v3.01: M 443A12 8908   (add 5" media support)
839 		*/
840 		if (strncmp(resp.vers[0].ver, "443A12", 6) < 0)
841 			WARNING("Printer FW out of date. Highly recommend upgrading EK305 to v3.01 or newer!\n");
842 	} else if (ctx->type == P_MITSU_K60) {
843 		/* Known versions:
844 		   v1.05: M 316M31 148C   (Add HG media support)
845 		*/
846 		if (strncmp(resp.vers[0].ver, "316M31", 6) < 0)
847 			WARNING("Printer FW out of date. Highly recommend upgrading K60 to v1.05 or newer!\n");
848 	} else if (ctx->type == P_MITSU_D70X) {
849 		/* Known versions:
850 		   v1.10: M 316V11 064D   (Add ultrafine mode, 6x6 support, 2x6 strip, and more?)
851 		   v1.12: M 316W11 9FC3   (??)
852 		   v1.13:                 (??)
853 		*/
854 		if (strncmp(resp.vers[0].ver, "316W11", 6) < 0)
855 			WARNING("Printer FW out of date. Highly recommend upgrading D70/D707 to v1.12 or newer!\n");
856 	} else if (ctx->type == P_FUJI_ASK300) {
857 		/* Known versions:
858 		   v?.??: M 316A21 7998   (ancient. no matte or ultrafine)
859 		   v?.??: M 316H21 F8EB
860 		   v4.20a: M 316J21 4431  (Add 2x6 strip support)
861 		*/
862 		if (strncmp(resp.vers[0].ver, "316J21", 6) < 0)
863 			WARNING("Printer FW out of date. Highly recommend upgrading ASK300 to v4.20a or newer!\n");
864 	}
865 
866 	return CUPS_BACKEND_OK;
867 }
868 
mitsu70x_cleanup_job(const void * vjob)869 static void mitsu70x_cleanup_job(const void *vjob) {
870 	const struct mitsu70x_printjob *job = vjob;
871 
872 	if (job->databuf)
873 		free(job->databuf);
874 	if (job->spoolbuf)
875 		free(job->spoolbuf);
876 
877 	free((void*)job);
878 }
879 
mitsu70x_teardown(void * vctx)880 static void mitsu70x_teardown(void *vctx) {
881 	struct mitsu70x_ctx *ctx = vctx;
882 
883 	if (!ctx)
884 		return;
885 
886 	if (ctx->dl_handle) {
887 		if (ctx->cpcdata)
888 			ctx->DestroyCPCData(ctx->cpcdata);
889 		if (ctx->ecpcdata)
890 			ctx->DestroyCPCData(ctx->ecpcdata);
891 		if (ctx->lut)
892 			ctx->Destroy3DColorTable(ctx->lut);
893 		DL_CLOSE(ctx->dl_handle);
894 	}
895 
896 	DL_EXIT();
897 
898 	free(ctx);
899 }
900 
901 #define JOB_EQUIV(__x)  if (job1->__x != job2->__x) goto done
902 
combine_jobs(const struct mitsu70x_printjob * job1,const struct mitsu70x_printjob * job2)903 static struct mitsu70x_printjob *combine_jobs(const struct mitsu70x_printjob *job1,
904 					      const struct mitsu70x_printjob *job2)
905 {
906 	struct mitsu70x_printjob *newjob = NULL;
907 	uint16_t newrows;
908 	uint16_t newcols;
909 	uint32_t newpad, finalpad;
910 	uint16_t lamoffset;
911 
912 	const struct mitsu70x_hdr *hdr1, *hdr2;
913 	struct mitsu70x_hdr *newhdr;
914 
915         /* Sanity check */
916         if (!job1 || !job2)
917                 goto done;
918 
919 	hdr1 = (struct mitsu70x_hdr *) job1->databuf;
920 	hdr2 = (struct mitsu70x_hdr *) job2->databuf;
921 
922 	JOB_EQUIV(rows);
923 	JOB_EQUIV(cols);
924 	JOB_EQUIV(matte);
925 	JOB_EQUIV(sharpen);
926 
927 	if (hdr1->multicut || hdr2->multicut)
928 		goto done;
929 	if (job1->raw_format || job2->raw_format)
930 		goto done;
931 	if (hdr1->speed != hdr2->speed)
932 		goto done;
933 
934 	switch (job1->rows) {
935 	case 1218:  /* K60, EK305 */
936 		newrows = 2454;
937 		newpad = 16;
938 		finalpad = 0;
939 		lamoffset = 0;
940 		break;
941 	case 1228:  /* D70, ASK300, D80 */
942 		newrows = 2730;
943 		newpad = 38;
944 		finalpad = 236;
945 		lamoffset = 12;
946 		break;
947 	case 1076: /* EK305, K60 3.5x5" prints */
948 		newrows = 2190;
949 		newpad = 49;
950 		finalpad = 0;
951 		lamoffset = 0;
952 		break;
953 	default:
954 		goto done;
955 	}
956 	newcols = job1->cols;
957 	newpad *= newcols;
958 	finalpad *= newcols;
959 
960 	/* Okay, it's kosher to proceed */
961 
962 	DEBUG("Combining jobs to save media\n");
963 
964         newjob = malloc(sizeof(*newjob));
965         if (!newjob) {
966                 ERROR("Memory allocation failure!\n");
967                 goto done;
968         }
969         memcpy(newjob, job1, sizeof(*newjob));
970 
971 	newjob->spoolbuf = NULL;
972 	newjob->rows = newrows;
973 	newjob->cols = newcols;
974 	newjob->planelen = (((newrows * newcols * 2) + 511) /512) * 512;
975 	if (newjob->matte) {
976 		newjob->matte = ((((newrows + lamoffset) * newcols * 2) + 511) / 512) * 512;
977 	}
978         newjob->databuf = malloc(sizeof(*newhdr) + newjob->planelen * 3 + newjob->matte);
979         newjob->datalen = 0;
980         if (!newjob->databuf) {
981 		mitsu70x_cleanup_job(newjob);
982 		newjob = NULL;
983                 ERROR("Memory allocation failure!\n");
984                 goto done;
985         }
986 	newhdr = (struct mitsu70x_hdr *) newjob->databuf;
987 
988 	/* Copy over header */
989 	memcpy(newhdr, hdr1, sizeof(*newhdr));
990 	newjob->datalen += sizeof(*newhdr);
991 
992 	newhdr->rows = cpu_to_be16(newrows);
993 	newhdr->cols = cpu_to_be16(newcols);
994 
995 	if (newjob->matte) {
996 		newhdr->lamrows = cpu_to_be16(newrows + lamoffset);
997 		newhdr->lamcols = cpu_to_be16(newcols);
998 	}
999 	newhdr->multicut = 1;
1000 	newhdr->deck = 0;  /* Let printer decide */
1001 
1002 	newjob->spoolbuf = malloc(newrows * newcols * 3);
1003 	newjob->spoolbuflen = 0;
1004 	if (!newjob->spoolbuf) {
1005 		mitsu70x_cleanup_job(newjob);
1006 		newjob = NULL;
1007                 ERROR("Memory allocation failure!\n");
1008                 goto done;
1009 	}
1010 
1011 	/* Fill in padding */
1012 	memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, finalpad * 3);
1013 	newjob->spoolbuflen += finalpad * 3;
1014 
1015 	/* Copy image payload */
1016 	memcpy(newjob->spoolbuf + newjob->spoolbuflen, job1->spoolbuf,
1017 	       job1->spoolbuflen);
1018 	newjob->spoolbuflen += job1->spoolbuflen;
1019 
1020 	/* Fill in padding */
1021 	memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, newpad * 3);
1022 	newjob->spoolbuflen += newpad * 3;
1023 
1024 	/* Copy image payload */
1025 	memcpy(newjob->spoolbuf + newjob->spoolbuflen, job2->spoolbuf,
1026 	       job2->spoolbuflen);
1027 	newjob->spoolbuflen += job2->spoolbuflen;
1028 
1029 	/* Okay, we're done. */
1030 
1031 done:
1032 	return newjob;
1033 }
1034 #undef JOB_EQUIV
1035 
mitsu70x_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)1036 static int mitsu70x_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
1037 	struct mitsu70x_ctx *ctx = vctx;
1038 	int i, remain;
1039 	struct mitsu70x_hdr mhdr;
1040 
1041 	struct mitsu70x_printjob *job = NULL;
1042 	struct dyesub_joblist *list;
1043 	int can_combine;
1044 
1045 	if (!ctx)
1046 		return CUPS_BACKEND_FAILED;
1047 
1048 	job = malloc(sizeof(*job));
1049 	if (!job) {
1050 		ERROR("Memory allocation failure!\n");
1051 		return CUPS_BACKEND_RETRY_CURRENT;
1052 	}
1053 	memset(job, 0, sizeof(*job));
1054 	job->copies = copies;
1055 
1056 repeat:
1057 	/* Read in initial header */
1058 	remain = sizeof(mhdr);
1059 	while (remain > 0) {
1060 		i = read(data_fd, ((uint8_t*)&mhdr) + sizeof(mhdr) - remain, remain);
1061 		if (i == 0) {
1062 			mitsu70x_cleanup_job(job);
1063 			return CUPS_BACKEND_CANCEL;
1064 		}
1065 		if (i < 0) {
1066 			mitsu70x_cleanup_job(job);
1067 			return CUPS_BACKEND_CANCEL;
1068 		}
1069 		remain -= i;
1070 	}
1071 
1072 	/* Skip over wakeup header if it's present. */
1073 	if (mhdr.hdr[0] == 0x1b &&
1074 	    mhdr.hdr[1] == 0x45 &&
1075 	    mhdr.hdr[2] == 0x57 &&
1076 	    mhdr.hdr[3] == 0x55) {
1077 		goto repeat;
1078 	}
1079 
1080 	/* Sanity check header */
1081 	if (mhdr.hdr[0] != 0x1b ||
1082 	    mhdr.hdr[1] != 0x5a ||
1083 	    mhdr.hdr[2] != 0x54) {
1084 		ERROR("Unrecognized data format!\n");
1085 		mitsu70x_cleanup_job(job);
1086 		return CUPS_BACKEND_CANCEL;
1087 	}
1088 
1089 	job->raw_format = !mhdr.mode;
1090 
1091 	/* Sanity check Matte mode */
1092 	if (!mhdr.laminate && mhdr.laminate_mode) {
1093 		if (ctx->type != P_MITSU_D70X) {
1094 			if (mhdr.speed != 0x03 && mhdr.speed != 0x04) {
1095 				WARNING("Forcing Ultrafine mode for matte printing!\n");
1096 				mhdr.speed = 0x04; /* Force UltraFine */
1097 			}
1098 		} else {
1099 			if (mhdr.speed != 0x03) {
1100 				mhdr.speed = 0x03; /* Force SuperFine */
1101 				WARNING("Forcing SuperFine mode for matte printing!\n");
1102 			}
1103 		}
1104 	}
1105 
1106 	/* Figure out the correction data table to use */
1107 	if (ctx->type == P_MITSU_D70X) {
1108 		job->laminatefname = CORRTABLE_PATH "/D70MAT01.raw";
1109 		job->lutfname = CORRTABLE_PATH "/CPD70L01.lut";
1110 
1111 		if (mhdr.speed == 3) {
1112 			job->cpcfname = CORRTABLE_PATH "/CPD70S01.cpc";
1113 		} else if (mhdr.speed == 4) {
1114 			job->cpcfname = CORRTABLE_PATH "/CPD70U01.cpc";
1115 		} else {
1116 			job->cpcfname = CORRTABLE_PATH "/CPD70N01.cpc";
1117 		}
1118 		if (mhdr.hdr[3] != 0x01) {
1119 			WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1120 			mhdr.hdr[3] = 0x01;
1121 		}
1122 	} else if (ctx->type == P_MITSU_D80) {
1123 		job->laminatefname = CORRTABLE_PATH "/D80MAT01.raw";
1124 		job->lutfname = CORRTABLE_PATH "/CPD80L01.lut";
1125 
1126 		if (mhdr.speed == 3) {
1127 			job->cpcfname = CORRTABLE_PATH "/CPD80S01.cpc";
1128 			job->ecpcfname = CORRTABLE_PATH "/CPD80E01.cpc";
1129 		} else if (mhdr.speed == 4) {
1130 			job->cpcfname = CORRTABLE_PATH "/CPD80U01.cpc";
1131 			job->ecpcfname = NULL;
1132 		} else {
1133 			job->cpcfname = CORRTABLE_PATH "/CPD80N01.cpc";
1134 			job->ecpcfname = NULL;
1135 		}
1136 		if (mhdr.hdr[3] != 0x01) {
1137 			WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1138 			mhdr.hdr[3] = 0x01;
1139 		}
1140 	} else if (ctx->type == P_MITSU_K60) {
1141 		job->laminatefname = CORRTABLE_PATH "/S60MAT02.raw";
1142 		job->lutfname = CORRTABLE_PATH "/CPS60L01.lut";
1143 
1144 		if (mhdr.speed == 3 || mhdr.speed == 4) {
1145 			mhdr.speed = 4; /* Ultra Fine */
1146 			job->cpcfname = CORRTABLE_PATH "/CPS60T03.cpc";
1147 		} else {
1148 			job->cpcfname = CORRTABLE_PATH "/CPS60T01.cpc";
1149 		}
1150 		if (mhdr.hdr[3] != 0x00) {
1151 			WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1152 			mhdr.hdr[3] = 0x00;
1153 		}
1154 	} else if (ctx->type == P_KODAK_305) {
1155 		job->laminatefname = CORRTABLE_PATH "/EK305MAT.raw"; // Same as K60
1156 		job->lutfname = CORRTABLE_PATH "/EK305L01.lut";
1157 
1158 		if (mhdr.speed == 3 || mhdr.speed == 4) {
1159 			mhdr.speed = 4; /* Ultra Fine */
1160 			job->cpcfname = CORRTABLE_PATH "/EK305T03.cpc";
1161 		} else {
1162 			job->cpcfname = CORRTABLE_PATH "/EK305T01.cpc";
1163 		}
1164 		// XXX what about using K60 media if we read back the proper code?
1165 		if (mhdr.hdr[3] != 0x90) {
1166 			WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1167 			mhdr.hdr[3] = 0x90;
1168 		}
1169 	} else if (ctx->type == P_FUJI_ASK300) {
1170 		job->laminatefname = CORRTABLE_PATH "/ASK300M2.raw"; // Same as D70
1171 //		job->lutfname = CORRTABLE_PATH "/CPD70L01.lut";  // XXX guess, driver did not come with external LUT!
1172 		if (mhdr.speed == 3 || mhdr.speed == 4) {
1173 			mhdr.speed = 3; /* Super Fine */
1174 			job->cpcfname = CORRTABLE_PATH "/ASK300T3.cpc";
1175 		} else {
1176 			job->cpcfname = CORRTABLE_PATH "/ASK300T1.cpc";
1177 		}
1178 		if (mhdr.hdr[3] != 0x80) {
1179 			WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1180 			mhdr.hdr[3] = 0x80;
1181 		}
1182 	}
1183 	if (!mhdr.use_lut)
1184 		job->lutfname = NULL;
1185 
1186 	job->sharpen = mhdr.sharpen - 1;
1187 	job->reverse = !mhdr.reversed;
1188 
1189 	/* Clean up header back to pristine. */
1190 	mhdr.use_lut = 0;
1191 	mhdr.mode = 0;
1192 	mhdr.sharpen = 0;
1193 	mhdr.reversed = 0;
1194 
1195 	/* Work out total printjob size */
1196 	job->cols = be16_to_cpu(mhdr.cols);
1197 	job->rows = be16_to_cpu(mhdr.rows);
1198 
1199 	job->planelen = job->rows * job->cols * 2;
1200 	job->planelen = (job->planelen + 511) / 512 * 512; /* Round to nearest 512 bytes. */
1201 
1202 	if (!mhdr.laminate && mhdr.laminate_mode) {
1203 		i = be16_to_cpu(mhdr.lamcols) * be16_to_cpu(mhdr.lamrows) * 2;
1204 		i = (i + 511) / 512 * 512; /* Round to nearest 512 bytes. */
1205 		job->matte = i;
1206 	}
1207 
1208 	remain = 3 * job->planelen + job->matte;
1209 
1210 	job->datalen = 0;
1211 	job->databuf = malloc(sizeof(mhdr) + remain + LAMINATE_STRIDE*2);  /* Give us a bit extra */
1212 
1213 	if (!job->databuf) {
1214 		ERROR("Memory allocation failure!\n");
1215 		mitsu70x_cleanup_job(job);
1216 		return CUPS_BACKEND_RETRY_CURRENT;
1217 	}
1218 
1219 	memcpy(job->databuf + job->datalen, &mhdr, sizeof(mhdr));
1220 	job->datalen += sizeof(mhdr);
1221 
1222 	if (job->raw_format) { /* RAW MODE */
1223 		DEBUG("Reading in %d bytes of 16bpp YMCL data\n", remain);
1224 
1225 		/* Read in the spool data */
1226 		while(remain) {
1227 			i = read(data_fd, job->databuf + job->datalen, remain);
1228 			if (i == 0) {
1229 				mitsu70x_cleanup_job(job);
1230 				return CUPS_BACKEND_CANCEL;
1231 			}
1232 			if (i < 0) {
1233 				mitsu70x_cleanup_job(job);
1234 				return CUPS_BACKEND_CANCEL;
1235 			}
1236 			job->datalen += i;
1237 			remain -= i;
1238 		}
1239 		goto done;
1240 	}
1241 
1242 	/* Non-RAW mode! */
1243 
1244 	remain = job->rows * job->cols * 3;
1245 	DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
1246 
1247 	job->spoolbuflen = 0;
1248 	job->spoolbuf = malloc(remain);
1249 	if (!job->spoolbuf) {
1250 		ERROR("Memory allocation failure!\n");
1251 		mitsu70x_cleanup_job(job);
1252 		return CUPS_BACKEND_RETRY_CURRENT;
1253 	}
1254 
1255 	/* Read in the BGR data */
1256 	while (remain) {
1257 		i = read(data_fd, job->spoolbuf + job->spoolbuflen, remain);
1258 		if (i == 0) {
1259 			mitsu70x_cleanup_job(job);
1260 			return CUPS_BACKEND_CANCEL;
1261 		}
1262 		if (i < 0) {
1263 			mitsu70x_cleanup_job(job);
1264 			return CUPS_BACKEND_CANCEL;
1265 		}
1266 		job->spoolbuflen += i;
1267 		remain -= i;
1268 	}
1269 
1270 	if (!ctx->dl_handle) {
1271 		// XXXFALLBACK write fallback code?
1272 		ERROR("!!! Image Processing Library not found, aborting!\n");
1273 		mitsu70x_cleanup_job(job);
1274 		return CUPS_BACKEND_CANCEL;
1275 	}
1276 
1277 	/* Run through basic LUT, if present and enabled */
1278 	if (job->lutfname && !ctx->lut) {  /* printer-specific, it is fixed per-job */
1279 		uint8_t *buf = malloc(LUT_LEN);
1280 		if (!buf) {
1281 			ERROR("Memory allocation failure!\n");
1282 			mitsu70x_cleanup_job(job);
1283 			return CUPS_BACKEND_RETRY_CURRENT;
1284 		}
1285 		if (ctx->Get3DColorTable(buf, job->lutfname)) {
1286 			ERROR("Unable to open LUT file '%s'\n", job->lutfname);
1287 			mitsu70x_cleanup_job(job);
1288 			return CUPS_BACKEND_CANCEL;
1289 		}
1290 		ctx->lut = ctx->Load3DColorTable(buf);
1291 		free(buf);
1292 		if (!ctx->lut) {
1293 			ERROR("Unable to parse LUT file '%s'!\n", job->lutfname);
1294 			mitsu70x_cleanup_job(job);
1295 			return CUPS_BACKEND_CANCEL;
1296 		}
1297 	}
1298 
1299 	if (job->lutfname && ctx->lut) {
1300 		DEBUG("Running print data through 3D LUT\n");
1301 		ctx->DoColorConv(ctx->lut, job->spoolbuf, job->cols, job->rows, job->cols * 3, COLORCONV_BGR);
1302 	}
1303 
1304 done:
1305 	list = dyesub_joblist_create(&mitsu70x_backend, ctx);
1306 
1307 	for (i = 0 ; i < ctx->num_decks ; i++) {
1308 		switch (ctx->medias[i]) {
1309 		case 0x1: // 5x3.5
1310 			if (job->rows == 1076)
1311 				job->decks_ok[i] = 1;
1312 			if (job->rows == 1076)
1313 				job->decks_exact[i] = 1;
1314 			break;
1315 		case 0x2: // 4x6
1316 			if (job->rows == 1218 ||
1317 			    job->rows == 1228)
1318 				job->decks_ok[i] = 1;
1319 			if (job->rows == 1218 ||
1320 			    job->rows == 1228)
1321 				job->decks_exact[i] = 1;
1322 			break;
1323 		case 0x4: // 5x7
1324 			if (job->rows == 1076 ||
1325 			    job->rows == 1524 ||
1326 			    job->rows == 2128)
1327 				job->decks_ok[i] = 1;
1328 			if (job->rows == 1524 ||
1329 			    job->rows == 2128)
1330 				job->decks_exact[i] = 1;
1331 			break;
1332 		case 0x5: // 6x9
1333 		case 0xf: // 6x8
1334 			/* This is made more complicated:
1335 			   some 6x8" jobs are 6x9" sized.  Let printer
1336 			   sort these out.  It's unlikely we'll have
1337 			   6x8" in one deck and 6x9" in the other!
1338 			*/
1339 			if (job->rows == 1218 ||
1340 			    job->rows == 1228 ||
1341 			    job->rows == 1820 ||
1342 			    job->rows == 2422 ||
1343 			    job->rows == 2564 ||
1344 			    job->rows == 2730)
1345 				job->decks_ok[i] = 1;
1346 			if (job->rows == 2422 ||
1347 			    job->rows == 2564 ||
1348 			    job->rows == 2730)
1349 				job->decks_exact[i] = 1;
1350 			break;
1351 		default:
1352 			job->decks_ok[i] = 0;
1353 			job->decks_exact[i] = 0;
1354 			break;
1355 		}
1356 	}
1357 
1358 	/* 6x4 can be combined, only on 6x8/6x9" media. */
1359 	can_combine = 0;
1360 	if (job->decks_exact[0] ||
1361 	    job->decks_exact[1]) {
1362 		/* Exact media match, don't combine. */
1363 	} else if (job->rows == 1218 ||
1364 		   job->rows == 1228) {
1365 		if (ctx->medias[0] == 0xf ||
1366 		    ctx->medias[0] == 0x5 ||
1367 		    ctx->medias[1] == 0xf || /* Two decks possible */
1368 		    ctx->medias[1] == 0x5)
1369 			can_combine = !job->raw_format;
1370 	} else if (job->rows == 1076) {
1371 		if (ctx->type == P_KODAK_305 ||
1372 		    ctx->type == P_MITSU_K60) {
1373 			if (ctx->medias[0] == 0x4)  /* Only one deck */
1374 				can_combine = !job->raw_format;
1375 		}
1376 	}
1377 
1378 	if (copies > 1 && can_combine) {
1379 		struct mitsu70x_printjob *combined;
1380                 combined = combine_jobs(job, job);
1381                 if (combined) {
1382                         combined->copies = job->copies / 2;
1383 			dyesub_joblist_addjob(list, combined);
1384 
1385 			if (job->copies & 1) {
1386 				job->copies = 1;
1387 			} else {
1388 				mitsu70x_cleanup_job(job);
1389 				job = NULL;
1390 			}
1391 		}
1392 	}
1393 
1394 	if (job) {
1395 		dyesub_joblist_addjob(list, job);
1396 	}
1397 
1398 	/* All further work is in main loop */
1399 	if (test_mode >= TEST_MODE_NOPRINT)
1400 		dyesub_joblist_print(list);
1401 
1402 	*vjob = list;
1403 
1404 	return CUPS_BACKEND_OK;
1405 }
1406 
mitsu70x_get_jobstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_jobstatus * resp,uint16_t jobid)1407 static int mitsu70x_get_jobstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_jobstatus *resp, uint16_t jobid)
1408 {
1409 	uint8_t cmdbuf[CMDBUF_LEN];
1410 	int num, ret;
1411 
1412 	/* Send Printer Query */
1413 	memset(cmdbuf, 0, CMDBUF_LEN);
1414 	cmdbuf[0] = 0x1b;
1415 	cmdbuf[1] = 0x56;
1416 	cmdbuf[2] = 0x31;
1417 	cmdbuf[3] = 0x30;  // XXX 30 == specific, 31 = "all"
1418 
1419 	cmdbuf[4] = (jobid >> 8) & 0xff;
1420 	cmdbuf[5] = jobid & 0xff;
1421 
1422 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1423 			     cmdbuf, 6)))
1424 		return ret;
1425 
1426 	memset(resp, 0, sizeof(*resp));
1427 
1428 	ret = read_data(ctx->dev, ctx->endp_up,
1429 			(uint8_t*) resp, sizeof(*resp), &num);
1430 
1431 	if (ret < 0)
1432 		return ret;
1433 	if (num != sizeof(*resp)) {
1434 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1435 		return 4;
1436 	}
1437 
1438 	return 0;
1439 }
1440 
1441 #if 0
1442 static int mitsu70x_get_jobs(struct mitsu70x_ctx *ctx, struct mitsu70x_jobs *resp)
1443 {
1444 	uint8_t cmdbuf[CMDBUF_LEN];
1445 	int num, ret;
1446 
1447 	/* Send Printer Query */
1448 	memset(cmdbuf, 0, CMDBUF_LEN);
1449 	cmdbuf[0] = 0x1b;
1450 	cmdbuf[1] = 0x56;
1451 	cmdbuf[2] = 0x31;
1452 	cmdbuf[3] = 0x31;
1453 	cmdbuf[4] = 0x00;
1454 	cmdbuf[5] = 0x00;
1455 
1456 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1457 			     cmdbuf, 6)))
1458 		return ret;
1459 
1460 	memset(resp, 0, sizeof(*resp));
1461 
1462 	ret = read_data(ctx->dev, ctx->endp_up,
1463 			(uint8_t*) resp, sizeof(*resp), &num);
1464 
1465 	if (ret < 0)
1466 		return ret;
1467 	if (num != sizeof(*resp)) {
1468 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1469 		return 4;
1470 	}
1471 
1472 	return 0;
1473 }
1474 #endif
1475 
mitsu70x_get_memorystatus(struct mitsu70x_ctx * ctx,const struct mitsu70x_printjob * job,uint8_t mcut,struct mitsu70x_memorystatus_resp * resp)1476 static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, const struct mitsu70x_printjob *job, uint8_t mcut, struct mitsu70x_memorystatus_resp *resp)
1477 {
1478 	uint8_t cmdbuf[CMDBUF_LEN];
1479 
1480 	uint16_t tmp;
1481 
1482 	int num;
1483 	int ret;
1484 
1485 	memset(cmdbuf, 0, CMDBUF_LEN);
1486 	cmdbuf[0] = 0x1b;
1487 	cmdbuf[1] = 0x56;
1488 	cmdbuf[2] = 0x33;
1489 	cmdbuf[3] = 0x00;
1490 	tmp = cpu_to_be16(job->cols);
1491 	memcpy(cmdbuf + 4, &tmp, 2);
1492 
1493 	/* We have to lie about print sizes in 4x6*2 multicut modes */
1494 	tmp = job->rows;
1495 	if (tmp == 2730 && mcut == 1) {
1496 		if (ctx->type == P_MITSU_D70X ||
1497 		    ctx->type == P_FUJI_ASK300) {
1498 			tmp = 2422;
1499 		}
1500 	}
1501 
1502 	tmp = cpu_to_be16(tmp);
1503 	memcpy(cmdbuf + 6, &tmp, 2);
1504 	cmdbuf[8] = job->matte ? 0x80 : 0x00;
1505 	cmdbuf[9] = 0x00;
1506 
1507 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1508 			     cmdbuf, 10)))
1509 		return CUPS_BACKEND_FAILED;
1510 
1511 	/* Read in the printer status */
1512 	ret = read_data(ctx->dev, ctx->endp_up,
1513 			(uint8_t*) resp, sizeof(*resp), &num);
1514 	if (ret < 0)
1515 		return CUPS_BACKEND_FAILED;
1516 
1517 	if (num != sizeof(*resp)) {
1518 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1519 		return CUPS_BACKEND_FAILED;
1520 	}
1521 
1522 	/* Make sure response is sane */
1523 	if (resp->hdr[0] != 0xe4 ||
1524 	    resp->hdr[1] != 0x56 ||
1525 	    resp->hdr[2] != 0x33) {
1526 		ERROR("Unknown response from printer\n");
1527 		return CUPS_BACKEND_FAILED;
1528 	}
1529 
1530 	return 0;
1531 }
1532 
mitsu70x_get_printerstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_printerstatus_resp * resp)1533 static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp)
1534 {
1535 	uint8_t cmdbuf[CMDBUF_LEN];
1536 	int num, ret;
1537 
1538 	/* Send Printer Query */
1539 	memset(cmdbuf, 0, CMDBUF_LEN);
1540 	cmdbuf[0] = 0x1b;
1541 	cmdbuf[1] = 0x56;
1542 	cmdbuf[2] = 0x32;
1543 	cmdbuf[3] = 0x30; /* or x31 or x32, for SINGLE DECK query!
1544 			     Results will only have one deck. */
1545 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1546 			     cmdbuf, 4)))
1547 		return ret;
1548 	memset(resp, 0, sizeof(*resp));
1549 	ret = read_data(ctx->dev, ctx->endp_up,
1550 			(uint8_t*) resp, sizeof(*resp), &num);
1551 
1552 	if (ret < 0)
1553 		return ret;
1554 	if (num != sizeof(*resp)) {
1555 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1556 		return 4;
1557 	}
1558 
1559 	return 0;
1560 }
1561 
mitsu70x_cancel_job(struct mitsu70x_ctx * ctx,uint16_t jobid)1562 static int mitsu70x_cancel_job(struct mitsu70x_ctx *ctx, uint16_t jobid)
1563 {
1564 	uint8_t cmdbuf[4];
1565 	int ret;
1566 
1567 	/* Send Job cancel.  No response. */
1568 	memset(cmdbuf, 0, 4);
1569 	cmdbuf[0] = 0x1b;
1570 	cmdbuf[1] = 0x44;
1571 	cmdbuf[2] = (jobid >> 8) & 0xff;
1572 	cmdbuf[3] = jobid & 0xff;
1573 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1574 			     cmdbuf, 4)))
1575 		return ret;
1576 
1577 	return 0;
1578 }
1579 
mitsu70x_set_sleeptime(struct mitsu70x_ctx * ctx,uint8_t time)1580 static int mitsu70x_set_sleeptime(struct mitsu70x_ctx *ctx, uint8_t time)
1581 {
1582 	uint8_t cmdbuf[4];
1583 	int ret;
1584 
1585 	/* 60 minutes max, according to all docs. */
1586 	if (time > 60)
1587 		time = 60;
1588 
1589 	/* Send Parameter.. */
1590 	memset(cmdbuf, 0, 4);
1591 	cmdbuf[0] = 0x1b;
1592 	cmdbuf[1] = 0x53;
1593 	cmdbuf[2] = 0x53;
1594 	cmdbuf[3] = time;
1595 
1596 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1597 			     cmdbuf, 4)))
1598 		return ret;
1599 
1600 	return 0;
1601 }
1602 
mitsu70x_set_iserial(struct mitsu70x_ctx * ctx,uint8_t enabled)1603 static int mitsu70x_set_iserial(struct mitsu70x_ctx *ctx, uint8_t enabled)
1604 {
1605 	uint8_t cmdbuf[4];
1606 	int ret;
1607 
1608 	if (enabled)
1609 		enabled = 0;
1610 	else
1611 		enabled = 0x80;
1612 
1613 	/* Send Parameter.. */
1614 	memset(cmdbuf, 0, 4);
1615 	cmdbuf[0] = 0x1b;
1616 	cmdbuf[1] = 0x53;
1617 	cmdbuf[2] = 0x4e;
1618 	cmdbuf[3] = enabled;
1619 
1620 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1621 			     cmdbuf, 4)))
1622 		return ret;
1623 
1624 	return 0;
1625 }
1626 
1627 #if 0
1628 /* Switches between "Driver" and "SDK" modes.
1629    Single-endpoint vs Multi-Endpoint, essentially.
1630    Not sure about the polarity.
1631  */
1632 static int mitsu70x_set_printermode(struct mitsu70x_ctx *ctx, uint8_t enabled)
1633 {
1634 	uint8_t cmdbuf[4];
1635 	int ret;
1636 
1637 	if (enabled)
1638 		enabled = 0;
1639 	else
1640 		enabled = 0x80;
1641 
1642 	/* Send Parameter.. */
1643 	memset(cmdbuf, 0, 4);
1644 	cmdbuf[0] = 0x1b;
1645 	cmdbuf[1] = 0x53;
1646 	cmdbuf[2] = 0x50;
1647 	cmdbuf[3] = enabled;
1648 
1649 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1650 			     cmdbuf, 4)))
1651 		return ret;
1652 
1653 	return 0;
1654 }
1655 #endif
1656 
mitsu70x_wakeup(struct mitsu70x_ctx * ctx,int wait)1657 static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx, int wait)
1658 {
1659 	int ret;
1660 	uint8_t buf[512];
1661 	struct mitsu70x_jobstatus jobstatus;
1662 
1663 top:
1664 	/* Query job status for jobid 0 (global) */
1665 	ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
1666 	if (ret)
1667 		return CUPS_BACKEND_FAILED;
1668 
1669 	/* Trigger a wakeup if necessary */
1670 	if (jobstatus.power) {
1671 		INFO("Waking up printer...\n");
1672 
1673 		memset(buf, 0, sizeof(buf));
1674 		buf[0] = 0x1b;
1675 		buf[1] = 0x45;
1676 		buf[2] = 0x57; // XXX also, 0x53, 0x54 seen.
1677 		buf[3] = 0x55;
1678 
1679 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1680 				     buf, sizeof(buf))))
1681 			return CUPS_BACKEND_FAILED;
1682 
1683 		if (wait) {
1684 			sleep(1);
1685 			goto top;
1686 		}
1687 	}
1688 
1689 
1690 	return CUPS_BACKEND_OK;
1691 }
1692 
d70_library_callback(void * context,void * buffer,uint32_t len)1693 static int d70_library_callback(void *context, void *buffer, uint32_t len)
1694 {
1695 	uint32_t chunk = len;
1696 	uint32_t offset = 0;
1697 	int ret = 0;
1698 
1699 	struct mitsu70x_ctx *ctx = context;
1700 
1701 	while (chunk > 0) {
1702 		if (chunk > CHUNK_LEN)
1703 			chunk = CHUNK_LEN;
1704 
1705 		ret = send_data(ctx->dev, ctx->endp_down, (uint8_t*)buffer + offset, chunk);
1706 		if (ret < 0)
1707 			break;
1708 
1709 		offset += chunk;
1710 		chunk = len - offset;
1711 	}
1712 
1713 	return ret;
1714 }
1715 
mitsu70x_main_loop(void * vctx,const void * vjob)1716 static int mitsu70x_main_loop(void *vctx, const void *vjob)
1717 {
1718 	struct mitsu70x_ctx *ctx = vctx;
1719 	struct mitsu70x_jobstatus jobstatus;
1720 	struct mitsu70x_printerstatus_resp resp;
1721 	struct mitsu70x_hdr *hdr;
1722 	uint8_t last_status[4] = {0xff, 0xff, 0xff, 0xff};
1723 
1724 	int ret;
1725 	int copies;
1726 	int deck, legal, reqdeck;
1727 
1728 	struct mitsu70x_printjob *job = (struct mitsu70x_printjob *) vjob; // XXX not clean.
1729 //	const struct mitsu70x_printjob *job = vjob;
1730 
1731 	if (!ctx)
1732 		return CUPS_BACKEND_FAILED;
1733 	if (!job)
1734 		return CUPS_BACKEND_FAILED;
1735 
1736 	copies = job->copies;
1737 	hdr = (struct mitsu70x_hdr*) job->databuf;
1738 
1739 	/* Keep track of deck requested */
1740 	reqdeck = hdr->deck;
1741 
1742 	if (job->raw_format)
1743 		goto bypass;
1744 
1745 	struct BandImage input;
1746 	uint8_t rew[2] = { 1, 1 }; /* 1 for rewind ok (default!) */
1747 
1748 	/* Load in the CPC file, if needed */
1749 	if (job->cpcfname && job->cpcfname != ctx->last_cpcfname) {
1750 		ctx->last_cpcfname = job->cpcfname;
1751 		if (ctx->cpcdata)
1752 			ctx->DestroyCPCData(ctx->cpcdata);
1753 		ctx->cpcdata = ctx->GetCPCData(job->cpcfname);
1754 		if (!ctx->cpcdata) {
1755 			ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
1756 			return CUPS_BACKEND_CANCEL;
1757 		}
1758 	}
1759 
1760 	/* Load in the secondary CPC, if needed */
1761 	if (job->ecpcfname != ctx->last_ecpcfname) {
1762 		ctx->last_ecpcfname = job->ecpcfname;
1763 		if (ctx->ecpcdata)
1764 			ctx->DestroyCPCData(ctx->ecpcdata);
1765 		if (job->ecpcfname) {
1766 			ctx->ecpcdata = ctx->GetCPCData(job->ecpcfname);
1767 			if (!ctx->ecpcdata) {
1768 				ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
1769 				return CUPS_BACKEND_CANCEL;
1770 			}
1771 		} else {
1772 			ctx->ecpcdata = NULL;
1773 		}
1774 	}
1775 
1776 	/* Convert using image processing library */
1777 	input.origin_rows = input.origin_cols = 0;
1778 	input.rows = job->rows;
1779 	input.cols = job->cols;
1780 	input.imgbuf = job->spoolbuf;
1781 	input.bytes_per_row = job->cols * 3;
1782 
1783 	ctx->output.origin_rows = ctx->output.origin_cols = 0;
1784 	ctx->output.rows = job->rows;
1785 	ctx->output.cols = job->cols;
1786 	ctx->output.imgbuf = job->databuf + job->datalen;
1787 	ctx->output.bytes_per_row = job->cols * 3 * 2;
1788 
1789 	DEBUG("Running print data through processing library\n");
1790 	if (ctx->DoImageEffect(ctx->cpcdata, ctx->ecpcdata,
1791 			       &input, &ctx->output, job->sharpen, job->reverse, rew)) {
1792 		ERROR("Image Processing failed, aborting!\n");
1793 		return CUPS_BACKEND_CANCEL;
1794 	}
1795 
1796 	/* Twiddle rewind stuff if needed */
1797 	if (ctx->type != P_MITSU_D70X) {
1798 		hdr->rewind[0] = !rew[0];
1799 		hdr->rewind[1] = !rew[1];
1800 		DEBUG("Rewind Inhibit? %02x %02x\n", hdr->rewind[0], hdr->rewind[1]);
1801 	}
1802 
1803 	/* Move up the pointer to after the image data */
1804 	job->datalen += 3*job->planelen;
1805 
1806 	/* Clean up */
1807 	// XXX not really necessary.
1808 	free(job->spoolbuf);
1809 	job->spoolbuf = NULL;
1810 	job->spoolbuflen = 0;
1811 
1812 	/* Now that we've filled everything in, read matte from file */
1813 	if (job->matte) {
1814 		int fd;
1815 		uint32_t j;
1816 		DEBUG("Reading %u bytes of matte data from disk (%d/%d)\n", job->matte, job->cols, LAMINATE_STRIDE);
1817 		fd = open(job->laminatefname, O_RDONLY);
1818 		if (fd < 0) {
1819 			ERROR("Unable to open matte lamination data file '%s'\n", job->laminatefname);
1820 			return CUPS_BACKEND_CANCEL;
1821 		}
1822 
1823 		for (j = 0 ; j < be16_to_cpu(hdr->lamrows) ; j++) {
1824 			int remain = LAMINATE_STRIDE * 2;
1825 
1826 			/* Read one row of lamination data at a time */
1827 			while (remain) {
1828 				int i = read(fd, job->databuf + job->datalen, remain);
1829 				if (i < 0)
1830 					return CUPS_BACKEND_CANCEL;
1831 				if (i == 0) {
1832 					/* We hit EOF, restart from beginning */
1833 					lseek(fd, 0, SEEK_SET);
1834 					continue;
1835 				}
1836 				job->datalen += i;
1837 				remain -= i;
1838 			}
1839 			/* Back off the buffer so we "wrap" on the print row. */
1840 			job->datalen -= ((LAMINATE_STRIDE - job->cols) * 2);
1841 		}
1842 		/* We're done */
1843 		close(fd);
1844 
1845 		/* Zero out the tail end of the buffer. */
1846 		j = be16_to_cpu(hdr->lamcols) * be16_to_cpu(hdr->lamrows) * 2;
1847 		memset(job->databuf + job->datalen, 0, job->matte - j);
1848 	}
1849 
1850 bypass:
1851 	/* Bypass */
1852 	if (test_mode >= TEST_MODE_NOPRINT)
1853 		return CUPS_BACKEND_OK;
1854 
1855 	INFO("Waiting for printer idle...\n");
1856 
1857 	/* Ensure printer is awake */
1858 	ret = mitsu70x_wakeup(ctx, 1);
1859 	if (ret)
1860 		return CUPS_BACKEND_FAILED;
1861 
1862 top:
1863 	/* Query job status for jobid 0 (global) */
1864 	ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
1865 	if (ret)
1866 		return CUPS_BACKEND_FAILED;
1867 
1868 	/* Figure out which deck(s) can be used.
1869 	   This should be in the main loop due to copy retries */
1870 
1871 	/* First, try to respect requested deck */
1872 	if (ctx->type == P_MITSU_D70X) {
1873 		deck = reqdeck; /* Respect D70 deck choice, 0 is automatic. */
1874 	} else {
1875 		deck = 1; /* All others have one deck only */
1876 	}
1877 
1878 	/* If user requested a specific deck, go with it, if it's legal */
1879 	if (deck == 1 && job->decks_ok[0]) {
1880 		deck = 1;
1881 	} else if (deck == 2 && job->decks_ok[1]) {
1882 		deck = 2;
1883 	/* If we have an exact match for media, use it exclusively */
1884 	} else if (job->decks_exact[0] && job->decks_exact[1]) {
1885 		deck = 1 | 2;
1886 	} else if (job->decks_exact[0]) {
1887 		deck = 1;
1888 	} else if (job->decks_exact[1]) {
1889 		deck = 2;
1890 	/* Use a non-exact match only if we don't have an exact match */
1891 	} else if (job->decks_ok[0] && job->decks_ok[1]) {
1892 		deck = 1 | 2;
1893 	} else if (job->decks_ok[0]) {
1894 		deck = 1;
1895 	} else if (job->decks_ok[1]) {
1896 		deck = 2;
1897 	} else {
1898 		ERROR("Loaded media does not match job!\n");
1899 		return CUPS_BACKEND_CANCEL;
1900 	}
1901 
1902 	if (ctx->num_decks > 1)
1903 		DEBUG("Deck selection mask: %d (%d %d %d/%d %d/%d) \n",
1904 		      deck, hdr->deck, job->rows,
1905 		      job->decks_exact[0], job->decks_exact[1],
1906 		      job->decks_ok[0], job->decks_ok[1]);
1907 
1908 	/* Okay, we know which decks are _legal_, pick one to use */
1909 	legal = deck;
1910 	if (deck & 1) {
1911 		if (jobstatus.temperature == TEMPERATURE_COOLING) {
1912 			if (ctx->num_decks == 2)
1913 				INFO("Lower deck cooling down...\n");
1914 			else
1915 				INFO("Printer cooling down...\n");
1916 			deck &= ~1;
1917 		} else if (jobstatus.error_status[0]) {
1918 			ERROR("%s %s/%s -> %s:  %02x/%02x/%02x\n",
1919 			      ctx->num_decks == 2 ? "LOWER:": "",
1920 			      mitsu70x_errorclass(jobstatus.error_status),
1921 			      mitsu70x_errors(jobstatus.error_status),
1922 			      mitsu70x_errorrecovery(jobstatus.error_status),
1923 			      jobstatus.error_status[0],
1924 			      jobstatus.error_status[1],
1925 			      jobstatus.error_status[2]);
1926 			deck &= ~1;
1927 			legal &= ~1;  /* Deck is offline! */
1928 		} else if (jobstatus.mecha_status[0] != MECHA_STATUS_IDLE) {
1929 			deck &= ~1;
1930 		}
1931 	}
1932 	if (deck & 2) {
1933 		if (jobstatus.temperature_up == TEMPERATURE_COOLING) {
1934 			INFO("Upper deck cooling down...\n");
1935 			deck &= ~2;
1936 		} else if (jobstatus.error_status_up[0]) {
1937 			ERROR("UPPER: %s/%s -> %s:  %02x/%02x/%02x\n",
1938 			      mitsu70x_errorclass(jobstatus.error_status_up),
1939 			      mitsu70x_errors(jobstatus.error_status_up),
1940 			      mitsu70x_errorrecovery(jobstatus.error_status_up),
1941 			      jobstatus.error_status_up[0],
1942 			      jobstatus.error_status_up[1],
1943 			      jobstatus.error_status_up[2]);
1944 			deck &= ~2;
1945 			legal &= ~2;  /* Deck is offline! */
1946 		} else if (jobstatus.mecha_status_up[0] != MECHA_STATUS_IDLE) {
1947 			deck &= ~2;
1948 		}
1949 	}
1950 
1951 	if (deck == 3) {
1952 		/* Both decks OK to use, pick one at random */
1953 		if (rand() & 1)
1954 			deck = 1;
1955 		else
1956 			deck = 2;
1957 	}
1958 
1959 	if (ctx->num_decks > 1)
1960 		DEBUG("Deck selected: %d\n", deck);
1961 
1962 	/* Great, we have no decks we can currently print this job on.. */
1963 	if (deck == 0) {
1964 		/* Halt queue if printer is entirely offline */
1965 		if (ctx->num_decks == 2) {
1966 			if (jobstatus.error_status[0] && jobstatus.error_status_up[0]) {
1967 				ERROR("Both decks offline due to errors\n");
1968 				return CUPS_BACKEND_STOP;
1969 			}
1970 		} else {
1971 			if (jobstatus.error_status[0]) {
1972 				ERROR("Printer offline due to errors\n");
1973 				return CUPS_BACKEND_STOP;
1974 			}
1975 		}
1976 
1977 		/* Hold job if we have no legal decks for it, but printer is online. */
1978 		if (!legal) {
1979 			ERROR("Legal deck for printjob has errors, aborting job");
1980 			return CUPS_BACKEND_HOLD;
1981 		}
1982 
1983 		/* Legal decks are busy, retry */
1984 		sleep(1);
1985 		goto top;
1986 	}
1987 
1988 	/* Perform memory status query */
1989 	{
1990 		struct mitsu70x_memorystatus_resp memory;
1991 		INFO("Checking Memory availability\n");
1992 
1993 		ret = mitsu70x_get_memorystatus(ctx, job, hdr->multicut, &memory);
1994 		if (ret)
1995 			return CUPS_BACKEND_FAILED;
1996 
1997 		/* Check size is sane */
1998 		if (memory.size || memory.memory == 0xff) {
1999 			ERROR("Unsupported print size!\n");
2000 			return CUPS_BACKEND_CANCEL;
2001 		}
2002 		if (memory.memory) {
2003 			INFO("Printer buffers full, retrying!\n");
2004 			sleep(1);
2005 			goto top;
2006 		}
2007 	}
2008 
2009 #if 0
2010 	/* Make sure we don't have any jobid collisions */
2011 	{
2012 		int i;
2013 		struct mitsu70x_jobs jobs;
2014 
2015 		ret = mitsu70x_get_jobs(ctx, &jobs);
2016 		if (ret)
2017 			return CUPS_BACKEND_FAILED;
2018 		for (i = 0 ; i < NUM_JOBS ; i++) {
2019 			if (jobs.jobs[0].id == 0)
2020 				break;
2021 			if (ctx->jobid == be16_to_cpu(jobs.jobs[0].id)) {
2022 				ctx->jobid++;
2023 				if (!ctx->jobid)
2024 					ctx->jobid++;
2025 				i = -1;
2026 			}
2027 		}
2028 	}
2029 #endif
2030 	while(!ctx->jobid || ctx->jobid == be16_to_cpu(jobstatus.jobid))
2031 		ctx->jobid++;
2032 
2033 	/* Set jobid */
2034 	hdr->jobid = cpu_to_be16(ctx->jobid);
2035 
2036 	/* Set deck */
2037 	hdr->deck = deck;
2038 
2039 	/* K60 and EK305 need the mcut type 1 specified for 4x6 prints! */
2040 	if ((ctx->type == P_MITSU_K60 || ctx->type == P_KODAK_305) &&
2041 	    job->cols == 0x0748 &&
2042 	    job->rows == 0x04c2 && !hdr->multicut) {
2043 		hdr->multicut = 1;
2044 	}
2045 
2046 	/* We're clear to send data over! */
2047 	INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
2048 
2049 	if ((ret = send_data(ctx->dev, ctx->endp_down,
2050 			     job->databuf,
2051 			     sizeof(struct mitsu70x_hdr))))
2052 		return CUPS_BACKEND_FAILED;
2053 
2054 	if (ctx->dl_handle && !job->raw_format) {
2055 		if (ctx->SendImageData(&ctx->output, ctx, d70_library_callback))
2056 			return CUPS_BACKEND_FAILED;
2057 
2058 		if (job->matte)
2059 			if (d70_library_callback(ctx, job->databuf + job->datalen - job->matte, job->matte))
2060 			    return CUPS_BACKEND_FAILED;
2061 	} else { // Fallback code..
2062                /* K60 and 305 need data sent in 256K chunks, but the first
2063                   chunk needs to subtract the length of the 512-byte header */
2064 
2065 		int chunk = CHUNK_LEN - sizeof(struct mitsu70x_hdr);
2066 		int sent = 512;
2067 		while (chunk > 0) {
2068 			if ((ret = send_data(ctx->dev, ctx->endp_down,
2069 					     job->databuf + sent, chunk)))
2070 				return CUPS_BACKEND_FAILED;
2071 			sent += chunk;
2072 			chunk = job->datalen - sent;
2073 			if (chunk > CHUNK_LEN)
2074 				chunk = CHUNK_LEN;
2075 		}
2076        }
2077 
2078 	/* Then wait for completion, if so desired.. */
2079 	INFO("Waiting for printer to acknowledge completion\n");
2080 
2081 	do {
2082 		sleep(1);
2083 
2084 		ret = mitsu70x_get_printerstatus(ctx, &resp);
2085 		if (ret)
2086 			return CUPS_BACKEND_FAILED;
2087 
2088 		ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
2089 		ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
2090 		if (ctx->num_decks == 2) {
2091 			ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
2092 			ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
2093 		}
2094 		if (ctx->marker[0].levelnow != ctx->last_l ||
2095 		    ctx->marker[1].levelnow != ctx->last_u) {
2096 			dump_markers(ctx->marker, ctx->num_decks, 0);
2097 			ctx->last_l = ctx->marker[0].levelnow;
2098 			ctx->last_u = ctx->marker[1].levelnow;
2099 		}
2100 
2101 		/* Query job status for our used jobid */
2102 		ret = mitsu70x_get_jobstatus(ctx, &jobstatus, ctx->jobid);
2103 		if (ret)
2104 			return CUPS_BACKEND_FAILED;
2105 
2106 		/* See if we hit a printer error. */
2107 		if (deck == 1) {
2108 			if (jobstatus.error_status[0]) {
2109 				ERROR("%s/%s -> %s:  %02x/%02x/%02x\n",
2110 				      mitsu70x_errorclass(jobstatus.error_status),
2111 				      mitsu70x_errors(jobstatus.error_status),
2112 				      mitsu70x_errorrecovery(jobstatus.error_status),
2113 				      jobstatus.error_status[0],
2114 				      jobstatus.error_status[1],
2115 				      jobstatus.error_status[2]);
2116 
2117 				/* Retry job on the other deck.. */
2118 				if (ctx->num_decks == 2)
2119 					goto top;
2120 
2121 				return CUPS_BACKEND_STOP;
2122 			}
2123 		} else if (deck == 2) {
2124 			if (jobstatus.error_status_up[0]) {
2125 				ERROR("UPPER: %s/%s -> %s:  %02x/%02x/%02x\n",
2126 				      mitsu70x_errorclass(jobstatus.error_status_up),
2127 				      mitsu70x_errors(jobstatus.error_status_up),
2128 				      mitsu70x_errorrecovery(jobstatus.error_status_up),
2129 				      jobstatus.error_status_up[0],
2130 				      jobstatus.error_status_up[1],
2131 				      jobstatus.error_status_up[2]);
2132 
2133 				/* Retry job on the other deck.. */
2134 				if (ctx->num_decks == 2)
2135 					goto top;
2136 
2137 				return CUPS_BACKEND_STOP;
2138 			}
2139 		}
2140 
2141 		/* Only print if job status is changed */
2142 		if (jobstatus.job_status[0] != last_status[0] ||
2143 		    jobstatus.job_status[1] != last_status[1] ||
2144 		    jobstatus.job_status[2] != last_status[2] ||
2145 		    jobstatus.job_status[3] != last_status[3])
2146 			INFO("%s: %02x/%02x/%02x/%02x\n",
2147 			     mitsu70x_jobstatuses(jobstatus.job_status),
2148 			     jobstatus.job_status[0],
2149 			     jobstatus.job_status[1],
2150 			     jobstatus.job_status[2],
2151 			     jobstatus.job_status[3]);
2152 
2153 		/* Check for job completion */
2154 		if (jobstatus.job_status[0] == JOB_STATUS0_END) {
2155 			if (jobstatus.job_status[1] ||
2156 			    jobstatus.job_status[2] ||
2157 			    jobstatus.job_status[3]) {
2158 				ERROR("Abnormal exit: %02x/%02x/%02x\n",
2159 				      jobstatus.job_status[1],
2160 				      jobstatus.job_status[2],
2161 				      jobstatus.job_status[3]);
2162 				return CUPS_BACKEND_STOP;
2163 			}
2164 			/* Job complete */
2165 			break;
2166 		}
2167 
2168 		/* See if we can return early, but wait until printing has started! */
2169 		if (fast_return && copies <= 1 && /* Copies generated by backend! */
2170 		    jobstatus.job_status[0] == JOB_STATUS0_PRINT &&
2171 		    jobstatus.job_status[1] > JOB_STATUS1_PRINT_MEDIALOAD)
2172 		{
2173 			INFO("Fast return mode enabled.\n");
2174 			break;
2175 		}
2176 
2177 		/* On a two deck system, try to use the second deck
2178 		   for additional copies. If we can't use it, we'll block. */
2179 		if (ctx->num_decks > 1 && copies > 1)
2180 			break;
2181 
2182 		/* Update cache for the next round */
2183 		memcpy(last_status, jobstatus.job_status, 4);
2184 	} while(1);
2185 
2186 	/* Clean up */
2187 	if (terminate)
2188 		copies = 1;
2189 
2190 	INFO("Print complete (%d copies remaining)\n", copies - 1);
2191 
2192 	if (copies && --copies) {
2193 		goto top;
2194 	}
2195 
2196 	return CUPS_BACKEND_OK;
2197 }
2198 
mitsu70x_dump_printerstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_printerstatus_resp * resp)2199 static void mitsu70x_dump_printerstatus(struct mitsu70x_ctx *ctx,
2200 					struct mitsu70x_printerstatus_resp *resp)
2201 {
2202 	uint32_t i;
2203 	uint8_t memory = ~resp->memory;
2204 
2205 	INFO("Model         : ");
2206 	for (i = 0 ; i < 6 ; i++) {
2207 		DEBUG2("%c", le16_to_cpu(resp->model[i]) & 0x7f);
2208 	}
2209 	DEBUG2("\n");
2210 	INFO("Serial Number : ");
2211 	for (i = 0 ; i < 6 ; i++) {
2212 		DEBUG2("%c", le16_to_cpu(resp->serno[i]) & 0x7f);
2213 	}
2214 	DEBUG2("\n");
2215 	for (i = 0 ; i < 7 ; i++) {
2216 		char buf[7];
2217 		char type;
2218 		if (resp->vers[i].ver[5] == '@')  /* "DUMMY@" */
2219 			continue;
2220 		memcpy(buf, resp->vers[i].ver, 6);
2221 		buf[6] = 0;
2222 		if (i == 0) type = 'M';
2223 		else if (i == 1) type = 'L';
2224 		else if (i == 2) type = 'R';
2225 		else if (i == 3) type = 'T';
2226 		else if (i == 4) type = 'F';
2227 		else type = i + 0x30;
2228 
2229 		INFO("FW Component: %c %s (%04x)\n",
2230 		     type, buf, be16_to_cpu(resp->vers[i].checksum));
2231 	}
2232 	INFO("Standby Timeout: %d minutes\n", resp->sleeptime);
2233 	INFO("iSerial Reporting: %s\n", resp->iserial ? "No" : "Yes" );
2234 	INFO("Power Status: %s\n", resp->power ? "Sleeping" : "Awake");
2235 	INFO("Available Memory Banks: %s%s%s%s%s%s%s%s\n",
2236 	     (memory & 0x01) ? "mem8 " : "",
2237 	     (memory & 0x02) ? "mem7 " : "",
2238 	     (memory & 0x04) ? "mem6 " : "",
2239 	     (memory & 0x08) ? "mem5 " : "",
2240 	     (memory & 0x10) ? "mem4 " : "",
2241 	     (memory & 0x20) ? "mem3 " : "",
2242 	     (memory & 0x40) ? "mem2 " : "",
2243 	     (memory & 0x80) ? "mem1 " : "");
2244 
2245 	if (resp->lower.error_status[0]) {
2246 		INFO("Lower Error Status: %s/%s -> %s\n",
2247 		     mitsu70x_errorclass(resp->lower.error_status),
2248 		     mitsu70x_errors(resp->lower.error_status),
2249 		     mitsu70x_errorrecovery(resp->lower.error_status));
2250 	}
2251 	INFO("Lower Temperature: %s\n", mitsu70x_temperatures(resp->lower.temperature));
2252 	INFO("Lower Mechanical Status: %s\n",
2253 	     mitsu70x_mechastatus(resp->lower.mecha_status));
2254 	INFO("Lower Media Type:  %s (%02x/%02x)\n",
2255 	     mitsu70x_media_types(resp->lower.media_brand, resp->lower.media_type),
2256 	     resp->lower.media_brand,
2257 	     resp->lower.media_type);
2258 	INFO("Lower Prints Remaining:  %03d/%03d\n",
2259 	     be16_to_cpu(resp->lower.remain),
2260 	     be16_to_cpu(resp->lower.capacity));
2261 	i = packed_bcd_to_uint32((char*)resp->lower.lifetime_prints, 4);
2262 	if (i)
2263 		i-= 10;
2264 	INFO("Lower Lifetime Prints:  %u\n", i);
2265 
2266 	if (ctx->num_decks == 2) {
2267 		if (resp->upper.error_status[0]) {
2268 			INFO("Upper Error Status: %s/%s -> %s\n",
2269 			     mitsu70x_errorclass(resp->upper.error_status),
2270 			     mitsu70x_errors(resp->upper.error_status),
2271 			     mitsu70x_errorrecovery(resp->upper.error_status));
2272 		}
2273 		INFO("Upper Temperature: %s\n", mitsu70x_temperatures(resp->upper.temperature));
2274 		INFO("Upper Mechanical Status: %s\n",
2275 		     mitsu70x_mechastatus(resp->upper.mecha_status));
2276 		INFO("Upper Media Type:  %s (%02x/%02x)\n",
2277 		     mitsu70x_media_types(resp->upper.media_brand, resp->upper.media_type),
2278 		     resp->upper.media_brand,
2279 		     resp->upper.media_type);
2280 		INFO("Upper Prints Remaining:  %03d/%03d\n",
2281 		     be16_to_cpu(resp->upper.remain),
2282 		     be16_to_cpu(resp->upper.capacity));
2283 
2284 		i = packed_bcd_to_uint32((char*)resp->upper.lifetime_prints, 4);
2285 		if (i)
2286 			i-= 10;
2287 		INFO("Upper Lifetime Prints:  %u\n", i);
2288 	}
2289 }
2290 
mitsu70x_query_jobs(struct mitsu70x_ctx * ctx)2291 static int mitsu70x_query_jobs(struct mitsu70x_ctx *ctx)
2292 {
2293 #if 0
2294 	struct mitsu70x_jobs jobs;
2295 #endif
2296 	struct mitsu70x_jobstatus jobstatus;
2297 	int ret;
2298 
2299 	ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
2300 	if (ret)
2301 		return CUPS_BACKEND_FAILED;
2302 
2303 	INFO("JOB00 ID     : %06u\n", jobstatus.jobid);
2304 	INFO("JOB00 status : %s\n", mitsu70x_jobstatuses(jobstatus.job_status));
2305 	INFO("Power Status: %s\n", jobstatus.power ? "Sleeping" : "Awake");
2306 
2307 	if (ctx->num_decks == 2) {
2308 		INFO("Lower Deck Mechanical Status: %s\n",
2309 		     mitsu70x_mechastatus(jobstatus.mecha_status));
2310 		if (jobstatus.error_status[0]) {
2311 			INFO("%s/%s -> %s\n",
2312 			     mitsu70x_errorclass(jobstatus.error_status),
2313 			     mitsu70x_errors(jobstatus.error_status),
2314 			     mitsu70x_errorrecovery(jobstatus.error_status));
2315 		}
2316 		INFO("Lower Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
2317 
2318 		INFO("Upper Deck Mechanical Status: %s\n",
2319 		     mitsu70x_mechastatus(jobstatus.mecha_status_up));
2320 		if (jobstatus.error_status_up[0]) {
2321 			INFO("%s/%s -> %s\n",
2322 			     mitsu70x_errorclass(jobstatus.error_status_up),
2323 			     mitsu70x_errors(jobstatus.error_status_up),
2324 			     mitsu70x_errorrecovery(jobstatus.error_status_up));
2325 		}
2326 		INFO("Upper Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature_up));
2327 	} else {
2328 		INFO("Mechanical Status: %s\n",
2329 		     mitsu70x_mechastatus(jobstatus.mecha_status));
2330 		if (jobstatus.error_status[0]) {
2331 			INFO("%s/%s -> %s\n",
2332 			     mitsu70x_errorclass(jobstatus.error_status),
2333 			     mitsu70x_errors(jobstatus.error_status),
2334 			     mitsu70x_errorrecovery(jobstatus.error_status));
2335 		}
2336 		INFO("Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
2337 	}
2338 
2339 	// memory status?
2340 
2341 #if 0
2342 	ret = mitsu70x_get_jobs(ctx, &jobs);
2343 	if (!ret) {
2344 		int i;
2345 		for (i = 0 ; i < NUM_JOBS ; i++) {
2346 			if (jobs.jobs[i].id == 0)
2347 				break;
2348 			INFO("JOB%02d ID     : %06u\n", i, jobs.jobs[i].id);
2349 			INFO("JOB%02d status : %s\n", i, mitsu70x_jobstatuses(jobs.jobs[i].status));
2350 		}
2351 	}
2352 
2353 done:
2354 #endif
2355 	return CUPS_BACKEND_OK;
2356 }
2357 
mitsu70x_query_status(struct mitsu70x_ctx * ctx)2358 static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
2359 {
2360 	struct mitsu70x_printerstatus_resp resp;
2361 	int ret;
2362 
2363 	ret = mitsu70x_get_printerstatus(ctx, &resp);
2364 	if (!ret)
2365 		mitsu70x_dump_printerstatus(ctx, &resp);
2366 
2367 	return ret;
2368 }
2369 
mitsu70x_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)2370 static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
2371 {
2372 	int ret, i;
2373 	struct mitsu70x_printerstatus_resp resp = { .hdr = { 0 } };
2374 
2375 	struct mitsu70x_ctx ctx = {
2376 		.dev = dev,
2377 		.endp_up = endp_up,
2378 		.endp_down = endp_down,
2379 	};
2380 
2381 	ret = mitsu70x_get_printerstatus(&ctx, &resp);
2382 
2383 	if (buf_len > 6)  /* Will we ever have a buffer under 6 bytes? */
2384 		buf_len = 6;
2385 
2386 	for (i = 0 ; i < buf_len ; i++) {
2387 		*buf++ = le16_to_cpu(resp.serno[i]) & 0x7f;
2388 	}
2389 	*buf = 0; /* Null-terminate the returned string */
2390 
2391 	return ret;
2392 }
2393 
2394 
mitsu70x_cmdline(void)2395 static void mitsu70x_cmdline(void)
2396 {
2397 	DEBUG("\t\t[ -s ]           # Query printer status\n");
2398 	DEBUG("\t\t[ -j ]           # Query job status\n");
2399 	DEBUG("\t\t[ -w ]           # Wake up printer\n");
2400 	DEBUG("\t\t[ -W ]           # Wake up printer and wait\n");
2401 	DEBUG("\t\t[ -k num ]       # Set standby time (1-60 minutes, 0 disables)\n");
2402 	DEBUG("\t\t[ -x num ]       # Set USB iSerialNumber Reporting (1 on, 0 off)\n");
2403 	DEBUG("\t\t[ -X jobid ]     # Abort a printjob\n");}
2404 
mitsu70x_cmdline_arg(void * vctx,int argc,char ** argv)2405 static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
2406 {
2407 	struct mitsu70x_ctx *ctx = vctx;
2408 	int i, j = 0;
2409 
2410 	if (!ctx)
2411 		return -1;
2412 
2413 	while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "jk:swWX:x:")) >= 0) {
2414 		switch(i) {
2415 		GETOPT_PROCESS_GLOBAL
2416 		case 'j':
2417 			j = mitsu70x_query_jobs(ctx);
2418 			break;
2419 		case 'k':
2420 			j = mitsu70x_set_sleeptime(ctx, atoi(optarg));
2421 			break;
2422 		case 's':
2423 			j = mitsu70x_query_status(ctx);
2424 			break;
2425 		case 'w':
2426 			j = mitsu70x_wakeup(ctx, 0);
2427 			break;
2428 		case 'W':
2429 			j = mitsu70x_wakeup(ctx, 1);
2430 			break;
2431 		case 'x':
2432 			j = mitsu70x_set_iserial(ctx, atoi(optarg));
2433 			break;
2434 		case 'X':
2435 			j = mitsu70x_cancel_job(ctx, atoi(optarg));
2436 			break;
2437 		default:
2438 			break;  /* Ignore completely */
2439 		}
2440 
2441 		if (j) return j;
2442 	}
2443 
2444 	return 0;
2445 }
2446 
mitsu70x_query_markers(void * vctx,struct marker ** markers,int * count)2447 static int mitsu70x_query_markers(void *vctx, struct marker **markers, int *count)
2448 {
2449 	struct mitsu70x_ctx *ctx = vctx;
2450 	struct mitsu70x_printerstatus_resp resp;
2451 	int ret;
2452 
2453 	*markers = ctx->marker;
2454 	*count = ctx->num_decks;
2455 
2456 	/* Tell CUPS about the consumables we report */
2457 	ret = mitsu70x_get_printerstatus(ctx, &resp);
2458 	if (ret)
2459 		return CUPS_BACKEND_FAILED;
2460 
2461 	if (resp.power) {
2462 		ret = mitsu70x_wakeup(ctx, 1);
2463 		if (ret)
2464 			return CUPS_BACKEND_FAILED;
2465 
2466 		ret = mitsu70x_get_printerstatus(ctx, &resp);
2467 		if (ret)
2468 			return CUPS_BACKEND_FAILED;
2469 	}
2470 
2471 	ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
2472 	ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
2473 	if (ctx->num_decks == 2) {
2474 		ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
2475 		ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
2476 	}
2477 
2478 	return CUPS_BACKEND_OK;
2479 }
2480 
2481 static const char *mitsu70x_prefixes[] = {
2482 	"mitsu70x", // Family entry, do not nuke.
2483 	"mitsubishi-d70dw", "mitsubishi-d80dw", "mitsubishi-k60dw", "kodak-305", "fujifilm-ask-300",
2484 	// Extras
2485 	"mitsubishi-d707dw", "mitsubishi-k60dws",
2486 	// backwards compatibility
2487 	"mitsud80", "mitsuk60", "kodak305", "fujiask300",
2488 	NULL,
2489 };
2490 
2491 /* Exported */
2492 struct dyesub_backend mitsu70x_backend = {
2493 	.name = "Mitsubishi CP-D70 family",
2494 	.version = "0.95",
2495 	.uri_prefixes = mitsu70x_prefixes,
2496 	.flags = BACKEND_FLAG_JOBLIST,
2497 	.cmdline_usage = mitsu70x_cmdline,
2498 	.cmdline_arg = mitsu70x_cmdline_arg,
2499 	.init = mitsu70x_init,
2500 	.attach = mitsu70x_attach,
2501 	.teardown = mitsu70x_teardown,
2502 	.cleanup_job = mitsu70x_cleanup_job,
2503 	.read_parse = mitsu70x_read_parse,
2504 	.main_loop = mitsu70x_main_loop,
2505 	.query_serno = mitsu70x_query_serno,
2506 	.query_markers = mitsu70x_query_markers,
2507 	.devices = {
2508 		{ USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, NULL, "mitsubishi-d70dw"},
2509 		{ USB_VID_MITSU, USB_PID_MITSU_K60, P_MITSU_K60, NULL, "mitsubishi-k60dw"},
2510 		{ USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D80, NULL, "mitsubishi-d80dw"},
2511 		{ USB_VID_KODAK, USB_PID_KODAK305, P_KODAK_305, NULL, "kodak-305"},
2512 		{ USB_VID_FUJIFILM, USB_PID_FUJI_ASK300, P_FUJI_ASK300, NULL, "fujifilm-ask-300"},
2513 		{ 0, 0, 0, NULL, NULL}
2514 	}
2515 };
2516 
2517 /* Mitsubish CP-D70DW/D707DW/K60DW-S/D80DW, Kodak 305, Fujifilm ASK-300
2518    data format:
2519 
2520    Spool file consists of two headers followed by three image planes
2521    and an optional lamination data plane.  All blocks are rounded up to
2522    a 512-byte boundary.
2523 
2524    All multi-byte numbers are big endian, ie MSB first.
2525 
2526    Header 1:  (AKA Wake Up)
2527 
2528    1b 45 57 55 00 00 00 00  00 00 00 00 00 00 00 00
2529    (padded by NULLs to a 512-byte boundary)
2530 
2531    Header 2:  (Print Header)
2532 
2533    1b 5a 54 PP JJ JJ RR RR  00 00 00 00 00 00 00 00
2534    XX XX YY YY QQ QQ ZZ ZZ  SS 00 00 00 00 00 00 00
2535    UU 00 00 00 00 00 00 00  LL TT 00 00 00 00 00 00
2536    MM 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
2537 
2538    (padded by NULLs to a 512-byte boundary)
2539 
2540    PP    == 0x01 on D70x/D80, 0x00 on K60, 0x90 on K305, 0x80 on ASK300
2541    JJ JJ == Job ID, can leave at 00 00
2542    XX XX == columns
2543    YY YY == rows
2544    QQ QQ == lamination columns (equal to XX XX)
2545    ZZ ZZ == lamination rows (YY YY + 12 on D70x/D80/ASK300, YY YY on others)
2546    RR RR == "rewind inhibit", 01 01 enabled, normally 00 00 (All but D70x/A300)
2547    SS    == Print mode: 00 = Fine, 03 = SuperFine (D70x/D80 only), 04 = UltraFine
2548             (Matte requires Superfine or Ultrafine)
2549    UU    == 00 = Auto, 01 = Lower Deck (required for !D70x), 02 = Upper Deck
2550    LL    == lamination enable, 00 == on, 01 == off
2551    TT    == lamination mode: 00 glossy, 02 matte
2552    MM    == 00 (normal), 01 = (Double-cut 4x6), 05 = (double-cut 2x6)
2553 
2554    Data planes:
2555    16-bit data, rounded up to 512-byte block (XX * YY * 2 bytes)
2556 
2557    Lamination plane: (only present if QQ and ZZ are nonzero)
2558    16-byte data, rounded up to 512-byte block (QQ * ZZ * 2 bytes)
2559 
2560  */
2561