1 /*
2 * Shinko/Sinfonia CHC-S6245 CUPS backend -- libusb-1.0 version
3 *
4 * (c) 2015-2019 Solomon Peachy <pizza@shaftnet.org>
5 *
6 * Low-level documentation was provided by Sinfonia, Inc. Thank you!
7 *
8 * The latest version of this program can be found at:
9 *
10 * http://git.shaftnet.org/cgit/selphy_print.git
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 *
25 * [http://www.gnu.org/licenses/gpl-2.0.html]
26 *
27 * SPDX-License-Identifier: GPL-2.0+
28 *
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <time.h>
41
42 #define BACKEND shinkos6245_backend
43
44 #include "backend_common.h"
45 #include "backend_sinfonia.h"
46
47 enum {
48 S_IDLE = 0,
49 S_PRINTER_READY_CMD,
50 S_PRINTER_SENT_DATA,
51 S_FINISHED,
52 };
53
54 /* Structs for printer */
55 struct s6245_print_cmd {
56 struct sinfonia_cmd_hdr hdr;
57 uint8_t id;
58 uint16_t count;
59 uint16_t columns;
60 uint16_t rows;
61 uint16_t columns2; /* These are necessary for EK8810 */
62 uint16_t rows2; /* */
63 uint8_t reserved[4];
64 uint8_t mode;
65 uint8_t method;
66 uint8_t reserved2;
67 } __attribute__((packed));
68
69 #define PARAM_DRIVER_MODE 0x3e
70 #define PARAM_PAPER_MODE 0x3f
71 #define PARAM_SLEEP_TIME 0x54
72
73 #define PARAM_DRIVER_WIZOFF 0x00000000
74 #define PARAM_DRIVER_WIZON 0x00000001
75
76 #define PARAM_PAPER_NOCUT 0x00000000
77 #define PARAM_PAPER_CUTLOAD 0x00000001
78
79 #define PARAM_SLEEP_5MIN 0x00000000
80 #define PARAM_SLEEP_15MIN 0x00000001
81 #define PARAM_SLEEP_30MIN 0x00000002
82 #define PARAM_SLEEP_60MIN 0x00000003
83 #define PARAM_SLEEP_120MIN 0x00000004
84 #define PARAM_SLEEP_240MIN 0x00000005
85
86 struct s6245_settime_cmd {
87 struct sinfonia_cmd_hdr hdr;
88 uint8_t enable; /* 0 or 1 */
89 uint8_t second;
90 uint8_t minute;
91 uint8_t hour;
92 uint8_t day;
93 uint8_t month;
94 uint8_t year;
95 } __attribute__((packed));
96
97 struct s6245_errorlog_cmd {
98 struct sinfonia_cmd_hdr hdr;
99 uint16_t index; /* 0 is latest */
100 } __attribute__((packed));
101
error_codes(uint8_t major,uint8_t minor)102 static const char *error_codes(uint8_t major, uint8_t minor)
103 {
104 switch(major) {
105 case 0x01: /* "Controller Error" */
106 switch(minor) {
107 case 0x01:
108 return "Controller: EEPROM Write Timeout";
109 case 0x09:
110 return "Controller: DSP FW Boot";
111 case 0x0A:
112 return "Controller: Invalid Print Parameter Table";
113 case 0x0B:
114 return "Controller: DSP FW Mismatch";
115 case 0x0C:
116 return "Controller: Print Parameter Table Mismatch";
117 case 0x0D:
118 return "Controller: FPGA Configuration Failed";
119 case 0x0F:
120 return "Controller: Main FW Checksum";
121 case 0x10:
122 return "Controller: Flash Write Failed";
123 case 0x11:
124 return "Controller: DSP Checksum";
125 case 0x12:
126 return "Controller: DSP FW Write Failed";
127 case 0x13:
128 return "Controller: Print Parameter Table Checksum";
129 case 0x14:
130 return "Controller: Print Parameter Table Write Failed";
131 case 0x15:
132 return "Controller: User Tone Curve Write Failed";
133 case 0x16:
134 return "Controller: MSP Communication";
135 case 0x17:
136 return "Controller: THV Autotuning";
137 case 0x18:
138 return "Controller: THV Value Out of Range";
139 case 0x19:
140 return "Controller: Thermal Head";
141 case 0x1B:
142 return "Controller: DSP Communication";
143 case 0x1C:
144 return "Controller: DSP DMA Failed";
145 default:
146 return "Controller: Unknown";
147 }
148 case 0x02: /* "Mechanical Error" */
149 switch (minor) {
150 case 0x01:
151 return "Mechanical: Pinch Head Home";
152 case 0x02:
153 return "Mechanical: Pinch Head (position 1)";
154 case 0x03:
155 return "Mechanical: Pinch Head (position 2)";
156 case 0x04:
157 return "Mechanical: Pinch Head (position 3)";
158 case 0x0B:
159 return "Mechanical: Cutter (Right)";
160 case 0x0C:
161 return "Mechanical: Cutter (Left)";
162 default:
163 return "Mechanical: Unknown";
164 }
165 case 0x03: /* "Sensor Error" */
166 switch (minor) {
167 case 0x01:
168 return "Sensor: Head Up";
169 case 0x02:
170 return "Sensor: Head Down";
171 case 0x0B:
172 return "Sensor: Cutter Left";
173 case 0x0C:
174 return "Sensor: Cutter Right";
175 case 0x0D:
176 return "Sensor: Cutter Left+Right";
177 case 0x15:
178 return "Sensor: Head Up Unstable";
179 case 0x16:
180 return "Sensor: Head Down Unstable";
181 case 0x17:
182 return "Sensor: Cutter Left Unstable";
183 case 0x18:
184 return "Sensor: Cutter Right Unstable";
185 case 0x19:
186 return "Sensor: Cover Open Unstable";
187 case 0x1E:
188 return "Sensor: Ribbon Mark (Cyan)";
189 case 0x1F:
190 return "Sensor: Ribbon Mark (OC)";
191 default:
192 return "Sensor: Unknown";
193 }
194 case 0x04: /* "Temperature Sensor Error" */
195 switch (minor) {
196 case 0x01:
197 return "Temp Sensor: Thermal Head Low";
198 case 0x02:
199 return "Temp Sensor: Thermal Head High";
200 case 0x05:
201 return "Temp Sensor: Environment Low";
202 case 0x06:
203 return "Temp Sensor: Environment High";
204 case 0x07:
205 return "Temp Sensor: Preheat";
206 case 0x08:
207 return "Temp Sensor: Thermal Protect";
208 default:
209 return "Temp Sensor: Unknown";
210 }
211 case 0x5: /* "Paper Jam" */
212 switch (minor) {
213 case 0x01:
214 return "Paper Jam: Loading Paper Top On";
215 case 0x02:
216 return "Paper Jam: Loading Print Position On";
217 case 0x03:
218 return "Paper Jam: Loading Print Position Off";
219 case 0x04:
220 return "Paper Jam: Loading Paper Top Off";
221 case 0x05:
222 return "Paper Jam: Loading Cut Print Position Off";
223 case 0x0C:
224 return "Paper Jam: Initializing Print Position Off";
225 case 0x0D:
226 return "Paper Jam: Initializing Print Position On";
227 case 0x15:
228 return "Paper Jam: Printing Print Position Off";
229 case 0x16:
230 return "Paper Jam: Printing Paper Top On";
231 case 0x17:
232 return "Paper Jam: Printing Paper Top Off";
233 case 0x1F:
234 return "Paper Jam: Precut Print Position Off";
235 case 0x20:
236 return "Paper Jam: Precut Print Position On";
237
238 case 0x29:
239 return "Paper Jam: Printing Paper Top On";
240 case 0x2A:
241 return "Paper Jam: Printing Pre-Yellow Print Position Off";
242 case 0x2B:
243 return "Paper Jam: Printing Yellow Print Position Off";
244 case 0x2C:
245 return "Paper Jam: Printing Yellow Print Position On";
246 case 0x2D:
247 return "Paper Jam: Printing Pre-Magenta Print Position Off";
248 case 0x2E:
249 return "Paper Jam: Printing Magenta Print Position On";
250 case 0x2F:
251 return "Paper Jam: Printing Magenta Print Position Off";
252 case 0x30:
253 return "Paper Jam: Printing Pre-Cyan Print Position Off";
254 case 0x31:
255 return "Paper Jam: Printing Cyan Print Position On";
256 case 0x32:
257 return "Paper Jam: Printing Cyan Print Position Off";
258 case 0x33:
259 return "Paper Jam: Printing Pre-OC Print Position Off";
260 case 0x34:
261 return "Paper Jam: Printing OC Print Position On";
262 case 0x35:
263 return "Paper Jam: Printing OC Print Position Off";
264 case 0x36:
265 return "Paper Jam: Cut Print Position Off";
266 case 0x37:
267 return "Paper Jam: Home Position Off";
268 case 0x38:
269 return "Paper Jam: Paper Top Off";
270 case 0x39:
271 return "Paper Jam: Print Position On";
272
273 case 0x51:
274 return "Paper Jam: Paper Empty On, Top On, Position On";
275 case 0x52:
276 return "Paper Jam: Paper Empty On, Top On, Position Off";
277 case 0x53:
278 return "Paper Jam: Paper Empty On, Top Off, Print Position On";
279 case 0x54:
280 return "Paper Jam: Paper Empty On, Top Of, Position Off";
281 case 0x55:
282 return "Paper Jam: Paper Empty Off, Top On, Position On";
283 case 0x56:
284 return "Paper Jam: Paper Empty Off, Top On, Position Off";
285 case 0x57:
286 return "Paper Jam: Paper Empty Off, Top Off, Position On";
287 case 0x60:
288 return "Paper Jam: Cutter Right";
289 case 0x61:
290 return "Paper Jam: Cutter Left";
291
292 default:
293 return "Paper Jam: Unknown";
294 }
295 case 0x06: /* User Error */
296 switch (minor) {
297 case 0x01:
298 return "Drawer Unit Open";
299 case 0x02:
300 return "Incorrect Ribbon";
301 case 0x03:
302 return "No/Empty Ribbon";
303 case 0x04:
304 return "Mismatched Ribbon";
305 case 0x08:
306 return "No Paper";
307 case 0x0C:
308 return "Paper End";
309 default:
310 return "Unknown";
311 }
312 default:
313 return "Unknown";
314 }
315 }
316
317 struct s6245_status_resp {
318 struct sinfonia_status_hdr hdr;
319 uint32_t count_lifetime;
320 uint32_t count_maint;
321 uint32_t count_paper;
322 uint32_t count_cutter;
323 uint32_t count_head;
324 uint32_t count_ribbon_left;
325 uint32_t reserved;
326
327 uint8_t bank1_printid;
328 uint16_t bank1_remaining;
329 uint16_t bank1_finished;
330 uint16_t bank1_specified;
331 uint8_t bank1_status;
332
333 uint8_t bank2_printid;
334 uint16_t bank2_remaining;
335 uint16_t bank2_finished;
336 uint16_t bank2_specified;
337 uint8_t bank2_status;
338
339 uint8_t reserved2[16];
340 uint8_t tonecurve_status;
341 uint8_t reserved3[6];
342 } __attribute__((packed));
343
344 struct s6245_geteeprom_resp {
345 struct sinfonia_status_hdr hdr;
346 uint8_t data[256];
347 } __attribute__((packed));
348
349 struct s6245_mediainfo_resp {
350 struct sinfonia_status_hdr hdr;
351 uint8_t ribbon_code;
352 uint8_t reserved;
353 uint8_t count;
354 struct sinfonia_mediainfo_item items[10]; /* Not all necessarily used */
355 } __attribute__((packed));
356
357 #define RIBBON_NONE 0x00
358 #define RIBBON_8x10 0x11
359 #define RIBBON_8x12 0x12
360
361 #define RIBBON_8x10K 0x03 /* XXX GUESS - EK8810 */
362 #define RIBBON_8x12K 0x04 /* EK8810 */
363
ribbon_sizes(uint8_t v)364 static const char *ribbon_sizes (uint8_t v) {
365 switch (v) {
366 case RIBBON_NONE:
367 return "None";
368 case RIBBON_8x10:
369 case RIBBON_8x10K:
370 return "8x10";
371 case RIBBON_8x12:
372 case RIBBON_8x12K:
373 return "8x12";
374 default:
375 return "Unknown";
376 }
377 }
378
ribbon_counts(uint8_t v)379 static int ribbon_counts (uint8_t v) {
380 switch (v) {
381 case RIBBON_8x10:
382 return 120;
383 case RIBBON_8x12:
384 return 100;
385 case RIBBON_8x10K:
386 return 250;
387 case RIBBON_8x12K:
388 return 250;
389 default:
390 return 120;
391 }
392 }
393
394 struct s6245_errorlog_resp {
395 struct sinfonia_status_hdr hdr;
396 uint16_t error_count;
397 uint8_t error_major;
398 uint8_t error_minor;
399 uint16_t reserved;
400 uint32_t print_counter;
401 uint16_t ribbon_remain;
402 uint8_t ribbon_takeup_diameter;
403 uint8_t ribbon_supply_diameter;
404 uint16_t main_fw_ver;
405 uint16_t dsp_fw_ver;
406 uint16_t print_param_ver;
407 uint16_t boot_fw_ver;
408 uint8_t time_sec;
409 uint8_t time_min;
410 uint8_t time_hour;
411 uint8_t time_day;
412 uint8_t time_month;
413 uint8_t time_year;
414 uint16_t reserved2;
415 uint8_t printer_thermistor;
416 uint8_t head_thermistor;
417 uint8_t printer_humidity;
418 uint8_t reserved3[13];
419 uint8_t status;
420 uint8_t reserved4[3];
421 uint16_t image_cols;
422 uint16_t image_rows;
423 uint8_t reserved5[8];
424 } __attribute__((packed));
425
426 /* Private data structure */
427 struct shinkos6245_ctx {
428 struct sinfonia_usbdev dev;
429
430 uint8_t jobid;
431
432 struct marker marker;
433
434 struct s6245_mediainfo_resp media;
435 };
436
437 #define CMDBUF_LEN sizeof(struct s6245_print_cmd)
438
get_status(struct shinkos6245_ctx * ctx)439 static int get_status(struct shinkos6245_ctx *ctx)
440 {
441 struct sinfonia_cmd_hdr cmd;
442 struct s6245_status_resp resp;
443 struct sinfonia_getextcounter_resp resp2;
444 int ret, num = 0;
445
446 cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
447 cmd.len = cpu_to_le16(0);
448
449 if ((ret = sinfonia_docmd(&ctx->dev,
450 (uint8_t*)&cmd, sizeof(cmd),
451 (uint8_t*) &resp, sizeof(resp),
452 &num)) < 0) {
453 return ret;
454 }
455
456 INFO("Printer Status: 0x%02x (%s)\n", resp.hdr.status,
457 sinfonia_status_str(resp.hdr.status));
458 if (resp.hdr.status == ERROR_PRINTER) {
459 if(resp.hdr.error == ERROR_NONE)
460 resp.hdr.error = resp.hdr.status;
461 INFO(" Error 0x%02x (%s) 0x%02x/0x%02x (%s)\n",
462 resp.hdr.error,
463 sinfonia_error_str(resp.hdr.error),
464 resp.hdr.printer_major,
465 resp.hdr.printer_minor, error_codes(resp.hdr.printer_major, resp.hdr.printer_minor));
466 }
467 if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct s6245_status_resp) - sizeof(struct sinfonia_status_hdr)))
468 return 0;
469
470 INFO(" Print Counts:\n");
471 INFO("\tSince Paper Changed:\t%08u\n", le32_to_cpu(resp.count_paper));
472 INFO("\tLifetime:\t\t%08u\n", le32_to_cpu(resp.count_lifetime));
473 INFO("\tMaintenance:\t\t%08u\n", le32_to_cpu(resp.count_maint));
474 INFO("\tPrint Head:\t\t%08u\n", le32_to_cpu(resp.count_head));
475 INFO(" Cutter Actuations:\t%08u\n", le32_to_cpu(resp.count_cutter));
476 INFO(" Ribbon Remaining:\t%8u%%\n", le32_to_cpu(resp.count_ribbon_left));
477 INFO(" Prints Remaining:\t%8u\n", ribbon_counts(ctx->media.ribbon_code) - le32_to_cpu(resp.count_paper));
478 INFO("Bank 1: 0x%02x (%s) Job %03u @ %03u/%03u (%03u remaining)\n",
479 resp.bank1_status, sinfonia_bank_statuses(resp.bank1_status),
480 resp.bank1_printid,
481 le16_to_cpu(resp.bank1_finished),
482 le16_to_cpu(resp.bank1_specified),
483 le16_to_cpu(resp.bank1_remaining));
484
485 INFO("Bank 2: 0x%02x (%s) Job %03u @ %03u/%03u (%03u remaining)\n",
486 resp.bank2_status, sinfonia_bank_statuses(resp.bank1_status),
487 resp.bank2_printid,
488 le16_to_cpu(resp.bank2_finished),
489 le16_to_cpu(resp.bank2_specified),
490 le16_to_cpu(resp.bank2_remaining));
491
492 INFO("Tonecurve Status: 0x%02x (%s)\n", resp.tonecurve_status, sinfonia_tonecurve_statuses(resp.tonecurve_status));
493
494
495 /* Query Extended counters */
496 if (ctx->dev.type == P_KODAK_8810)
497 return 0; /* Kodak 8810 returns 12 bytes of garbage. */
498
499 cmd.cmd = cpu_to_le16(SINFONIA_CMD_EXTCOUNTER);
500 cmd.len = cpu_to_le16(0);
501
502 if ((ret = sinfonia_docmd(&ctx->dev,
503 (uint8_t*)&cmd, sizeof(cmd),
504 (uint8_t*)&resp2, sizeof(resp2),
505 &num)) < 0) {
506 return ret;
507 }
508
509 if (le16_to_cpu(resp2.hdr.payload_len) < 12)
510 return 0;
511
512 INFO("Lifetime Distance: %08u inches\n", le32_to_cpu(resp2.lifetime_distance));
513 INFO("Maintenance Distance: %08u inches\n", le32_to_cpu(resp2.maint_distance));
514 INFO("Head Distance: %08u inches\n", le32_to_cpu(resp2.head_distance));
515
516 return 0;
517 }
518
get_errorlog(struct shinkos6245_ctx * ctx)519 static int get_errorlog(struct shinkos6245_ctx *ctx)
520 {
521 struct s6245_errorlog_cmd cmd;
522 struct s6245_errorlog_resp resp;
523 int num = 0;
524 int i = 0;
525
526 cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_ERRORLOG);
527 cmd.hdr.len = cpu_to_le16(2);
528
529 do {
530 int ret;
531 cmd.index = i;
532
533 if ((ret = sinfonia_docmd(&ctx->dev,
534 (uint8_t*)&cmd, sizeof(cmd),
535 (uint8_t*)&resp, sizeof(resp),
536 &num)) < 0) {
537 return ret;
538 }
539
540 if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct s6245_errorlog_resp) - sizeof(struct sinfonia_status_hdr)))
541 return -2;
542
543 INFO("Stored Error ID %d:\n", i);
544 INFO(" %04d-%02u-%02u %02u:%02u:%02u @ %08u prints : 0x%02x/0x%02x (%s)\n",
545 resp.time_year + 2000, resp.time_month, resp.time_day,
546 resp.time_hour, resp.time_min, resp.time_sec,
547 le32_to_cpu(resp.print_counter),
548 resp.error_major, resp.error_minor,
549 error_codes(resp.error_major, resp.error_minor));
550 INFO(" Temp: %02u/%02u Hum: %02u\n",
551 resp.printer_thermistor, resp.head_thermistor, resp.printer_humidity);
552 } while (++i < le16_to_cpu(resp.error_count));
553
554 return 0;
555 }
556
dump_mediainfo(struct s6245_mediainfo_resp * resp)557 static void dump_mediainfo(struct s6245_mediainfo_resp *resp)
558 {
559 int i;
560
561 INFO("Loaded Media Type: %s\n", ribbon_sizes(resp->ribbon_code));
562 INFO("Supported Media Information: %u entries:\n", resp->count);
563 for (i = 0 ; i < resp->count ; i++) {
564 INFO(" %02d: C 0x%02x (%s), %04ux%04u, P 0x%02x (%s)\n", i,
565 resp->items[i].code,
566 sinfonia_print_codes(resp->items[i].code, 1),
567 resp->items[i].columns,
568 resp->items[i].rows,
569 resp->items[i].method,
570 sinfonia_print_methods(resp->items[i].method));
571 }
572 }
573
shinkos6245_cmdline(void)574 static void shinkos6245_cmdline(void)
575 {
576 DEBUG("\t\t[ -c filename ] # Get user/NV tone curve\n");
577 DEBUG("\t\t[ -C filename ] # Set user/NV tone curve\n");
578 DEBUG("\t\t[ -e ] # Query error log\n");
579 DEBUG("\t\t[ -F ] # Flash Printer LED\n");
580 DEBUG("\t\t[ -i ] # Query printer info\n");
581 DEBUG("\t\t[ -k num ] # Set sleep time (5-240 minutes)\n");
582 DEBUG("\t\t[ -l filename ] # Get current tone curve\n");
583 DEBUG("\t\t[ -L filename ] # Set current tone curve\n");
584 DEBUG("\t\t[ -m ] # Query media\n");
585 DEBUG("\t\t[ -r ] # Reset user/NV tone curve\n");
586 DEBUG("\t\t[ -R ] # Reset printer to factory defaults\n");
587 DEBUG("\t\t[ -s ] # Query status\n");
588 DEBUG("\t\t[ -X jobid ] # Abort a printjob\n");
589 }
590
shinkos6245_cmdline_arg(void * vctx,int argc,char ** argv)591 int shinkos6245_cmdline_arg(void *vctx, int argc, char **argv)
592 {
593 struct shinkos6245_ctx *ctx = vctx;
594 int i, j = 0;
595
596 if (!ctx)
597 return -1;
598
599 while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "c:C:eFik:l:L:mrR:sX:")) >= 0) {
600 switch(i) {
601 GETOPT_PROCESS_GLOBAL
602 case 'c':
603 j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_USER, optarg);
604 break;
605 case 'C':
606 j = sinfonia_settonecurve(&ctx->dev, TONECURVE_USER, optarg);
607 break;
608 case 'e':
609 if (ctx->dev.type == P_KODAK_8810) {
610 j = sinfonia_geterrorlog(&ctx->dev);
611 } else {
612 j = get_errorlog(ctx);
613 }
614 break;
615 case 'F':
616 j = sinfonia_flashled(&ctx->dev);
617 break;
618 case 'i':
619 j = sinfonia_getfwinfo(&ctx->dev);
620 break;
621 case 'k': {
622 i = atoi(optarg);
623 if (i < 5)
624 i = 0;
625 else if (i < 15)
626 i = 1;
627 else if (i < 30)
628 i = 2;
629 else if (i < 60)
630 i = 3;
631 else if (i < 120)
632 i = 4;
633 else if (i < 240)
634 i = 5;
635 else
636 i = 5;
637
638 j = sinfonia_setparam(&ctx->dev, PARAM_SLEEP_TIME, i);
639 break;
640 }
641 case 'l':
642 j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
643 break;
644 case 'L':
645 j = sinfonia_settonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
646 break;
647 case 'm':
648 dump_mediainfo(&ctx->media);
649 break;
650 case 'r':
651 j = sinfonia_resetcurve(&ctx->dev, RESET_TONE_CURVE, TONE_CURVE_ID);
652 break;
653 case 'R':
654 j = sinfonia_resetcurve(&ctx->dev, RESET_PRINTER, 0);
655 break;
656 case 's':
657 j = get_status(ctx);
658 break;
659 case 'X':
660 j = sinfonia_canceljob(&ctx->dev, atoi(optarg));
661 break;
662 default:
663 break; /* Ignore completely */
664 }
665
666 if (j) return j;
667 }
668
669 return 0;
670 }
671
shinkos6245_init(void)672 static void *shinkos6245_init(void)
673 {
674 struct shinkos6245_ctx *ctx = malloc(sizeof(struct shinkos6245_ctx));
675 if (!ctx) {
676 ERROR("Memory Allocation Failure!\n");
677 return NULL;
678 }
679 memset(ctx, 0, sizeof(struct shinkos6245_ctx));
680
681 return ctx;
682 }
683
shinkos6245_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)684 static int shinkos6245_attach(void *vctx, struct libusb_device_handle *dev, int type,
685 uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
686 {
687 struct shinkos6245_ctx *ctx = vctx;
688
689 int num;
690
691 ctx->dev.dev = dev;
692 ctx->dev.endp_up = endp_up;
693 ctx->dev.endp_down = endp_down;
694 ctx->dev.type = type;
695 ctx->dev.error_codes = &error_codes;
696
697 /* Ensure jobid is sane */
698 ctx->jobid = jobid & 0x7f;
699 if (!ctx->jobid)
700 ctx->jobid++;
701
702 /* Query Media */
703 if (test_mode < TEST_MODE_NOATTACH) {
704 struct sinfonia_cmd_hdr cmd;
705 cmd.cmd = cpu_to_le16(SINFONIA_CMD_MEDIAINFO);
706 cmd.len = cpu_to_le16(0);
707
708 if (sinfonia_docmd(&ctx->dev,
709 (uint8_t*)&cmd, sizeof(cmd),
710 (uint8_t*)&ctx->media, sizeof(ctx->media),
711 &num)) {
712 return CUPS_BACKEND_FAILED;
713 }
714
715 /* Byteswap media descriptor.. */
716 int i;
717 for (i = 0 ; i < ctx->media.count ; i++) {
718 ctx->media.items[i].columns = le16_to_cpu(ctx->media.items[i].columns);
719 ctx->media.items[i].rows = le16_to_cpu(ctx->media.items[i].rows);
720 }
721
722 } else {
723 int media_code = RIBBON_8x12;
724 if (getenv("MEDIA_CODE"))
725 media_code = atoi(getenv("MEDIA_CODE"));
726
727 ctx->media.ribbon_code = media_code;
728 }
729
730 ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
731 ctx->marker.name = ribbon_sizes(ctx->media.ribbon_code);
732 ctx->marker.levelmax = 100;
733 ctx->marker.levelnow = -2;
734
735 return CUPS_BACKEND_OK;
736 }
737
shinkos6245_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)738 static int shinkos6245_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
739 struct shinkos6245_ctx *ctx = vctx;
740 struct sinfonia_printjob *job = NULL;
741 int ret;
742
743 if (!ctx)
744 return CUPS_BACKEND_FAILED;
745
746 job = malloc(sizeof(*job));
747 if (!job) {
748 ERROR("Memory allocation failure!\n");
749 return CUPS_BACKEND_RETRY_CURRENT;
750 }
751 memset(job, 0, sizeof(*job));
752
753 /* Common read/parse code */
754 if (ctx->dev.type == P_KODAK_8810) {
755 ret = sinfonia_raw18_read_parse(data_fd, job);
756 } else {
757 ret = sinfonia_read_parse(data_fd, 6245, job);
758 }
759 if (ret) {
760 free(job);
761 return ret;
762 }
763
764 if (job->jp.copies > 1)
765 job->copies = job->jp.copies;
766 else
767 job->copies = copies;
768
769 *vjob = job;
770
771 return CUPS_BACKEND_OK;
772 }
773
shinkos6245_main_loop(void * vctx,const void * vjob)774 static int shinkos6245_main_loop(void *vctx, const void *vjob) {
775 struct shinkos6245_ctx *ctx = vctx;
776
777 int ret, num;
778 uint8_t cmdbuf[CMDBUF_LEN];
779
780 int last_state = -1, state = S_IDLE;
781 uint8_t mcut;
782 int copies;
783
784 struct sinfonia_cmd_hdr *cmd = (struct sinfonia_cmd_hdr *) cmdbuf;;
785 struct s6245_print_cmd *print = (struct s6245_print_cmd *) cmdbuf;
786 struct s6245_status_resp sts, sts2;
787 struct sinfonia_status_hdr resp;
788
789 struct sinfonia_printjob *job = (struct sinfonia_printjob*) vjob;
790
791 copies = job->copies;
792
793 /* Cap copies */
794 // XXX 120 for 8x10 media, 100 for 8x12 media (S6245)
795 // 250 for 8x12, 300 for 8x10 (Kodak 8810)
796 if (copies > 120)
797 copies = 120;
798
799 /* Set up mcut */
800 switch (job->jp.media) {
801 case CODE_8x4_2:
802 case CODE_8x5_2:
803 case CODE_8x6_2:
804 mcut = PRINT_METHOD_COMBO_2;
805 break;
806 case CODE_8x4_3:
807 mcut = PRINT_METHOD_COMBO_3;
808 break;
809 default:
810 mcut = PRINT_METHOD_STD;
811 }
812 // XXX what about mcut |= PRINT_METHOD_DISABLE_ERR;
813
814 #if 0
815 int i;
816 /* Validate print sizes */
817 for (i = 0; i < ctx->media.count ; i++) {
818 /* Look for matching media */
819 if (ctx->media.items[i].columns == job->jp.columns &&
820 ctx->media.items[i].rows == job->jp.rows)
821 break;
822 }
823 if (i == ctx->media.count) {
824 ERROR("Incorrect media loaded for print!\n");
825 return CUPS_BACKEND_HOLD;
826 }
827 #else
828 if (ctx->media.ribbon_code != RIBBON_8x12 &&
829 ctx->media.ribbon_code != RIBBON_8x12K &&
830 job->jp.rows > 3024) {
831 ERROR("Incorrect media loaded for print!\n");
832 return CUPS_BACKEND_HOLD;
833 }
834
835 #endif
836
837 /* Send Set Time */
838 if (ctx->dev.type != P_KODAK_8810) {
839 struct s6245_settime_cmd *settime = (struct s6245_settime_cmd *)cmdbuf;
840 time_t now = time(NULL);
841 struct tm *cur = localtime(&now);
842
843 memset(cmdbuf, 0, CMDBUF_LEN);
844 cmd->cmd = cpu_to_le16(SINFONIA_CMD_SETTIME);
845 cmd->len = cpu_to_le16(0);
846 settime->enable = 1;
847 settime->second = cur->tm_sec;
848 settime->minute = cur->tm_min;
849 settime->hour = cur->tm_hour;
850 settime->day = cur->tm_mday;
851 settime->month = cur->tm_mon;
852 settime->year = cur->tm_year + 1900 - 2000;
853
854 if ((ret = sinfonia_docmd(&ctx->dev,
855 cmdbuf, sizeof(*settime),
856 (uint8_t*)&resp, sizeof(resp),
857 &num)) < 0) {
858 return CUPS_BACKEND_FAILED;
859 }
860 if (resp.result != RESULT_SUCCESS) {
861 ERROR("Bad result %02x\n", resp.result);
862 goto fail;
863 }
864 }
865
866 // XXX check copies against remaining media!
867
868 top:
869 if (state != last_state) {
870 if (dyesub_debug)
871 DEBUG("last_state %d new %d\n", last_state, state);
872 }
873
874 /* Send Status Query */
875 memset(cmdbuf, 0, CMDBUF_LEN);
876 cmd->cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
877 cmd->len = cpu_to_le16(0);
878
879 if ((ret = sinfonia_docmd(&ctx->dev,
880 cmdbuf, sizeof(*cmd),
881 (uint8_t*)&sts, sizeof(sts),
882 &num)) < 0) {
883 return CUPS_BACKEND_FAILED;
884 }
885
886 if (memcmp(&sts2, &sts, sizeof(sts))) {
887 memcpy(&sts2, &sts, sizeof(sts));
888
889 INFO("Printer Status: 0x%02x (%s)\n",
890 sts.hdr.status, sinfonia_status_str(sts.hdr.status));
891
892 if (ctx->marker.levelnow != (int)sts.count_ribbon_left) {
893 ctx->marker.levelnow = sts.count_ribbon_left;
894 dump_markers(&ctx->marker, 1, 0);
895 }
896
897 if (sts.hdr.result != RESULT_SUCCESS)
898 goto printer_error;
899 if (sts.hdr.error == ERROR_PRINTER)
900 goto printer_error;
901 } else if (state == last_state) {
902 sleep(1);
903 goto top;
904 }
905 last_state = state;
906
907 fflush(stderr);
908
909 switch (state) {
910 case S_IDLE:
911 INFO("Waiting for printer idle\n");
912
913 /* make sure we're not colliding with an existing
914 jobid */
915 while (ctx->jobid == sts.bank1_printid ||
916 ctx->jobid == sts.bank2_printid) {
917 ctx->jobid++;
918 ctx->jobid &= 0x7f;
919 if (!ctx->jobid)
920 ctx->jobid++;
921 }
922
923 /* If either bank is free, continue */
924 if (sts.bank1_status == BANK_STATUS_FREE ||
925 sts.bank2_status == BANK_STATUS_FREE)
926 state = S_PRINTER_READY_CMD;
927
928 break;
929 case S_PRINTER_READY_CMD:
930 // XXX send "get eeprom backup command"
931
932 INFO("Sending print job (internal id %u)\n", ctx->jobid);
933
934 memset(cmdbuf, 0, CMDBUF_LEN);
935 print->hdr.cmd = cpu_to_le16(SINFONIA_CMD_PRINTJOB);
936 print->hdr.len = cpu_to_le16(sizeof (*print) - sizeof(*cmd));
937 print->id = ctx->jobid;
938 print->count = cpu_to_le16(copies);
939 print->columns = print->columns2 = cpu_to_le16(job->jp.columns);
940 print->rows = print->rows2 = cpu_to_le16(job->jp.rows);
941 print->mode = job->jp.oc_mode;
942 print->method = mcut;
943
944 if ((ret = sinfonia_docmd(&ctx->dev,
945 cmdbuf, sizeof(*print),
946 (uint8_t*)&resp, sizeof(resp),
947 &num)) < 0) {
948 return ret;
949 }
950
951 if (resp.result != RESULT_SUCCESS) {
952 if (resp.error == ERROR_BUFFER_FULL) {
953 INFO("Printer Buffers full, retrying\n");
954 break;
955 } else if ((resp.status & 0xf0) == 0x30 || sts.hdr.status == ERROR_BUFFER_FULL) {
956 INFO("Printer busy (%s), retrying\n", sinfonia_status_str(sts.hdr.status));
957 break;
958 } else if (resp.status != ERROR_NONE)
959 goto printer_error;
960 }
961
962 INFO("Sending image data to printer\n");
963 if ((ret = send_data(ctx->dev.dev, ctx->dev.endp_down,
964 job->databuf, job->datalen)))
965 return CUPS_BACKEND_FAILED;
966
967 INFO("Waiting for printer to acknowledge completion\n");
968 sleep(1);
969 state = S_PRINTER_SENT_DATA;
970 break;
971 case S_PRINTER_SENT_DATA:
972 if (fast_return) {
973 INFO("Fast return mode enabled.\n");
974 state = S_FINISHED;
975 } else if (sts.hdr.status == STATUS_READY) {
976 state = S_FINISHED;
977 }
978 break;
979 default:
980 break;
981 };
982
983 if (state != S_FINISHED)
984 goto top;
985
986 INFO("Print complete\n");
987
988 return CUPS_BACKEND_OK;
989
990 printer_error:
991 ERROR("Printer reported error: %#x (%s) status: %#x (%s) -> %#x.%#x (%s)\n",
992 sts.hdr.error,
993 sinfonia_error_str(sts.hdr.error),
994 sts.hdr.status,
995 sinfonia_status_str(sts.hdr.status),
996 sts.hdr.printer_major, sts.hdr.printer_minor,
997 error_codes(sts.hdr.printer_major, sts.hdr.printer_minor));
998 fail:
999 return CUPS_BACKEND_FAILED;
1000 }
1001
shinkos6245_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)1002 static int shinkos6245_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
1003 {
1004 struct sinfonia_cmd_hdr cmd;
1005 struct sinfonia_getserial_resp resp;
1006 int ret, num = 0;
1007
1008 struct sinfonia_usbdev sdev = {
1009 .dev = dev,
1010 .endp_up = endp_up,
1011 .endp_down = endp_down,
1012 };
1013
1014 cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSERIAL);
1015 cmd.len = cpu_to_le16(0);
1016
1017 if ((ret = sinfonia_docmd(&sdev,
1018 (uint8_t*)&cmd, sizeof(cmd),
1019 (uint8_t*)&resp, sizeof(resp),
1020 &num)) < 0) {
1021 return ret;
1022 }
1023
1024 /* Copy and Null-terminate */
1025 num = (buf_len > (int)sizeof(resp.data)) ? (int)sizeof(resp.data) : (buf_len - 1);
1026 memcpy(buf, resp.data, num);
1027 buf[num] = 0;
1028
1029 return CUPS_BACKEND_OK;
1030 }
1031
shinkos6245_query_markers(void * vctx,struct marker ** markers,int * count)1032 static int shinkos6245_query_markers(void *vctx, struct marker **markers, int *count)
1033 {
1034 struct shinkos6245_ctx *ctx = vctx;
1035 struct sinfonia_cmd_hdr cmd;
1036 struct s6245_status_resp status;
1037 int num;
1038
1039 /* Query Status */
1040 cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
1041 cmd.len = cpu_to_le16(0);
1042
1043 if (sinfonia_docmd(&ctx->dev,
1044 (uint8_t*)&cmd, sizeof(cmd),
1045 (uint8_t*)&status, sizeof(status),
1046 &num)) {
1047 return CUPS_BACKEND_FAILED;
1048 }
1049
1050 ctx->marker.levelnow = le32_to_cpu(status.count_ribbon_left);
1051
1052 *markers = &ctx->marker;
1053 *count = 1;
1054
1055 return CUPS_BACKEND_OK;
1056 }
1057
1058 /* Exported */
1059 #define USB_VID_SHINKO 0x10CE
1060 #define USB_PID_SHINKO_S6245 0x001D
1061 #define USB_VID_HITI 0x0D16
1062 #define USB_PID_HITI_P910L 0x000E
1063 #define USB_VID_KODAK 0x040A
1064 #define USB_PID_KODAK_8810 0x404D
1065
1066 static const char *shinkos6245_prefixes[] = {
1067 "sinfonia-chcs6245", "hiti-p910l", "kodak-8810",
1068 // extras
1069 "shinko-chcs6245",
1070 // backwards compatibility
1071 "shinkos6245", "hitip910",
1072 NULL
1073 };
1074
1075 struct dyesub_backend shinkos6245_backend = {
1076 .name = "Sinfonia CHC-S6245 / Kodak 8810",
1077 .version = "0.22" " (lib " LIBSINFONIA_VER ")",
1078 .uri_prefixes = shinkos6245_prefixes,
1079 .cmdline_usage = shinkos6245_cmdline,
1080 .cmdline_arg = shinkos6245_cmdline_arg,
1081 .init = shinkos6245_init,
1082 .attach = shinkos6245_attach,
1083 .cleanup_job = sinfonia_cleanup_job,
1084 .read_parse = shinkos6245_read_parse,
1085 .main_loop = shinkos6245_main_loop,
1086 .query_serno = shinkos6245_query_serno,
1087 .query_markers = shinkos6245_query_markers,
1088 .devices = {
1089 { USB_VID_SHINKO, USB_PID_SHINKO_S6245, P_SHINKO_S6245, NULL, "shinfonia-chcs6245"},
1090 { USB_VID_HITI, USB_PID_HITI_P910L, P_SHINKO_S6245, NULL, "hiti-p910l"},
1091 { USB_VID_KODAK, USB_PID_KODAK_8810, P_KODAK_8810, NULL, "kodak-8810"},
1092 { 0, 0, 0, NULL, NULL}
1093 }
1094 };
1095
1096 /* CHC-S6245 data format
1097
1098 Spool file consists of an 116-byte header, followed by RGB-packed data,
1099 followed by a 4-byte footer. Header appears to consist of a series of
1100 4-byte Little Endian words.
1101
1102 10 00 00 00 MM MM 00 00 01 00 00 00 01 00 00 00 MM == Model (ie 6245d)
1103 64 00 00 00 00 00 00 00 TT 00 00 00 00 00 00 00 TT == 0x20 8x4, 0x21 8x5, 0x22 8x6, 0x23 8x8, 0x10 8x10, 0x11 8x12
1104 00 00 00 00 00 00 00 00 XX 00 00 00 00 00 00 00 XX == 0x03 matte, 0x02 glossy, 0x01 no coat
1105 00 00 00 00 WW WW 00 00 HH HH 00 00 NN 00 00 00 WW/HH Width, Height (LE), NN == Copies
1106 00 00 00 00 00 00 00 00 00 00 00 00 ce ff ff ff
1107 00 00 00 00 ce ff ff ff QQ QQ 00 00 ce ff ff ff QQ == DPI (300)
1108 00 00 00 00 ce ff ff ff 00 00 00 00 00 00 00 00
1109 00 00 00 00
1110
1111 [[Packed RGB payload of WW*HH*3 bytes]]
1112
1113 04 03 02 01 [[ footer ]]
1114
1115 Kodak 8810 data format: (Note: EK8810 is actually a Sinfonia CHC-S1845-5A)
1116
1117 Spool file is the print_cmd_hdr (22 bytes) followed by RGB-packed data.
1118
1119 01 40 0a 00 Fixed header
1120 XX Job ID
1121 CC CC Number of copies (1-???)
1122 WW WW Number of columns
1123 HH HH Number of rows
1124 WW WW Number of columns
1125 HH HH Number of rows
1126 00 00 00 00 Reserved/Unknown
1127 LL Laminate, 0x02/0x03 (on/satin)
1128 MM Print Method
1129 00 Reserved/Unknown
1130
1131 */
1132