1 /*
2 * Kodak 6800/6850 Photo Printer CUPS backend -- libusb-1.0 version
3 *
4 * (c) 2013-2019 Solomon Peachy <pizza@shaftnet.org>
5 *
6 * Development of this backend was sponsored by:
7 *
8 * LiveLink Technology [ www.livelinktechnology.net ]
9 *
10 * The latest version of this program can be found at:
11 *
12 * http://git.shaftnet.org/cgit/selphy_print.git
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the Free
16 * Software Foundation; either version 2 of the License, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 *
27 * [http://www.gnu.org/licenses/gpl-2.0.html]
28 *
29 * SPDX-License-Identifier: GPL-2.0+
30 *
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <signal.h>
42
43 #define BACKEND kodak6800_backend
44
45 #include "backend_common.h"
46 #include "backend_sinfonia.h"
47
48 #define USB_VID_KODAK 0x040A
49 #define USB_PID_KODAK_6800 0x4021
50 #define USB_PID_KODAK_6850 0x402B
51
52 /* File header */
53 struct kodak6800_hdr {
54 uint8_t hdr[7]; /* Always 03 1b 43 48 43 0a 00 */
55 uint8_t jobid; /* Non-zero */
56 uint16_t copies; /* BE, in BCD format (1-9999) */
57 uint16_t columns; /* BE */
58 uint16_t rows; /* BE */
59 uint8_t size; /* media size; 0x06 for 6x8, 0x00 for 6x4, 0x07 for 5x7 */
60 uint8_t laminate; /* 0x01 to laminate, 0x00 for not */
61 uint8_t method; /* 0x00 or 0x01 (for 4x6 on 6x8 media), 0x21 for 2x6, 0x23 for 3x6 */
62 } __attribute__((packed));
63
64 struct kodak68x0_status_readback {
65 uint8_t hdr; /* Always 01 */
66 uint8_t status; /* STATUS_* */
67 uint8_t status1; /* STATUS1_* */
68 uint32_t status2; /* STATUS2_* */
69 uint8_t errcode; /* Error ## */
70 uint32_t lifetime; /* Lifetime Prints (BE) */
71 uint32_t maint; /* Maint Prints (BE) */
72 uint32_t media; /* Media Prints (6850), Unknown (6800) (BE) */
73 uint32_t cutter; /* Cutter Actuations (BE) */
74 uint8_t nullB[2];
75 uint8_t errtype; /* seen 0x00 or 0xd0 */
76 uint8_t donor; /* Percentage, 0-100 */
77 uint16_t main_boot; /* Always 003 */
78 uint16_t main_fw; /* seen 6xx/8xx (6850) and 2xx/3xx/4xx (6800) */
79 uint16_t dsp_boot; /* Always 001 */
80 uint16_t dsp_fw; /* Seen 5xx (6850) and 1xx (6800) */
81 uint8_t b1_jobid;
82 uint8_t b2_jobid;
83 uint16_t b1_remain; /* Remaining prints in job */
84 uint16_t b1_complete; /* Completed prints in job */
85 uint16_t b1_total; /* Total prints in job */
86 uint16_t b2_remain; /* Remaining prints in job */
87 uint16_t b2_complete; /* Completed prints in job */
88 uint16_t b2_total; /* Total prints in job */
89 uint8_t curve_status; /* Always seems to be 0x00 */
90 } __attribute__((packed));
91
92 #define MAX_MEDIAS 16
93
94 struct kodak68x0_media_readback {
95 uint8_t hdr; /* Always 0x01 */
96 uint8_t type; /* Media code, KODAK68x0_MEDIA_xxx */
97 uint8_t null[5];
98 uint8_t count; /* Always 0x04 (6800) or 0x06 (6850)? */
99 struct sinfonia_mediainfo_item sizes[];
100 } __attribute__((packed));
101
102 #define CMDBUF_LEN 17
103
104 /* Private data structure */
105 struct kodak6800_ctx {
106 struct libusb_device_handle *dev;
107 uint8_t endp_up;
108 uint8_t endp_down;
109
110 int type;
111 int supports_sub4x6;
112
113 uint8_t jobid;
114
115 struct sinfonia_mediainfo_item sizes[MAX_MEDIAS];
116 uint8_t media_count;
117 uint8_t media_type;
118
119 struct kodak68x0_status_readback sts;
120
121 struct marker marker;
122 };
123
124 /* Baseline commands */
kodak6800_do_cmd(struct kodak6800_ctx * ctx,void * cmd,int cmd_len,void * resp,int resp_len,int * actual_len)125 static int kodak6800_do_cmd(struct kodak6800_ctx *ctx,
126 void *cmd, int cmd_len,
127 void *resp, int resp_len,
128 int *actual_len)
129 {
130 int ret;
131
132 /* Write command */
133 if ((ret = send_data(ctx->dev, ctx->endp_down,
134 cmd, cmd_len)))
135 return (ret < 0) ? ret : -99;
136
137 /* Read response */
138 ret = read_data(ctx->dev, ctx->endp_up,
139 resp, resp_len, actual_len);
140 if (ret < 0)
141 return ret;
142
143 return 0;
144 }
145
kodak68x0_dump_mediainfo(struct sinfonia_mediainfo_item * sizes,uint8_t media_count,uint8_t media_type)146 static void kodak68x0_dump_mediainfo(struct sinfonia_mediainfo_item *sizes,
147 uint8_t media_count, uint8_t media_type)
148 {
149 int i;
150
151 if (media_type == KODAK6_MEDIA_NONE) {
152 INFO("No Media Loaded\n");
153 return;
154 }
155 kodak6_dumpmediacommon(media_type);
156
157 INFO("Legal print sizes:\n");
158 for (i = 0 ; i < media_count ; i++) {
159 INFO("\t%d: %dx%d (%02x)\n", i,
160 sizes[i].columns,
161 sizes[i].rows,
162 sizes[i].method);
163 }
164 INFO("\n");
165 }
166
167 #define MAX_MEDIA_LEN (sizeof(struct kodak68x0_media_readback) + MAX_MEDIAS * sizeof(struct sinfonia_mediainfo_item))
168
kodak6800_get_mediainfo(struct kodak6800_ctx * ctx)169 static int kodak6800_get_mediainfo(struct kodak6800_ctx *ctx)
170 {
171 struct kodak68x0_media_readback *media;
172 uint8_t req[16];
173 int ret, num, i, j;
174
175 memset(req, 0, sizeof(req));
176 media = malloc(MAX_MEDIA_LEN);
177 if (!media) {
178 ERROR("Memory allocation failure!\n");
179 return CUPS_BACKEND_RETRY_CURRENT;
180 }
181
182 for (j = 0 ; j < 2 ; j ++) {
183 memset(media, 0, sizeof(*media));
184
185 req[0] = 0x03;
186 req[1] = 0x1b;
187 req[2] = 0x43;
188 req[3] = 0x48;
189 req[4] = 0x43;
190 req[5] = 0x1a;
191 req[6] = j;
192
193 /* Issue command and get response */
194 if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
195 media, MAX_MEDIA_LEN,
196 &num))) {
197 free(media);
198 return ret;
199 }
200
201 /* Validate proper response */
202 if (media->hdr != CMD_CODE_OK ||
203 media->null[0] != 0x00) {
204 ERROR("Unexpected response from media query!\n");
205 free(media);
206 return CUPS_BACKEND_STOP;
207 }
208 ctx->media_type = media->type;
209
210 for (i = 0; i < media->count ; i++) {
211 memcpy(&ctx->sizes[ctx->media_count], &media->sizes[i], sizeof(struct sinfonia_mediainfo_item));
212 ctx->sizes[ctx->media_count].rows = be16_to_cpu(ctx->sizes[ctx->media_count].rows);
213 ctx->sizes[ctx->media_count].columns = be16_to_cpu(ctx->sizes[ctx->media_count].columns);
214 ctx->media_count++;
215 }
216 if (i < 6)
217 break;
218 }
219
220 free(media);
221 return CUPS_BACKEND_OK;
222 }
223
kodak68x0_canceljob(struct kodak6800_ctx * ctx,int id)224 static int kodak68x0_canceljob(struct kodak6800_ctx *ctx,
225 int id)
226 {
227 uint8_t req[16];
228 int ret, num;
229
230 memset(req, 0, sizeof(req));
231
232 req[0] = 0x03;
233 req[1] = 0x1b;
234 req[2] = 0x43;
235 req[3] = 0x48;
236 req[4] = 0x43;
237 req[5] = 0x13;
238 req[6] = id;
239
240 /* Issue command and get response */
241 if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
242 &ctx->sts, sizeof(ctx->sts),
243 &num)))
244 return ret;
245
246 /* Validate proper response */
247 if (ctx->sts.hdr != CMD_CODE_OK) {
248 ERROR("Unexpected response from job cancel!\n");
249 return -99;
250 }
251
252 return 0;
253 }
254
kodak68x0_reset(struct kodak6800_ctx * ctx)255 static int kodak68x0_reset(struct kodak6800_ctx *ctx)
256 {
257 uint8_t req[16];
258 int ret, num;
259
260 memset(req, 0, sizeof(req));
261
262 req[0] = 0x03;
263 req[1] = 0x1b;
264 req[2] = 0x43;
265 req[3] = 0x48;
266 req[4] = 0xc0;
267
268 /* Issue command and get response */
269 if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
270 &ctx->sts, sizeof(ctx->sts),
271 &num)))
272 return ret;
273
274 /* Validate proper response */
275 if (ctx->sts.hdr != CMD_CODE_OK) {
276 ERROR("Unexpected response from job cancel!\n");
277 return -99;
278 }
279
280 return 0;
281 }
282
kodak68x0_dump_status(struct kodak6800_ctx * ctx,struct kodak68x0_status_readback * status)283 static void kodak68x0_dump_status(struct kodak6800_ctx *ctx, struct kodak68x0_status_readback *status)
284 {
285 char *detail;
286
287 switch (status->status) {
288 case STATUS_PRINTING:
289 detail = "Printing";
290 break;
291 case STATUS_IDLE:
292 detail = "Idle";
293 break;
294 default:
295 detail = "Unknown";
296 break;
297 }
298 INFO("Printer Status : %s\n", detail);
299
300 INFO("Printer State : %s # %02x %08x %02x\n",
301 sinfonia_1x45_status_str(status->status1, status->status2, status->errcode),
302 status->status1, status->status2, status->errcode);
303
304 INFO("Bank 1 ID: %u\n", status->b1_jobid);
305 INFO("\tPrints: %d/%d complete\n",
306 be16_to_cpu(status->b1_complete), be16_to_cpu(status->b1_total));
307 INFO("Bank 2 ID: %u\n", status->b2_jobid);
308 INFO("\tPrints: %d/%d complete\n",
309 be16_to_cpu(status->b2_complete), be16_to_cpu(status->b2_total));
310
311 switch (status->curve_status) {
312 case CURVE_TABLE_STATUS_INITIAL:
313 detail = "Initial/Default";
314 break;
315 case CURVE_TABLE_STATUS_USERSET:
316 detail = "User Stored";
317 break;
318 case CURVE_TABLE_STATUS_CURRENT:
319 detail = "Current";
320 break;
321 default:
322 detail = "Unknown";
323 break;
324 }
325 INFO("Tone Curve Status: %s\n", detail);
326
327 INFO("Counters:\n");
328 INFO("\tLifetime : %u\n", be32_to_cpu(status->lifetime));
329 INFO("\tThermal Head : %u\n", be32_to_cpu(status->maint));
330 INFO("\tCutter : %u\n", be32_to_cpu(status->cutter));
331
332 if (ctx->type == P_KODAK_6850) {
333 int max;
334
335 INFO("\tMedia : %u\n", be32_to_cpu(status->media));
336
337 switch(ctx->media_type) {
338 case KODAK6_MEDIA_6R:
339 case KODAK6_MEDIA_6TR2:
340 max = 375;
341 break;
342 default:
343 max = 0;
344 break;
345 }
346
347 if (max) {
348 INFO("\t Remaining : %u\n", max - be32_to_cpu(status->media));
349 } else {
350 INFO("\t Remaining : Unknown\n");
351 }
352 }
353 INFO("Main FW version : %d\n", be16_to_cpu(status->main_fw));
354 INFO("DSP FW version : %d\n", be16_to_cpu(status->dsp_fw));
355 INFO("Donor : %u%%\n", status->donor);
356 INFO("\n");
357 }
358
kodak6800_get_status(struct kodak6800_ctx * ctx,struct kodak68x0_status_readback * status)359 static int kodak6800_get_status(struct kodak6800_ctx *ctx,
360 struct kodak68x0_status_readback *status)
361 {
362 uint8_t req[16];
363 int ret, num;
364
365 memset(req, 0, sizeof(req));
366 memset(status, 0, sizeof(*status));
367
368 req[0] = 0x03;
369 req[1] = 0x1b;
370 req[2] = 0x43;
371 req[3] = 0x48;
372 req[4] = 0x43;
373 req[5] = 0x03;
374
375 /* Issue command and get response */
376 if ((ret = kodak6800_do_cmd(ctx, req, sizeof(req),
377 status, sizeof(*status),
378 &num)))
379 return ret;
380
381 /* Validate proper response */
382 if (status->hdr != CMD_CODE_OK) {
383 ERROR("Unexpected response from status query!\n");
384 return -99;
385 }
386
387 /* Byteswap important stuff */
388 status->status2 = be32_to_cpu(status->status2);
389
390 return 0;
391 }
392
kodak6800_get_tonecurve(struct kodak6800_ctx * ctx,char * fname)393 static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
394 {
395 uint8_t cmdbuf[16];
396 uint8_t respbuf[64];
397 int ret, num = 0;
398 int i;
399
400 uint16_t *data = malloc(TONE_CURVE_SIZE);
401 if (!data) {
402 ERROR("Memory Allocation Failure\n");
403 return -1;
404 }
405
406 INFO("Dump Tone Curve to '%s'\n", fname);
407
408 /* Initial Request */
409 cmdbuf[0] = 0x03;
410 cmdbuf[1] = 0x1b;
411 cmdbuf[2] = 0x43;
412 cmdbuf[3] = 0x48;
413 cmdbuf[4] = 0x43;
414 cmdbuf[5] = 0x0c;
415 cmdbuf[6] = 0x54;
416 cmdbuf[7] = 0x4f;
417 cmdbuf[8] = 0x4e;
418 cmdbuf[9] = 0x45;
419 cmdbuf[10] = 0x72;
420 cmdbuf[11] = 0x01; /* 01 for user tonecurve, can be 00 or 02 */
421 cmdbuf[12] = 0x00; /* param table? */
422 cmdbuf[13] = 0x00;
423 cmdbuf[14] = 0x00;
424 cmdbuf[15] = 0x00;
425
426 respbuf[0] = 0xff;
427 /* Issue command and get response */
428 if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
429 respbuf, sizeof(respbuf),
430 &num)))
431
432 /* Validate proper response */
433 if (respbuf[0] != CMD_CODE_OK) {
434 ERROR("Unexpected response from tonecurve query!\n");
435 ret = -99;
436 goto done;
437 }
438
439 /* Then we can poll the data */
440 cmdbuf[0] = 0x03;
441 cmdbuf[1] = 0x1b;
442 cmdbuf[2] = 0x43;
443 cmdbuf[3] = 0x48;
444 cmdbuf[4] = 0x43;
445 cmdbuf[5] = 0x0c;
446 cmdbuf[6] = 0x54;
447 cmdbuf[7] = 0x4f;
448 cmdbuf[8] = 0x4e;
449 cmdbuf[9] = 0x45;
450 cmdbuf[10] = 0x20;
451 for (i = 0 ; i < 24 ; i++) {
452 /* Issue command and get response */
453 if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
454 respbuf, sizeof(respbuf),
455 &num)))
456 goto done;
457
458 if (num != 64) {
459 ERROR("Short read! (%d/%d)\n", num, 51);
460 ret = 4;
461 goto done;
462 }
463
464 /* Copy into buffer */
465 memcpy(((uint8_t*)data)+i*64, respbuf, 64);
466 }
467
468 /* Open file and write it out */
469 {
470 int tc_fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
471 if (tc_fd < 0) {
472 ret = 4;
473 goto done;
474 }
475
476 for (i = 0 ; i < 768; i++) {
477 /* Byteswap appropriately */
478 data[i] = cpu_to_be16(le16_to_cpu(data[i]));
479 ret = write(tc_fd, &data[i], sizeof(uint16_t));
480 }
481 close(tc_fd);
482 }
483
484 done:
485 /* We're done */
486 free(data);
487
488 return ret;
489 }
490
kodak6800_set_tonecurve(struct kodak6800_ctx * ctx,char * fname)491 static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
492 {
493 uint8_t cmdbuf[64];
494 uint8_t respbuf[64];
495 int ret, num = 0;
496 int remain;
497
498 uint16_t *data = malloc(TONE_CURVE_SIZE);
499 uint8_t *ptr;
500
501 if (!data) {
502 ERROR("Memory Allocation Failure\n");
503 return -1;
504 }
505
506 INFO("Set Tone Curve from '%s'\n", fname);
507
508 /* Read in file */
509 if ((ret = dyesub_read_file(fname, data, TONE_CURVE_SIZE, NULL))) {
510 ERROR("Failed to read Tone Curve file\n");
511 goto done;
512 }
513
514 /* Byteswap data to printer's format */
515 for (ret = 0; ret < (TONE_CURVE_SIZE)/2 ; ret++) {
516 data[ret] = cpu_to_le16(be16_to_cpu(data[ret]));
517 }
518
519 /* Initial Request */
520 cmdbuf[0] = 0x03;
521 cmdbuf[1] = 0x1b;
522 cmdbuf[2] = 0x43;
523 cmdbuf[3] = 0x48;
524 cmdbuf[4] = 0x43;
525 cmdbuf[5] = 0x0c;
526 cmdbuf[6] = 0x54;
527 cmdbuf[7] = 0x4f;
528 cmdbuf[8] = 0x4e;
529 cmdbuf[9] = 0x45;
530 cmdbuf[10] = 0x77;
531 cmdbuf[11] = 0x01; /* User TC. Can be 00 or 02 */
532 cmdbuf[12] = 0x00; /* param table? */
533 cmdbuf[13] = 0x00;
534 cmdbuf[14] = 0x00;
535 cmdbuf[15] = 0x00;
536
537 /* Issue command and get response */
538 if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
539 respbuf, sizeof(respbuf),
540 &num)))
541
542 /* Validate proper response */
543 if (num != 51) {
544 ERROR("Short read! (%d/%d)\n", num, 51);
545 ret = 4;
546 goto done;
547 }
548
549 if (respbuf[0] != CMD_CODE_OK) {
550 ERROR("Unexpected response from tonecurve set!\n");
551 ret = -99;
552 goto done;
553 }
554
555 ptr = (uint8_t*) data;
556 remain = TONE_CURVE_SIZE;
557 while (remain > 0) {
558 int count = remain > 63 ? 63 : remain;
559
560 cmdbuf[0] = 0x03;
561 memcpy(cmdbuf+1, ptr, count);
562
563 remain -= count;
564 ptr += count;
565
566 /* Issue command and get response */
567 if ((ret = kodak6800_do_cmd(ctx, cmdbuf, count + 1,
568 respbuf, sizeof(respbuf),
569 &num)))
570
571 if (num != 51) {
572 ERROR("Short read! (%d/%d)\n", num, 51);
573 ret = 4;
574 goto done;
575 }
576 if (respbuf[0] != CMD_CODE_OK) {
577 ERROR("Unexpected response from tonecurve set!\n");
578 ret = -99;
579 goto done;
580 }
581 };
582
583 done:
584 /* We're done */
585 free(data);
586 return ret;
587 }
588
kodak6800_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)589 static int kodak6800_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
590 {
591 struct kodak6800_ctx ctx = {
592 .dev = dev,
593 .endp_up = endp_up,
594 .endp_down = endp_down,
595 };
596
597 int ret;
598 int num;
599
600 uint8_t resp[33];
601 uint8_t req[16];
602
603 memset(req, 0, sizeof(req));
604 memset(resp, 0, sizeof(resp));
605
606 req[0] = 0x03;
607 req[1] = 0x1b;
608 req[2] = 0x43;
609 req[3] = 0x48;
610 req[4] = 0x43;
611 req[5] = 0x12;
612
613 /* Issue command and get response */
614 if ((ret = kodak6800_do_cmd(&ctx, req, sizeof(req),
615 resp, sizeof(resp),
616 &num)))
617 return ret;
618
619 if (num != 32) {
620 ERROR("Short read! (%d/%d)\n", num, 32);
621 return -2;
622 }
623
624 strncpy(buf, (char*)resp+24, buf_len);
625 buf[buf_len-1] = 0;
626
627 return 0;
628 }
629
kodak6850_send_unk(struct kodak6800_ctx * ctx)630 static int kodak6850_send_unk(struct kodak6800_ctx *ctx)
631 {
632 uint8_t cmdbuf[16];
633 uint8_t rdbuf[64];
634 int ret = 0, num = 0;
635
636 memset(cmdbuf, 0, sizeof(cmdbuf));
637 cmdbuf[0] = 0x03;
638 cmdbuf[1] = 0x1b;
639 cmdbuf[2] = 0x43;
640 cmdbuf[3] = 0x48;
641 cmdbuf[4] = 0x43;
642 cmdbuf[5] = 0x4c;
643
644 /* Issue command and get response */
645 if ((ret = kodak6800_do_cmd(ctx, cmdbuf, sizeof(cmdbuf),
646 rdbuf, sizeof(rdbuf),
647 &num)))
648 return -1;
649
650 if (num != 51) {
651 ERROR("Short read! (%d/%d)\n", num, 51);
652 return CUPS_BACKEND_FAILED;
653 }
654
655 if (rdbuf[0] != CMD_CODE_OK ||
656 rdbuf[2] != 0x43) {
657 ERROR("Unexpected response from printer init!\n");
658 return CUPS_BACKEND_FAILED;
659 }
660
661 #if 0
662 // XXX No particular idea what this actually is
663 if (rdbuf[1] != 0x01 && rdbuf[1] != 0x00) {
664 ERROR("Unexpected status code (0x%02x)!\n", rdbuf[1]);
665 return CUPS_BACKEND_FAILED;
666 }
667 #endif
668 return ret;
669 }
670
kodak6800_cmdline(void)671 static void kodak6800_cmdline(void)
672 {
673 DEBUG("\t\t[ -c filename ] # Get tone curve\n");
674 DEBUG("\t\t[ -C filename ] # Set tone curve\n");
675 DEBUG("\t\t[ -m ] # Query media\n");
676 DEBUG("\t\t[ -s ] # Query status\n");
677 DEBUG("\t\t[ -R ] # Reset printer\n");
678 DEBUG("\t\t[ -X jobid ] # Cancel Job\n");
679 }
680
kodak6800_cmdline_arg(void * vctx,int argc,char ** argv)681 static int kodak6800_cmdline_arg(void *vctx, int argc, char **argv)
682 {
683 struct kodak6800_ctx *ctx = vctx;
684 int i, j = 0;
685
686 if (!ctx)
687 return -1;
688
689 while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:c:mRsX:")) >= 0) {
690 switch(i) {
691 GETOPT_PROCESS_GLOBAL
692 case 'c':
693 j = kodak6800_get_tonecurve(ctx, optarg);
694 break;
695 case 'C':
696 j = kodak6800_set_tonecurve(ctx, optarg);
697 break;
698 case 'm':
699 kodak68x0_dump_mediainfo(ctx->sizes, ctx->media_count, ctx->media_type);
700 break;
701 case 'R':
702 kodak68x0_reset(ctx);
703 break;
704 case 's': {
705 j = kodak6800_get_status(ctx, &ctx->sts);
706 if (!j)
707 kodak68x0_dump_status(ctx, &ctx->sts);
708 break;
709 }
710 case 'X':
711 j = kodak68x0_canceljob(ctx, atoi(optarg));
712 break;
713 default:
714 break; /* Ignore completely */
715 }
716
717 if (j) return j;
718 }
719
720 return 0;
721 }
722
kodak6800_init(void)723 static void *kodak6800_init(void)
724 {
725 struct kodak6800_ctx *ctx = malloc(sizeof(struct kodak6800_ctx));
726 if (!ctx) {
727 ERROR("Memory Allocation Failure\n");
728 return NULL;
729 }
730 memset(ctx, 0, sizeof(struct kodak6800_ctx));
731
732 return ctx;
733 }
734
kodak6800_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)735 static int kodak6800_attach(void *vctx, struct libusb_device_handle *dev, int type,
736 uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
737 {
738 struct kodak6800_ctx *ctx = vctx;
739
740 ctx->dev = dev;
741 ctx->endp_up = endp_up;
742 ctx->endp_down = endp_down;
743 ctx->type = type;
744
745 /* Ensure jobid is sane */
746 ctx->jobid = jobid & 0x7f;
747 if (!ctx->jobid)
748 ctx->jobid++;
749
750 if (test_mode < TEST_MODE_NOATTACH) {
751 /* Query printer status */
752 if (kodak6800_get_status(ctx, &ctx->sts)) {
753 ERROR("Can't query status\n");
754 return CUPS_BACKEND_FAILED;
755 }
756 uint16_t fw = be16_to_cpu(ctx->sts.main_fw);
757 if (ctx->type == P_KODAK_6850) {
758 if ((fw >= 878) ||
759 (fw < 800 && fw >= 678)) {
760 ctx->supports_sub4x6 = 1;
761 } else {
762 WARNING("Printer FW out of date, recommend updating for current media and features\n");
763 }
764 } else {
765 if ((fw >= 459) ||
766 (fw < 400 && fw >= 359) ||
767 (fw < 300 && fw >= 259)) {
768 ctx->supports_sub4x6 = 1;
769 } else {
770 WARNING("Printer FW out of date, recommend updating for current media and features\n");
771 }
772 }
773
774 /* Query media info */
775 if (kodak6800_get_mediainfo(ctx)) {
776 ERROR("Can't query media\n");
777 return CUPS_BACKEND_FAILED;
778 }
779 } else {
780 int media_code = KODAK6_MEDIA_6TR2;
781 if (getenv("MEDIA_CODE"))
782 media_code = atoi(getenv("MEDIA_CODE"));
783
784 ctx->media_type = media_code;
785 ctx->supports_sub4x6 = 1;
786 }
787
788 ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
789 ctx->marker.name = kodak6_mediatypes(ctx->media_type);
790 ctx->marker.levelmax = 100; /* Ie percentage */
791 ctx->marker.levelnow = -2;
792
793 return CUPS_BACKEND_OK;
794 }
795
kodak6800_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)796 static int kodak6800_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
797 struct kodak6800_ctx *ctx = vctx;
798 int ret;
799
800 struct kodak6800_hdr hdr;
801 struct sinfonia_printjob *job = NULL;
802
803 if (!ctx)
804 return CUPS_BACKEND_FAILED;
805
806 job = malloc(sizeof(*job));
807 if (!job) {
808 ERROR("Memory allocation failure!\n");
809 return CUPS_BACKEND_RETRY_CURRENT;
810 }
811 memset(job, 0, sizeof(*job));
812
813 /* Read in then validate header */
814 ret = read(data_fd, &hdr, sizeof(hdr));
815 if (ret < 0 || ret != sizeof(hdr)) {
816 if (ret == 0) {
817 sinfonia_cleanup_job(job);
818 return CUPS_BACKEND_CANCEL;
819 }
820 ERROR("Read failed (%d/%d/%d)\n",
821 ret, 0, (int)sizeof(hdr));
822 perror("ERROR: Read failed");
823 sinfonia_cleanup_job(job);
824 return CUPS_BACKEND_CANCEL;
825 }
826 if (hdr.hdr[0] != 0x03 ||
827 hdr.hdr[1] != 0x1b ||
828 hdr.hdr[2] != 0x43 ||
829 hdr.hdr[3] != 0x48 ||
830 hdr.hdr[4] != 0x43) {
831 ERROR("Unrecognized data format!\n");
832 sinfonia_cleanup_job(job);
833 return CUPS_BACKEND_CANCEL;
834 }
835
836 uint16_t rows = be16_to_cpu(hdr.rows);
837 uint16_t cols = be16_to_cpu(hdr.columns);
838 if (rows != 1240 && rows != 2434 && rows != 2140 && !ctx->supports_sub4x6) {
839 ERROR("Printer Firmware does not support non-4x6/8x6/5x7 prints, please upgrade!\n");
840 sinfonia_cleanup_job(job);
841 return CUPS_BACKEND_CANCEL;
842 }
843
844 job->datalen = rows * cols * 3;
845 job->databuf = malloc(job->datalen);
846 if (!job->databuf) {
847 ERROR("Memory allocation failure!\n");
848 sinfonia_cleanup_job(job);
849 return CUPS_BACKEND_RETRY_CURRENT;
850 }
851
852 /* Windows driver only sends 634 rows of data, work around */
853 if (rows == 636 && hdr.size == 6 && hdr.method == 0) {
854 rows = 634;
855 job->datalen -= 1844*2*3;
856 }
857
858 /* Read in the spool data */
859 {
860 int remain = job->datalen;
861 uint8_t *ptr = job->databuf;
862 do {
863 ret = read(data_fd, ptr, remain);
864 if (ret < 0) {
865 ERROR("Read failed (%d/%d/%d)\n",
866 ret, remain, job->datalen);
867 perror("ERROR: Read failed");
868 sinfonia_cleanup_job(job);
869 return CUPS_BACKEND_CANCEL;
870 }
871 ptr += ret;
872 remain -= ret;
873 } while (remain);
874 }
875
876 /* Undo the Windows workaround... */
877 if (rows == 634) {
878 rows = 636;
879 job->datalen += 1844*2*3;
880 }
881
882 /* Perform some header re-jiggery */
883 if (hdr.size == 0) {
884 if (cols == 1844)
885 hdr.size = 6;
886 else if (cols == 1548)
887 hdr.size = 7;
888 }
889 if (hdr.method == 0) {
890 if (rows == 636) {
891 hdr.method = 0x21;
892 } else if (rows == 936) {
893 hdr.method = 0x23;
894 } else if (rows == 1240) {
895 hdr.method = 0x01;
896 } else if (rows == 1282) {
897 hdr.method = 0x20;
898 } else if (rows == 1882) {
899 hdr.method = 0x22;
900 } else if (rows == 2490) {
901 hdr.method = 0x2;
902 }
903 }
904
905 hdr.copies = be16_to_cpu(hdr.copies);
906 hdr.copies = packed_bcd_to_uint32((char*)&hdr.copies, 2);
907 if (hdr.copies > 1)
908 copies = hdr.copies;
909
910 /* Fill out job structure */
911 job->jp.copies = copies;
912 job->jp.rows = rows;
913 job->jp.columns = cols;
914 job->jp.media = hdr.size;
915 job->jp.oc_mode = hdr.laminate;
916 job->jp.method = hdr.method;
917
918 *vjob = job;
919
920 return CUPS_BACKEND_OK;
921 }
922
kodak6800_main_loop(void * vctx,const void * vjob)923 static int kodak6800_main_loop(void *vctx, const void *vjob) {
924 struct kodak6800_ctx *ctx = vctx;
925
926 int num, ret;
927 int copies;
928
929 const struct sinfonia_printjob *job = vjob;
930
931 if (!ctx)
932 return CUPS_BACKEND_FAILED;
933 if (!job)
934 return CUPS_BACKEND_FAILED;
935
936 copies = job->jp.copies;
937
938 /* Validate against supported media list */
939 for (num = 0 ; num < ctx->media_count; num++) {
940 if (ctx->sizes[num].rows == job->jp.rows &&
941 ctx->sizes[num].columns == job->jp.columns &&
942 ctx->sizes[num].method == job->jp.method)
943 break;
944 }
945 if (num == ctx->media_count) {
946 ERROR("Print size unsupported by media!\n");
947 return CUPS_BACKEND_HOLD;
948 }
949
950 INFO("Waiting for printer idle\n");
951
952 while(1) {
953 if (kodak6800_get_status(ctx, &ctx->sts))
954 return CUPS_BACKEND_FAILED;
955
956 if (ctx->marker.levelnow != ctx->sts.donor) {
957 ctx->marker.levelnow = ctx->sts.donor;
958 dump_markers(&ctx->marker, 1, 0);
959 }
960
961 if (ctx->sts.status1 == STATE_STATUS1_ERROR) {
962 INFO("Printer State: %s # %02x %08x %02x\n",
963 sinfonia_1x45_status_str(ctx->sts.status1, ctx->sts.status2, ctx->sts.errcode),
964 ctx->sts.status1, ctx->sts.status2, ctx->sts.errcode);
965 return CUPS_BACKEND_FAILED;
966 }
967
968 /* make sure we're not colliding with an existing
969 jobid */
970 while (ctx->jobid == ctx->sts.b1_jobid ||
971 ctx->jobid == ctx->sts.b2_jobid) {
972 ctx->jobid++;
973 ctx->jobid &= 0x7f;
974 if (!ctx->jobid)
975 ctx->jobid++;
976 }
977
978 /* See if we have an open bank */
979 if (!ctx->sts.b1_remain ||
980 !ctx->sts.b2_remain)
981 break;
982
983 sleep(1);
984 }
985
986 /* This command is unknown, sort of a secondary status query */
987 if (ctx->type == P_KODAK_6850) {
988 ret = kodak6850_send_unk(ctx);
989 if (ret)
990 return ret;
991 }
992
993 /* Fix max print count. */
994 if (copies > 9999)
995 copies = 9999;
996
997 /* Fill out printjob header */
998 struct kodak6800_hdr hdr;
999 hdr.hdr[0] = 0x03;
1000 hdr.hdr[1] = 0x1b;
1001 hdr.hdr[2] = 0x43;
1002 hdr.hdr[3] = 0x48;
1003 hdr.hdr[4] = 0x43;
1004 hdr.hdr[5] = 0x0a;
1005 hdr.hdr[6] = 0x00;
1006 hdr.jobid = ctx->jobid;
1007 hdr.copies = uint16_to_packed_bcd(copies);
1008 hdr.columns = cpu_to_be16(job->jp.columns);
1009 hdr.rows = cpu_to_be16(job->jp.rows);
1010 hdr.size = job->jp.media;
1011 hdr.laminate = job->jp.oc_mode;
1012 hdr.method = job->jp.method;
1013
1014 INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
1015 if ((ret = kodak6800_do_cmd(ctx, (uint8_t*) &hdr, sizeof(hdr),
1016 &ctx->sts, sizeof(ctx->sts),
1017 &num)))
1018 return ret;
1019
1020 if (ctx->sts.hdr != CMD_CODE_OK) {
1021 ERROR("Unexpected response from print command!\n");
1022 return CUPS_BACKEND_FAILED;
1023 }
1024
1025 // sleep(1); // Appears to be necessary for reliability
1026 INFO("Sending image data\n");
1027 if ((send_data(ctx->dev, ctx->endp_down,
1028 job->databuf, job->datalen)) != 0)
1029 return CUPS_BACKEND_FAILED;
1030
1031 INFO("Waiting for printer to acknowledge completion\n");
1032 do {
1033 sleep(1);
1034 if (kodak6800_get_status(ctx, &ctx->sts))
1035 return CUPS_BACKEND_FAILED;
1036
1037 if (ctx->marker.levelnow != ctx->sts.donor) {
1038 ctx->marker.levelnow = ctx->sts.donor;
1039 dump_markers(&ctx->marker, 1, 0);
1040 }
1041
1042 if (ctx->sts.status1 == STATE_STATUS1_ERROR) {
1043 INFO("Printer State: %s # %02x %08x %02x\n",
1044 sinfonia_1x45_status_str(ctx->sts.status1, ctx->sts.status2, ctx->sts.errcode),
1045 ctx->sts.status1, ctx->sts.status2, ctx->sts.errcode);
1046 return CUPS_BACKEND_FAILED;
1047 }
1048
1049 /* If all prints are complete, we're done! */
1050 if (ctx->sts.b1_jobid == hdr.jobid && ctx->sts.b1_complete == ctx->sts.b1_total)
1051 break;
1052 if (ctx->sts.b2_jobid == hdr.jobid && ctx->sts.b2_complete == ctx->sts.b2_total)
1053 break;
1054
1055 if (fast_return) {
1056 INFO("Fast return mode enabled.\n");
1057 break;
1058 }
1059
1060 } while (1);
1061
1062 INFO("Print complete\n");
1063
1064 return CUPS_BACKEND_OK;
1065 }
1066
kodak6800_query_markers(void * vctx,struct marker ** markers,int * count)1067 static int kodak6800_query_markers(void *vctx, struct marker **markers, int *count)
1068 {
1069 struct kodak6800_ctx *ctx = vctx;
1070
1071 /* Query printer status */
1072 if (kodak6800_get_status(ctx, &ctx->sts))
1073 return CUPS_BACKEND_FAILED;
1074
1075 ctx->marker.levelnow = ctx->sts.donor;
1076
1077 *markers = &ctx->marker;
1078 *count = 1;
1079
1080 return CUPS_BACKEND_OK;
1081 }
1082
1083 static const char *kodak6800_prefixes[] = {
1084 "kodak68x0", // Family driver, do not nuke.
1085 "kodak-6800", "kodak-6850",
1086 // Backwards-compatibility
1087 "kodak6800", "kodak6850",
1088 NULL
1089 };
1090
1091 /* Exported */
1092 struct dyesub_backend kodak6800_backend = {
1093 .name = "Kodak 6800/6850",
1094 .version = "0.73" " (lib " LIBSINFONIA_VER ")",
1095 .uri_prefixes = kodak6800_prefixes,
1096 .cmdline_usage = kodak6800_cmdline,
1097 .cmdline_arg = kodak6800_cmdline_arg,
1098 .init = kodak6800_init,
1099 .attach = kodak6800_attach,
1100 .cleanup_job = sinfonia_cleanup_job,
1101 .read_parse = kodak6800_read_parse,
1102 .main_loop = kodak6800_main_loop,
1103 .query_serno = kodak6800_query_serno,
1104 .query_markers = kodak6800_query_markers,
1105 .devices = {
1106 { USB_VID_KODAK, USB_PID_KODAK_6800, P_KODAK_6800, "Kodak", "kodak-6800"},
1107 { USB_VID_KODAK, USB_PID_KODAK_6850, P_KODAK_6850, "Kodak", "kodak-6850"},
1108 { 0, 0, 0, NULL, NULL}
1109 }
1110 };
1111
1112 /* Kodak 6800/6850 data format
1113
1114 Spool file consists of 17-byte header followed by plane-interleaved BGR data.
1115 Native printer resolution is 1844 pixels per row, and 1240 or 2434 rows.
1116
1117 6850 Adds support for 5x7, with 1548 pixels per row and 2140 columns.
1118
1119 All fields are BIG ENDIAN unless otherwise specified.
1120
1121 Header:
1122
1123 03 1b 43 48 43 0a 00 Fixed header
1124 II Job ID (1-255)
1125 NN NN Number of copies in BCD form (0001->9999)
1126 WW WW Number of columns (Fixed at 1844 on 6800)
1127 HH HH Number of rows.
1128 SS Print size -- 0x00 (4x6) 0x06 (8x6) 0x07 (5x7 on 6850)
1129 LL Laminate mode -- 0x00 (off) or 0x01 (on)
1130 UU Print mode -- 0x00 (normal) or 0x01 (4x6 on 8x6) 0x21 (2x6) 0x23 (3x6)
1131
1132 ************************************************************************
1133
1134 Note: 6800 is Shinko CHC-S1145-5A, 6850 is Shinko CHC-S1145-5B
1135
1136 Both are very similar to Shinko S1245!
1137
1138 ************************************************************************
1139
1140 This command is unique to the 6850:
1141
1142 -> 03 1b 43 48 43 4c 00 00 00 00 00 00 00 00 00 00 [???]
1143 <- [51 octets]
1144
1145 01 01 43 48 43 4c 00 00 00 00 00 00 00 00 00 00 <-- Everything after this
1146 00 00 01 29 00 00 3b 0a 00 00 00 0e 00 03 02 90 line is the same as
1147 00 01 02 1d 03 00 00 00 00 01 00 01 00 00 00 00 the "status" resp.
1148 00 00 00
1149
1150 01 00 43 48 43 4c 00 00 00 00 00 00 00 00 00 00
1151 00 00 00 01 00 00 b7 d3 00 00 00 5c 00 03 02 8c
1152 00 01 02 1c 00 00 00 00 00 01 00 01 00 00 00 00
1153 00 00 00
1154
1155 An additional command that's also unknown
1156
1157 -> 03 1b 43 48 43 4d 01 00 00 00 00 00 00 00 00 00
1158 <- 01 02 01 00 00 00 00 00 00 00 5d ca 00 00 5d ca
1159 00 00 00 15 00 00 b8 f8 00 00 00 40 00 03 02 a6
1160 00 01 02 31 1e 00 00 00 00 01 00 01 00 00 00 00
1161 00 00 00
1162
1163 One more note for the 6850. These sizes have been seen:
1164
1165 1844x2434, method 0x03
1166 1844x2490, method 0x05
1167 1844x2222, method 0x00
1168
1169 */
1170