1 /*
2  *   Kodak 605 Photo Printer CUPS backend -- libusb-1.0 version
3  *
4  *   (c) 2013-2019 Solomon Peachy <pizza@shaftnet.org>
5  *
6  *   The latest version of this program can be found at:
7  *
8  *     http://git.shaftnet.org/cgit/selphy_print.git
9  *
10  *   This program is free software; you can redistribute it and/or modify it
11  *   under the terms of the GNU General Public License as published by the Free
12  *   Software Foundation; either version 2 of the License, or (at your option)
13  *   any later version.
14  *
15  *   This program is distributed in the hope that it will be useful, but
16  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  *   for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
22  *
23  *          [http://www.gnu.org/licenses/gpl-2.0.html]
24  *
25  *   SPDX-License-Identifier: GPL-2.0+
26  *
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 
39 #define BACKEND kodak605_backend
40 
41 #include "backend_common.h"
42 #include "backend_sinfonia.h"
43 
44 #define USB_VID_KODAK       0x040A
45 #define USB_PID_KODAK_605   0x402E
46 #define USB_PID_KODAK_7000  0x4035
47 #define USB_PID_KODAK_7010  0x4037
48 #define USB_PID_KODAK_7015  0x4038
49 
50 /* List of confirmed commands */
51 //#define SINFONIA_CMD_GETSTATUS  0x0001
52 //#define SINFONIA_CMD_MEDIAINFO  0x0002
53 //#define SINFONIA_CMD_PRINTJOB   0x4001
54 //#define SINFONIA_CMD_UPDATE     0xC004
55 
56 /* Media structure */
57 struct kodak605_media_list {
58 	struct sinfonia_status_hdr hdr;
59 	uint8_t  unk;  /* always seen 02 */
60 	uint8_t  type; /* KODAK68x0_MEDIA_* */
61 	uint8_t  count;
62 	struct sinfonia_mediainfo_item entries[];
63 } __attribute__((packed));
64 
65 #define MAX_MEDIA_LEN 128
66 
67 /* Status response */
68 struct kodak605_status {
69 	struct sinfonia_status_hdr hdr;
70 /*@10*/	uint32_t ctr_life;  /* Lifetime Prints */
71 	uint32_t ctr_maint; /* Prints since last maintenance */
72 	uint32_t ctr_media; /* Prints on current media */
73 	uint32_t ctr_cut;   /* Cutter Actuations */
74 	uint32_t ctr_head;  /* Prints on current head */
75 /*@30*/	uint8_t  donor;     /* Donor Percentage remaining */
76 /*@31*/	uint8_t  null_1[7]; /* 00 00 00 00 00 00 00 */
77 /*@38*/	uint8_t  b1_id;     /* jobid */
78 	uint16_t b1_remain;
79 	uint16_t b1_complete;
80 	uint16_t b1_total;
81 /*@45*/	uint8_t  b1_sts;    /* See BANK_STATUS_* */
82 	uint8_t  b2_id;     /* jobid */
83 	uint16_t b2_remain;
84 	uint16_t b2_complete;
85 	uint16_t b2_total;
86 /*@53*/	uint8_t  b2_sts;    /* see BANK_STATUS_* */
87 /*@54*/	uint8_t  id;        /* current job id ( 00/01/02 seen ) */
88 /*@55*/ uint16_t remain;    /* in current job */
89 /*@57*/	uint16_t complete;  /* in current job */
90 /*@59*/	uint16_t total;     /* in current job */
91 /*@61*/	uint8_t  null_2[9]; /* 00 00 00 00 00 00 00 00 00 */
92 /*@70*/	uint8_t  unk_12[6]; /* 01 00 00 00 00 00 (605) 01 01 01 01 00 00 (EK7000) */
93 /*@76*/	uint8_t  unk_13[1]; // EK7000-series only?
94 } __attribute__((packed));
95 
96 #define CMDBUF_LEN 4
97 
98 /* Private data structure */
99 struct kodak605_ctx {
100 	struct sinfonia_usbdev dev;
101 
102 	uint8_t jobid;
103 
104 	struct kodak605_media_list *media;
105 
106 	struct marker marker;
107 };
108 
109 /* Note this is for Kodak 7000-series only! */
error_codes(uint8_t major,uint8_t minor)110 static const char *error_codes(uint8_t major, uint8_t minor)
111 {
112 	switch(major) {
113 	case 0x01: /* "Controller Error" */
114 		switch(minor) {
115 		case 0x01:
116 			return "Controller: EEPROM Write Timeout";
117 		case 0x02:
118 			return "Controller: EEPROM Verify";
119 		case 0x09:
120 			return "Controller: DSP FW Boot";
121 		case 0x0A:
122 			return "Controller: Invalid Print Parameter Table";
123 		case 0x0B:
124 			return "Controller: DSP FW Mismatch";
125 		case 0x0C:
126 			return "Controller: Print Parameter Table Mismatch";
127 		case 0x0D:
128 			return "Controller: ASIC Error";
129 		case 0x0E:
130 			return "Controller: FPGA Error";
131 		case 0x0F:
132 			return "Controller: Main FW Checksum";
133 		case 0x10:
134 			return "Controller: Main FW Write Failed";
135 		case 0x11:
136 			return "Controller: DSP Checksum";
137 		case 0x12:
138 			return "Controller: DSP FW Write Failed";
139 		case 0x13:
140 			return "Controller: Print Parameter Table Checksum";
141 		case 0x14:
142 			return "Controller: Print Parameter Table Write Failed";
143 		case 0x15:
144 			return "Controller: User Tone Curve Write Failed";
145 		case 0x16:
146 			return "Controller: Main-DSP Communication";
147 		case 0x17:
148 			return "Controller: DSP DMA Failed";
149 		case 0x18:
150 			return "Controller: Matte Pattern Write Failed";
151 		case 0x19:
152 			return "Controller: Matte not Initialized";
153 		case 0x20:
154 			return "Controller: Serial Number Error";
155 		default:
156 			return "Controller: Unknown";
157 		}
158 	case 0x02: /* "Mechanical Error" */
159 		switch (minor) {
160 		case 0x01:
161 			return "Mechanical: Pinch Head Up";
162 		case 0x02:
163 			return "Mechanical: Pinch Head Down";
164 		case 0x03:
165 			return "Mechanical: Pinch Roll Main Up Feed Up";
166 		case 0x04:
167 			return "Mechanical: Pinch Roll Main Dn Feed Up";
168 		case 0x05:
169 			return "Mechanical: Pinch Roll Main Dn Feed Dn";
170 		case 0x06:
171 			return "Mechanical: Pinch Roll Eject Up";
172 		case 0x07:
173 			return "Mechanical: Pinch Roll Eject Dn";
174 		case 0x0B:
175 			return "Mechanical: Cutter (Left->Right)";
176 		case 0x0C:
177 			return "Mechanical: Cutter (Right->Left)";
178 		default:
179 			return "Mechanical: Unknown";
180 		}
181 	case 0x03: /* "Sensor Error" */
182 		switch (minor) {
183 		case 0x01:
184 			return "Sensor: Head Up/Dn All On";
185 		case 0x02:
186 			return "Sensor: Feed Pitch Roll Up/Dn All On";
187 		case 0x05:
188 			return "Sensor: Cutter L/R All On";
189 		case 0x06:
190 			return "Sensor: Cutter L Stuck On";
191 		case 0x07:
192 			return "Sensor: Cutter Move not Detected";
193 		case 0x08:
194 			return "Sensor: Cutter R Stuck On";
195 		case 0x09:
196 			return "Sensor: Head Up Unstable";
197 		case 0x0A:
198 			return "Sensor: Head Dn Unstable";
199 		case 0x0B:
200 			return "Sensor: Main/Feed Pinch Up Unstabe";
201 		case 0x0C:
202 			return "Sensor: Main/Feed Pinch Dn Unstable";
203 		case 0x0D:
204 			return "Sensor: Eject Up Unstable";
205 		case 0x0E:
206 			return "Sensor: Eject Dn Unstable";
207 		case 0x0F:
208 			return "Sensor: Left Cutter Unstable";
209 		case 0x10:
210 			return "Sensor: Right Cutter Unstable";
211 		case 0x11:
212 			return "Sensor: Center Cutter Unstable";
213 		case 0x12:
214 			return "Sensor: Upper Cover Unstable";
215 		case 0x13:
216 			return "Sensor: Paper Cover Unstable";
217 		case 0x14:
218 			return "Sensor: Ribbon Takeup Unstable";
219 		case 0x15:
220 			return "Sensor: Ribbon Supply Unstable";
221 		default:
222 			return "Sensor: Unknown";
223 		}
224 	case 0x04: /* "Temperature Sensor Error" */
225 		switch (minor) {
226 		case 0x01:
227 			return "Temp Sensor: Thermal Head High";
228 		case 0x02:
229 			return "Temp Sensor: Thermal Head Low";
230 		case 0x05:
231 			return "Temp Sensor: Environment High";
232 		case 0x09:
233 			return "Temp Sensor: Environment Low";
234 		case 0x0A:
235 			return "Temp Sensor: Preheat";
236 		default:
237 			return "Temp Sensor: Unknown";
238 		}
239 	case 0x5: /* "Paper Jam" */
240 		switch (minor) {
241 		// XXX these have been seen on EK7000:
242 		// case 0x0c:
243 		// case 0x36:
244 		case 0x3D:
245 			return "Paper Jam: Feed Cut->Home";
246 		case 0x3E:
247 			return "Paper Jam: Feed Cut->Exit Stuck Off";
248 		case 0x3F:
249 			return "Paper Jam: Feed Cut->Exit Stuck On";
250 		case 0x4A:
251 			return "Paper Jam: Idle / Paper Set";
252 		case 0x51:
253 			return "Paper Jam: Paper Exit On";
254 		case 0x52:
255 			return "Paper Jam: Print Position On";
256 		case 0x53:
257 			return "Paper Jam: Paper Empty On";
258 		case 0x54:
259 			return "Paper Jam: Idle / Paper Not Set";
260 		default:
261 			return "Paper Jam: Unknown";
262 		}
263 	case 0x06: /* User Error */
264 		switch (minor) {
265 		case 0x01:
266 			return "Drawer Unit Open";
267 		case 0x02:
268 			return "Incorrect Ribbon";
269 		case 0x03:
270 			return "No/Empty Ribbon";
271 		case 0x04:
272 			return "Mismatched Ribbon";
273 		case 0x08:
274 			return "No Paper";
275 		case 0x0C:
276 			return "Paper End";
277 		default:
278 			return "User: Unknown";
279 		}
280 	default:
281 		return "Unknown";
282 	}
283 }
284 
kodak605_get_media(struct kodak605_ctx * ctx,struct kodak605_media_list * media)285 static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_list *media)
286 {
287 	struct sinfonia_cmd_hdr cmd;
288 
289 	int i, ret, num = 0;
290 
291 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_MEDIAINFO);
292 	cmd.len = cpu_to_le16(0);
293 
294 	if ((ret = sinfonia_docmd(&ctx->dev,
295 				  (uint8_t*)&cmd, sizeof(cmd),
296 				  (uint8_t*)media, MAX_MEDIA_LEN,
297 				  &num))) {
298 		return ret;
299 	}
300 
301 	for (i = 0 ; i < media->count; i++) {
302 		media->entries[i].rows = le16_to_cpu(media->entries[i].rows);
303 		media->entries[i].columns = le16_to_cpu(media->entries[i].columns);
304 	}
305 
306 	return 0;
307 }
308 
kodak605_get_status(struct kodak605_ctx * ctx,struct kodak605_status * sts)309 static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status *sts)
310 {
311 	struct sinfonia_cmd_hdr cmd;
312 
313 	int ret, num = 0;
314 
315 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
316 	cmd.len = cpu_to_le16(0);
317 
318 	if ((ret = sinfonia_docmd(&ctx->dev,
319 				  (uint8_t*)&cmd, sizeof(cmd),
320 				  (uint8_t*)sts, sizeof(*sts), &num)) < 0) {
321 		return ret;
322 	}
323 
324 	return 0;
325 }
326 
kodak605_init(void)327 static void *kodak605_init(void)
328 {
329 	struct kodak605_ctx *ctx = malloc(sizeof(struct kodak605_ctx));
330 	if (!ctx) {
331 		ERROR("Memory Allocation Failure!\n");
332 		return NULL;
333 	}
334 	memset(ctx, 0, sizeof(struct kodak605_ctx));
335 
336 	ctx->media = malloc(MAX_MEDIA_LEN);
337 
338 	return ctx;
339 }
340 
kodak605_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)341 static int kodak605_attach(void *vctx, struct libusb_device_handle *dev, int type,
342 			   uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
343 {
344 	struct kodak605_ctx *ctx = vctx;
345 
346 	ctx->dev.dev = dev;
347 	ctx->dev.endp_up = endp_up;
348 	ctx->dev.endp_down = endp_down;
349 	ctx->dev.type = type;
350 	ctx->dev.error_codes = &error_codes;
351 
352 	/* Make sure jobid is sane */
353 	ctx->jobid = jobid & 0x7f;
354 	if (!ctx->jobid)
355 		ctx->jobid++;
356 
357 	if (test_mode < TEST_MODE_NOATTACH) {
358 		/* Query media info */
359 		if (kodak605_get_media(ctx, ctx->media)) {
360 			ERROR("Can't query media\n");
361 			return CUPS_BACKEND_FAILED;
362 		}
363 	} else {
364 		int media_code = KODAK6_MEDIA_6TR2;
365 		if (getenv("MEDIA_CODE"))
366 			media_code = atoi(getenv("MEDIA_CODE"));
367 
368 		ctx->media->type = media_code;
369 	}
370 
371 	ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
372 	ctx->marker.name = kodak6_mediatypes(ctx->media->type);
373 	ctx->marker.levelmax = 100; /* Ie percentage */
374 	ctx->marker.levelnow = -2;
375 
376 	return CUPS_BACKEND_OK;
377 }
378 
kodak605_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)379 static int kodak605_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
380 	struct kodak605_ctx *ctx = vctx;
381 	int ret;
382 
383 	struct sinfonia_printjob *job = NULL;
384 
385 	if (!ctx)
386 		return CUPS_BACKEND_CANCEL;
387 
388 	job = malloc(sizeof(*job));
389 	if (!job) {
390 		ERROR("Memory allocation failure!\n");
391 		return CUPS_BACKEND_RETRY_CURRENT;
392 	}
393 	memset(job, 0, sizeof(*job));
394 
395 	/* Read in header */
396 	ret = sinfonia_raw10_read_parse(data_fd, job);
397 	if (ret) {
398 		free(job);
399 		return ret;
400 	}
401 
402 	/* Printer handles generating copies.. */
403 	if (le16_to_cpu(job->jp.copies) < (uint16_t)copies)
404 		job->jp.copies = cpu_to_le16(copies);
405 
406 	*vjob = job;
407 
408 	return CUPS_BACKEND_OK;
409 }
410 
kodak605_main_loop(void * vctx,const void * vjob)411 static int kodak605_main_loop(void *vctx, const void *vjob) {
412 	struct kodak605_ctx *ctx = vctx;
413 
414 	struct kodak605_status sts;
415 
416 	int num, ret;
417 
418 	const struct sinfonia_printjob *job = vjob;
419 
420 	if (!ctx)
421 		return CUPS_BACKEND_FAILED;
422 	if (!job)
423 		return CUPS_BACKEND_FAILED;
424 
425 	/* Validate against supported media list */
426 	for (num = 0 ; num < ctx->media->count; num++) {
427 		if (ctx->media->entries[num].rows == job->jp.rows &&
428 		    ctx->media->entries[num].columns == job->jp.columns)
429 			break;
430 	}
431 	if (num == ctx->media->count) {
432 		ERROR("Print size unsupported by media!\n");
433 		return CUPS_BACKEND_HOLD;
434 	}
435 
436 	INFO("Waiting for printer idle\n");
437 
438 	while(1) {
439 		if ((ret = kodak605_get_status(ctx, &sts)))
440 			return CUPS_BACKEND_FAILED;
441 
442 		if (ctx->marker.levelnow != sts.donor) {
443 			ctx->marker.levelnow = sts.donor;
444 			dump_markers(&ctx->marker, 1, 0);
445 		}
446 
447 		if (sts.hdr.result != RESULT_SUCCESS) {
448 			ERROR("Printer Status:  %02x (%s)\n", sts.hdr.status,
449 			      sinfonia_status_str(sts.hdr.status));
450 			ERROR("Result: %02x Error: %02x (%s) %02x/%02x = %s\n",
451 			      sts.hdr.result, sts.hdr.error,
452 			      sinfonia_error_str(sts.hdr.error),
453 			      sts.hdr.printer_major, sts.hdr.printer_minor,
454 			      error_codes(sts.hdr.printer_major, sts.hdr.printer_minor));
455 			return CUPS_BACKEND_FAILED;
456 		}
457 
458 		/* Make sure we're not colliding with an existing
459 		   jobid */
460 		while (ctx->jobid == sts.b1_id ||
461 		       ctx->jobid == sts.b2_id) {
462 			ctx->jobid++;
463 			ctx->jobid &= 0x7f;
464 			if (!ctx->jobid)
465 				ctx->jobid++;
466 		}
467 
468 		/* Wait for a free buffer */
469 		if (sts.b1_sts == BANK_STATUS_FREE ||
470 		    sts.b2_sts == BANK_STATUS_FREE) {
471 			break;
472 		}
473 
474 		sleep(1);
475 	}
476 
477 	/* Send print job */
478 	struct sinfonia_printcmd10_hdr hdr;
479 
480 	INFO("Sending print job (internal id %u)\n", ctx->jobid);
481 
482 	/* Set up header */
483 	hdr.hdr.cmd = cpu_to_le16(SINFONIA_CMD_PRINTJOB);
484 	hdr.hdr.len = cpu_to_le16(10);
485 	hdr.jobid = ctx->jobid;
486 	hdr.rows = cpu_to_le16(job->jp.rows);
487 	hdr.columns = cpu_to_le16(job->jp.columns);
488 	hdr.copies = cpu_to_le16(job->jp.copies);
489 	hdr.media = job->jp.media;
490 	hdr.oc_mode = job->jp.oc_mode;
491 	hdr.method = job->jp.method;
492 
493 retry_print:
494 	if ((ret = sinfonia_docmd(&ctx->dev,
495 				  (uint8_t*)&hdr, sizeof(hdr),
496 				  (uint8_t*)&sts.hdr, sizeof(sts.hdr),
497 				  &num)) < 0) {
498 		return ret;
499 	}
500 
501 	if (sts.hdr.result != RESULT_SUCCESS) {
502 		if (sts.hdr.error == ERROR_BUFFER_FULL) {
503 			INFO("Printer Buffers full, retrying\n");
504 			sleep(1);
505 			goto retry_print;
506 		} else if ((sts.hdr.status & 0xf0) == 0x30 || sts.hdr.status == ERROR_BUFFER_FULL) {
507 			INFO("Printer busy (%02x : %s), retrying\n", sts.hdr.status, sinfonia_status_str(sts.hdr.status));
508 
509 		} else {
510 			ERROR("Unexpected response from print command!\n");
511 			ERROR("Printer Status:  %02x: %s\n", sts.hdr.status, sinfonia_status_str(sts.hdr.status));
512 			ERROR("Result: %02x Error: %02x (%02x %02x = %s)\n",
513 			      sts.hdr.result, sts.hdr.error,
514 			      sts.hdr.printer_major, sts.hdr.printer_minor,
515 			      error_codes(sts.hdr.printer_major, sts.hdr.printer_minor));
516 
517 			return CUPS_BACKEND_FAILED;
518 		}
519 	}
520 
521 	INFO("Sending image data\n");
522 	if ((ret = send_data(ctx->dev.dev, ctx->dev.endp_down,
523 			     job->databuf, job->datalen)))
524 		return CUPS_BACKEND_FAILED;
525 
526 	INFO("Waiting for printer to acknowledge completion\n");
527 	do {
528 		sleep(1);
529 		if ((kodak605_get_status(ctx, &sts)) != 0)
530 			return CUPS_BACKEND_FAILED;
531 
532 		if (ctx->marker.levelnow != sts.donor) {
533 			ctx->marker.levelnow = sts.donor;
534 			dump_markers(&ctx->marker, 1, 0);
535 		}
536 
537 		INFO("Printer Status:  %02x (%s)\n", sts.hdr.status,
538 		     sinfonia_status_str(sts.hdr.status));
539 
540 		if (sts.hdr.result != RESULT_SUCCESS ||
541 		    sts.hdr.error == ERROR_PRINTER) {
542 			INFO("Result: %02x Error: %02x (%s) %02x/%02x = %s\n",
543 			     sts.hdr.result, sts.hdr.error,
544 			     sinfonia_error_str(sts.hdr.error),
545 			     sts.hdr.printer_major, sts.hdr.printer_minor,
546 			     error_codes(sts.hdr.printer_major, sts.hdr.printer_minor));
547 			return CUPS_BACKEND_STOP;
548 		}
549 
550 		/* Wait for completion */
551 		if (sts.b1_id == ctx->jobid && sts.b1_complete == sts.b1_total)
552 			break;
553 		if (sts.b2_id == ctx->jobid && sts.b2_complete == sts.b2_total)
554 			break;
555 
556 		if (sts.hdr.status == STATUS_READY)
557 			break;
558 
559 		if (fast_return) {
560 			INFO("Fast return mode enabled.\n");
561 			break;
562 		}
563 	} while(1);
564 
565 	INFO("Print complete\n");
566 	return CUPS_BACKEND_OK;
567 }
568 
kodak605_dump_status(struct kodak605_ctx * ctx,struct kodak605_status * sts)569 static void kodak605_dump_status(struct kodak605_ctx *ctx, struct kodak605_status *sts)
570 {
571 	INFO("Status: %02x (%s)\n",
572 	     sts->hdr.status, sinfonia_status_str(sts->hdr.status));
573 	INFO("Error: %02x (%s) %02x/%02x = %s\n",
574 	     sts->hdr.error, sinfonia_error_str(sts->hdr.error),
575 	     sts->hdr.printer_major, sts->hdr.printer_minor,
576 	     error_codes(sts->hdr.printer_major, sts->hdr.printer_minor));
577 
578 	INFO("Bank 1: %s Job %03u @ %03u/%03u\n",
579 	     sinfonia_bank_statuses(sts->b1_sts), sts->b1_id,
580 	     le16_to_cpu(sts->b1_complete), le16_to_cpu(sts->b1_total));
581 	INFO("Bank 2: %s Job %03u @ %03u/%03u\n",
582 	     sinfonia_bank_statuses(sts->b2_sts), sts->b2_id,
583 	     le16_to_cpu(sts->b2_complete), le16_to_cpu(sts->b2_total));
584 
585 	INFO("Lifetime prints   : %u\n", le32_to_cpu(sts->ctr_life));
586 	INFO("Cutter actuations : %u\n", le32_to_cpu(sts->ctr_cut));
587 	INFO("Head prints       : %u\n", le32_to_cpu(sts->ctr_head));
588 	INFO("Media prints      : %u\n", le32_to_cpu(sts->ctr_media));
589 	{
590 		int max;
591 
592 		switch(ctx->media->type) {
593 		case KODAK6_MEDIA_6R:
594 		case KODAK6_MEDIA_6TR2:
595 			max = 375;
596 			break;
597 		case KODAK7_MEDIA_6R:
598 			max = 570;
599 			break;
600 		default:
601 			max = 0;
602 			break;
603 		}
604 
605 		if (max) {
606 			INFO("\t  Remaining     : %u\n", max - le32_to_cpu(sts->ctr_media));
607 		} else {
608 			INFO("\t  Remaining     : Unknown\n");
609 		}
610 	}
611 
612 	INFO("Donor             : %u%%\n", sts->donor);
613 }
614 
kodak605_dump_mediainfo(struct kodak605_media_list * media)615 static void kodak605_dump_mediainfo(struct kodak605_media_list *media)
616 {
617 	int i;
618 
619         if (media->type == KODAK6_MEDIA_NONE) {
620                 DEBUG("No Media Loaded\n");
621                 return;
622         }
623 	kodak6_dumpmediacommon(media->type);
624 
625 	DEBUG("Legal print sizes:\n");
626 	for (i = 0 ; i < media->count ; i++) {
627 		DEBUG("\t%d: %ux%u (%x)\n", i,
628 		      media->entries[i].columns,
629 		      media->entries[i].rows,
630 		      media->entries[i].code);
631 	}
632 	DEBUG("\n");
633 }
634 
kodak605_cmdline(void)635 static void kodak605_cmdline(void)
636 {
637 	DEBUG("\t\t[ -c filename ]  # Get user/NV tone curve\n");
638 	DEBUG("\t\t[ -C filename ]  # Set tone curve\n");
639 	DEBUG("\t\t[ -e ]           # Query error log\n");
640 	DEBUG("\t\t[ -F ]           # Flash Printer LED\n");
641 	DEBUG("\t\t[ -i ]           # Query printer info\n");
642 	DEBUG("\t\t[ -l filename ]  # Get current tone curve\n");
643 	DEBUG("\t\t[ -L filename ]  # Set current tone curve\n");
644 	DEBUG("\t\t[ -m ]           # Query media\n");
645 	DEBUG("\t\t[ -r ]           # Reset user/NV tone curve\n");
646 	DEBUG("\t\t[ -R ]           # Reset printer to factory defaults\n");
647 	DEBUG("\t\t[ -s ]           # Query status\n");
648 	DEBUG("\t\t[ -X jobid ]     # Cancel job\n");
649 }
650 
kodak605_cmdline_arg(void * vctx,int argc,char ** argv)651 static int kodak605_cmdline_arg(void *vctx, int argc, char **argv)
652 {
653 	struct kodak605_ctx *ctx = vctx;
654 	int i, j = 0;
655 
656 	if (!ctx)
657 		return -1;
658 
659 	while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "c:C:eFil:L:mrRsX:")) >= 0) {
660 		switch(i) {
661 		GETOPT_PROCESS_GLOBAL
662 		case 'c':
663 			j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_USER, optarg);
664 			break;
665 		case 'C':
666 			j = sinfonia_settonecurve(&ctx->dev, TONECURVE_USER, optarg);
667 			break;
668 		case 'e':
669 			j = sinfonia_geterrorlog(&ctx->dev);
670 			break;
671 		case 'F':
672 			j = sinfonia_flashled(&ctx->dev);
673 			break;
674 		case 'i':
675 			j = sinfonia_getfwinfo(&ctx->dev);
676 			break;
677 		case 'l':
678 			j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
679 			break;
680 		case 'L':
681 			j = sinfonia_settonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
682 			break;
683 		case 'm':
684 			kodak605_dump_mediainfo(ctx->media);
685 			break;
686 		case 'r':
687 			j = sinfonia_resetcurve(&ctx->dev, RESET_TONE_CURVE, TONE_CURVE_ID);
688 			break;
689 		case 'R':
690 			j = sinfonia_resetcurve(&ctx->dev, RESET_PRINTER, 0);
691 			break;
692 		case 's': {
693 			struct kodak605_status sts;
694 
695 			j = kodak605_get_status(ctx, &sts);
696 			if (!j)
697 				kodak605_dump_status(ctx, &sts);
698 			break;
699 		case 'X':
700 			j = sinfonia_canceljob(&ctx->dev, atoi(optarg));
701 			break;
702 		}
703 		default:
704 			break;  /* Ignore completely */
705 		}
706 
707 		if (j) return j;
708 	}
709 
710 	return 0;
711 }
712 
kodak605_query_markers(void * vctx,struct marker ** markers,int * count)713 static int kodak605_query_markers(void *vctx, struct marker **markers, int *count)
714 {
715 	struct kodak605_ctx *ctx = vctx;
716 	struct kodak605_status sts;
717 
718 	/* Query printer status */
719 	if (kodak605_get_status(ctx, &sts))
720 		return CUPS_BACKEND_FAILED;
721 
722 	ctx->marker.levelnow = sts.donor;
723 
724 	*markers = &ctx->marker;
725 	*count = 1;
726 
727 	return CUPS_BACKEND_OK;
728 }
729 
730 static const char *kodak605_prefixes[] = {
731 	"kodak605",  // Family driver, do NOT nuke.
732 	"kodak-605", "kodak-7000", "kodak-7010", "kodak-7015",
733 	NULL,
734 };
735 
736 /* Exported */
737 struct dyesub_backend kodak605_backend = {
738 	.name = "Kodak 605/70xx",
739 	.version = "0.45" " (lib " LIBSINFONIA_VER ")",
740 	.uri_prefixes = kodak605_prefixes,
741 	.cmdline_usage = kodak605_cmdline,
742 	.cmdline_arg = kodak605_cmdline_arg,
743 	.init = kodak605_init,
744 	.attach = kodak605_attach,
745 	.cleanup_job = sinfonia_cleanup_job,
746 	.read_parse = kodak605_read_parse,
747 	.main_loop = kodak605_main_loop,
748 	.query_markers = kodak605_query_markers,
749 	.devices = {
750 		{ USB_VID_KODAK, USB_PID_KODAK_605, P_KODAK_605, "Kodak", "kodak-605"},
751 		{ USB_VID_KODAK, USB_PID_KODAK_7000, P_KODAK_7000, "Kodak", "kodak-7000"},
752 		{ USB_VID_KODAK, USB_PID_KODAK_7010, P_KODAK_701X, "Kodak", "kodak-7010"},
753 		{ USB_VID_KODAK, USB_PID_KODAK_7015, P_KODAK_701X, "Kodak", "kodak-7015"},
754 		{ 0, 0, 0, NULL, NULL}
755 	}
756 };
757 
758 /* Kodak 605/70xx data format
759 
760   Spool file consists of 14-byte header followed by plane-interleaved BGR data.
761   Native printer resolution is 1844 pixels per row on all models but 7015,
762   which is 1548 pixels per row.
763 
764   All fields are LITTLE ENDIAN unless otherwise specified
765 
766   Header:
767 
768   01 40 0a 00                    Fixed header
769   XX                             Job ID
770   CC CC                          Number of copies (1-???)
771   WW WW                          Number of columns (Fixed at 1844 or 1548)
772   HH HH                          Number of rows
773   DD                             0x01 (4x6) 0x03 (8x6)
774   LL                             Laminate, 0x01/0x02/0x03 (off/on/satin[70xx only])
775   00                             Print Mode (???)
776 
777   ************************************************************************
778 
779   Note:  Kodak 605  is actually a Shinko CHC-S1545-5A
780   Note:  Kodak 7000 is actually a Shinko CHC-S1645-5A
781   Note:  Kodak 7010 is actually a Shinko CHC-S1645-5B
782   Note:  Kodak 7015 is actually a Shinko CHC-S1645-5C
783 
784   ************************************************************************
785 
786 */
787