1 /*
2  *   Mitsubishi CP-D90DW Photo Printer CUPS backend
3  *
4  *   (c) 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 #define BACKEND mitsud90_backend
40 
41 #include "backend_common.h"
42 
43 #define USB_VID_MITSU       0x06D3
44 #define USB_PID_MITSU_D90   0x3B60
45 
46 const char *mitsu70x_media_types(uint8_t brand, uint8_t type);
47 const char *mitsu70x_temperatures(uint8_t temp);
48 
49 /* Printer data structures */
50 #define D90_STATUS_TYPE_MODEL  0x01 // 10, null-terminated ASCII. 'CPD90D'
51 #define D90_STATUS_TYPE_x02    0x02 // 1, 0x5f ?
52 #define D90_STATUS_TYPE_FW_0b  0x0b // 8, 34 31 34 42 31 31 a7 de (414D11)
53 #define D90_STATUS_TYPE_FW_MA  0x0c // 8, 34 31 35 41 38 31 86 bf (415A81)  // MAIN FW
54 #define D90_STATUS_TYPE_FW_F   0x0d // 8, 34 31 36 41 35 31 dc 8a (416A51)  // FPGA FW
55 #define D90_STATUS_TYPE_FW_T   0x0e // 8, 34 31 37 45 31 31 e7 e6 (417E11)  // TABLE FW
56 #define D90_STATUS_TYPE_FW_0f  0x0f // 8, 34 31 38 41 31 32 6c 64 (418A12)
57 #define D90_STATUS_TYPE_FW_11  0x11 // 8, 34 32 31 51 31 31 74 f2 (421Q11)
58 #define D90_STATUS_TYPE_FW_ME  0x13 // 8, 34 31 39 45 31 31 15 bf (419E11)  // MECHA FW
59 
60 #define D90_STATUS_TYPE_ERROR  0x16 // 11 (see below)
61 #define D90_STATUS_TYPE_MECHA  0x17 // 2  (see below)
62 #define D90_STATUS_TYPE_x1e    0x1e // 1, power state or time?  (x00)
63 #define D90_STATUS_TYPE_TEMP   0x1f // 1  (see below)
64 #define D90_STATUS_TYPE_x22    0x22 // 2,  all 0
65 #define D90_STATUS_TYPE_x28    0x28 // 2,  all 0, seen some sort of counter?
66 #define D90_STATUS_TYPE_x29    0x29 // 8,  e0 07 00 00 21 e6 b3 22
67 #define D90_STATUS_TYPE_MEDIA  0x2a // 10 (see below)
68 #define D90_STATUS_TYPE_x2b    0x2b // 2,  all 0
69 #define D90_STATUS_TYPE_x2c    0x2c // 2,  00 56
70 #define D90_STATUS_TYPE_x65    0x65 // 50, ac 80 00 01 bb b8 fe 48 05 13 5d 9c 00 33 00 00  00 00 00 00 00 00 00 00 00 00 02 39 00 00 00 00  03 13 00 02 10 40 00 00 00 00 00 00 05 80 00 3a  00 00
71 #define D90_STATUS_TYPE_x82    0x82 // 1,  80 (iserial disabled?)
72 #define D90_STATUS_TYPE_x83    0x83 // 1,  00
73 #define D90_STATUS_TYPE_x84    0x84 // 1,  00
74 
75 //#define D90_STATUS_TYPE_x85    0x85 // 2, 00 ?? BE, wait time?
76                                     // combined total of 5.
77 
78 struct mitsud90_fw_resp_single {
79 	uint8_t  version[6];
80 	uint16_t csum;
81 } __attribute__((packed));
82 
83 struct mitsud90_media_resp {
84 	uint8_t  hdr[4];  /* e4 47 44 30 */
85 	struct {
86 		uint8_t  brand;
87 		uint8_t  type;
88 		uint8_t  unk_a[2];
89 		uint16_t capacity; /* BE */
90 		uint16_t remain;  /* BE */
91 		uint8_t  unk_b[2];
92 	} __attribute__((packed)) media; /* D90_STATUS_TYPE_MEDIA */
93 } __attribute__((packed));
94 
95 struct mitsud90_status_resp {
96 	uint8_t  hdr[4];  /* e4 47 44 30 */
97 	/* D90_STATUS_TYPE_ERROR */
98 	uint8_t  code[2]; /* 00 is ok, nonzero is error */
99 	uint8_t  unk[9];
100 	/* D90_STATUS_TYPE_MECHA */
101 	uint8_t  mecha[2];
102 	/* D90_STATUS_TYPE_TEMP */
103 	uint8_t  temp;
104 } __attribute__((packed));
105 
106 struct mitsud90_info_resp {
107 	uint8_t  hdr[4];  /* e4 47 44 30 */
108 	uint8_t  model[10];
109 	uint8_t  x02;
110 	struct mitsud90_fw_resp_single fw_vers[7];
111 	uint8_t  x1e;
112 	uint8_t  x22[2];
113 	uint8_t  x28[2];
114 	uint8_t  x29[8];
115 	uint8_t  x2b[2];
116 	uint8_t  x2c[2];
117 	uint8_t  x65[50];
118 	uint8_t  x82;
119 	uint8_t  x83;
120 	uint8_t  x84;
121 } __attribute__((packed));
122 
123 #define D90_MECHA_STATUS_IDLE         0x00
124 #define D90_MECHA_STATUS_PRINTING     0x50
125 #define D90_MECHA_STATUS_INIT         0x80
126 #define D90_MECHA_STATUS_INIT_FEEDCUT 0x10
127 
128 #define D90_MECHA_STATUS_PRINT_FEEDING 0x10  // feeding ?
129 #define D90_MECHA_STATUS_PRINT_PRE_Y   0x21  // pre Y ?
130 #define D90_MECHA_STATUS_PRINT_Y       0x22  // Y ?
131 #define D90_MECHA_STATUS_PRINT_PRE_M   0x23  // pre M ?
132 #define D90_MECHA_STATUS_PRINT_M       0x24  // M ?
133 #define D90_MECHA_STATUS_PRINT_PRE_C   0x25  // pre C ? guess!
134 #define D90_MECHA_STATUS_PRINT_C       0x26  // C ?
135 #define D90_MECHA_STATUS_PRINT_PRE_OC  0x27  // pre OC ? guess!
136 #define D90_MECHA_STATUS_PRINT_OC      0x28  // O C?
137 #define D90_MECHA_STATUS_PRINTING_x2f  0x2f  // ??
138 #define D90_MECHA_STATUS_PRINTING_x38  0x38  // eject ?
139 
140 #define D90_ERROR_STATUS_OK         0x00
141 #define D90_ERROR_STATUS_OK_WARMING 0x40
142 #define D90_ERROR_STATUS_OK_COOLING 0x80
143 #define D90_ERROR_STATUS_RIBBON     0x21
144 #define D90_ERROR_STATUS_PAPER      0x22
145 #define D90_ERROR_STATUS_PAP_RIB    0x23
146 #define D90_ERROR_STATUS_OPEN       0x29
147 
148 struct mitsud90_job_query {
149 	uint8_t  hdr[4];  /* 1b 47 44 31 */
150 	uint16_t jobid;   /* BE */
151 };
152 
153 struct mitsud90_job_resp {
154 	uint8_t  hdr[4];  /* e4 47 44 31 */
155 	uint8_t  unk1;
156 	uint8_t  unk2;
157 	uint16_t unk3;
158 };
159 
160 struct mitsud90_job_hdr {
161 	uint8_t  hdr[6]; /* 1b 53 50 30 00 33 */
162 	uint16_t cols;   /* BE */
163 	uint16_t rows;   /* BE */
164 	uint8_t  unk[5]; /* 64 00 00 01 00 */
165 	union {
166 #if 0
167 		struct {
168 			uint8_t  margin;
169 			uint16_t position;
170 		} cuts[3] __attribute__((packed));
171 #endif
172 		uint8_t cutzero[9];
173 	} __attribute__((packed));
174 	uint8_t  zero[24];
175 
176 	uint8_t  overcoat;
177 	uint8_t  quality;
178 	uint8_t  colorcorr;
179 	uint8_t  sharp_h;
180 	uint8_t  sharp_v;
181 	uint8_t  zero_b[5];
182 	union {
183 		struct {
184 			uint16_t pano_on;   /* 0x0001 when pano is on,  */
185 			uint8_t  pano_tot;  /* 2 or 3 */
186 			uint8_t  pano_pg;   /* 1, 2, 3 */
187 			uint16_t pano_rows; /* always 0x097c (BE), ie 2428 ie 8" print */
188 			uint16_t pano_rows2; /* Always 0x30 less than pano_rows */
189 			uint16_t pano_zero; /* 0x0000 */
190 			uint8_t  pano_unk[6];  /* 02 58 00 0c 00 06 */
191 		} pano __attribute__((packed));
192 		uint8_t zero_c[16];
193 	};
194 	uint8_t zero_d[6];
195 	uint8_t zero_fill[432];
196 } __attribute__((packed));
197 
198 struct mitsud90_plane_hdr {
199 	uint8_t  hdr[10]; /* 1b 5a 54 01 00 09 00 00 00 00 */
200 	uint16_t cols;  /* BE */
201 	uint16_t rows;  /* BE */
202 	uint8_t  zero_fill[498];
203 };
204 
205 struct mitsud90_job_footer {
206 	uint8_t hdr[4]; /* 1b 42 51 31 */
207 	uint8_t pad;
208 	uint8_t seconds; /* 0x05 by default (windows) */
209 };
210 
211 struct mitsud90_memcheck {
212 	uint8_t  hdr[4]; /* 1b 47 44 33 */
213 	uint8_t  unk[2]; /* 00 33 */
214 	uint16_t cols;   /* BE */
215 	uint16_t rows;   /* BE */
216 	uint8_t  unk_b[4]; /* 64 00 00 01  */
217 	uint8_t  zero_fill[498];
218 };
219 
220 struct mitsud90_memcheck_resp {
221 	uint8_t  hdr[4];   /* e4 47 44 43 */
222 	uint8_t  size_bad; /* 0x00 is ok */
223 	uint8_t  mem_bad;  /* 0x00 is ok */
224 };
225 
mitsud90_mecha_statuses(const uint8_t * code)226 const char *mitsud90_mecha_statuses(const uint8_t *code)
227 {
228 	switch (code[0]) {
229 	case D90_MECHA_STATUS_IDLE:
230 		return "Idle";
231 	case D90_MECHA_STATUS_PRINTING:
232 		switch (code[1]) {
233 		case D90_MECHA_STATUS_PRINT_FEEDING:
234 			return "Feeding Media";
235 		case D90_MECHA_STATUS_PRINT_PRE_Y:
236 		case D90_MECHA_STATUS_PRINT_Y:
237 			return "Printing Yellow";
238 		case D90_MECHA_STATUS_PRINT_PRE_M:
239 		case D90_MECHA_STATUS_PRINT_M:
240 			return "Printing Magenta";
241 		case D90_MECHA_STATUS_PRINT_PRE_C:
242 		case D90_MECHA_STATUS_PRINT_C:
243 			return "Printing Cyan";
244 		case D90_MECHA_STATUS_PRINT_PRE_OC:
245 		case D90_MECHA_STATUS_PRINT_OC:
246 			return "Applying Overcoat";
247 		case D90_MECHA_STATUS_PRINTING_x2f:
248 		case D90_MECHA_STATUS_PRINTING_x38:
249 			return "Ejecting Media?";
250 		default:
251 			return "Printing (Unknown)";
252 		}
253 	case D90_MECHA_STATUS_INIT:
254 		if (code[1] == D90_MECHA_STATUS_INIT_FEEDCUT)
255 			return "Feed & Cut paper";
256 		else
257 			return "Initializing";
258 	default:
259 		return "Unknown";
260 	}
261 }
262 
mitsud90_error_codes(const uint8_t * code)263 const char *mitsud90_error_codes(const uint8_t *code)
264 {
265 	switch(code[0]) {
266 	case D90_ERROR_STATUS_OK:
267 		if (code[1] & D90_ERROR_STATUS_OK_WARMING)
268 			return "Heating";
269 		else if (code[1] & D90_ERROR_STATUS_OK_COOLING)
270 			return "Cooling Down";
271 		else
272 			return "Idle";
273 	case D90_ERROR_STATUS_RIBBON:
274 		switch (code[1]) {
275 		case 0x00:
276 			return "Ribbon exhausted";
277 		case 0x10:
278 			return "Insufficient remaining ribbon";
279 		case 0x20:
280 			return "Ribbon Cue Timeout";
281 		case 0x30:
282 			return "Cannot Cue Ribbon";
283 		case 0x90:
284 			return "No ribbon";
285 		default:
286 			return "Unknown Ribbon Error";
287 		}
288 	case D90_ERROR_STATUS_PAPER:
289 		switch (code[1]) {
290 		case 0x00:
291 			return "No paper";
292 		case 0x02:
293 			return "Paper exhausted";
294 		default:
295 			return "Unknown Paper Error";
296 		}
297 	case D90_ERROR_STATUS_PAP_RIB:
298 		switch (code[1]) {
299 		case 0x00:
300 			return "Ribbon/Paper mismatch";
301 		case 0x90:
302 			return "Ribbon/Job mismatch";
303 		default:
304 			return "Unknown ribbon match error";
305 		}
306 	case 0x26:
307 		return "Illegal Ribbon";
308 	case 0x28:
309 		return "Cut Bin Missing";
310 	case D90_ERROR_STATUS_OPEN:
311 		switch (code[1]) {
312 		case 0x00:
313 			return "Printer Open during Stop";
314 		case 0x10:
315 			return "Printer Open during Initialization";
316 		case 0x90:
317 			return "Printer Open during Printing";
318 		default:
319 			return "Unknown Door error";
320 		}
321 	case 0x2f:
322 		return "Printer turned off during printing";
323 	case 0x31:
324 		return "Ink feed stop";
325 	case 0x32:
326 		return "Ink Skip 1 timeout";
327 	case 0x33:
328 		return "Ink Skip 2 timeout";
329 	case 0x34:
330 		return "Ink Sticking";
331 	case 0x35:
332 		return "Ink return stop";
333 	case 0x36:
334 		return "Ink Rewind timeout";
335 	case 0x37:
336 		return "Winding sensing error";
337 	case 0x40:
338 	case 0x41:
339 	case 0x42:
340 	case 0x43:
341 	case 0x44:
342 		return "Paper Jam";
343 	case 0x60:
344 		if (code[1] == 0x20)
345 			return "Preheat error";
346 		else if (code[1] == 0x04)
347 			return "Humidity sensor error";
348 		else if (code[1] & 0x1f)
349 			return "Thermistor error";
350 		else
351 			return "Unknown error";
352 	case 0x61:
353 		if (code[1] == 0x00)
354 			return "Color Sensor Error";
355 		else if (code[1] & 0x10)
356 			return "Matte OP Error";
357 		else
358 			return "Unknown error";
359 	case 0x62:
360 		return "Data Transfer error";
361 	case 0x63:
362 		return "EEPROM error";
363 	case 0x64:
364 		return "Flash access error";
365 	case 0x65:
366 		return "FPGA configuration error";
367 	case 0x66:
368 		return "Power voltage Error";
369 	case 0x67:
370 		return "RFID access error";
371 	case 0x68:
372 		if (code[1] == 0x00)
373 			return "Fan Lock Error";
374 		else if (code[1] == 0x90)
375 			return "MDA Error";
376 		else
377 			return "Unknown error";
378 	case 0x69:
379 		if (code[1] == 0x10)
380 			return "DDR Error";
381 		else if (code[1] == 0x00)
382 			return "Firmware Error";
383 		else
384 			return "Unknown error";
385 	case 0x70:
386 	case 0x71:
387 	case 0x73:
388 	case 0x75:
389 		return "Mechanical Error (check ribbon and power cycle)";
390 	case 0x82:
391 		return "USB Timeout";
392 	case 0x83:
393 		return "Illegal paper size";
394 	case 0x84:
395 		return "Illegal parameter";
396 	case 0x85:
397 		return "Job Cancel";
398 	case 0x89:
399 		return "Last Job Error";
400 	default:
401 		return "Unknown";
402 	}
403 }
404 
mitsud90_dump_status(struct mitsud90_status_resp * resp)405 static void mitsud90_dump_status(struct mitsud90_status_resp *resp)
406 {
407 	INFO("Error Status: %s (%02x %02x) -- %02x %02x %02x %02x  %02x %02x %02x %02x  %02x\n",
408 	     mitsud90_error_codes(resp->code),
409 	     resp->code[0], resp->code[1],
410 	     resp->unk[0], resp->unk[1], resp->unk[2], resp->unk[3],
411 	     resp->unk[4], resp->unk[5], resp->unk[6], resp->unk[7],
412 	     resp->unk[8]);
413 	INFO("Printer Status: %s (%02x %02x)\n",
414 	     mitsud90_mecha_statuses(resp->mecha),
415 	     resp->mecha[0], resp->mecha[1]);
416 	INFO("Temperature Status: %s\n",
417 	     mitsu70x_temperatures(resp->temp));
418 }
419 
420 /* Private data structure */
421 struct mitsud90_printjob {
422 	uint8_t *databuf;
423 	int datalen;
424 	int copies;
425 };
426 
427 struct mitsud90_ctx {
428 	struct libusb_device_handle *dev;
429 	uint8_t endp_up;
430 	uint8_t endp_down;
431 
432 	int type;
433 
434 	/* Used in parsing.. */
435 	struct mitsud90_job_footer holdover;
436 	int holdover_on;
437 
438 	struct marker marker;
439 };
440 
mitsud90_query_media(struct mitsud90_ctx * ctx,struct mitsud90_media_resp * resp)441 static int mitsud90_query_media(struct mitsud90_ctx *ctx, struct mitsud90_media_resp *resp)
442 {
443 	uint8_t cmdbuf[8];
444 	int ret, num;
445 
446 	cmdbuf[0] = 0x1b;
447 	cmdbuf[1] = 0x47;
448 	cmdbuf[2] = 0x44;
449 	cmdbuf[3] = 0x30;
450 	cmdbuf[4] = 0;
451 	cmdbuf[5] = 0;
452 	cmdbuf[6] = 0x01;  /* Number of commands */
453 	cmdbuf[7] = D90_STATUS_TYPE_MEDIA;
454 
455 	if ((ret = send_data(ctx->dev, ctx->endp_down,
456 			     cmdbuf, sizeof(cmdbuf))))
457 		return ret;
458 	memset(resp, 0, sizeof(*resp));
459 
460 	ret = read_data(ctx->dev, ctx->endp_up,
461 			(uint8_t*) resp, sizeof(*resp), &num);
462 
463 	if (ret < 0)
464 		return ret;
465 	if (num != sizeof(*resp)) {
466 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
467 		return 4;
468 	}
469 
470 	return CUPS_BACKEND_OK;
471 }
472 
mitsud90_query_status(struct mitsud90_ctx * ctx,struct mitsud90_status_resp * resp)473 static int mitsud90_query_status(struct mitsud90_ctx *ctx, struct mitsud90_status_resp *resp)
474 {
475 	uint8_t cmdbuf[10];
476 	int ret, num;
477 
478 	cmdbuf[0] = 0x1b;
479 	cmdbuf[1] = 0x47;
480 	cmdbuf[2] = 0x44;
481 	cmdbuf[3] = 0x30;
482 	cmdbuf[4] = 0;
483 	cmdbuf[5] = 0;
484 	cmdbuf[6] = 0x03;  /* Number of commands */
485 	cmdbuf[7] = D90_STATUS_TYPE_ERROR;
486 	cmdbuf[8] = D90_STATUS_TYPE_MECHA;
487 	cmdbuf[9] = D90_STATUS_TYPE_TEMP;
488 
489 	if ((ret = send_data(ctx->dev, ctx->endp_down,
490 			     cmdbuf, sizeof(cmdbuf))))
491 		return ret;
492 	memset(resp, 0, sizeof(*resp));
493 
494 	ret = read_data(ctx->dev, ctx->endp_up,
495 			(uint8_t*) resp, sizeof(*resp), &num);
496 
497 	if (ret < 0)
498 		return ret;
499 	if (num != sizeof(*resp)) {
500 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
501 		return 4;
502 	}
503 
504 	return CUPS_BACKEND_OK;
505 }
506 
507 /* Generic functions */
508 
mitsud90_init(void)509 static void *mitsud90_init(void)
510 {
511 	struct mitsud90_ctx *ctx = malloc(sizeof(struct mitsud90_ctx));
512 	if (!ctx) {
513 		ERROR("Memory Allocation Failure!\n");
514 		return NULL;
515 	}
516 	memset(ctx, 0, sizeof(struct mitsud90_ctx));
517 
518 	return ctx;
519 }
520 
mitsud90_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)521 static int mitsud90_attach(void *vctx, struct libusb_device_handle *dev, int type,
522 			    uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
523 {
524 	struct mitsud90_ctx *ctx = vctx;
525 	struct mitsud90_media_resp resp;
526 
527 	UNUSED(jobid);
528 
529 	ctx->dev = dev;
530 	ctx->endp_up = endp_up;
531 	ctx->endp_down = endp_down;
532 	ctx->type = type;
533 
534 	if (test_mode < TEST_MODE_NOATTACH) {
535 		if (mitsud90_query_media(ctx, &resp))
536 			return CUPS_BACKEND_FAILED;
537 	} else {
538 		resp.media.brand = 0xff;
539 		resp.media.type = 0x0f;
540 		resp.media.capacity = cpu_to_be16(230);
541 		resp.media.remain = cpu_to_be16(200);
542 	}
543 
544 	ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
545 	ctx->marker.name = mitsu70x_media_types(resp.media.brand, resp.media.type);
546 	ctx->marker.levelmax = be16_to_cpu(resp.media.capacity);
547 	ctx->marker.levelnow = be16_to_cpu(resp.media.remain);
548 
549 	return CUPS_BACKEND_OK;
550 }
551 
mitsud90_cleanup_job(const void * vjob)552 static void mitsud90_cleanup_job(const void *vjob)
553 {
554 	const struct mitsud90_printjob *job = vjob;
555 
556 	if (job->databuf)
557 		free(job->databuf);
558 
559 	free((void*)job);
560 }
561 
mitsud90_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)562 static int mitsud90_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
563 	struct mitsud90_ctx *ctx = vctx;
564 	int i, remain;
565 	struct mitsud90_job_hdr *hdr;
566 
567 	struct mitsud90_printjob *job;;
568 
569 	if (!ctx)
570 		return CUPS_BACKEND_FAILED;
571 
572 	job = malloc(sizeof(*job));
573 	if (!job) {
574 		ERROR("Memory allocation failure!\n");
575 		return CUPS_BACKEND_RETRY_CURRENT;
576 	}
577 	memset(job, 0, sizeof(*job));
578 	job->copies = copies;
579 
580 	/* Just allocate a worst-case buffer */
581 	job->datalen = 0;
582 	job->databuf = malloc(sizeof(struct mitsud90_job_hdr) +
583 			      sizeof(struct mitsud90_plane_hdr) +
584 			      sizeof(struct mitsud90_job_footer) +
585 			      1852*2729*3);
586 	if (!job->databuf) {
587 		ERROR("Memory allocation failure!\n");
588 		mitsud90_cleanup_job(job);
589 		return CUPS_BACKEND_RETRY_CURRENT;
590 	}
591 
592 	/* Make sure there's no holdover */
593 	if (ctx->holdover_on) {
594 		memcpy(job->databuf, &ctx->holdover, sizeof(ctx->holdover));
595 		job->datalen += sizeof(ctx->holdover);
596 		ctx->holdover_on = 0;
597 	}
598 
599 	/* Read in first header. */
600 	remain = sizeof(struct mitsud90_job_hdr) - job->datalen;
601 	while (remain) {
602 		i = read(data_fd, (job->databuf + job->datalen), remain);
603 		if (i == 0) {
604 			mitsud90_cleanup_job(job);
605 			return CUPS_BACKEND_CANCEL;
606 		}
607 		if (i < 0) {
608 			mitsud90_cleanup_job(job);
609 			return CUPS_BACKEND_CANCEL;
610 		}
611 		remain -= i;
612 		job->datalen += i;
613 	}
614 
615 	/* Sanity check header */
616 	hdr = (struct mitsud90_job_hdr *) job->databuf;
617 	if (hdr->hdr[0] != 0x1b ||
618 	    hdr->hdr[1] != 0x53 ||
619 	    hdr->hdr[2] != 0x50 ||
620 	    hdr->hdr[3] != 0x30 ) {
621 		ERROR("Unrecognized data format (%02x%02x%02x%02x)!\n",
622 		      hdr->hdr[0], hdr->hdr[1], hdr->hdr[2], hdr->hdr[3]);
623 		mitsud90_cleanup_job(job);
624 		return CUPS_BACKEND_CANCEL;
625 	}
626 
627 	/* Now read in the rest */
628 	remain = sizeof(struct mitsud90_plane_hdr) + be16_to_cpu(hdr->cols) * be16_to_cpu(hdr->rows) * 3;
629 	while(remain) {
630 		i = read(data_fd, job->databuf + job->datalen, remain);
631 		if (i == 0) {
632 			mitsud90_cleanup_job(job);
633 			return CUPS_BACKEND_CANCEL;
634 		}
635 		if (i < 0) {
636 			mitsud90_cleanup_job(job);
637 			return CUPS_BACKEND_CANCEL;
638 		}
639 		job->datalen += i;
640 		remain -= i;
641 	}
642 
643 	/* Read in the footer.  Hopefully. */
644 	remain = sizeof(struct mitsud90_job_footer);
645 	i = read(data_fd, job->databuf + job->datalen, remain);
646 	if (i == 0) {
647 		mitsud90_cleanup_job(job);
648 		return CUPS_BACKEND_CANCEL;
649 	}
650 	if (i < 0) {
651 		mitsud90_cleanup_job(job);
652 		return CUPS_BACKEND_CANCEL;
653 	}
654 
655 	/* See if this is a job footer.  If it is, keep, else holdover. */
656 	if (job->databuf[job->datalen + 0] != 0x1b ||
657 	    job->databuf[job->datalen + 1] != 0x42 ||
658 	    job->databuf[job->datalen + 2] != 0x51 ||
659 	    job->databuf[job->datalen + 3] != 0x31) {
660 		memcpy(&ctx->holdover, job->databuf + job->datalen, sizeof(struct mitsud90_job_footer));
661 	        ctx->holdover_on = 1;
662 	} else {
663 		job->datalen += i;
664 		ctx->holdover_on = 0;
665 	}
666 
667 	/* Sanity check */
668 	if (hdr->pano.pano_on) {
669 		ERROR("Unable to handle panorama jobs yet\n");
670 		mitsud90_cleanup_job(job);
671 		return CUPS_BACKEND_CANCEL;
672 	}
673 
674 	*vjob = job;
675 
676 	return CUPS_BACKEND_OK;
677 }
678 
mitsud90_main_loop(void * vctx,const void * vjob)679 static int mitsud90_main_loop(void *vctx, const void *vjob) {
680 	struct mitsud90_ctx *ctx = vctx;
681 	struct mitsud90_job_hdr *hdr;
682 	struct mitsud90_status_resp resp;
683 	uint8_t last_status[2] = {0xff, 0xff};
684 
685 	int sent;
686 	int ret;
687 	int copies;
688 
689 	const struct mitsud90_printjob *job = vjob;
690 
691 	if (!ctx)
692 		return CUPS_BACKEND_FAILED;
693 	if (!job)
694 		return CUPS_BACKEND_FAILED;
695 	copies = job->copies;
696 
697 	hdr = (struct mitsud90_job_hdr*) job->databuf;
698 
699 	INFO("Waiting for printer idle...\n");
700 
701 top:
702 	sent = 0;
703 
704 	// XXX Figure out if printer is asleep, and wake it up if necessary.
705 
706 	/* Query status, wait for idle or error out */
707 	do {
708 		if (mitsud90_query_status(ctx, &resp))
709 			return CUPS_BACKEND_FAILED;
710 
711 		if (resp.code[0] != D90_ERROR_STATUS_OK) {
712 			ERROR("Printer reported error condition: %s (%02x %02x)\n",
713 			      mitsud90_error_codes(resp.code), resp.code[0], resp.code[1]);
714 			return CUPS_BACKEND_STOP;
715 		}
716 
717 		if (resp.code[1] & D90_ERROR_STATUS_OK_WARMING ||
718 		    resp.temp & D90_ERROR_STATUS_OK_WARMING ) {
719 			INFO("Printer warming up\n");
720 			sleep(1);
721 			continue;
722 		}
723 		if (resp.code[1] & D90_ERROR_STATUS_OK_COOLING ||
724 			   resp.temp & D90_ERROR_STATUS_OK_COOLING) {
725 			INFO("Printer cooling down\n");
726 			sleep(1);
727 			continue;
728 		}
729 
730 		if (resp.mecha[0] != last_status[0] ||
731 		    resp.mecha[1] != last_status[1]) {
732 			INFO("Printer status: %s\n",
733 			     mitsud90_mecha_statuses(resp.mecha));
734 			last_status[0] = resp.mecha[0];
735 			last_status[1] = resp.mecha[1];
736 		}
737 
738 		if (resp.mecha[0] == D90_MECHA_STATUS_IDLE) {
739 			break;
740 			// we don't have to wait until idle, just
741 			// until we have free buffers.  Don't know how
742 			// to check this though.. XXXX
743 		}
744 	} while(1);
745 
746 
747 	/* Send memory check */
748 	{
749 		struct mitsud90_memcheck mem;
750 		struct mitsud90_memcheck_resp mem_resp;
751 		int num;
752 
753 		memcpy(&mem, hdr, sizeof(mem));
754 		mem.hdr[0] = 0x1b;
755 		mem.hdr[1] = 0x47;
756 		mem.hdr[2] = 0x44;
757 		mem.hdr[3] = 0x33;
758 
759 		if ((ret = send_data(ctx->dev, ctx->endp_down,
760 				     (uint8_t*) &mem, sizeof(mem))))
761 			return CUPS_BACKEND_FAILED;
762 
763 		ret = read_data(ctx->dev, ctx->endp_up,
764 				(uint8_t*)&mem_resp, sizeof(mem_resp), &num);
765 
766 		if (ret < 0)
767 			return ret;
768 		if (num != sizeof(mem_resp)) {
769 			ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(mem_resp));
770 			return 4;
771 		}
772 		if (mem_resp.size_bad || mem_resp.mem_bad == 0xff) {
773 			ERROR("Printer reported bad print params (%02x)\n", mem_resp.size_bad);
774 			return CUPS_BACKEND_CANCEL;
775 		}
776 		if (mem_resp.mem_bad) {
777 			ERROR("Printer buffers full, retrying!\n");
778 			sleep(1);
779 			goto top;
780 		}
781 	}
782 
783 	/* Send header */
784 	if ((ret = send_data(ctx->dev, ctx->endp_down,
785 			     job->databuf + sent, sizeof(*hdr))))
786 		return CUPS_BACKEND_FAILED;
787 	sent += sizeof(*hdr);
788 
789 	/* Send Plane header */
790 	if ((ret = send_data(ctx->dev, ctx->endp_down,
791 			     job->databuf + sent, sizeof(*hdr))))
792 		return CUPS_BACKEND_FAILED;
793 	sent += sizeof(*hdr);
794 
795 	/* Send payload + footer */
796 	if ((ret = send_data(ctx->dev, ctx->endp_down,
797 			     job->databuf + sent, job->datalen - sent)))
798 		return CUPS_BACKEND_FAILED;
799 //	sent += (job->datalen - sent);
800 
801 	/* Wait for completion */
802 	do {
803 		sleep(1);
804 
805 		if (mitsud90_query_status(ctx, &resp))
806 			return CUPS_BACKEND_FAILED;
807 
808 		if (resp.code[0] != D90_ERROR_STATUS_OK) {
809 			ERROR("Printer reported error condition: %s (%02x %02x)\n",
810 			      mitsud90_error_codes(resp.code), resp.code[0], resp.code[1]);
811 			return CUPS_BACKEND_STOP;
812 		}
813 
814 		if (resp.mecha[0] != last_status[0] ||
815 		    resp.mecha[1] != last_status[1]) {
816 			INFO("Printer status: %s\n",
817 			     mitsud90_mecha_statuses(resp.mecha));
818 			last_status[0] = resp.mecha[0];
819 			last_status[1] = resp.mecha[1];
820 		}
821 
822 		/* Terminate when printing complete */
823 		if (resp.mecha[0] == D90_MECHA_STATUS_IDLE) {
824 			break;
825 		}
826 
827 		if (fast_return && copies <= 1) { /* Copies generated by backend? */
828 			INFO("Fast return mode enabled.\n");
829 			break;
830 		}
831 	} while(1);
832 
833 	/* Clean up */
834 	if (terminate)
835 		copies = 1;
836 
837 	INFO("Print complete (%d copies remaining)\n", copies - 1);
838 
839 	if (copies && --copies) {
840 		goto top;
841 	}
842 
843 	return CUPS_BACKEND_OK;
844 }
845 
mitsud90_query_job(struct mitsud90_ctx * ctx,uint16_t jobid,struct mitsud90_job_resp * resp)846 static int mitsud90_query_job(struct mitsud90_ctx *ctx, uint16_t jobid,
847 	struct mitsud90_job_resp *resp)
848 {
849 	struct mitsud90_job_query req;
850 	int ret, num;
851 
852 	req.hdr[0] = 0x1b;
853 	req.hdr[1] = 0x47;
854 	req.hdr[2] = 0x44;
855 	req.hdr[3] = 0x31;
856 	req.jobid = cpu_to_be16(jobid);
857 
858 	if ((ret = send_data(ctx->dev, ctx->endp_down,
859 			     (uint8_t*) &req, sizeof(req))))
860 		return ret;
861 	memset(resp, 0, sizeof(*resp));
862 	ret = read_data(ctx->dev, ctx->endp_up,
863 			(uint8_t*) resp, sizeof(*resp), &num);
864 
865 	if (ret < 0)
866 		return ret;
867 	if (num != sizeof(*resp)) {
868 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
869 		return 4;
870 	}
871 
872 	return CUPS_BACKEND_OK;
873 }
874 
mitsud90_get_jobstatus(struct mitsud90_ctx * ctx,uint16_t jobid)875 static int mitsud90_get_jobstatus(struct mitsud90_ctx *ctx, uint16_t jobid)
876 {
877 	struct mitsud90_job_resp resp;
878 
879 	if (mitsud90_query_job(ctx, jobid, &resp))
880 		return CUPS_BACKEND_FAILED;
881 
882 	INFO("Job Status:  %04x = %02x/%02x/%04x\n",
883 	     jobid, resp.unk1, resp.unk2, be16_to_cpu(resp.unk3));
884 
885 	return CUPS_BACKEND_OK;
886 }
887 
mitsud90_get_media(struct mitsud90_ctx * ctx)888 static int mitsud90_get_media(struct mitsud90_ctx *ctx)
889 {
890 	struct mitsud90_media_resp resp;
891 
892 	if (mitsud90_query_media(ctx, &resp))
893 		return CUPS_BACKEND_FAILED;
894 
895 	INFO("Media Type:  %s (%02x/%02x)\n",
896 	     mitsu70x_media_types(resp.media.brand, resp.media.type),
897 	     resp.media.brand,
898 	     resp.media.type);
899 	INFO("Prints Remaining:  %03d/%03d\n",
900 	     be16_to_cpu(resp.media.remain),
901 	     be16_to_cpu(resp.media.capacity));
902 
903 	return CUPS_BACKEND_OK;
904 }
905 
mitsud90_get_status(struct mitsud90_ctx * ctx)906 static int mitsud90_get_status(struct mitsud90_ctx *ctx)
907 {
908 	struct mitsud90_status_resp resp;
909 
910 	if (mitsud90_query_status(ctx, &resp))
911 		return CUPS_BACKEND_FAILED;
912 
913 	mitsud90_dump_status(&resp);
914 
915 	return CUPS_BACKEND_OK;
916 }
917 
mitsud90_get_info(struct mitsud90_ctx * ctx)918 int mitsud90_get_info(struct mitsud90_ctx *ctx)
919 {
920 	uint8_t cmdbuf[26];
921 	int ret, num;
922 	struct mitsud90_info_resp resp;
923 
924 	cmdbuf[0] = 0x1b;
925 	cmdbuf[1] = 0x47;
926 	cmdbuf[2] = 0x44;
927 	cmdbuf[3] = 0x30;
928 	cmdbuf[4] = 0;
929 	cmdbuf[5] = 0;
930 	cmdbuf[6] = 19;  /* Number of commands */
931 
932 	cmdbuf[7] = D90_STATUS_TYPE_MODEL;
933 	cmdbuf[8] = 0x02;
934 	cmdbuf[9] = 0x0b;
935 	cmdbuf[10] = 0x0c;
936 
937 	cmdbuf[11] = 0x0d;
938 	cmdbuf[12] = 0x0e;
939 	cmdbuf[13] = 0x0f;
940 	cmdbuf[14] = 0x11;
941 
942 	cmdbuf[15] = 0x13;
943 	cmdbuf[16] = 0x1e;
944 	cmdbuf[17] = 0x22;
945 	cmdbuf[18] = 0x28;
946 
947 	cmdbuf[19] = 0x29;
948 	cmdbuf[20] = 0x2b;
949 	cmdbuf[21] = 0x2c;
950 	cmdbuf[22] = 0x65;
951 
952 	cmdbuf[23] = 0x82;
953 	cmdbuf[24] = 0x83;
954 	cmdbuf[25] = 0x84;
955 
956 	if ((ret = send_data(ctx->dev, ctx->endp_down,
957 			     cmdbuf, sizeof(cmdbuf))))
958 		return ret;
959 	memset(&resp, 0, sizeof(resp));
960 
961 	ret = read_data(ctx->dev, ctx->endp_up,
962 			(uint8_t*) &resp, sizeof(resp), &num);
963 
964 	if (ret < 0)
965 		return ret;
966 	if (num != sizeof(resp)) {
967 		ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(resp));
968 		return 4;
969 	}
970 
971 	/* start dumping output */
972 	memset(cmdbuf, 0, sizeof(cmdbuf));
973 	memcpy(cmdbuf, resp.model, sizeof(resp.model));
974 	INFO("Model: %s\n", (char*)cmdbuf);
975 	for (num = 0; num < 7 ; num++) {
976 		memset(cmdbuf, 0, sizeof(cmdbuf));
977 		memcpy(cmdbuf, resp.fw_vers[num].version, sizeof(resp.fw_vers[num].version));
978 		INFO("FW Component %02d: %s (%04x)\n",
979 		     num, cmdbuf, be16_to_cpu(resp.fw_vers[num].csum));
980 	}
981 	INFO("TYPE_02: %02x\n", resp.x02);
982 	INFO("TYPE_1e: %02x\n", resp.x1e);
983 	INFO("TYPE_22: %02x %02x\n", resp.x22[0], resp.x22[1]);
984 	INFO("TYPE_28: %02x %02x\n", resp.x28[0], resp.x28[1]);
985 	INFO("TYPE_29: %02x %02x %02x %02x %02x %02x %02x %02x\n",
986 	     resp.x29[0], resp.x29[1], resp.x29[2], resp.x29[3],
987 	     resp.x29[4], resp.x29[5], resp.x29[6], resp.x29[7]);
988 	INFO("TYPE_2b: %02x %02x\n", resp.x2b[0], resp.x2b[1]);
989 	INFO("TYPE_2c: %02x %02x\n", resp.x2c[0], resp.x2c[1]);
990 
991 	INFO("TYPE_65:");
992 	for (num = 0; num < 50 ; num++) {
993 		DEBUG2(" %02x", resp.x65[num]);
994 	}
995 	DEBUG2("\n");
996 	INFO("TYPE_1e: %82x\n", resp.x82);
997 	INFO("TYPE_1e: %83x\n", resp.x83);
998 
999 	/* XXX Dump iSerial, sleep time settings */
1000 	// XXX what about resume, wait time, "cut limit" ?
1001 
1002 	return CUPS_BACKEND_OK;
1003 }
1004 
mitsud90_dumpall(struct mitsud90_ctx * ctx)1005 static int mitsud90_dumpall(struct mitsud90_ctx *ctx)
1006 {
1007 	int i;
1008 	uint8_t cmdbuf[8];
1009 	uint8_t buf[256];
1010 
1011 	cmdbuf[0] = 0x1b;
1012 	cmdbuf[1] = 0x47;
1013 	cmdbuf[2] = 0x44;
1014 	cmdbuf[3] = 0x30;
1015 	cmdbuf[4] = 0;
1016 	cmdbuf[5] = 0;
1017 	cmdbuf[6] = 0x01;  /* Number of commands */
1018 
1019 	for (i = 0 ; i < 256 ; i++) {
1020 		int num, ret;
1021 
1022 		cmdbuf[7] = i;
1023 
1024 		if ((ret = send_data(ctx->dev, ctx->endp_down,
1025 				     cmdbuf, sizeof(cmdbuf))))
1026 			return ret;
1027 		memset(buf, 0, sizeof(buf));
1028 
1029 		ret = read_data(ctx->dev, ctx->endp_up,
1030 				buf, sizeof(buf), &num);
1031 
1032 		if (ret <= 0)
1033 			continue;
1034 
1035 		if (num > 4) {
1036 			DEBUG("TYPE %02x LEN: %d (%d)\n", i, num, num - 4);
1037 			DEBUG("<--");
1038 			for (ret = 0; ret < num ; ret ++) {
1039 				DEBUG2(" %x", buf[ret]);
1040 			}
1041 			DEBUG2("\n");
1042 		}
1043 	}
1044 
1045 	return CUPS_BACKEND_OK;
1046 }
1047 
mitsud90_set_iserial(struct mitsud90_ctx * ctx,uint8_t enabled)1048 static int mitsud90_set_iserial(struct mitsud90_ctx *ctx, uint8_t enabled)
1049 {
1050 	uint8_t cmdbuf[23];
1051 	int ret, num;
1052 
1053 	enabled = (enabled) ? 0: 0x80;
1054 
1055 	/* Send Parameter.. */
1056 	cmdbuf[0] = 0x1b;
1057 	cmdbuf[1] = 0x31;
1058 	cmdbuf[2] = 0x36;
1059 	cmdbuf[3] = 0x30;
1060 	cmdbuf[4] = 0x41;
1061 	cmdbuf[5] = 0xbe;
1062 	cmdbuf[6] = 0x00;
1063 	cmdbuf[7] = 0x00;
1064 
1065 	cmdbuf[8] = 0x00;
1066 	cmdbuf[9] = 0x01;
1067 	cmdbuf[10] = 0x00;
1068 	cmdbuf[11] = 0x00;
1069 	cmdbuf[12] = 0x00;
1070 	cmdbuf[13] = 0x11;
1071 	cmdbuf[14] = 0xff;
1072 	cmdbuf[15] = 0xff;
1073 
1074 	cmdbuf[16] = 0xff;
1075 	cmdbuf[17] = 0xfe;
1076 	cmdbuf[18] = 0xff;
1077 	cmdbuf[19] = 0xff;
1078 	cmdbuf[20] = 0xff;
1079 	cmdbuf[21] = 0xfe;
1080 	cmdbuf[22] = enabled;
1081 
1082 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1083 			     cmdbuf, sizeof(cmdbuf))))
1084 		return ret;
1085 
1086 	ret = read_data(ctx->dev, ctx->endp_up,
1087 			cmdbuf, sizeof(cmdbuf), &num);
1088 
1089 	/* No response */
1090 
1091 	return ret;
1092 }
1093 
mitsud90_set_sleeptime(struct mitsud90_ctx * ctx,uint16_t time)1094 static int mitsud90_set_sleeptime(struct mitsud90_ctx *ctx, uint16_t time)
1095 {
1096 	uint8_t cmdbuf[24];
1097 	int ret;
1098 
1099 	/* 255 minutes max, according to RE work */
1100 	if (time > 255)
1101 		time = 255;
1102 
1103 	/* Send Parameter.. */
1104 	cmdbuf[0] = 0x1b;
1105 	cmdbuf[1] = 0x31;
1106 	cmdbuf[2] = 0x36;
1107 	cmdbuf[3] = 0x30;
1108 	cmdbuf[4] = 0x41;
1109 	cmdbuf[5] = 0xbe;
1110 	cmdbuf[6] = 0x00;
1111 	cmdbuf[7] = 0x00;
1112 
1113 	cmdbuf[8] = 0x00;
1114 	cmdbuf[9] = 0x02;
1115 	cmdbuf[10] = 0x00;
1116 	cmdbuf[11] = 0x00;
1117 	cmdbuf[12] = 0x05;
1118 	cmdbuf[13] = 0x02;
1119 	cmdbuf[14] = 0xff;
1120 	cmdbuf[15] = 0xff;
1121 
1122 	cmdbuf[16] = 0xff;
1123 	cmdbuf[17] = 0xfd;
1124 	cmdbuf[18] = 0xff;
1125 	cmdbuf[19] = 0xff;
1126 	cmdbuf[20] = 0xfa;
1127 	cmdbuf[21] = 0xff;
1128 	cmdbuf[22] = (time >> 8) & 0xff;
1129 	cmdbuf[23] = time & 0xff;
1130 
1131 	if ((ret = send_data(ctx->dev, ctx->endp_down,
1132 			     cmdbuf, 4)))
1133 		return ret;
1134 
1135 	/* No response */
1136 
1137 	return 0;
1138 }
1139 
mitsud90_cmdline(void)1140 static void mitsud90_cmdline(void)
1141 {
1142 	DEBUG("\t\t[ -i ]           # Query printer info\n");
1143 	DEBUG("\t\t[ -j jobid ]     # Query job status\n");
1144 	DEBUG("\t\t[ -k time ]      # Set sleep time in minutes\n");
1145 	DEBUG("\t\t[ -m ]           # Query printer media\n");
1146 	DEBUG("\t\t[ -s ]           # Query printer status\n");
1147 	DEBUG("\t\t[ -x 0|1 ]       # Enable/disable iSerial reporting\n");
1148 //	DEBUG("\t\t[ -Z ]           # Dump all parameters\n");
1149 }
1150 
mitsud90_cmdline_arg(void * vctx,int argc,char ** argv)1151 static int mitsud90_cmdline_arg(void *vctx, int argc, char **argv)
1152 {
1153 	struct mitsud90_ctx *ctx = vctx;
1154 	int i, j = 0;
1155 
1156 	if (!ctx)
1157 		return -1;
1158 
1159 	while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "ij:k:msx:Z")) >= 0) {
1160 		switch(i) {
1161 		GETOPT_PROCESS_GLOBAL
1162 		case 'i':
1163 			j = mitsud90_get_info(ctx);
1164 			break;
1165 		case 'j':
1166 			j = mitsud90_get_jobstatus(ctx, atoi(optarg));
1167 			break;
1168 		case 'k':
1169 			j = mitsud90_set_sleeptime(ctx, atoi(optarg));
1170 			break;
1171 		case 'm':
1172 			j = mitsud90_get_media(ctx);
1173 			break;
1174 		case 's':
1175 			j = mitsud90_get_status(ctx);
1176 			break;
1177 		case 'x':
1178 			j = mitsud90_set_iserial(ctx, atoi(optarg));
1179 			break;
1180 		case 'Z':
1181 			j = mitsud90_dumpall(ctx);
1182 			break;
1183 		default:
1184 			break;  /* Ignore completely */
1185 		}
1186 
1187 		if (j) return j;
1188 	}
1189 
1190 	return 0;
1191 }
1192 
mitsud90_query_markers(void * vctx,struct marker ** markers,int * count)1193 static int mitsud90_query_markers(void *vctx, struct marker **markers, int *count)
1194 {
1195 	struct mitsud90_ctx *ctx = vctx;
1196 	struct mitsud90_media_resp resp;
1197 
1198 	*markers = &ctx->marker;
1199 	*count = 1;
1200 
1201 	if (mitsud90_query_media(ctx, &resp))
1202 		return CUPS_BACKEND_FAILED;
1203 
1204 	ctx->marker.levelnow = be16_to_cpu(resp.media.remain);
1205 
1206 	return CUPS_BACKEND_OK;
1207 }
1208 
1209 static const char *mitsud90_prefixes[] = {
1210 	"mitsubishi-d90dw",
1211 	// backwards compatibility
1212 	"mitsud90",
1213 	NULL
1214 };
1215 
1216 /* Exported */
1217 struct dyesub_backend mitsud90_backend = {
1218 	.name = "Mitsubishi CP-D90DW",
1219 	.version = "0.13",
1220 	.uri_prefixes = mitsud90_prefixes,
1221 	.cmdline_arg = mitsud90_cmdline_arg,
1222 	.cmdline_usage = mitsud90_cmdline,
1223 	.init = mitsud90_init,
1224 	.attach = mitsud90_attach,
1225 	.cleanup_job = mitsud90_cleanup_job,
1226 	.read_parse = mitsud90_read_parse,
1227 	.main_loop = mitsud90_main_loop,
1228 	.query_markers = mitsud90_query_markers,
1229 	.devices = {
1230 		{ USB_VID_MITSU, USB_PID_MITSU_D90, P_MITSU_D90, NULL, "mitsubishi-d90dw"},
1231 		{ 0, 0, 0, NULL, NULL}
1232 	}
1233 };
1234 
1235 /*
1236    Mitsubishi CP-D90DW data format
1237 
1238    All multi-byte values are BIG endian
1239 
1240  [[HEADER 1]]
1241 
1242    1b 53 50 30 00 33 XX XX  YY YY 64 00 00 01 00 ??  XX XX == COLS, YY XX ROWS (BE)
1243    ?? ?? ?? ?? ?? ?? ?? ??  00 00 00 00 00 00 00 00  <-- cut position, see below
1244    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1245    QQ RR SS HH VV 00 00 00  00 00 01 00 03 II 09 7c  QQ == 02 matte, 00 glossy,
1246    09 4c 00 00 02 58 00 0c  00 06                    RR == 00 auto, 03 == fine, 02 == superfine.
1247                                                      SS == 00 colorcorr, 01 == none
1248                                                      HH/VV sharpening for Horiz/Vert, 0-8, 0 is off, 4 is normal
1249   [pad to 512b]
1250 
1251                 normal  == rows  00  00 00  00  00 00  00  00 00
1252                 4x6div2 == 1226  00  02 65  01  00 00  01  00 00
1253                 8x6div2 == 2488  01  04 be  00  00 00  00  00 00
1254 
1255 		    guesses based on SDK docs:
1256 
1257 		9x6div2 == 2728  01  05 36  00  00 00  00  00 00
1258 		9x6div3 == 2724  00  03 90  00  07 14  00  00 00
1259 		9x6div4 == 2628  00  02 97  00  05 22  00  07 ad
1260 
1261     from [01 00 03 03] onwards, only shows in 8x20" PANORAMA prints.  Assume 2" overlap.
1262     II == 01 02 03 (which panel # in panorama!)
1263     [02 58] == 600, aka 2" * 300dpi?
1264     [09 4c] == 2380  (48 less than 8 size? (trim length on ends?)
1265     [09 7c] == 2428  (ie 8" print)
1266 
1267      (6x20 == 1852x6036)
1268      (6x14 == 1852x4232)
1269 
1270      3*8" panels == 2428*3=7284.  -6036 = 1248.  /2 = 624 (0x270)
1271 
1272  [[DATA PLANE HEADER]]
1273 
1274    1b 5a 54 01 00 09 00 00  00 00 XX XX YY YY 00 00
1275    ...
1276    [pad to 512b]
1277 
1278     data, BGR packed, 8bpp.  No padding to 512b!
1279 
1280  [[FOOTER]]
1281 
1282    1b 42 51 31 00 TT                  ## TT == secs to wait for second print
1283 
1284 
1285  ****************************************************
1286 
1287 Comms Protocol for D90:
1288 
1289  [[ ERROR STATUS ]]
1290 
1291 -> 1b 47 44 30 00 00 01 16
1292 <- e4 47 44 30 00 00 00 00  00 00 00 00 00 00 00   [Normal/OK]
1293 <- e4 47 44 30 XX 00 00 00  00 00 00 00 00 3f 37   [Error condition]
1294                                                    XX == 29 (printer open)
1295                                                          28 (cut bin missing)
1296 <- e4 47 44 30 21 90 00 00  01 00 00 00 00 3f 37   No ribbon
1297 
1298  [[ MEDIA STATUS ]]
1299 
1300 -> 1b 47 44 30 00 00 01 2a
1301 <- e4 47 44 30 ff 0f 50 00  01 ae 01 9b 01 00      [Normal/OK]
1302 <- e4 47 44 30 ff ff ff ff  ff ff ff ff ff ff      [Error]
1303 
1304  [[ MECHA STATUS ]]
1305 
1306 -> 1b 47 44 30 00 00 01 17
1307 <- e4 47 44 30 SS SS
1308 
1309  [[ TEMPERATURE QUERY ]]
1310 
1311 -> 1b 47 44 30 00 00 01 1f
1312 <- e4 47 44 30 HH
1313 
1314  [[ UNKNOWN QUERY ]]
1315 -> 1b 47 44 30 00 00 01 28
1316 <- e4 47 44 30 XX XX        Unknown, seems to increment.
1317 
1318  [[ JOB STATUS QUERY ?? ]]
1319 
1320 -> 1b 47 44 31 00 00 JJ JJ  Jobid?
1321 <- e4 47 44 31 XX YY ZZ ZZ  No idea.. sure.
1322 
1323  [[ COMBINED STATUS QUERIES ]]
1324 
1325 -> 1b 47 44 30 00 00 04 16  17 1f 2a
1326 <- e4 47 44 30
1327 
1328    MM NN 00 00 ZZ 00 00 00  00 QQ QQ   [id 16, total 11]
1329    SS SS                               [id 17, total 2]
1330    HH                                  [id 1f, total 1]
1331    VV TT WW 00 XX XX YY YY  01 00      [id 2a, total 10]
1332 
1333    WW    == 0x50 or 0x00 (seen, no idea what it means)
1334    VV    == Media vendor (0xff etc)
1335    TT    == Media type, 0x02/0x0f etc (see mitsu70x_media_types!)
1336    XX XX == Media capacity, BE
1337    YY YY == Media remain,   BE
1338    QQ QQ == 00 00 normal, 3f 37 error
1339    MM NN == MM major err (00 if no error) NN minor error.
1340    ZZ    == 01 seen for _some_ errors.
1341    SS SS == Mecha Status  (00 == ready, 50 == printing, 80+10 == feedandcut, 80 == initializing?
1342    HH    == Temperature state.  00 is OK, 0x40 is low, 0x80 is hot.
1343    II II == ??
1344    JJ JJ == ??
1345 
1346  [[ WAKE UP PRINTER ]]
1347 -> 1b 45 57 55
1348 
1349  [[ GET iSERIAL ]]
1350 
1351 -> 1b 61 36 36 41 be 00 00
1352    00 01 00 00 00 11 ff ff
1353    ff fe ff ff ff ee
1354 <- e4 61 36 36 41 be 00 00
1355    00 01 00 00 00 11 ff ff
1356    ff fe ff ff ff ee XX      <- XX is 0x80 or 0x00.  (0x80)  ISERIAL OFF
1357 
1358  [[ GET CUT? ]]
1359 
1360 -> 1b 61 36 36 45 ba 00 00
1361    00 01 00 00 05 07 ff ff
1362    ff fe ff ff fa f8
1363 -> e4 61 36 36 45 ba 00 00
1364    00 01 00 00 05 07 ff ff
1365    ff fe ff ff fa f8 XX      <- XX is 0x80 or 0x00    (0x00)  CUT ON?
1366 
1367  [[ GET WAIT TIME ]]
1368 
1369 -> 1b 61 36 36 45 00 00 00
1370    00 01 00 00 05 05 ff ff
1371    ff fe ff ff fa fb
1372 -> 1b 61 36 36 45 00 00 00
1373    00 01 00 00 05 05 ff ff
1374    ff fe ff ff fa fb XX      <- XX is time in seconds.
1375 
1376  [[ GET RESUME? ]]
1377 
1378 -> 1b 61 36 36 45 ba 00 00
1379    00 01 00 00 05 06 ff ff
1380    ff fe ff ff fa f9
1381 -> e4 61 36 36 45 ba 00 00
1382    00 01 00 00 05 06 ff ff
1383    ff fe ff ff fa f9 XX      <- XX is 0x80 or 0x00    (0x80)  (OFF)
1384 
1385  [[ GET SLEEP TIME! ]]
1386 
1387 -> 1b 61 36 36 45 ba 00 00
1388    00 02 00 00 05 02 ff ff
1389    ff fd ff ff fa fd
1390 <- e4 61 36 36 45 00 00 00
1391    00 02 00 00 05 02 ff ff
1392    ff fd ff ff fa fd XX 00     <- XX, sleep time in minutes.
1393 
1394  [[ SET SLEEP TIME! ]]
1395 
1396 -> 1b 61 36 30 45 ba 00 00
1397    00 02 00 00 05 02 ff ff
1398    ff fd ff ff fa fd XX 00     <- XX, sleep time in minutes.
1399 
1400  [[ SET iSERIAL ]]
1401 
1402 -> 1b 61 36 30 41 be 00 00
1403    00 01 00 00 00 11 ff ff
1404    ff fe ff ff ff ee XX        <- XX 0x80 OFF, 0x00 ON.
1405 
1406  [[ SANITY CHECK PRINT ARGUMENTS / MEMTEST ]]
1407 
1408 -> 1b 47 44 33 00 33 07 3c  04 ca 64 00 00 01 00 00
1409    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1410    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1411    00 00 00 04 04 00 00 00  00 00 00 00 00 00 00 00
1412    [[ pad to 512 ]]
1413 
1414    ... 07 3c onwards is the same as main payload header.
1415 
1416 <- e4 47 44 43 XX YY
1417 
1418    ... possibly the same as the D70's "memorystatus"
1419        XX == size ok (non-zero if bad size)
1420        YY == memory ok (non-zero or 0xff if full?)
1421 
1422  [[ SEND OVER HDRs and DATA ]]
1423 
1424    ... Print arguments:
1425 
1426 -> 1b 53 50 30 00 33 07 3c  04 ca 64 00 00 01 00 00
1427    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1428    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
1429    00 00 00 04 04 00 00 00  00 00 00 00 00 00 00 00
1430    [[ pad to 512 ]]
1431 
1432    ... Data transfer.  Plane header:
1433 
1434 -> 1b 5a 54 01 00 09 00 00  00 00 07 3c 04 ca 00 00
1435    [[ pad to 512 ]]
1436 
1437 -> [[print data]] [[ padded? ]]
1438 -> [[print data]]
1439 
1440 -> 1b 42 51 31 00 ZZ
1441 
1442    ... Footer.
1443    ZZ == Seconds to wait for follow-up print (0x05)
1444 
1445 
1446  */
1447