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