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