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