1 /*
2  *   Shinko/Sinfonia CHC-S6145 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.  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  *   An additional permission is granted, under the GPLv2 section 10, to combine
28  *   and/or redistribute this program with the proprietary libS6145ImageProcess
29  *   library, providing you have *written permission* from Sinfonia Technology
30  *   Co. LTD to use and/or redistribute that library.
31  *
32  *   You must still adhere to all other terms of the license to this program
33  *   (ie GPLv2) and the license of the libS6145ImageProcess library.
34  *
35  *   SPDX-License-Identifier: GPL-2.0+ with special exception
36  *
37  */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include <errno.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <signal.h>
49 #include <time.h>
50 
51 /* For Integration into gutenprint */
52 #if defined(HAVE_CONFIG_H)
53 #include <config.h>
54 #endif
55 
56 #if defined(USE_DLOPEN)
57 #define WITH_DYNAMIC
58 #include <dlfcn.h>
59 #define DL_INIT() do {} while(0)
60 #define DL_OPEN(__x) dlopen(__x, RTLD_NOW)
61 #define DL_SYM(__x, __y) dlsym(__x, __y)
62 #define DL_CLOSE(__x) dlclose(__x)
63 #define DL_EXIT() do {} while(0)
64 #elif defined(USE_LTDL)
65 #define WITH_DYNAMIC
66 #include <ltdl.h>
67 #define DL_INIT() lt_dlinit()
68 #define DL_OPEN(__x) lt_dlopen(__x)
69 #define DL_SYM(__x, __y) lt_dlsym(__x, __y)
70 #define DL_CLOSE(__x) do {} while(0)
71 #define DL_EXIT() lt_dlexit()
72 #else
73 #define DL_INIT()     do {} while(0)
74 #define DL_CLOSE(__x) do {} while(0)
75 #define DL_EXIT()     do {} while(0)
76 #warning "No dynamic loading support!"
77 #endif
78 
79 #define BACKEND shinkos6145_backend
80 
81 #include "backend_common.h"
82 #include "backend_sinfonia.h"
83 
84 /* Image processing library function prototypes */
85 typedef int (*ImageProcessingFN)(unsigned char *, unsigned short *, void *);
86 typedef int (*ImageAvrCalcFN)(unsigned char *, unsigned short, unsigned short, unsigned char *);
87 
88 #define LIB_NAME    "libS6145ImageProcess.so"    // Official library
89 #define LIB_NAME_RE "libS6145ImageReProcess.so" // Reimplemented library
90 
91 enum {
92 	S_IDLE = 0,
93 	S_PRINTER_READY_CMD,
94 	S_PRINTER_SENT_DATA,
95 	S_FINISHED,
96 };
97 
98 /* "Image Correction Parameter" File */
99 // 128 bytes total, apparently an array of 32-bit values
100 struct tankParamTable {
101 	uint32_t trdTankSize;
102 	uint32_t sndTankSize;
103 	uint32_t fstTankSize;
104 	uint32_t trdTankIniEnergy;
105 	uint32_t sndTankIniEnergy;
106 	uint32_t fstTankIniEnergy;
107 	uint32_t trdTrdConductivity;
108 	uint32_t sndSndConductivity;
109 	uint32_t fstFstConductivity;
110 	uint32_t outTrdConductivity;
111 	uint32_t trdSndConductivity;
112 	uint32_t sndFstConductivity;
113 	uint32_t fstOutConductivity;
114 	uint32_t plusMaxEnergy;
115 	uint32_t minusMaxEnergy;
116 	uint32_t plusMaxEnergyPreRead;
117 	uint32_t minusMaxEnergyPreRead;
118 	uint32_t preReadLevelDiff;
119 	uint32_t rsvd[14]; // null?
120 } __attribute__((packed));
121 
122 struct shinkos6145_correctionparam {
123 	uint16_t pulseTransTable_Y[256];   // @0
124 	uint16_t pulseTransTable_M[256];   // @512
125 	uint16_t pulseTransTable_C[256];   // @1024
126 	uint16_t pulseTransTable_O[256];   // @1536
127 
128 	uint16_t lineHistCoefTable_Y[256]; // @2048
129 	uint16_t lineHistCoefTable_M[256]; // @2560
130 	uint16_t lineHistCoefTable_C[256]; // @3072
131 	uint16_t lineHistCoefTable_O[256]; // @3584
132 
133 	uint16_t lineCorrectEnvA_Y;        // @4096
134 	uint16_t lineCorrectEnvA_M;        // @4098
135 	uint16_t lineCorrectEnvA_C;        // @4100
136 	uint16_t lineCorrectEnvA_O;        // @4102
137 
138 	uint16_t lineCorrectEnvB_Y;        // @4104
139 	uint16_t lineCorrectEnvB_M;        // @4106
140 	uint16_t lineCorrectEnvB_C;        // @4108
141 	uint16_t lineCorrectEnvB_O;        // @4110
142 
143 	uint16_t lineCorrectEnvC_Y;        // @4112
144 	uint16_t lineCorrectEnvC_M;        // @4114
145 	uint16_t lineCorrectEnvC_C;        // @4116
146 	uint16_t lineCorrectEnvC_O;        // @4118
147 
148 	uint32_t lineCorrectSlice_Y;       // @4120
149 	uint32_t lineCorrectSlice_M;       // @4124
150 	uint32_t lineCorrectSlice_C;       // @4128
151 	uint32_t lineCorrectSlice_O;       // @4132
152 
153 	uint32_t lineCorrectSlice1Line_Y;  // @4136
154 	uint32_t lineCorrectSlice1Line_M;  // @4140
155 	uint32_t lineCorrectSlice1Line_C;  // @4144
156 	uint32_t lineCorrectSlice1Line_O;  // @4148
157 
158 	uint32_t lineCorrectPulseMax_Y;    // @4152 [array]
159 	uint32_t lineCorrectPulseMax_M;    // @4156 [array]
160 	uint32_t lineCorrectPulseMax_C;    // @4160 [array]
161 	uint32_t lineCorrectPulseMax_O;    // @4164 [array]
162 
163 	struct tankParamTable tableTankParam_Y; // @4168
164 	struct tankParamTable tableTankParam_M; // @4296
165 	struct tankParamTable tableTankParam_C; // @4424
166 	struct tankParamTable tableTankParam_O; // @4552
167 
168 	uint16_t tankPlusMaxEnergyTable_Y[256]; // @4680
169 	uint16_t tankPlusMaxEnergyTable_M[256]; // @5192
170 	uint16_t tankPlusMaxEnergyTable_C[256]; // @5704
171 	uint16_t tankPlusMaxEnergyTable_O[256]; // @6216
172 
173 	uint16_t tankMinusMaxEnergy_Y[256];     // @6728
174 	uint16_t tankMinusMaxEnergy_M[256];     // @7240
175 	uint16_t tankMinusMaxEnergy_C[256];     // @7752
176 	uint16_t tankMinusMaxEnergy_O[256];     // @8264
177 
178 	uint16_t printMaxPulse_Y; // @8776
179 	uint16_t printMaxPulse_M; // @8778
180 	uint16_t printMaxPulse_C; // @8780
181 	uint16_t printMaxPulse_O; // @8782
182 
183 	uint16_t mtfWeightH_Y;    // @8784
184 	uint16_t mtfWeightH_M;    // @8786
185 	uint16_t mtfWeightH_C;    // @8788
186 	uint16_t mtfWeightH_O;    // @8790
187 
188 	uint16_t mtfWeightV_Y;    // @8792
189 	uint16_t mtfWeightV_M;    // @8794
190 	uint16_t mtfWeightV_C;    // @8796
191 	uint16_t mtfWeightV_O;    // @8798
192 
193 	uint16_t mtfSlice_Y;      // @8800
194 	uint16_t mtfSlice_M;      // @8802
195 	uint16_t mtfSlice_C;      // @8804
196 	uint16_t mtfSlice_O;      // @8806
197 
198 	uint16_t val_1;           // @8808 // 1 enables linepreprintprocess
199 	uint16_t val_2;		  // @8810 // 1 enables ctankprocess
200 	uint16_t printOpLevel;    // @8812
201 	uint16_t matteMode;	  // @8814 // 1 for matte
202 
203 	uint16_t randomBase[4];   // @8816 [use lower byte of each]
204 
205 	uint16_t matteSize;       // @8824
206 	uint16_t matteGloss;      // @8826
207 	uint16_t matteDeglossBlk; // @8828
208 	uint16_t matteDeglossWht; // @8830
209 
210 	uint16_t printSideOffset; // @8832
211 	uint16_t headDots;        // @8834 [always 0x0780, ie 1920. print width
212 
213 	uint16_t SideEdgeCoefTable[128];   // @8836
214 	uint8_t  rsvd_2[256];              // @9092, null?
215 	uint16_t SideEdgeLvCoefTable[256]; // @9348
216 	uint8_t  rsvd_3[2572];             // @9860, null?
217 
218 	/* User-supplied data */
219 	uint16_t width;           // @12432
220 	uint16_t height;          // @12434
221 	uint8_t  pad[3948];       // @12436, null.
222 } __attribute__((packed)); /* 16384 bytes */
223 
224 /* Structs for printer */
225 struct s6145_print_cmd {
226 	struct sinfonia_cmd_hdr hdr;
227 	uint8_t  id;
228 	uint16_t count;
229 	uint16_t columns;
230 	uint16_t rows;
231 	uint8_t  media;      /* reserved in docs, but brava21 uses this */
232 	uint8_t  combo_wait;
233 	uint8_t  reserved[6];
234 	uint8_t  unk_1;      /* Brava 21 sets this to 1 */
235 	uint8_t  method;
236 	uint8_t  image_avg;
237 } __attribute__((packed));
238 
239 #define PARAM_OC_PRINT     0x20
240 #define PARAM_PAPER_PRESV  0x3d
241 #define PARAM_DRIVER_MODE  0x3e
242 #define PARAM_PAPER_MODE   0x3f
243 #define PARAM_REGION_CODE  0x53 // Brava 21 only?
244 #define PARAM_SLEEP_TIME   0x54
245 
246 
247 #define PARAM_OC_PRINT_OFF   0x00000001
248 #define PARAM_OC_PRINT_GLOSS 0x00000002
249 #define PARAM_OC_PRINT_MATTE 0x00000003
250 
251 #define PARAM_PAPER_PRESV_OFF 0x00000000
252 #define PARAM_PAPER_PRESV_ON  0x00000001
253 
254 #define PARAM_DRIVER_WIZOFF 0x00000000
255 #define PARAM_DRIVER_WIZON  0x00000001
256 
257 #define PARAM_PAPER_NOCUT   0x00000000
258 #define PARAM_PAPER_CUTLOAD 0x00000001
259 
260 #define PARAM_SLEEP_5MIN    0x00000000
261 #define PARAM_SLEEP_15MIN   0x00000001
262 #define PARAM_SLEEP_30MIN   0x00000002
263 #define PARAM_SLEEP_60MIN   0x00000003
264 #define PARAM_SLEEP_120MIN  0x00000004
265 #define PARAM_SLEEP_240MIN  0x00000005
266 
error_codes(uint8_t major,uint8_t minor)267 static const char *error_codes(uint8_t major, uint8_t minor)
268 {
269 	switch(major) {
270 	case 0x01: /* "Controller Error" */
271 		switch(minor) {
272 		case 0x01:
273 			return "Controller: EEPROM Write Timeout";
274 		case 0x0A:
275 			return "Controller: Invalid Print Parameter Table";
276 		case 0x0C:
277 			return "Controller: Print Parameter Table Mismatch";
278 		case 0x0F:
279 			return "Controller: Main FW Checksum";
280 		case 0x10:
281 			return "Controller: Flash Write Failed";
282 		case 0x13:
283 			return "Controller: Print Parameter Table Checksum";
284 		case 0x14:
285 			return "Controller: Print Parameter Table Write Failed";
286 		case 0x15:
287 			return "Controller: User Tone Curve Write Failed";
288 		case 0x16:
289 			return "Controller: MSP Communication";
290 		case 0x17:
291 			return "Controller: THV Autotuning";
292 		case 0x18:
293 			return "Controller: THV Value Out of Range";
294 		case 0x19:
295 			return "Controller: Thermal Head";
296 		case 0x1A:
297 			return "Controller: Wake from Power Save Failed";
298 		default:
299 			return "Controller: Unknown";
300 		}
301 	case 0x02: /* "Mechanical Error" */
302 		switch (minor) {
303 		case 0x01:
304 			return "Mechanical: Pinch Head Home";
305 		case 0x02:
306 			return "Mechanical: Pinch Head (position 1)";
307 		case 0x03:
308 			return "Mechanical: Pinch Head (position 2)";
309 		case 0x04:
310 			return "Mechanical: Pinch Head (position 3)";
311 		case 0x0B:
312 			return "Mechanical: Cutter (Right)";
313 		case 0x0C:
314 			return "Mechanical: Cutter (Left)";
315 		default:
316 			return "Mechanical: Unknown";
317 		}
318 	case 0x03: /* "Sensor Error" */
319 		switch (minor) {
320 		case 0x01:
321 			return "Sensor: Head Up";
322 		case 0x02:
323 			return "Sensor: Head Down";
324 		case 0x0B:
325 			return "Sensor: Cutter Left";
326 		case 0x0C:
327 			return "Sensor: Cutter Right";
328 		case 0x0D:
329 			return "Sensor: Cutter Left+Right";
330 		case 0x15:
331 			return "Sensor: Head Up Unstable";
332 		case 0x16:
333 			return "Sensor: Head Down Unstable";
334 		case 0x17:
335 			return "Sensor: Cutter Left Unstable";
336 		case 0x18:
337 			return "Sensor: Cutter Right Unstable";
338 		case 0x19:
339 			return "Sensor: Cover Open Unstable";
340 		case 0x1E:
341 			return "Sensor: Ribbon Mark (Cyan)";
342 		case 0x1F:
343 			return "Sensor: Ribbon Mark (OC)";
344 		default:
345 			return "Sensor: Unknown";
346 		}
347 	case 0x04: /* "Temperature Sensor Error" */
348 		switch (minor) {
349 		case 0x01:
350 			return "Temp Sensor: Thermal Head Low";
351 		case 0x02:
352 			return "Temp Sensor: Thermal Head High";
353 		case 0x05:
354 			return "Temp Sensor: Environment Low";
355 		case 0x06:
356 			return "Temp Sensor: Environment High";
357 		case 0x07:
358 			return "Temp Sensor: Preheat";
359 		case 0x08:
360 			return "Temp Sensor: Thermal Protect";
361 		default:
362 			return "Temp Sensor: Unknown";
363 		}
364 	case 0x5: /* "Paper Jam" */
365 		switch (minor) {
366 		case 0x01:
367 			return "Paper Jam: Loading Paper Top On";
368 		case 0x02:
369 			return "Paper Jam: Loading Print Position On";
370 		case 0x03:
371 			return "Paper Jam: Loading Print Position Off";
372 		case 0x04:
373 			return "Paper Jam: Loading Paper Top Off";
374 		case 0x05:
375 			return "Paper Jam: Loading Cut Print Position Off";
376 		case 0x0C:
377 			return "Paper Jam: Initializing Print Position Off";
378 		case 0x0D:
379 			return "Paper Jam: Initializing Print Position On";
380 		case 0x15:
381 			return "Paper Jam: Printing Print Position Off";
382 		case 0x16:
383 			return "Paper Jam: Printing Paper Top On";
384 		case 0x17:
385 			return "Paper Jam: Printing Paper Top Off";
386 		case 0x1F:
387 			return "Paper Jam: Precut Print Position Off";
388 		case 0x20:
389 			return "Paper Jam: Precut Print Position On";
390 
391 		case 0x29:
392 			return "Paper Jam: Printing Paper Top On";
393 		case 0x2A:
394 			return "Paper Jam: Printing Pre-Yellow Print Position Off";
395 		case 0x2B:
396 			return "Paper Jam: Printing Yellow Print Position Off";
397 		case 0x2C:
398 			return "Paper Jam: Printing Yellow Print Position On";
399 		case 0x2D:
400 			return "Paper Jam: Printing Pre-Magenta Print Position Off";
401 		case 0x2E:
402 			return "Paper Jam: Printing Magenta Print Position On";
403 		case 0x2F:
404 			return "Paper Jam: Printing Magenta Print Position Off";
405 		case 0x30:
406 			return "Paper Jam: Printing Pre-Cyan Print Position Off";
407 		case 0x31:
408 			return "Paper Jam: Printing Cyan Print Position On";
409 		case 0x32:
410 			return "Paper Jam: Printing Cyan Print Position Off";
411 		case 0x33:
412 			return "Paper Jam: Printing Pre-OC Print Position Off";
413 		case 0x34:
414 			return "Paper Jam: Printing OC Print Position On";
415 		case 0x35:
416 			return "Paper Jam: Printing OC Print Position Off";
417 		case 0x36:
418 			return "Paper Jam: Cut Print Position Off";
419 		case 0x37:
420 			return "Paper Jam: Home Position Off";
421 		case 0x38:
422 			return "Paper Jam: Paper Top Off";
423 		case 0x39:
424 			return "Paper Jam: Print Position On";
425 
426 		case 0x51:
427 			return "Paper Jam: Paper Empty On, Top On, Position On";
428 		case 0x52:
429 			return "Paper Jam: Paper Empty On, Top On, Position Off";
430 		case 0x54:
431 			return "Paper Jam: Paper Empty On, Top Off, Position Off";
432 		case 0x60:
433 			return "Paper Jam: Cutter Right";
434 		case 0x61:
435 			return "Paper Jam: Cutter Left";
436 
437 		default:
438 			return "Paper Jam: Unknown";
439 		}
440 	case 0x06: /* User Error */
441 		switch (minor) {
442 		case 0x01:
443 			return "Drawer Unit Open";
444 		case 0x02:
445 			return "Incorrect Ribbon";
446 		case 0x04:
447 			return "Ribbon Empty";
448 		case 0x08:
449 			return "No Paper";
450 		case 0x0C:
451 			return "Paper End";
452 		default:
453 			return "Unknown";
454 		}
455 	default:
456 		return "Unknown";
457 	}
458 }
459 
460 struct s6145_status_resp {
461 	struct sinfonia_status_hdr hdr;
462 	uint32_t count_lifetime;
463 	uint32_t count_maint;
464 	uint32_t count_paper;
465 	uint32_t count_cutter;
466 	uint32_t count_head;
467 	uint32_t count_ribbon_left;
468 	uint32_t reserved;
469 
470 	uint8_t  bank1_printid;
471 	uint16_t bank1_remaining;
472 	uint16_t bank1_finished;
473 	uint16_t bank1_specified;
474 	uint8_t  bank1_status;
475 
476 	uint8_t  bank2_printid;
477 	uint16_t bank2_remaining;
478 	uint16_t bank2_finished;
479 	uint16_t bank2_specified;
480 	uint8_t  bank2_status;
481 
482 	uint8_t  reserved2[16];
483 	uint8_t  tonecurve_status;
484 	uint8_t  reserved3[6];
485 } __attribute__((packed));
486 
487 struct s6145_geteeprom_resp {
488 	struct sinfonia_status_hdr hdr;
489 	uint8_t data[256];
490 } __attribute__((packed));
491 
492 #define RIBBON_NONE   0x00
493 #define RIBBON_4x6    0x01
494 #define RIBBON_3_5x5  0x02
495 #define RIBBON_5x7    0x03
496 #define RIBBON_6x8    0x04
497 #define RIBBON_6x9    0x05
498 // XXX what about 89xXXXmm ribbons?
499 
ribbon_sizes(uint8_t v)500 static int ribbon_sizes (uint8_t v) {
501 	switch (v) {
502 	case RIBBON_4x6:
503 		return 300;
504 	case RIBBON_3_5x5:
505 		return 340;
506 	case RIBBON_5x7:
507 		return 170;
508 	case RIBBON_6x8:
509 		return 150;
510 	case RIBBON_6x9:
511 		return 130; // XXX guessed
512 	// XXX 89x??? rubbons.
513 	default:
514 		return 300; // don't want 0.
515 	}
516 }
517 
print_ribbons(uint8_t v)518 static const char *print_ribbons (uint8_t v) {
519 	switch (v) {
520 	case RIBBON_NONE:
521 		return "None";
522 	case RIBBON_4x6:
523 		return "4x6";
524 	case RIBBON_3_5x5:
525 		return "3.5x5";
526 	case RIBBON_5x7:
527 		return "5x7";
528 	case RIBBON_6x8:
529 		return "6x8";
530 	case RIBBON_6x9:
531 		return "6x9";
532 	// XXX 89x??? ribbons.
533 	default:
534 		return "Unknown";
535 	}
536 }
537 
538 struct s6145_mediainfo_resp {
539 	struct sinfonia_status_hdr hdr;
540 	uint8_t  ribbon;
541 	uint8_t  reserved;
542 	uint8_t  count;
543 	struct sinfonia_mediainfo_item items[10];  /* Not all necessarily used */
544 } __attribute__((packed));
545 
546 struct s6145_imagecorr_resp {
547 	struct sinfonia_status_hdr hdr;
548 	uint16_t total_size;
549 } __attribute__((packed));
550 
551 struct s6145_imagecorr_data {
552 	uint8_t  remain_pkt;
553 	uint8_t  return_size;
554 	uint8_t  data[16];
555 } __attribute__((packed));
556 
557 /* Private data structure */
558 struct shinkos6145_ctx {
559 	struct sinfonia_usbdev dev;
560 
561 	uint8_t jobid;
562 
563 	uint8_t image_avg[3]; /* CMY */
564 
565 	struct marker marker;
566 
567 	struct s6145_mediainfo_resp media;
568 
569 	uint8_t *eeprom;
570 	size_t eepromlen;
571 
572 	void *dl_handle;
573 	ImageProcessingFN ImageProcessing;
574 	ImageAvrCalcFN ImageAvrCalc;
575 
576 	struct shinkos6145_correctionparam *corrdata;
577 	size_t corrdatalen;
578 };
579 
580 static int shinkos6145_get_imagecorr(struct shinkos6145_ctx *ctx);
581 static int shinkos6145_get_eeprom(struct shinkos6145_ctx *ctx);
582 
get_status(struct shinkos6145_ctx * ctx)583 static int get_status(struct shinkos6145_ctx *ctx)
584 {
585 	struct sinfonia_cmd_hdr cmd;
586 	struct s6145_status_resp resp;
587 	struct sinfonia_getextcounter_resp resp2;
588 	int ret, num = 0;
589 	uint32_t val;
590 
591 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
592 	cmd.len = cpu_to_le16(0);
593 
594 	if ((ret = sinfonia_docmd(&ctx->dev,
595 				  (uint8_t*)&cmd, sizeof(cmd),
596 				  (uint8_t*)&resp, sizeof(resp), &num)) < 0) {
597 		return ret;
598 	}
599 
600 	INFO("Printer Status:  0x%02x (%s)\n", resp.hdr.status,
601 	     sinfonia_status_str(resp.hdr.status));
602 	if (resp.hdr.status == ERROR_PRINTER) {
603 		if(resp.hdr.error == ERROR_NONE)
604 			resp.hdr.error = resp.hdr.status;
605 		INFO(" Error 0x%02x (%s) 0x%02x/0x%02x (%s)\n",
606 		     resp.hdr.error,
607 		     sinfonia_error_str(resp.hdr.error),
608 		     resp.hdr.printer_major,
609 		     resp.hdr.printer_minor, error_codes(resp.hdr.printer_major, resp.hdr.printer_minor));
610 	}
611 	if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct s6145_status_resp) - sizeof(struct sinfonia_status_hdr)))
612 		return -1;
613 
614 	INFO(" Print Counts:\n");
615 	INFO("\tSince Paper Changed:\t%08u\n", le32_to_cpu(resp.count_paper));
616 	INFO("\tLifetime:\t\t%08u\n", le32_to_cpu(resp.count_lifetime));
617 	INFO("\tMaintenance:\t\t%08u\n", le32_to_cpu(resp.count_maint));
618 	INFO("\tPrint Head:\t\t%08u\n", le32_to_cpu(resp.count_head));
619 	INFO(" Cutter Actuations:\t%08u\n", le32_to_cpu(resp.count_cutter));
620 	INFO(" Ribbon Remaining:\t%08u\n", le32_to_cpu(resp.count_ribbon_left));
621 	INFO("Bank 1: 0x%02x (%s) Job %03u @ %03u/%03u (%03u remaining)\n",
622 	     resp.bank1_status, sinfonia_bank_statuses(resp.bank1_status),
623 	     resp.bank1_printid,
624 	     le16_to_cpu(resp.bank1_finished),
625 	     le16_to_cpu(resp.bank1_specified),
626 	     le16_to_cpu(resp.bank1_remaining));
627 
628 	INFO("Bank 2: 0x%02x (%s) Job %03u @ %03u/%03u (%03u remaining)\n",
629 	     resp.bank2_status, sinfonia_bank_statuses(resp.bank1_status),
630 	     resp.bank2_printid,
631 	     le16_to_cpu(resp.bank2_finished),
632 	     le16_to_cpu(resp.bank2_specified),
633 	     le16_to_cpu(resp.bank2_remaining));
634 
635 	INFO("Tonecurve Status: 0x%02x (%s)\n", resp.tonecurve_status, sinfonia_tonecurve_statuses(resp.tonecurve_status));
636 
637 	/* Query Extended counters */
638 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_EXTCOUNTER);
639 	cmd.len = cpu_to_le16(0);
640 
641 	if ((ret = sinfonia_docmd(&ctx->dev,
642 				  (uint8_t*)&cmd, sizeof(cmd),
643 				  (uint8_t*)&resp2, sizeof(resp2),
644 				  &num)) < 0) {
645 		return ret;
646 	}
647 	if (le16_to_cpu(resp2.hdr.payload_len) != (sizeof(struct sinfonia_getextcounter_resp) - sizeof(struct sinfonia_status_hdr)))
648 		return -1;
649 
650 	INFO("Lifetime Distance:     %08u inches\n", le32_to_cpu(resp2.lifetime_distance));
651 	INFO("Maintenance Distance:  %08u inches\n", le32_to_cpu(resp2.maint_distance));
652 	INFO("Head Distance:         %08u inches\n", le32_to_cpu(resp2.head_distance));
653 
654 	/* Query various params */
655 	if (ctx->dev.type == P_SHINKO_S6145D) {
656 		if ((ret = sinfonia_getparam(&ctx->dev, PARAM_REGION_CODE, &val))) {
657 			ERROR("Failed to execute command\n");
658 			return ret;
659 		}
660 		INFO("Region Code: %#x\n", val);
661 
662 	}
663 	if ((ret = sinfonia_getparam(&ctx->dev, PARAM_PAPER_PRESV, &val))) {
664 		ERROR("Failed to execute command\n");
665 		return ret;
666 	}
667 	INFO("Paper Preserve mode: %s\n", (val ? "On" : "Off"));
668 
669 	if ((ret = sinfonia_getparam(&ctx->dev, PARAM_DRIVER_MODE, &val))) {
670 		ERROR("Failed to execute command\n");
671 		return ret;
672 	}
673 	INFO("Driver mode:         %s\n", (val ? "On" : "Off"));
674 
675 	if ((ret = sinfonia_getparam(&ctx->dev, PARAM_PAPER_MODE, &val))) {
676 		ERROR("Failed to execute command\n");
677 		return ret;
678 	}
679 	INFO("Paper load mode:     %s\n", (val ? "Cut" : "No Cut"));
680 
681 	if ((ret = sinfonia_getparam(&ctx->dev, PARAM_SLEEP_TIME, &val))) {
682 		ERROR("Failed to execute command\n");
683 		return ret;
684 	}
685 	if (val == 0)
686 		val = 5;
687 	else if (val == 1)
688 		val = 15;
689 	else if (val == 2)
690 		val = 30;
691 	else if (val == 3)
692 		val = 60;
693 	else if (val == 4)
694 		val = 120;
695 	else if (val >= 5)
696 		val = 240;
697 	else
698 		val = 240; // default?
699 
700 	INFO("Sleep delay:         %u minutes\n", val);
701 
702 	return 0;
703 }
704 
dump_mediainfo(struct s6145_mediainfo_resp * resp)705 static void dump_mediainfo(struct s6145_mediainfo_resp *resp)
706 {
707 	int i;
708 
709 	INFO("Loaded Media Type:  %s\n", print_ribbons(resp->ribbon));
710 	INFO("Supported Print Sizes: %u entries:\n", resp->count);
711 	for (i = 0 ; i < resp->count ; i++) {
712 		INFO(" %02d: C 0x%02x (%s), %04ux%04u, P 0x%02x (%s)\n", i,
713 		     resp->items[i].code,
714 		     sinfonia_print_codes(resp->items[i].code, 0),
715 		     resp->items[i].columns,
716 		     resp->items[i].rows,
717 		     resp->items[i].method,
718 		     sinfonia_print_methods(resp->items[i].method));
719 	}
720 }
721 
shinkos6145_dump_corrdata(struct shinkos6145_ctx * ctx,char * fname)722 static int shinkos6145_dump_corrdata(struct shinkos6145_ctx *ctx, char *fname)
723 {
724 	int ret;
725 
726 	ret = shinkos6145_get_imagecorr(ctx);
727 	if (ret) {
728 		ERROR("Failed to execute command\n");
729 		return ret;
730 	}
731 
732 	/* Open file and write it out */
733 	{
734 		int fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
735 		if (fd < 0) {
736 			ERROR("Unable to open filename\n");
737 			return fd;
738 		}
739 
740 		ret = write(fd, ctx->corrdata, sizeof(struct shinkos6145_correctionparam));
741 		close(fd);
742 	}
743 
744 	/* Free the buffers */
745 	free(ctx->corrdata);
746 	ctx->corrdata = NULL;
747 	ctx->corrdatalen = 0;
748 
749 	return ret;
750 }
751 
shinkos6145_dump_eeprom(struct shinkos6145_ctx * ctx,char * fname)752 static int shinkos6145_dump_eeprom(struct shinkos6145_ctx *ctx, char *fname)
753 {
754 	int ret;
755 
756 	ret = shinkos6145_get_eeprom(ctx);
757 	if (ret) {
758 		ERROR("Failed to execute command\n");
759 		return ret;
760 	}
761 
762 	/* Open file and write it out */
763 	{
764 		int fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
765 		if (fd < 0) {
766 			ERROR("Unable to open filename\n");
767 			return fd;
768 		}
769 
770 		ret = write(fd, ctx->eeprom, ctx->eepromlen);
771 		close(fd);
772 	}
773 
774 	/* Free the buffers */
775 	free(ctx->eeprom);
776 	ctx->eeprom = NULL;
777 	ctx->eepromlen = 0;
778 
779 	return ret;
780 }
781 
shinkos6145_get_imagecorr(struct shinkos6145_ctx * ctx)782 static int shinkos6145_get_imagecorr(struct shinkos6145_ctx *ctx)
783 {
784 	struct sinfonia_cmd_hdr cmd;
785 	struct s6145_imagecorr_resp resp;
786 
787 	size_t total = 0;
788 	int ret, num;
789 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETCORR);
790 	cmd.len = 0;
791 
792 	if (ctx->corrdata) {
793 		free(ctx->corrdata);
794 		ctx->corrdata = NULL;
795 	}
796 
797 	if ((ret = sinfonia_docmd(&ctx->dev,
798 				  (uint8_t*)&cmd, sizeof(cmd),
799 				  (uint8_t*)&resp, sizeof(resp),
800 				  &num)) < 0) {
801 		goto done;
802 	}
803 
804 	ctx->corrdatalen = le16_to_cpu(resp.total_size);
805 	INFO("Fetching %zu bytes of image correction data\n", ctx->corrdatalen);
806 
807 	ctx->corrdata = malloc(sizeof(struct shinkos6145_correctionparam));
808 	if (!ctx->corrdata) {
809 		ERROR("Memory allocation failure\n");
810 		ret = -ENOMEM;
811 		goto done;
812 	}
813 	memset(ctx->corrdata, 0, sizeof(struct shinkos6145_correctionparam));
814 	total = 0;
815 
816 	while (total < ctx->corrdatalen) {
817 		struct s6145_imagecorr_data data;
818 
819 		ret = read_data(ctx->dev.dev, ctx->dev.endp_up, (uint8_t *) &data,
820 				sizeof(data),
821 				&num);
822 		if (ret < 0)
823 			goto done;
824 
825 		memcpy(((uint8_t*)ctx->corrdata) + total, data.data, sizeof(data.data));
826 		total += sizeof(data.data);
827 
828 		if (data.remain_pkt == 0)
829 			DEBUG("correction block transferred (%zu/%zu total)\n", total, ctx->corrdatalen);
830 
831 	}
832 
833 
834 done:
835 	return ret;
836 }
837 
shinkos6145_get_eeprom(struct shinkos6145_ctx * ctx)838 static int shinkos6145_get_eeprom(struct shinkos6145_ctx *ctx)
839 {
840 	struct sinfonia_cmd_hdr cmd;
841 	struct s6145_geteeprom_resp resp;
842 
843 	int ret, num;
844 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETEEPROM);
845 	cmd.len = 0;
846 
847 	if (ctx->eeprom) {
848 		free(ctx->eeprom);
849 		ctx->eeprom = NULL;
850 	}
851 
852 	if ((ret = sinfonia_docmd(&ctx->dev,
853 				  (uint8_t*)&cmd, sizeof(cmd),
854 				  (uint8_t*)&resp, sizeof(resp),
855 				  &num)) < 0) {
856 		goto done;
857 	}
858 
859 	ctx->eepromlen = le16_to_cpu(resp.hdr.payload_len);
860 	ctx->eeprom = malloc(ctx->eepromlen);
861 	if (!ctx->eeprom) {
862 		ERROR("Memory allocation failure\n");
863 		ret = -ENOMEM;
864 		goto done;
865 	}
866 	memcpy(ctx->eeprom, resp.data, ctx->eepromlen);
867 
868 done:
869 	return ret;
870 }
871 
shinkos6145_cmdline(void)872 static void shinkos6145_cmdline(void)
873 {
874 	DEBUG("\t\t[ -c filename ]  # Get user/NV tone curve\n");
875 	DEBUG("\t\t[ -C filename ]  # Set user/NV tone curve\n");
876 	DEBUG("\t\t[ -e ]           # Query error log\n");
877 	DEBUG("\t\t[ -F ]           # Flash Printer LED\n");
878 	DEBUG("\t\t[ -i ]           # Query printer info\n");
879 	DEBUG("\t\t[ -k num ]       # Set sleep time (5-240 minutes)\n");
880 	DEBUG("\t\t[ -l filename ]  # Get current tone curve\n");
881 	DEBUG("\t\t[ -L filename ]  # Set current tone curve\n");
882 	DEBUG("\t\t[ -m ]           # Query media\n");
883 	DEBUG("\t\t[ -q filename ]  # Extract eeprom data\n");
884 	DEBUG("\t\t[ -Q filename ]  # Extract image correction params\n");
885 	DEBUG("\t\t[ -r ]           # Reset user/NV tone curve\n");
886 	DEBUG("\t\t[ -R ]           # Reset printer to factory defaults\n");
887 	DEBUG("\t\t[ -s ]           # Query status\n");
888 	DEBUG("\t\t[ -X jobid ]     # Abort a printjob\n");
889 }
890 
shinkos6145_cmdline_arg(void * vctx,int argc,char ** argv)891 int shinkos6145_cmdline_arg(void *vctx, int argc, char **argv)
892 {
893 	struct shinkos6145_ctx *ctx = vctx;
894 	int i, j = 0;
895 
896 	if (!ctx)
897 		return -1;
898 
899 	while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "c:C:eFik:l:L:mr:Q:q:rR:sX:")) >= 0) {
900 		switch(i) {
901 		GETOPT_PROCESS_GLOBAL
902 		case 'c':
903 			j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_USER, optarg);
904 			break;
905 		case 'C':
906 			j = sinfonia_settonecurve(&ctx->dev, TONECURVE_USER, optarg);
907 			break;
908 		case 'e':
909 			j = sinfonia_geterrorlog(&ctx->dev);
910 			break;
911 		case 'F':
912 			j = sinfonia_flashled(&ctx->dev);
913 			break;
914 		case 'i':
915 			j = sinfonia_getfwinfo(&ctx->dev);
916 			break;
917 		case 'k': {
918 			i = atoi(optarg);
919 			if (i <= 5)
920 				i = 0;
921 			else if (i <= 15)
922 				i = 1;
923 			else if (i <= 30)
924 				i = 2;
925 			else if (i <= 60)
926 				i = 3;
927 			else if (i <= 120)
928 				i = 4;
929 			else if (i <= 240)
930 				i = 5;
931 			else
932 				i = 5;
933 
934 			j = sinfonia_setparam(&ctx->dev, PARAM_SLEEP_TIME, i);
935 			break;
936 		}
937 		case 'l':
938 			j = sinfonia_gettonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
939 			break;
940 		case 'L':
941 			j = sinfonia_settonecurve(&ctx->dev, TONECURVE_CURRENT, optarg);
942 			break;
943 		case 'm':
944 			dump_mediainfo(&ctx->media);
945 			break;
946 		case 'q':
947 			j = shinkos6145_dump_eeprom(ctx, optarg);
948 			break;
949 		case 'Q':
950 			j = shinkos6145_dump_corrdata(ctx, optarg);
951 			break;
952 		case 'r':
953 			j = sinfonia_resetcurve(&ctx->dev, RESET_TONE_CURVE, TONE_CURVE_ID);
954 			break;
955 		case 'R':
956 			j = sinfonia_resetcurve(&ctx->dev, RESET_PRINTER, 0);
957 			break;
958 		case 's':
959 			j = get_status(ctx);
960 			break;
961 		case 'X':
962 			j = sinfonia_canceljob(&ctx->dev, atoi(optarg));
963 			break;
964 		default:
965 			break;  /* Ignore completely */
966 		}
967 
968 		if (j) return j;
969 	}
970 
971 	return 0;
972 }
973 
shinkos6145_init(void)974 static void *shinkos6145_init(void)
975 {
976 	struct shinkos6145_ctx *ctx = malloc(sizeof(struct shinkos6145_ctx));
977 	if (!ctx) {
978 		ERROR("Memory Allocation Failure!\n");
979 		return NULL;
980 	}
981 	memset(ctx, 0, sizeof(struct shinkos6145_ctx));
982 
983 	DL_INIT();
984 
985 	return ctx;
986 }
987 
shinkos6145_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)988 static int shinkos6145_attach(void *vctx, struct libusb_device_handle *dev, int type,
989 			      uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
990 {
991 	struct shinkos6145_ctx *ctx = vctx;
992 
993 	ctx->dev.dev = dev;
994 	ctx->dev.endp_up = endp_up;
995 	ctx->dev.endp_down = endp_down;
996 	ctx->dev.type = type;
997 	ctx->dev.error_codes = &error_codes;
998 
999 	/* Attempt to open the library */
1000 #if defined(WITH_DYNAMIC)
1001 	INFO("Attempting to load image processing library\n");
1002 	ctx->dl_handle = DL_OPEN(LIB_NAME); /* Try the Sinfonia one first */
1003 	if (!ctx->dl_handle)
1004 		ctx->dl_handle = DL_OPEN(LIB_NAME_RE); /* Then the RE one */
1005 	if (!ctx->dl_handle)
1006 		WARNING("Image processing library not found, using internal fallback code\n");
1007 	if (ctx->dl_handle) {
1008 		ctx->ImageProcessing = DL_SYM(ctx->dl_handle, "ImageProcessing");
1009 		ctx->ImageAvrCalc = DL_SYM(ctx->dl_handle, "ImageAvrCalc");
1010 		if (!ctx->ImageProcessing || !ctx->ImageAvrCalc) {
1011 			WARNING("Problem resolving symbols in imaging processing library\n");
1012 			DL_CLOSE(ctx->dl_handle);
1013 			ctx->dl_handle = NULL;
1014 		} else {
1015 			INFO("Image processing library successfully loaded\n");
1016 		}
1017 	}
1018 #else
1019 	WARNING("Dynamic library support not enabled, using internal fallback code\n");
1020 #endif
1021 
1022 	/* Ensure jobid is sane */
1023 	ctx->jobid = (jobid & 0x7f);
1024 	if (!ctx->jobid)
1025 		ctx->jobid++;
1026 
1027 	if (test_mode < TEST_MODE_NOATTACH) {
1028 		/* Query Media */
1029 		struct sinfonia_cmd_hdr cmd;
1030 		int num;
1031 
1032 		cmd.cmd = cpu_to_le16(SINFONIA_CMD_MEDIAINFO);
1033 		cmd.len = cpu_to_le16(0);
1034 
1035 		if (sinfonia_docmd(&ctx->dev,
1036 				   (uint8_t*)&cmd, sizeof(cmd),
1037 				   (uint8_t*)&ctx->media, sizeof(ctx->media),
1038 				   &num)) {
1039 			return CUPS_BACKEND_FAILED;
1040 		}
1041 
1042 		/* Byteswap media descriptor.. */
1043 		int i;
1044 		for (i = 0 ; i < ctx->media.count ; i++) {
1045 			ctx->media.items[i].columns = le16_to_cpu(ctx->media.items[i].columns);
1046 			ctx->media.items[i].rows = le16_to_cpu(ctx->media.items[i].rows);
1047 		}
1048 	} else {
1049 		int media_code = RIBBON_6x8;
1050 		if (getenv("MEDIA_CODE"))
1051 			media_code = atoi(getenv("MEDIA_CODE"));
1052 
1053 		ctx->media.ribbon = media_code;
1054 	}
1055 
1056 	ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
1057 	ctx->marker.name = print_ribbons(ctx->media.ribbon);
1058 	ctx->marker.levelmax = ribbon_sizes(ctx->media.ribbon);
1059 	ctx->marker.levelnow = -2;
1060 
1061 	return CUPS_BACKEND_OK;
1062 }
1063 
shinkos6145_teardown(void * vctx)1064 static void shinkos6145_teardown(void *vctx) {
1065 	struct shinkos6145_ctx *ctx = vctx;
1066 
1067 	if (!ctx)
1068 		return;
1069 
1070 	if (ctx->eeprom)
1071 		free(ctx->eeprom);
1072 	if (ctx->corrdata)
1073 		free(ctx->corrdata);
1074 	if (ctx->dl_handle)
1075 		DL_CLOSE(ctx->dl_handle);
1076 
1077 	DL_EXIT();
1078 
1079 	free(ctx);
1080 }
1081 
lib6145_calc_avg(struct shinkos6145_ctx * ctx,const struct sinfonia_printjob * job,uint16_t rows,uint16_t cols)1082 static void lib6145_calc_avg(struct shinkos6145_ctx *ctx,
1083 			     const struct sinfonia_printjob *job,
1084 			     uint16_t rows, uint16_t cols)
1085 {
1086 	uint32_t plane, i, planelen;
1087 	planelen = rows * cols;
1088 
1089 	for (plane = 0 ; plane < 3 ; plane++) {
1090 		uint64_t sum = 0;
1091 
1092 		for (i = 0 ; i < planelen ; i++) {
1093 			sum += job->databuf[(planelen * plane) + i];
1094 		}
1095 		ctx->image_avg[plane] = (sum / planelen);
1096 	}
1097 }
1098 
lib6145_process_image(uint8_t * src,uint16_t * dest,struct shinkos6145_correctionparam * corrdata,uint8_t oc_mode)1099 static void lib6145_process_image(uint8_t *src, uint16_t *dest,
1100 				  struct shinkos6145_correctionparam *corrdata,
1101 				  uint8_t oc_mode)
1102 {
1103 	uint32_t in, out;
1104 
1105 	uint16_t pad_l, pad_r, row_lim;
1106 	uint16_t row, col;
1107 
1108 	row_lim = le16_to_cpu(corrdata->headDots);
1109 	pad_l = (row_lim - le16_to_cpu(corrdata->width)) / 2;
1110 	pad_r = pad_l + le16_to_cpu(corrdata->width);
1111 	out = 0;
1112 	in = 0;
1113 
1114 	/* Convert YMC 8-bit to 16-bit, and pad appropriately to full stripe */
1115 	for (row = 0 ; row < le16_to_cpu(corrdata->height) ; row++) {
1116 		for (col = 0 ; col < row_lim; col++) {
1117 			uint16_t val;
1118 			if (col < pad_l) {
1119 				val = 0;
1120 			} else if (col < pad_r) {
1121 				val = corrdata->pulseTransTable_Y[src[in++]];
1122 			} else {
1123 				val = 0;
1124 			}
1125 			dest[out++] = val;
1126 		}
1127 	}
1128 	for (row = 0 ; row < le16_to_cpu(corrdata->height) ; row++) {
1129 		for (col = 0 ; col < row_lim; col++) {
1130 			uint16_t val;
1131 			if (col < pad_l) {
1132 				val = 0;
1133 			} else if (col < pad_r) {
1134 				val = corrdata->pulseTransTable_M[src[in++]];
1135 			} else {
1136 				val = 0;
1137 			}
1138 			dest[out++] = val;
1139 		}
1140 	}
1141 	for (row = 0 ; row < le16_to_cpu(corrdata->height) ; row++) {
1142 		for (col = 0 ; col < row_lim; col++) {
1143 			uint16_t val;
1144 			if (col < pad_l) {
1145 				val = 0;
1146 			} else if (col < pad_r) {
1147 				val = corrdata->pulseTransTable_C[src[in++]];
1148 			} else {
1149 				val = 0;
1150 			}
1151 			dest[out++] = val;
1152 		}
1153 	}
1154 
1155 	/* Generate lamination plane, if desired */
1156 	if (oc_mode > PRINT_MODE_NO_OC) {
1157 		// XXX matters if we're using glossy/matte...
1158 		for (row = 0 ; row < le16_to_cpu(corrdata->height) ; row++) {
1159 			for (col = 0 ; col < row_lim; col++) {
1160 				uint16_t val;
1161 				if (col < pad_l) {
1162 					val = 0;
1163 				} else if (col < pad_r) {
1164 					val = corrdata->pulseTransTable_O[corrdata->printOpLevel];
1165 				} else {
1166 					val = 0;
1167 				}
1168 				dest[out++] = val;
1169 			}
1170 		}
1171 	}
1172 }
1173 
shinkos6145_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)1174 static int shinkos6145_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
1175 	struct shinkos6145_ctx *ctx = vctx;
1176 	struct sinfonia_printjob *job = NULL;
1177 	int ret;
1178 	int model;
1179 	uint8_t input_ymc;
1180 
1181 	if (!ctx)
1182 		return CUPS_BACKEND_FAILED;
1183 
1184 	if (ctx->dev.type == P_SHINKO_S6145 ||
1185 	    ctx->dev.type == P_SHINKO_S6145D)
1186 		model = 6145;
1187 	else
1188 		model = 2245;
1189 
1190 	job = malloc(sizeof(*job));
1191 	if (!job) {
1192 		ERROR("Memory allocation failure!\n");
1193 		return CUPS_BACKEND_RETRY_CURRENT;
1194 	}
1195 	memset(job, 0, sizeof(*job));
1196 
1197 	/* Common read/parse code */
1198 	if (ctx->dev.type == P_KODAK_6900) {
1199 		ret = sinfonia_raw28_read_parse(data_fd, job);
1200 	} else {
1201 		ret = sinfonia_read_parse(data_fd, model, job);
1202 	}
1203 	if (ret) {
1204 		free(job);
1205 		return ret;
1206 	}
1207 
1208 	if (job->jp.copies > 1)
1209 		job->copies = job->jp.copies;
1210 	else
1211 		job->copies = copies;
1212 
1213 	/* Extended spool format to re-purpose an unused header field.
1214 	   When bit 0 is set, this tells the backend that the data is
1215 	   already in planar YMC format (vs packed RGB) so we don't need
1216 	   to do the conversion ourselves.  Saves some processing overhead */
1217 	input_ymc = job->jp.ext_flags & 0x01;
1218 
1219 	/* Convert packed RGB to planar YMC if necessary */
1220 	if (!input_ymc) {
1221 		INFO("Converting Packed RGB to Planar YMC\n");
1222 		int planelen = job->jp.columns * job->jp.rows;
1223 		uint8_t *databuf3 = malloc(job->datalen);
1224 		int i;
1225 		if (!databuf3) {
1226 			ERROR("Memory allocation failure!\n");
1227 			sinfonia_cleanup_job(job);
1228 			return CUPS_BACKEND_RETRY_CURRENT;
1229 		}
1230 		for (i = 0 ; i < planelen ; i++) {
1231 			uint8_t r, g, b;
1232 			r = job->databuf[3*i];
1233 			g = job->databuf[3*i+1];
1234 			b = job->databuf[3*i+2];
1235 			databuf3[i] = 255 - b;
1236 			databuf3[planelen + i] = 255 - g;
1237 			databuf3[planelen + planelen + i] = 255 - r;
1238 		}
1239 		free(job->databuf);
1240 		job->databuf = databuf3;
1241 	}
1242 
1243 	// if (job->copies > 1 && hdr->media == 0 && hdr->method == 0)
1244 	// and if printer_media == 6x8 or 6x9
1245 	// combine 4x6 + 4x6 -> 8x6
1246 	// 1844x2492 = 1844x1240.. delta = 12.
1247 
1248 	*vjob = job;
1249 
1250 	return CUPS_BACKEND_OK;
1251 }
1252 
shinkos6145_main_loop(void * vctx,const void * vjob)1253 static int shinkos6145_main_loop(void *vctx, const void *vjob) {
1254 	struct shinkos6145_ctx *ctx = vctx;
1255 
1256 	int ret, num;
1257 
1258 	int i, last_state = -1, state = S_IDLE;
1259 
1260 	struct sinfonia_cmd_hdr cmd;
1261 	struct s6145_status_resp sts, sts2;
1262 
1263 	uint32_t cur_mode;
1264 
1265 	struct sinfonia_printjob *job = (struct sinfonia_printjob*) vjob; /* XXX stupid, we can't do this. */
1266 
1267 	if (!job)
1268 		return CUPS_BACKEND_FAILED;
1269 
1270 	/* Validate print sizes */
1271 	for (i = 0; i < ctx->media.count ; i++) {
1272 		/* Look for matching media */
1273 		if (ctx->media.items[i].columns == job->jp.columns &&
1274 		    ctx->media.items[i].rows == job->jp.rows &&
1275 		    ctx->media.items[i].method == job->jp.method &&
1276 		    ctx->media.items[i].code == job->jp.media)
1277 			break;
1278 	}
1279 	if (i == ctx->media.count) {
1280 		ERROR("Incorrect media loaded for print!\n");
1281 		return CUPS_BACKEND_HOLD;
1282 	}
1283 
1284 	// XXX check copies against remaining media?
1285 
1286 	/* Query printer mode */
1287 	ret = sinfonia_getparam(&ctx->dev, PARAM_OC_PRINT, &cur_mode);
1288 	if (ret) {
1289 		ERROR("Failed to execute command\n");
1290 		return ret;
1291 	}
1292 
1293 top:
1294 	if (state != last_state) {
1295 		if (dyesub_debug)
1296 			DEBUG("last_state %d new %d\n", last_state, state);
1297 	}
1298 
1299 	/* Send Status Query */
1300 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
1301 	cmd.len = cpu_to_le16(0);
1302 
1303 	if ((ret = sinfonia_docmd(&ctx->dev,
1304 				  (uint8_t*)&cmd, sizeof(cmd),
1305 				  (uint8_t*)&sts, sizeof(sts),
1306 				  &num)) < 0) {
1307 		return CUPS_BACKEND_FAILED;
1308 	}
1309 
1310 	if (memcmp(&sts, &sts2, sizeof(sts))) {
1311 		memcpy(&sts2, &sts, sizeof(sts));
1312 
1313 		INFO("Printer Status: 0x%02x (%s)\n",
1314 		     sts.hdr.status, sinfonia_status_str(sts.hdr.status));
1315 
1316 		if (ctx->marker.levelnow != (int)sts.count_ribbon_left) {
1317 			ctx->marker.levelnow = sts.count_ribbon_left;
1318 			dump_markers(&ctx->marker, 1, 0);
1319 		}
1320 
1321 		if (sts.hdr.result != RESULT_SUCCESS)
1322 			goto printer_error;
1323 		if (sts.hdr.status == ERROR_PRINTER)
1324 			goto printer_error;
1325 	} else if (state == last_state) {
1326 		sleep(1);
1327 		goto top;
1328 	}
1329 	last_state = state;
1330 
1331 	fflush(stderr);
1332 
1333 	switch (state) {
1334 	case S_IDLE:
1335 		INFO("Waiting for printer idle\n");
1336 		/* If either bank is free, continue */
1337 		if (sts.bank1_status == BANK_STATUS_FREE ||
1338 		    sts.bank2_status == BANK_STATUS_FREE)
1339 			state = S_PRINTER_READY_CMD;
1340 
1341 		break;
1342 	case S_PRINTER_READY_CMD: {
1343 		/* Set matte/etc */
1344 
1345 		uint32_t oc_mode = job->jp.oc_mode;
1346 		uint32_t updated = 0;
1347 
1348 		if (!oc_mode) /* if nothing set, default to glossy */
1349 			oc_mode = PARAM_OC_PRINT_GLOSS;
1350 
1351 		if (cur_mode != oc_mode) {
1352 			/* If cur_mode is not the same as desired oc_mode,
1353 			   change it -- but we have to wait until the printer
1354 			   is COMPLETELY idle */
1355 			if (sts.bank1_status != BANK_STATUS_FREE ||
1356 			    sts.bank2_status != BANK_STATUS_FREE) {
1357 				INFO("Need to switch overcoat mode, waiting for printer idle\n");
1358 				sleep(1);
1359 				goto top;
1360 			}
1361 			ret = sinfonia_setparam(&ctx->dev, PARAM_OC_PRINT, oc_mode);
1362 			if (ret) {
1363 				ERROR("Failed to execute command\n");
1364 				return ret;
1365 			}
1366 			updated = 1;
1367 		}
1368 
1369 		ret = shinkos6145_get_eeprom(ctx);
1370 		if (ret) {
1371 			ERROR("Failed to execute command\n");
1372 			return ret;
1373 		}
1374 
1375 		/* Get image correction parameters if necessary */
1376 		if (updated || !ctx->corrdata || !ctx->corrdatalen) {
1377 			ret = shinkos6145_get_imagecorr(ctx);
1378 			if (ret) {
1379 				ERROR("Failed to execute command\n");
1380 				return ret;
1381 			}
1382 		}
1383 
1384 		/* Set up library transform... */
1385 		uint32_t newlen = le16_to_cpu(ctx->corrdata->headDots) *
1386 			job->jp.rows * sizeof(uint16_t) * 4;
1387 		uint16_t *databuf2 = malloc(newlen);
1388 
1389 		/* Set the size in the correctiondata */
1390 		ctx->corrdata->width = cpu_to_le16(job->jp.columns);
1391 		ctx->corrdata->height = cpu_to_le16(job->jp.rows);
1392 
1393 
1394 		/* Perform the actual library transform */
1395 		if (ctx->dl_handle) {
1396 			INFO("Calling image processing library...\n");
1397 
1398 			if (ctx->ImageAvrCalc(job->databuf, job->jp.columns, job->jp.rows, ctx->image_avg)) {
1399 				free(databuf2);
1400 				ERROR("Library returned error!\n");
1401 				return CUPS_BACKEND_FAILED;
1402 			}
1403 			ctx->ImageProcessing(job->databuf, databuf2, ctx->corrdata);
1404 		} else {
1405 			WARNING("Utilizing fallback internal image processing code\n");
1406 			WARNING(" *** Output quality will be poor! *** \n");
1407 
1408 			lib6145_calc_avg(ctx, job, job->jp.columns, job->jp.rows);
1409 			lib6145_process_image(job->databuf, databuf2, ctx->corrdata, oc_mode);
1410 		}
1411 
1412 		free(job->databuf);
1413 		job->databuf = (uint8_t*) databuf2;
1414 		job->datalen = newlen;
1415 
1416 		struct s6145_print_cmd print;
1417 
1418 		INFO("Sending print job (internal id %u)\n", ctx->jobid);
1419 
1420 		memset(&print, 0, sizeof(print));
1421 		print.hdr.cmd = cpu_to_le16(SINFONIA_CMD_PRINTJOB);
1422 		print.hdr.len = cpu_to_le16(sizeof (print) - sizeof(cmd));
1423 
1424 		print.id = ctx->jobid;
1425 		print.count = cpu_to_le16(job->copies);
1426 		print.columns = cpu_to_le16(job->jp.columns);
1427 		print.rows = cpu_to_le16(job->jp.rows);
1428 		print.image_avg = ctx->image_avg[2]; /* Cyan level */
1429 		print.method = cpu_to_le32(job->jp.method);
1430 		print.combo_wait = 0;
1431 
1432 		/* Brava21 header has a few quirks */
1433 		if(ctx->dev.type == P_SHINKO_S6145D) {
1434 			print.media = job->jp.media;
1435 			print.unk_1 = 0x01;
1436 		}
1437 
1438 		if ((ret = sinfonia_docmd(&ctx->dev,
1439 					  (uint8_t*)&print, sizeof(print),
1440 					  (uint8_t*)&sts, sizeof(sts),
1441 					  &num)) < 0) {
1442 			return ret;
1443 		}
1444 
1445 		if (sts.hdr.result != RESULT_SUCCESS) {
1446 			if (sts.hdr.error == ERROR_BUFFER_FULL) {
1447 				INFO("Printer Buffers full, retrying\n");
1448 				break;
1449 			} else if ((sts.hdr.status & 0xf0) == 0x30 || sts.hdr.status == 0x21) {
1450 				INFO("Printer busy (%s), retrying\n", sinfonia_status_str(sts.hdr.status));
1451 				break;
1452 			} else if (sts.hdr.status != ERROR_NONE)
1453 				goto printer_error;
1454 		}
1455 
1456 		INFO("Sending image data to printer\n");
1457 		// XXX we shouldn't send the lamination layer over if
1458 		// it's not needed.  hdr->oc_mode == PRINT_MODE_NO_OC
1459 		if ((ret = send_data(ctx->dev.dev, ctx->dev.endp_down,
1460 				     job->databuf, job->datalen)))
1461 			return CUPS_BACKEND_FAILED;
1462 
1463 		INFO("Waiting for printer to acknowledge completion\n");
1464 		sleep(1);
1465 		state = S_PRINTER_SENT_DATA;
1466 		break;
1467 	}
1468 	case S_PRINTER_SENT_DATA:
1469 		if (fast_return) {
1470 			INFO("Fast return mode enabled.\n");
1471 			state = S_FINISHED;
1472 		} else if (sts.hdr.status == STATUS_READY) {
1473 			state = S_FINISHED;
1474 		}
1475 		break;
1476 	default:
1477 		break;
1478 	};
1479 
1480 	if (state != S_FINISHED)
1481 		goto top;
1482 
1483 	INFO("Print complete\n");
1484 
1485 	return CUPS_BACKEND_OK;
1486 
1487 printer_error:
1488 	ERROR("Printer reported error: %#x (%s) status: %#x (%s) -> %#x.%#x (%s)\n",
1489 	      sts.hdr.error,
1490 	      sinfonia_error_str(sts.hdr.error),
1491 	      sts.hdr.status,
1492 	      sinfonia_status_str(sts.hdr.status),
1493 	      sts.hdr.printer_major, sts.hdr.printer_minor,
1494 	      error_codes(sts.hdr.printer_major, sts.hdr.printer_minor));
1495 	return CUPS_BACKEND_FAILED;
1496 }
1497 
shinkos6145_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)1498 static int shinkos6145_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
1499 {
1500 	struct sinfonia_cmd_hdr cmd;
1501 	struct sinfonia_getserial_resp resp;
1502 	int ret, num = 0;
1503 
1504 	struct sinfonia_usbdev sdev = {
1505 		.dev = dev,
1506 		.endp_up = endp_up,
1507 		.endp_down = endp_down,
1508 	};
1509 
1510 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSERIAL);
1511 	cmd.len = cpu_to_le16(0);
1512 
1513 	if ((ret = sinfonia_docmd(&sdev,
1514 				  (uint8_t*)&cmd, sizeof(cmd),
1515 				  (uint8_t*)&resp, sizeof(resp),
1516 				  &num)) < 0) {
1517 		return ret;
1518 	}
1519 
1520 	/* Copy and Null-terminate */
1521 	num = (buf_len > (int)sizeof(resp.data)) ? (int)sizeof(resp.data) : (buf_len - 1);
1522 	memcpy(buf, resp.data, num);
1523 	buf[num] = 0;
1524 
1525 	return CUPS_BACKEND_OK;
1526 }
1527 
shinkos6145_query_markers(void * vctx,struct marker ** markers,int * count)1528 static int shinkos6145_query_markers(void *vctx, struct marker **markers, int *count)
1529 {
1530 	struct shinkos6145_ctx *ctx = vctx;
1531 	struct sinfonia_cmd_hdr cmd;
1532 	struct s6145_status_resp sts;
1533 	int num;
1534 
1535 	/* Query Status */
1536 	cmd.cmd = cpu_to_le16(SINFONIA_CMD_GETSTATUS);
1537 	cmd.len = cpu_to_le16(0);
1538 
1539 	if (sinfonia_docmd(&ctx->dev,
1540 			   (uint8_t*)&cmd, sizeof(cmd),
1541 			   (uint8_t*)&sts, sizeof(sts),
1542 			   &num)) {
1543 		return CUPS_BACKEND_FAILED;
1544 	}
1545 
1546 	ctx->marker.levelnow = le32_to_cpu(sts.count_ribbon_left);
1547 
1548 	*markers = &ctx->marker;
1549 	*count = 1;
1550 
1551 	return CUPS_BACKEND_OK;
1552 }
1553 
1554 /* Exported */
1555 #define USB_VID_SHINKO        0x10CE
1556 #define USB_PID_SHINKO_S6145  0x0019
1557 #define USB_PID_SHINKO_S6145D 0x001E /* Aka CIAAT Brava 21 */
1558 #define USB_PID_SHINKO_S2245  0x0039
1559 #define USB_VID_KODAK         0x040a
1560 //#define USB_PID_KODAK_6900    0xXXXX /* Aka S2245-6A */
1561 #define USB_VID_HITI          0x0D16
1562 #define USB_PID_HITI_M610     0x0010
1563 
1564 static const char *shinkos6145_prefixes[] = {
1565 	"sinfonia-chcs6145", "ciaat-brava-21",
1566 	"sinfonia-chcs2245", "hiti-m610", // "kodak-6900",
1567 	// extras
1568 	"shinko-chcs6145",
1569 	// backwards-compatiblity
1570 	"shinkos6145", "brava21",
1571 	NULL
1572 };
1573 
1574 struct dyesub_backend shinkos6145_backend = {
1575 	.name = "Shinko/Sinfonia CHC-S6145/CS2/S2245/S3",
1576 	.version = "0.40" " (lib " LIBSINFONIA_VER ")",
1577 	.uri_prefixes = shinkos6145_prefixes,
1578 	.cmdline_usage = shinkos6145_cmdline,
1579 	.cmdline_arg = shinkos6145_cmdline_arg,
1580 	.init = shinkos6145_init,
1581 	.attach = shinkos6145_attach,
1582 	.teardown = shinkos6145_teardown,
1583 	.cleanup_job = sinfonia_cleanup_job,
1584 	.read_parse = shinkos6145_read_parse,
1585 	.main_loop = shinkos6145_main_loop,
1586 	.query_serno = shinkos6145_query_serno,
1587 	.query_markers = shinkos6145_query_markers,
1588 	.devices = {
1589 		{ USB_VID_SHINKO, USB_PID_SHINKO_S6145, P_SHINKO_S6145, NULL, "sinfonia-chcs6145"},
1590 		{ USB_VID_SHINKO, USB_PID_SHINKO_S6145D, P_SHINKO_S6145D, NULL, "ciaat-brava-21"},
1591 		{ USB_VID_SHINKO, USB_PID_SHINKO_S2245, P_SHINKO_S2245, NULL, "sinfonia-chcs2245"},
1592 //		{ USB_VID_KODAK, USB_PID_KODAK_6900, P_SHINKO_S2245, NULL, "sinfonia-chcs6145"},
1593 		{ USB_VID_HITI, USB_PID_HITI_M610, P_SHINKO_S2245, NULL, "hiti-m610"},
1594 		{ 0, 0, 0, NULL, NULL}
1595 	}
1596 };
1597 
1598 /* CHC-S6145 spool file format
1599 
1600   Spool file consists of an 116-byte header, followed by RGB-packed data,
1601   followed by a 4-byte footer.  Header appears to consist of a series of
1602   4-byte Little Endian words.
1603 
1604    10 00 00 00 MM MM 00 00  HH 00 00 00 01 00 00 00  MM == Model (ie 6145d), HH == 0x02 (5" media), 0x03 (6" media)
1605    64 00 00 00 00 00 00 00  TT 00 00 00 00 00 00 00  TT == 0x08 5x5, 0x03 5x7, 0x07 2x6, 0x00 4x6, 0x06 6x6/6x6+6x2/6x8
1606    UU 00 00 00 ZZ 00 00 00  XX 00 00 00 00 00 00 00  XX == 0x00 default, 0x02 glossy, 0x03 matte, ZZ == 0x00 default, 0x01 == std qual; UU == 0x00 normal, 0x04 2x6*2, 0x05 6x6+2x6
1607    00 00 00 00 WW WW 00 00  HH HH 00 00 NN 00 00 00  WW/HH Width, Height (LE), NN == Copies
1608    00 00 00 00 00 00 00 00  00 00 00 00 ce ff ff ff
1609    00 00 00 00 ce ff ff ff  QQ QQ 00 00 ce ff ff ff  QQ == DPI (300)
1610    00 00 00 00 ce ff ff ff  00 00 00 00 00 00 00 00
1611    00 00 00 00
1612 
1613    [[Packed RGB payload of WW*HH*3 bytes]]
1614 
1615    04 03 02 01  [[ footer ]]
1616 
1617 */
1618