1 /*
2 * Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version
3 *
4 * (c) 2013-2018 Solomon Peachy <pizza@shaftnet.org>
5 *
6 * The latest version of this program can be found at:
7 *
8 * http://git.shaftnet.org/cgit/selphy_print.git
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 *
23 * [http://www.gnu.org/licenses/gpl-2.0.html]
24 *
25 * SPDX-License-Identifier: GPL-2.0+
26 *
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <signal.h>
38
39 /* For Integration into gutenprint */
40 #if defined(HAVE_CONFIG_H)
41 #include <config.h>
42 #endif
43
44 #if defined(USE_DLOPEN)
45 #define WITH_DYNAMIC
46 #include <dlfcn.h>
47 #define DL_INIT() do {} while(0)
48 #define DL_OPEN(__x) dlopen(__x, RTLD_NOW)
49 #define DL_SYM(__x, __y) dlsym(__x, __y)
50 #define DL_CLOSE(__x) dlclose(__x)
51 #define DL_EXIT() do {} while(0)
52 #elif defined(USE_LTDL)
53 #define WITH_DYNAMIC
54 #include <ltdl.h>
55 #define DL_INIT() lt_dlinit()
56 #define DL_OPEN(__x) lt_dlopen(__x)
57 #define DL_SYM(__x, __y) lt_dlsym(__x, __y)
58 #define DL_CLOSE(__x) do {} while(0)
59 #define DL_EXIT() lt_dlexit()
60 #else
61 #define DL_INIT() do {} while(0)
62 #define DL_CLOSE(__x) do {} while(0)
63 #define DL_EXIT() do {} while(0)
64 #warning "No dynamic loading support!"
65 #endif
66
67 #define BACKEND mitsu70x_backend
68
69 #include "backend_common.h"
70
71 // #include "lib70x/libMitsuD70ImageReProcess.h"
72
73 #ifndef LUT_LEN
74 #define COLORCONV_RGB 0
75 #define COLORCONV_BGR 1
76
77 #define LUT_LEN 14739
78 struct BandImage {
79 void *imgbuf;
80 int32_t bytes_per_row;
81 uint16_t origin_cols;
82 uint16_t origin_rows;
83 uint16_t cols;
84 uint16_t rows;
85 };
86 #endif
87
88 #define REQUIRED_LIB_APIVERSION 4
89
90 /* Image processing library function prototypes */
91 #define LIB_NAME_RE "libMitsuD70ImageReProcess.so" // Reimplemented library
92
93 typedef int (*lib70x_getapiversionFN)(void);
94 typedef int (*Get3DColorTableFN)(uint8_t *buf, const char *filename);
95 typedef struct CColorConv3D *(*Load3DColorTableFN)(const uint8_t *ptr);
96 typedef void (*Destroy3DColorTableFN)(struct CColorConv3D *this);
97 typedef void (*DoColorConvFN)(struct CColorConv3D *this, uint8_t *data, uint16_t cols, uint16_t rows, uint32_t bytes_per_row, int rgb_bgr);
98 typedef struct CPCData *(*get_CPCDataFN)(const char *filename);
99 typedef void (*destroy_CPCDataFN)(struct CPCData *data);
100 typedef int (*do_image_effectFN)(struct CPCData *cpc, struct CPCData *ecpc, struct BandImage *input, struct BandImage *output, int sharpen, int reverse, uint8_t rew[2]);
101 typedef int (*send_image_dataFN)(struct BandImage *out, void *context,
102 int (*callback_fn)(void *context, void *buffer, uint32_t len));
103
104 #ifndef CORRTABLE_PATH
105 #ifdef PACKAGE_DATA_DIR
106 #define CORRTABLE_PATH PACKAGE_DATA_DIR "/backend_data"
107 #else
108 #error "Must define CORRTABLE_PATH or PACKAGE_DATA_DIR!"
109 #endif
110 #endif
111
112 #define USB_VID_MITSU 0x06D3
113 #define USB_PID_MITSU_D70X 0x3B30
114 #define USB_PID_MITSU_K60 0x3B31
115 #define USB_PID_MITSU_D80 0x3B36
116 #define USB_VID_KODAK 0x040a
117 #define USB_PID_KODAK305 0x404f
118 #define USB_VID_FUJIFILM 0x04cb
119 #define USB_PID_FUJI_ASK300 0x5006
120
121 /* Width of the laminate data file */
122 #define LAMINATE_STRIDE 1864
123
124 /* Max size of data chunk sent over */
125 #define CHUNK_LEN (256*1024)
126
127 /* Private data structure */
128 struct mitsu70x_printjob {
129 uint8_t *databuf;
130 int datalen;
131
132 uint8_t *spoolbuf;
133 int spoolbuflen;
134
135 uint16_t rows;
136 uint16_t cols;
137 uint32_t planelen;
138 uint32_t matte;
139 int raw_format;
140 int copies;
141
142 int decks_exact[2]; /* Media is exact match */
143 int decks_ok[2]; /* Media can be used */
144
145 /* These are used only for the image processing */
146 int sharpen; /* ie mhdr.sharpen - 1 */
147 int reverse;
148
149 char *laminatefname;
150 char *lutfname;
151 char *cpcfname;
152 char *ecpcfname;
153 };
154
155 struct mitsu70x_ctx {
156 struct libusb_device_handle *dev;
157 uint8_t endp_up;
158 uint8_t endp_down;
159 int type;
160
161 uint16_t jobid;
162
163 struct marker marker[2];
164 uint8_t medias[2];
165
166 uint16_t last_l;
167 uint16_t last_u;
168 int num_decks;
169
170 void *dl_handle;
171 lib70x_getapiversionFN GetAPIVersion;
172 Get3DColorTableFN Get3DColorTable;
173 Load3DColorTableFN Load3DColorTable;
174 Destroy3DColorTableFN Destroy3DColorTable;
175 DoColorConvFN DoColorConv;
176 get_CPCDataFN GetCPCData;
177 destroy_CPCDataFN DestroyCPCData;
178 do_image_effectFN DoImageEffect60;
179 do_image_effectFN DoImageEffect70;
180 do_image_effectFN DoImageEffect80;
181 do_image_effectFN DoImageEffect;
182 send_image_dataFN SendImageData;
183
184 struct CColorConv3D *lut;
185 struct CPCData *cpcdata;
186 struct CPCData *ecpcdata;
187
188 char *last_cpcfname;
189 char *last_ecpcfname;
190
191 struct BandImage output;
192 };
193
194 /* Printer data structures */
195 struct mitsu70x_jobstatus {
196 uint8_t hdr[4]; /* E4 56 31 30 */
197 uint16_t jobid; /* BE */
198 uint16_t mecha_no; /* BE */
199 uint8_t job_status[4];
200 uint8_t memory;
201 uint8_t power;
202 uint8_t mecha_status[2];
203 uint8_t temperature;
204 uint8_t error_status[3];
205 uint8_t mecha_status_up[2];
206 uint8_t temperature_up;
207 uint8_t error_status_up[3];
208 } __attribute__((packed));
209
210 struct mitsu70x_job {
211 uint16_t id; /* BE */
212 uint8_t status[4];
213 } __attribute__((packed));
214
215 #define NUM_JOBS 170
216
217 struct mitsu70x_jobs {
218 uint8_t hdr[4]; /* E4 56 31 31 */
219 struct mitsu70x_job jobs[NUM_JOBS];
220 } __attribute__((packed));
221
222 #define TEMPERATURE_NORMAL 0x00
223 #define TEMPERATURE_PREHEAT 0x40
224 #define TEMPERATURE_COOLING 0x80
225
226 #define MECHA_STATUS_INIT 0x80
227 #define MECHA_STATUS_FEED 0x50
228 #define MECHA_STATUS_LOAD 0x40
229 #define MECHA_STATUS_LOAD2 0x30
230 #define MECHA_STATUS_PRINT 0x20
231 #define MECHA_STATUS_IDLE 0x00
232
233 #define JOB_STATUS0_NONE 0x00
234 #define JOB_STATUS0_DATA 0x10
235 #define JOB_STATUS0_QUEUE 0x20
236 #define JOB_STATUS0_PRINT 0x50
237 #define JOB_STATUS0_ASSIGN 0x70 // XXX undefined.
238 #define JOB_STATUS0_END 0x80
239
240 #define JOB_STATUS1_PRINT_MEDIALOAD 0x10
241 #define JOB_STATUS1_PRINT_PRE_Y 0x20
242 #define JOB_STATUS1_PRINT_Y 0x30
243 #define JOB_STATUS1_PRINT_PRE_M 0x40
244 #define JOB_STATUS1_PRINT_M 0x50
245 #define JOB_STATUS1_PRINT_PRE_C 0x60
246 #define JOB_STATUS1_PRINT_C 0x70
247 #define JOB_STATUS1_PRINT_PRE_OC 0x80
248 #define JOB_STATUS1_PRINT_OC 0x90
249 #define JOB_STATUS1_PRINT_EJECT 0xA0
250
251 #define JOB_STATUS1_END_OK 0x00
252 #define JOB_STATUS1_END_MECHA 0x10 // 0x10...0x7f
253 #define JOB_STATUS1_END_HEADER 0x80
254 #define JOB_STATUS1_END_PRINT 0x90
255 #define JOB_STATUS1_END_INTERRUPT 0xA0
256
257 #define JOB_STATUS2_END_HEADER_ERROR 0x00
258 #define JOB_STATUS2_END_HEADER_MEMORY 0x10
259 #define JOB_STATUS2_END_PRINT_MEDIA 0x00
260 #define JOB_STATUS2_END_PRINT_PREVERR 0x10
261 #define JOB_STATUS2_END_INT_TIMEOUT 0x00
262 #define JOB_STATUS2_END_INT_CANCEL 0x10
263 #define JOB_STATUS2_END_INT_DISCON 0x20
264
265 /* Error codes */
266 #define ERROR_STATUS0_NOSTRIPBIN 0x01
267 #define ERROR_STATUS0_NORIBBON 0x02
268 #define ERROR_STATUS0_NOPAPER 0x03
269 #define ERROR_STATUS0_MEDIAMISMATCH 0x04
270 #define ERROR_STATUS0_RIBBONCNTEND 0x05
271 #define ERROR_STATUS0_BADRIBBON 0x06
272 #define ERROR_STATUS0_BADJOBPARAM 0x07
273 #define ERROR_STATUS0_PAPEREND 0x08
274 #define ERROR_STATUS0_RIBBONEND 0x09
275 #define ERROR_STATUS0_DOOROPEN_IDLE 0x0A
276 #define ERROR_STATUS0_DOOROPEN_PRNT 0x0B
277 #define ERROR_STATUS0_POWEROFF 0x0C // Powered off during printing..?
278 #define ERROR_STATUS0_NOMCOP 0x0D
279 #define ERROR_STATUS0_RIBBONSKIP1 0x0E
280 #define ERROR_STATUS0_RIBBONSKIP2 0x0F
281 #define ERROR_STATUS0_RIBBONJAM 0x10
282 #define ERROR_STATUS0_RIBBON_OTHER 0x11 // 0x11->0x1F
283 #define ERROR_STATUS0_PAPER_JAM 0x20 // 0x20->0x2F
284 #define ERROR_STATUS0_MECHANICAL 0x30 // 0x30->0x39
285 #define ERROR_STATUS0_RFID 0x3A
286 #define ERROR_STATUS0_FLASH 0x3B
287 #define ERROR_STATUS0_EEPROM 0x3C
288 #define ERROR_STATUS0_PREHEAT 0x3D
289 #define ERROR_STATUS0_MDASTATE 0x3E
290 #define ERROR_STATUS0_PSUFANLOCKED 0x3F
291 #define ERROR_STATUS0_OTHERS 0x40 // 0x40..?
292
293 /* Error classifications */
294 #define ERROR_STATUS1_PAPER 0x01
295 #define ERROR_STATUS1_RIBBON 0x02
296 #define ERROR_STATUS1_SETTING 0x03
297 #define ERROR_STATUS1_OPEN 0x05
298 #define ERROR_STATUS1_NOSTRIPBIN 0x06
299 #define ERROR_STATUS1_PAPERJAM 0x07
300 #define ERROR_STATUS1_RIBBONSYS 0x08
301 #define ERROR_STATUS1_MECHANICAL 0x09
302 #define ERROR_STATUS1_ELECTRICAL 0x0A
303 #define ERROR_STATUS1_FIRMWARE 0x0E
304 #define ERROR_STATUS1_OTHER 0x0F
305
306 /* Error recovery conditions */
307 #define ERROR_STATUS2_AUTO 0x00
308 #define ERROR_STATUS2_RELOAD_PAPER 0x01
309 #define ERROR_STATUS2_RELOAD_RIBBON 0x02
310 #define ERROR_STATUS2_CHANGE_BOTH 0x03
311 #define ERROR_STATUS2_CHANGE_ONE 0x04
312 #define ERROR_STATUS2_CLOSEUNIT 0x05
313 #define ERROR_STATUS2_ATTACHSTRIPBIN 0x06
314 #define ERROR_STATUS2_CLEARJAM 0x07
315 #define ERROR_STATUS2_CHECKRIBBON 0x08
316 #define ERROR_STATUS2_OPENCLOSEUNIT 0x0A
317 #define ERROR_STATUS2_POWEROFF 0x0F
318
319 struct mitsu70x_status_deck {
320 uint8_t mecha_status[2];
321 uint8_t temperature; /* D70/D80 family only, K60 no? */
322 uint8_t error_status[3];
323 uint8_t rsvd_a[10]; /* K60 [1] == temperature? All: [3:6] == some counter in BCD. K60 [9] == ?? */
324 uint8_t media_brand;
325 uint8_t media_type;
326 uint8_t rsvd_b[2];
327 int16_t capacity; /* media capacity */
328 int16_t remain; /* media remaining */
329 uint8_t rsvd_c[2];
330 uint8_t lifetime_prints[4]; /* lifetime prints on deck + 10, in BCD! */
331 uint8_t rsvd_d[2]; // Unknown
332 uint16_t rsvd_e[16]; /* all 80 00 */
333 } __attribute__((packed));
334
335 struct mitsu70x_status_ver {
336 char ver[6];
337 uint16_t checksum; /* Presumably BE */
338 } __attribute__((packed));
339
340 struct mitsu70x_printerstatus_resp {
341 uint8_t hdr[4]; /* E4 56 32 30 */
342 uint8_t memory;
343 uint8_t power;
344 uint8_t unk[20];
345 uint8_t sleeptime; /* In minutes, 0-60 */
346 uint8_t iserial; /* 0x00 for Enabled, 0x80 for Disabled */
347 uint8_t unk_b[5]; // [4] == 0x44 on D70x, 0x02 on D80
348 uint8_t dual_deck; /* 0x80 for dual-deck D707 */
349 uint8_t unk_c[6]; // [3] == 0x5f on D70x, 0x01 on D80. [5] == 0xbd on D70x, 0x87 on D80
350 int16_t model[6]; /* LE, UTF-16 */
351 int16_t serno[6]; /* LE, UTF-16 */
352 struct mitsu70x_status_ver vers[7]; // components are 'MLRTF'
353 uint8_t null[2];
354 uint8_t user_serno[6]; /* XXX Supposedly, don't know how to set it */
355 struct mitsu70x_status_deck lower;
356 struct mitsu70x_status_deck upper;
357 } __attribute__((packed));
358
359 struct mitsu70x_memorystatus_resp {
360 uint8_t hdr[3]; /* E4 56 33 */
361 uint8_t memory;
362 uint8_t size;
363 uint8_t rsvd;
364 } __attribute__((packed));
365
366 // XXX also seen commands 0x67, 0x72, 0x54, 0x6e
367
368 struct mitsu70x_hdr {
369 uint8_t hdr[4]; /* 1b 5a 54 XX */ // XXX also, seen 1b 5a 43!
370 uint16_t jobid;
371 uint8_t rewind[2]; /* K60/EK305/D80 only */
372 uint8_t zero0[8];
373
374 uint16_t cols;
375 uint16_t rows;
376 uint16_t lamcols;
377 uint16_t lamrows;
378 uint8_t speed;
379 uint8_t zero1[7];
380
381 uint8_t deck; /* 0 = default, 1 = lower, 2 = upper -- Non-D70/D707 is always '1' */
382 uint8_t zero2[7];
383 uint8_t laminate; /* 00 == on, 01 == off */
384 uint8_t laminate_mode; /* 00 == glossy, 02 == matte */
385 uint8_t zero3[6];
386
387 uint8_t multicut;
388 uint8_t zero4[12]; /* NOTE: everything past this point is an extension */
389 uint8_t sharpen; /* 0-9. 5 is "normal", 0 is "off" */
390 uint8_t mode; /* 0 for cooked YMC planar, 1 for packed BGR */
391 uint8_t use_lut; /* in BGR mode, 0 disables, 1 enables */
392 uint8_t reversed; /* 1 tells the backend the row data is correct */
393 uint8_t pad[447];
394 } __attribute__((packed));
395
396 static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp);
397 static int mitsu70x_main_loop(void *vctx, const void *vjob);
398
399 /* Error dumps, etc */
400
mitsu70x_temperatures(uint8_t temp)401 const char *mitsu70x_temperatures(uint8_t temp)
402 {
403 switch(temp) {
404 case TEMPERATURE_NORMAL:
405 return "Normal";
406 case TEMPERATURE_PREHEAT:
407 return "Warming Up";
408 case TEMPERATURE_COOLING:
409 return "Cooling Down";
410 default:
411 break;
412 }
413 return "Unknown Temperature Status";
414 }
415
mitsu70x_mechastatus(uint8_t * sts)416 static const char *mitsu70x_mechastatus(uint8_t *sts)
417 {
418 switch(sts[0]) {
419 case MECHA_STATUS_INIT:
420 return "Initializing";
421 case MECHA_STATUS_FEED:
422 return "Paper Feeding/Cutting";
423 case MECHA_STATUS_LOAD:
424 case MECHA_STATUS_LOAD2:
425 return "Media Loading";
426 case MECHA_STATUS_PRINT:
427 return "Printing";
428 case MECHA_STATUS_IDLE:
429 return "Idle";
430 default:
431 break;
432 }
433 return "Unknown Mechanical Status";
434 }
435
mitsu70x_jobstatuses(uint8_t * sts)436 static const char *mitsu70x_jobstatuses(uint8_t *sts)
437 {
438 switch(sts[0]) {
439 case JOB_STATUS0_NONE:
440 return "No Job";
441 case JOB_STATUS0_DATA:
442 return "Data transfer";
443 case JOB_STATUS0_QUEUE:
444 return "Queued for printing";
445 case JOB_STATUS0_PRINT:
446 switch(sts[1]) {
447 case JOB_STATUS1_PRINT_MEDIALOAD:
448 return "Media loading";
449 case JOB_STATUS1_PRINT_PRE_Y:
450 return "Waiting to print yellow plane";
451 case JOB_STATUS1_PRINT_Y:
452 return "Printing yellow plane";
453 case JOB_STATUS1_PRINT_PRE_M:
454 return "Waiting to print magenta plane";
455 case JOB_STATUS1_PRINT_M:
456 return "Printing magenta plane";
457 case JOB_STATUS1_PRINT_PRE_C:
458 return "Waiting to print cyan plane";
459 case JOB_STATUS1_PRINT_C:
460 return "Printing cyan plane";
461 case JOB_STATUS1_PRINT_PRE_OC:
462 return "Waiting to laminate page";
463 case JOB_STATUS1_PRINT_OC:
464 return "Laminating page";
465 case JOB_STATUS1_PRINT_EJECT:
466 return "Ejecting page";
467 default:
468 return "Unknown 'Print' status1";
469 }
470 break;
471 case JOB_STATUS0_ASSIGN:
472 return "Unknown 'Assignment' status1";
473 case JOB_STATUS0_END:
474 switch(sts[1]) {
475 case JOB_STATUS1_END_OK:
476 return "Normal End";
477 case JOB_STATUS1_END_HEADER:
478 switch(sts[2]) {
479 case JOB_STATUS2_END_HEADER_ERROR:
480 return "Incorrect Header data (bad print size?)";
481 case JOB_STATUS2_END_HEADER_MEMORY:
482 return "Insufficient printer memory";
483 default:
484 return "Unknown 'End Header' status2";
485 }
486 break;
487 case JOB_STATUS1_END_PRINT:
488 switch(sts[2]) {
489 case JOB_STATUS2_END_PRINT_MEDIA:
490 return "Incorrect mediasize";
491 case JOB_STATUS2_END_PRINT_PREVERR:
492 return "Previous job terminated abnormally";
493 default:
494 return "Unknown 'End Print' status2";
495 }
496 break;
497 case JOB_STATUS1_END_INTERRUPT:
498 switch(sts[2]) {
499 case JOB_STATUS2_END_INT_TIMEOUT:
500 return "Timeout";
501 case JOB_STATUS2_END_INT_CANCEL:
502 return "Job cancelled";
503 case JOB_STATUS2_END_INT_DISCON:
504 return "Printer disconnected";
505 default:
506 return "Unknown 'End Print' status2";
507 }
508 break;
509 default:
510 if (sts[1] >= 0x10 && sts[1] <= 0x7f)
511 return "Mechanical Error";
512 else
513 return "Unknown 'End' status1";
514 }
515 break;
516 default:
517 break;
518 }
519
520 return "Unknown status0";
521 }
522
mitsu70x_errorclass(uint8_t * err)523 static const char *mitsu70x_errorclass(uint8_t *err)
524 {
525 switch(err[1]) {
526 case ERROR_STATUS1_PAPER:
527 return "Paper";
528 case ERROR_STATUS1_RIBBON:
529 return "Ribbon";
530 case ERROR_STATUS1_SETTING:
531 return "Job settings";
532 case ERROR_STATUS1_OPEN:
533 return "Cover open";
534 case ERROR_STATUS1_NOSTRIPBIN:
535 return "No cut bin";
536 case ERROR_STATUS1_PAPERJAM:
537 return "Paper jam";
538 case ERROR_STATUS1_RIBBONSYS:
539 return "Ribbon system";
540 case ERROR_STATUS1_MECHANICAL:
541 return "Mechanical";
542 case ERROR_STATUS1_ELECTRICAL:
543 return "Electrical";
544 case ERROR_STATUS1_FIRMWARE:
545 return "Firmware";
546 case ERROR_STATUS1_OTHER:
547 return "Other";
548 default:
549 break;
550 }
551 return "Unknown error class";
552 }
553
mitsu70x_errorrecovery(uint8_t * err)554 static const char *mitsu70x_errorrecovery(uint8_t *err)
555 {
556 switch(err[1]) {
557 case ERROR_STATUS2_AUTO:
558 return "Automatic recovery";
559 case ERROR_STATUS2_RELOAD_PAPER:
560 return "Reload or change paper";
561 case ERROR_STATUS2_RELOAD_RIBBON:
562 return "Reload or change ribbon";
563 case ERROR_STATUS2_CHANGE_BOTH:
564 return "Change paper and ribbon";
565 case ERROR_STATUS2_CHANGE_ONE:
566 return "Change paper or ribbon";
567 case ERROR_STATUS2_CLOSEUNIT:
568 return "Close printer";
569 case ERROR_STATUS2_ATTACHSTRIPBIN:
570 return "Attach Strip Bin";
571 case ERROR_STATUS2_CLEARJAM:
572 return "Remove and reload paper";
573 case ERROR_STATUS2_CHECKRIBBON:
574 return "Check ribbon and reload paper";
575 case ERROR_STATUS2_OPENCLOSEUNIT:
576 return "Open then close printer";
577 case ERROR_STATUS2_POWEROFF:
578 return "Power-cycle printer";
579 default:
580 break;
581 }
582 return "Unknown recovery";
583 }
584
mitsu70x_errors(uint8_t * err)585 static const char *mitsu70x_errors(uint8_t *err)
586 {
587 switch(err[0]) {
588 case ERROR_STATUS0_NOSTRIPBIN:
589 return "Strip bin not attached";
590 case ERROR_STATUS0_NORIBBON:
591 return "No ribbon detected";
592 case ERROR_STATUS0_NOPAPER:
593 return "No paper loaded";
594 case ERROR_STATUS0_MEDIAMISMATCH:
595 return "Ribbon/Paper mismatch";
596 case ERROR_STATUS0_RIBBONCNTEND:
597 return "Ribbon count end";
598 case ERROR_STATUS0_BADRIBBON:
599 return "Illegal Ribbon";
600 case ERROR_STATUS0_BADJOBPARAM:
601 return "Job does not match loaded media";
602 case ERROR_STATUS0_PAPEREND:
603 return "End of paper detected";
604 case ERROR_STATUS0_RIBBONEND:
605 return "End of ribbon detected";
606 case ERROR_STATUS0_DOOROPEN_IDLE:
607 case ERROR_STATUS0_DOOROPEN_PRNT:
608 return "Printer door open";
609 case ERROR_STATUS0_POWEROFF:
610 return "Printer powered off"; // nonsense..
611 case ERROR_STATUS0_RIBBONSKIP1:
612 case ERROR_STATUS0_RIBBONSKIP2:
613 return "Ribbon skipped";
614 case ERROR_STATUS0_RIBBONJAM:
615 return "Ribbon stuck to paper";
616 case ERROR_STATUS0_RFID:
617 return "RFID read error";
618 case ERROR_STATUS0_FLASH:
619 return "FLASH read error";
620 case ERROR_STATUS0_EEPROM:
621 return "EEPROM read error";
622 case ERROR_STATUS0_PREHEAT:
623 return "Preheating unit time out";
624 case ERROR_STATUS0_MDASTATE:
625 return "Unknown MDA state";
626 case ERROR_STATUS0_PSUFANLOCKED:
627 return "Power supply fan locked up";
628 default:
629 break;
630 }
631
632 if (err[0] >= ERROR_STATUS0_RIBBON_OTHER &&
633 err[0] < ERROR_STATUS0_PAPER_JAM) {
634 return "Unknown ribbon error";
635 // XXX use err[1]/err[2] codes?
636 }
637 if (err[0] >= ERROR_STATUS0_PAPER_JAM &&
638 err[0] < ERROR_STATUS0_MECHANICAL) {
639 return "Paper jam";
640 // XXX use err[1]/err[2] codes?
641 }
642 if (err[0] >= ERROR_STATUS0_MECHANICAL &&
643 err[0] < ERROR_STATUS0_RFID) {
644 return "Unknown mechanical error";
645 // XXX use err[1]/err[2] codes?
646 }
647
648 return "Unknown error";
649 }
650
mitsu70x_media_types(uint8_t brand,uint8_t type)651 const char *mitsu70x_media_types(uint8_t brand, uint8_t type)
652 {
653 if (brand == 0xff && type == 0x01)
654 return "CK-D735 (3.5x5)";
655 else if (brand == 0xff && type == 0x02)
656 return "CK-D746 (4x6)";
657 else if (brand == 0xff && type == 0x04)
658 return "CK-D757 (5x7)";
659 else if (brand == 0xff && type == 0x05)
660 return "CK-D769 (6x9)";
661 else if (brand == 0xff && type == 0x0f)
662 return "CK-D768/CK-D868 (6x8)";
663 else if (brand == 0x6c && type == 0x84)
664 return "Kodak 5R (5x7)";
665 else if (brand == 0x6c && type == 0x8f)
666 return "Kodak 6R (6x8)";
667 else if (brand == 0x61 && type == 0x84)
668 return "CK-K57R (5x7)";
669 else if (brand == 0x61 && type == 0x8f)
670 return "CK-K76R (6x8)";
671 else if (brand == 0x7a && type == 0x01)
672 return "RL-CF900 (3.5x5)";
673 else if (brand == 0x7a && type == 0x02)
674 return "RK-CF800/4R (4x6)";
675 else if (brand == 0x7a && type == 0x04)
676 return "R2L-CF460/5R (5x7)";
677 else if (brand == 0x7a && type == 0x0f)
678 return "R68-CF400/6R (6x8)";
679 else
680 return "Unknown";
681
682 // Also CK-D715, CK-D718, CK-D720, CK-D723 (4x6,5x8,6x8,6x9) for D70-S model
683 // CK-D746-U for D70-U model
684 // CK-D820 (6x8) for D80-S model
685 // D90 can use _all_ of these types except for the -U!
686
687 }
688
689 #define CMDBUF_LEN 512
690 #define READBACK_LEN 256
691
mitsu70x_init(void)692 static void *mitsu70x_init(void)
693 {
694 struct mitsu70x_ctx *ctx = malloc(sizeof(struct mitsu70x_ctx));
695 if (!ctx) {
696 ERROR("Memory Allocation Failure!\n");
697 return NULL;
698 }
699 memset(ctx, 0, sizeof(struct mitsu70x_ctx));
700
701 DL_INIT();
702
703 return ctx;
704 }
705
mitsu70x_attach(void * vctx,struct libusb_device_handle * dev,int type,uint8_t endp_up,uint8_t endp_down,uint8_t jobid)706 static int mitsu70x_attach(void *vctx, struct libusb_device_handle *dev, int type,
707 uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
708 {
709 struct mitsu70x_ctx *ctx = vctx;
710
711 ctx->jobid = jobid;
712 if (!ctx->jobid)
713 jobid++;
714
715 ctx->dev = dev;
716 ctx->endp_up = endp_up;
717 ctx->endp_down = endp_down;
718 ctx->type = type;
719
720 ctx->last_l = ctx->last_u = 65535;
721
722 /* Attempt to open the library */
723 #if defined(WITH_DYNAMIC)
724 DEBUG("Attempting to load image processing library\n");
725 ctx->dl_handle = DL_OPEN(LIB_NAME_RE);
726 if (!ctx->dl_handle)
727 WARNING("Image processing library not found, using internal fallback code\n");
728 if (ctx->dl_handle) {
729 ctx->GetAPIVersion = DL_SYM(ctx->dl_handle, "lib70x_getapiversion");
730 if (!ctx->GetAPIVersion) {
731 ERROR("Problem resolving API Version symbol in imaging processing library, too old or not installed?\n");
732 DL_CLOSE(ctx->dl_handle);
733 ctx->dl_handle = NULL;
734 return CUPS_BACKEND_FAILED;
735 }
736 if (ctx->GetAPIVersion() != REQUIRED_LIB_APIVERSION) {
737 ERROR("Image processing library API version mismatch!\n");
738 DL_CLOSE(ctx->dl_handle);
739 ctx->dl_handle = NULL;
740 return CUPS_BACKEND_FAILED;
741 }
742
743 ctx->Get3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Get3DColorTable");
744 ctx->Load3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Load3DColorTable");
745 ctx->Destroy3DColorTable = DL_SYM(ctx->dl_handle, "CColorConv3D_Destroy3DColorTable");
746 ctx->DoColorConv = DL_SYM(ctx->dl_handle, "CColorConv3D_DoColorConv");
747 ctx->GetCPCData = DL_SYM(ctx->dl_handle, "get_CPCData");
748 ctx->DestroyCPCData = DL_SYM(ctx->dl_handle, "destroy_CPCData");
749 ctx->DoImageEffect60 = DL_SYM(ctx->dl_handle, "do_image_effect60");
750 ctx->DoImageEffect70 = DL_SYM(ctx->dl_handle, "do_image_effect70");
751 ctx->DoImageEffect80 = DL_SYM(ctx->dl_handle, "do_image_effect80");
752 ctx->SendImageData = DL_SYM(ctx->dl_handle, "send_image_data");
753 if (!ctx->Get3DColorTable || !ctx->Load3DColorTable ||
754 !ctx->Destroy3DColorTable || !ctx->DoColorConv ||
755 !ctx->GetCPCData || !ctx->DestroyCPCData ||
756 !ctx->DoImageEffect60 || !ctx->DoImageEffect70 ||
757 !ctx->DoImageEffect80 || !ctx->SendImageData) {
758 ERROR("Problem resolving symbols in imaging processing library\n");
759 DL_CLOSE(ctx->dl_handle);
760 ctx->dl_handle = NULL;
761 return CUPS_BACKEND_FAILED;
762 } else {
763 DEBUG("Image processing library successfully loaded\n");
764 }
765 }
766
767 switch (ctx->type) {
768 case P_MITSU_D80:
769 ctx->DoImageEffect = ctx->DoImageEffect80;
770 break;
771 case P_MITSU_K60:
772 case P_KODAK_305:
773 ctx->DoImageEffect = ctx->DoImageEffect60;
774 break;
775 default:
776 ctx->DoImageEffect = ctx->DoImageEffect70;
777 break;
778 }
779 #else
780 WARNING("Dynamic library support not enabled, using internal fallback code\n");
781 #endif
782
783 struct mitsu70x_printerstatus_resp resp;
784 int ret;
785
786 if (test_mode < TEST_MODE_NOATTACH) {
787 ret = mitsu70x_get_printerstatus(ctx, &resp);
788 if (ret) {
789 ERROR("Unable to get printer status! (%d)\n", ret);
790 return CUPS_BACKEND_FAILED;
791 }
792 } else {
793 int media_code = 0xf;
794 if (getenv("MEDIA_CODE"))
795 media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
796
797 resp.upper.mecha_status[0] = MECHA_STATUS_INIT;
798 resp.lower.mecha_status[0] = MECHA_STATUS_INIT;
799 resp.upper.capacity = cpu_to_be16(230);
800 resp.lower.capacity = cpu_to_be16(230);
801 resp.upper.remain = cpu_to_be16(200);
802 resp.lower.remain = cpu_to_be16(200);
803 resp.upper.media_brand = 0xff;
804 resp.lower.media_brand = 0xff;
805 resp.upper.media_type = media_code;
806 resp.lower.media_type = media_code;
807 resp.dual_deck = 0x80; /* Make it a dual deck */
808 resp.vers[0].ver[0] = 0;
809 }
810
811 /* Figure out if we're a D707 with two decks */
812 if (ctx->type == P_MITSU_D70X &&
813 resp.dual_deck == 0x80)
814 ctx->num_decks = 2;
815 else
816 ctx->num_decks = 1;
817
818 /* Set up markers */
819 ctx->marker[0].color = "#00FFFF#FF00FF#FFFF00";
820 ctx->marker[0].name = mitsu70x_media_types(resp.lower.media_brand, resp.lower.media_type);
821 ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
822 ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
823 ctx->medias[0] = resp.lower.media_type & 0xf;
824
825 if (ctx->num_decks == 2) {
826 ctx->marker[1].color = "#00FFFF#FF00FF#FFFF00";
827 ctx->marker[1].name = mitsu70x_media_types(resp.upper.media_brand, resp.upper.media_type);
828 ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
829 ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
830 ctx->medias[1] = resp.upper.media_type & 0xf;
831 }
832
833 /* FW sanity checking */
834 if (ctx->type == P_KODAK_305) {
835 /* Known versions:
836 v1.02: M 316E81 1433 (Add Ultrafine and matte support)
837 v1.04: M 316F83 2878 (Add 2x6 strip and support new "Triton" media)
838 v3.01: M 443A12 8908 (add 5" media support)
839 */
840 if (strncmp(resp.vers[0].ver, "443A12", 6) < 0)
841 WARNING("Printer FW out of date. Highly recommend upgrading EK305 to v3.01 or newer!\n");
842 } else if (ctx->type == P_MITSU_K60) {
843 /* Known versions:
844 v1.05: M 316M31 148C (Add HG media support)
845 */
846 if (strncmp(resp.vers[0].ver, "316M31", 6) < 0)
847 WARNING("Printer FW out of date. Highly recommend upgrading K60 to v1.05 or newer!\n");
848 } else if (ctx->type == P_MITSU_D70X) {
849 /* Known versions:
850 v1.10: M 316V11 064D (Add ultrafine mode, 6x6 support, 2x6 strip, and more?)
851 v1.12: M 316W11 9FC3 (??)
852 v1.13: (??)
853 */
854 if (strncmp(resp.vers[0].ver, "316W11", 6) < 0)
855 WARNING("Printer FW out of date. Highly recommend upgrading D70/D707 to v1.12 or newer!\n");
856 } else if (ctx->type == P_FUJI_ASK300) {
857 /* Known versions:
858 v?.??: M 316A21 7998 (ancient. no matte or ultrafine)
859 v?.??: M 316H21 F8EB
860 v4.20a: M 316J21 4431 (Add 2x6 strip support)
861 */
862 if (strncmp(resp.vers[0].ver, "316J21", 6) < 0)
863 WARNING("Printer FW out of date. Highly recommend upgrading ASK300 to v4.20a or newer!\n");
864 }
865
866 return CUPS_BACKEND_OK;
867 }
868
mitsu70x_cleanup_job(const void * vjob)869 static void mitsu70x_cleanup_job(const void *vjob) {
870 const struct mitsu70x_printjob *job = vjob;
871
872 if (job->databuf)
873 free(job->databuf);
874 if (job->spoolbuf)
875 free(job->spoolbuf);
876
877 free((void*)job);
878 }
879
mitsu70x_teardown(void * vctx)880 static void mitsu70x_teardown(void *vctx) {
881 struct mitsu70x_ctx *ctx = vctx;
882
883 if (!ctx)
884 return;
885
886 if (ctx->dl_handle) {
887 if (ctx->cpcdata)
888 ctx->DestroyCPCData(ctx->cpcdata);
889 if (ctx->ecpcdata)
890 ctx->DestroyCPCData(ctx->ecpcdata);
891 if (ctx->lut)
892 ctx->Destroy3DColorTable(ctx->lut);
893 DL_CLOSE(ctx->dl_handle);
894 }
895
896 DL_EXIT();
897
898 free(ctx);
899 }
900
901 #define JOB_EQUIV(__x) if (job1->__x != job2->__x) goto done
902
combine_jobs(const struct mitsu70x_printjob * job1,const struct mitsu70x_printjob * job2)903 static struct mitsu70x_printjob *combine_jobs(const struct mitsu70x_printjob *job1,
904 const struct mitsu70x_printjob *job2)
905 {
906 struct mitsu70x_printjob *newjob = NULL;
907 uint16_t newrows;
908 uint16_t newcols;
909 uint32_t newpad, finalpad;
910 uint16_t lamoffset;
911
912 const struct mitsu70x_hdr *hdr1, *hdr2;
913 struct mitsu70x_hdr *newhdr;
914
915 /* Sanity check */
916 if (!job1 || !job2)
917 goto done;
918
919 hdr1 = (struct mitsu70x_hdr *) job1->databuf;
920 hdr2 = (struct mitsu70x_hdr *) job2->databuf;
921
922 JOB_EQUIV(rows);
923 JOB_EQUIV(cols);
924 JOB_EQUIV(matte);
925 JOB_EQUIV(sharpen);
926
927 if (hdr1->multicut || hdr2->multicut)
928 goto done;
929 if (job1->raw_format || job2->raw_format)
930 goto done;
931 if (hdr1->speed != hdr2->speed)
932 goto done;
933
934 switch (job1->rows) {
935 case 1218: /* K60, EK305 */
936 newrows = 2454;
937 newpad = 16;
938 finalpad = 0;
939 lamoffset = 0;
940 break;
941 case 1228: /* D70, ASK300, D80 */
942 newrows = 2730;
943 newpad = 38;
944 finalpad = 236;
945 lamoffset = 12;
946 break;
947 case 1076: /* EK305, K60 3.5x5" prints */
948 newrows = 2190;
949 newpad = 49;
950 finalpad = 0;
951 lamoffset = 0;
952 break;
953 default:
954 goto done;
955 }
956 newcols = job1->cols;
957 newpad *= newcols;
958 finalpad *= newcols;
959
960 /* Okay, it's kosher to proceed */
961
962 DEBUG("Combining jobs to save media\n");
963
964 newjob = malloc(sizeof(*newjob));
965 if (!newjob) {
966 ERROR("Memory allocation failure!\n");
967 goto done;
968 }
969 memcpy(newjob, job1, sizeof(*newjob));
970
971 newjob->spoolbuf = NULL;
972 newjob->rows = newrows;
973 newjob->cols = newcols;
974 newjob->planelen = (((newrows * newcols * 2) + 511) /512) * 512;
975 if (newjob->matte) {
976 newjob->matte = ((((newrows + lamoffset) * newcols * 2) + 511) / 512) * 512;
977 }
978 newjob->databuf = malloc(sizeof(*newhdr) + newjob->planelen * 3 + newjob->matte);
979 newjob->datalen = 0;
980 if (!newjob->databuf) {
981 mitsu70x_cleanup_job(newjob);
982 newjob = NULL;
983 ERROR("Memory allocation failure!\n");
984 goto done;
985 }
986 newhdr = (struct mitsu70x_hdr *) newjob->databuf;
987
988 /* Copy over header */
989 memcpy(newhdr, hdr1, sizeof(*newhdr));
990 newjob->datalen += sizeof(*newhdr);
991
992 newhdr->rows = cpu_to_be16(newrows);
993 newhdr->cols = cpu_to_be16(newcols);
994
995 if (newjob->matte) {
996 newhdr->lamrows = cpu_to_be16(newrows + lamoffset);
997 newhdr->lamcols = cpu_to_be16(newcols);
998 }
999 newhdr->multicut = 1;
1000 newhdr->deck = 0; /* Let printer decide */
1001
1002 newjob->spoolbuf = malloc(newrows * newcols * 3);
1003 newjob->spoolbuflen = 0;
1004 if (!newjob->spoolbuf) {
1005 mitsu70x_cleanup_job(newjob);
1006 newjob = NULL;
1007 ERROR("Memory allocation failure!\n");
1008 goto done;
1009 }
1010
1011 /* Fill in padding */
1012 memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, finalpad * 3);
1013 newjob->spoolbuflen += finalpad * 3;
1014
1015 /* Copy image payload */
1016 memcpy(newjob->spoolbuf + newjob->spoolbuflen, job1->spoolbuf,
1017 job1->spoolbuflen);
1018 newjob->spoolbuflen += job1->spoolbuflen;
1019
1020 /* Fill in padding */
1021 memset(newjob->spoolbuf + newjob->spoolbuflen, 0xff, newpad * 3);
1022 newjob->spoolbuflen += newpad * 3;
1023
1024 /* Copy image payload */
1025 memcpy(newjob->spoolbuf + newjob->spoolbuflen, job2->spoolbuf,
1026 job2->spoolbuflen);
1027 newjob->spoolbuflen += job2->spoolbuflen;
1028
1029 /* Okay, we're done. */
1030
1031 done:
1032 return newjob;
1033 }
1034 #undef JOB_EQUIV
1035
mitsu70x_read_parse(void * vctx,const void ** vjob,int data_fd,int copies)1036 static int mitsu70x_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
1037 struct mitsu70x_ctx *ctx = vctx;
1038 int i, remain;
1039 struct mitsu70x_hdr mhdr;
1040
1041 struct mitsu70x_printjob *job = NULL;
1042 struct dyesub_joblist *list;
1043 int can_combine;
1044
1045 if (!ctx)
1046 return CUPS_BACKEND_FAILED;
1047
1048 job = malloc(sizeof(*job));
1049 if (!job) {
1050 ERROR("Memory allocation failure!\n");
1051 return CUPS_BACKEND_RETRY_CURRENT;
1052 }
1053 memset(job, 0, sizeof(*job));
1054 job->copies = copies;
1055
1056 repeat:
1057 /* Read in initial header */
1058 remain = sizeof(mhdr);
1059 while (remain > 0) {
1060 i = read(data_fd, ((uint8_t*)&mhdr) + sizeof(mhdr) - remain, remain);
1061 if (i == 0) {
1062 mitsu70x_cleanup_job(job);
1063 return CUPS_BACKEND_CANCEL;
1064 }
1065 if (i < 0) {
1066 mitsu70x_cleanup_job(job);
1067 return CUPS_BACKEND_CANCEL;
1068 }
1069 remain -= i;
1070 }
1071
1072 /* Skip over wakeup header if it's present. */
1073 if (mhdr.hdr[0] == 0x1b &&
1074 mhdr.hdr[1] == 0x45 &&
1075 mhdr.hdr[2] == 0x57 &&
1076 mhdr.hdr[3] == 0x55) {
1077 goto repeat;
1078 }
1079
1080 /* Sanity check header */
1081 if (mhdr.hdr[0] != 0x1b ||
1082 mhdr.hdr[1] != 0x5a ||
1083 mhdr.hdr[2] != 0x54) {
1084 ERROR("Unrecognized data format!\n");
1085 mitsu70x_cleanup_job(job);
1086 return CUPS_BACKEND_CANCEL;
1087 }
1088
1089 job->raw_format = !mhdr.mode;
1090
1091 /* Sanity check Matte mode */
1092 if (!mhdr.laminate && mhdr.laminate_mode) {
1093 if (ctx->type != P_MITSU_D70X) {
1094 if (mhdr.speed != 0x03 && mhdr.speed != 0x04) {
1095 WARNING("Forcing Ultrafine mode for matte printing!\n");
1096 mhdr.speed = 0x04; /* Force UltraFine */
1097 }
1098 } else {
1099 if (mhdr.speed != 0x03) {
1100 mhdr.speed = 0x03; /* Force SuperFine */
1101 WARNING("Forcing SuperFine mode for matte printing!\n");
1102 }
1103 }
1104 }
1105
1106 /* Figure out the correction data table to use */
1107 if (ctx->type == P_MITSU_D70X) {
1108 job->laminatefname = CORRTABLE_PATH "/D70MAT01.raw";
1109 job->lutfname = CORRTABLE_PATH "/CPD70L01.lut";
1110
1111 if (mhdr.speed == 3) {
1112 job->cpcfname = CORRTABLE_PATH "/CPD70S01.cpc";
1113 } else if (mhdr.speed == 4) {
1114 job->cpcfname = CORRTABLE_PATH "/CPD70U01.cpc";
1115 } else {
1116 job->cpcfname = CORRTABLE_PATH "/CPD70N01.cpc";
1117 }
1118 if (mhdr.hdr[3] != 0x01) {
1119 WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1120 mhdr.hdr[3] = 0x01;
1121 }
1122 } else if (ctx->type == P_MITSU_D80) {
1123 job->laminatefname = CORRTABLE_PATH "/D80MAT01.raw";
1124 job->lutfname = CORRTABLE_PATH "/CPD80L01.lut";
1125
1126 if (mhdr.speed == 3) {
1127 job->cpcfname = CORRTABLE_PATH "/CPD80S01.cpc";
1128 job->ecpcfname = CORRTABLE_PATH "/CPD80E01.cpc";
1129 } else if (mhdr.speed == 4) {
1130 job->cpcfname = CORRTABLE_PATH "/CPD80U01.cpc";
1131 job->ecpcfname = NULL;
1132 } else {
1133 job->cpcfname = CORRTABLE_PATH "/CPD80N01.cpc";
1134 job->ecpcfname = NULL;
1135 }
1136 if (mhdr.hdr[3] != 0x01) {
1137 WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1138 mhdr.hdr[3] = 0x01;
1139 }
1140 } else if (ctx->type == P_MITSU_K60) {
1141 job->laminatefname = CORRTABLE_PATH "/S60MAT02.raw";
1142 job->lutfname = CORRTABLE_PATH "/CPS60L01.lut";
1143
1144 if (mhdr.speed == 3 || mhdr.speed == 4) {
1145 mhdr.speed = 4; /* Ultra Fine */
1146 job->cpcfname = CORRTABLE_PATH "/CPS60T03.cpc";
1147 } else {
1148 job->cpcfname = CORRTABLE_PATH "/CPS60T01.cpc";
1149 }
1150 if (mhdr.hdr[3] != 0x00) {
1151 WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1152 mhdr.hdr[3] = 0x00;
1153 }
1154 } else if (ctx->type == P_KODAK_305) {
1155 job->laminatefname = CORRTABLE_PATH "/EK305MAT.raw"; // Same as K60
1156 job->lutfname = CORRTABLE_PATH "/EK305L01.lut";
1157
1158 if (mhdr.speed == 3 || mhdr.speed == 4) {
1159 mhdr.speed = 4; /* Ultra Fine */
1160 job->cpcfname = CORRTABLE_PATH "/EK305T03.cpc";
1161 } else {
1162 job->cpcfname = CORRTABLE_PATH "/EK305T01.cpc";
1163 }
1164 // XXX what about using K60 media if we read back the proper code?
1165 if (mhdr.hdr[3] != 0x90) {
1166 WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1167 mhdr.hdr[3] = 0x90;
1168 }
1169 } else if (ctx->type == P_FUJI_ASK300) {
1170 job->laminatefname = CORRTABLE_PATH "/ASK300M2.raw"; // Same as D70
1171 // job->lutfname = CORRTABLE_PATH "/CPD70L01.lut"; // XXX guess, driver did not come with external LUT!
1172 if (mhdr.speed == 3 || mhdr.speed == 4) {
1173 mhdr.speed = 3; /* Super Fine */
1174 job->cpcfname = CORRTABLE_PATH "/ASK300T3.cpc";
1175 } else {
1176 job->cpcfname = CORRTABLE_PATH "/ASK300T1.cpc";
1177 }
1178 if (mhdr.hdr[3] != 0x80) {
1179 WARNING("Print job has wrong submodel specifier (%x)\n", mhdr.hdr[3]);
1180 mhdr.hdr[3] = 0x80;
1181 }
1182 }
1183 if (!mhdr.use_lut)
1184 job->lutfname = NULL;
1185
1186 job->sharpen = mhdr.sharpen - 1;
1187 job->reverse = !mhdr.reversed;
1188
1189 /* Clean up header back to pristine. */
1190 mhdr.use_lut = 0;
1191 mhdr.mode = 0;
1192 mhdr.sharpen = 0;
1193 mhdr.reversed = 0;
1194
1195 /* Work out total printjob size */
1196 job->cols = be16_to_cpu(mhdr.cols);
1197 job->rows = be16_to_cpu(mhdr.rows);
1198
1199 job->planelen = job->rows * job->cols * 2;
1200 job->planelen = (job->planelen + 511) / 512 * 512; /* Round to nearest 512 bytes. */
1201
1202 if (!mhdr.laminate && mhdr.laminate_mode) {
1203 i = be16_to_cpu(mhdr.lamcols) * be16_to_cpu(mhdr.lamrows) * 2;
1204 i = (i + 511) / 512 * 512; /* Round to nearest 512 bytes. */
1205 job->matte = i;
1206 }
1207
1208 remain = 3 * job->planelen + job->matte;
1209
1210 job->datalen = 0;
1211 job->databuf = malloc(sizeof(mhdr) + remain + LAMINATE_STRIDE*2); /* Give us a bit extra */
1212
1213 if (!job->databuf) {
1214 ERROR("Memory allocation failure!\n");
1215 mitsu70x_cleanup_job(job);
1216 return CUPS_BACKEND_RETRY_CURRENT;
1217 }
1218
1219 memcpy(job->databuf + job->datalen, &mhdr, sizeof(mhdr));
1220 job->datalen += sizeof(mhdr);
1221
1222 if (job->raw_format) { /* RAW MODE */
1223 DEBUG("Reading in %d bytes of 16bpp YMCL data\n", remain);
1224
1225 /* Read in the spool data */
1226 while(remain) {
1227 i = read(data_fd, job->databuf + job->datalen, remain);
1228 if (i == 0) {
1229 mitsu70x_cleanup_job(job);
1230 return CUPS_BACKEND_CANCEL;
1231 }
1232 if (i < 0) {
1233 mitsu70x_cleanup_job(job);
1234 return CUPS_BACKEND_CANCEL;
1235 }
1236 job->datalen += i;
1237 remain -= i;
1238 }
1239 goto done;
1240 }
1241
1242 /* Non-RAW mode! */
1243
1244 remain = job->rows * job->cols * 3;
1245 DEBUG("Reading in %d bytes of 8bpp BGR data\n", remain);
1246
1247 job->spoolbuflen = 0;
1248 job->spoolbuf = malloc(remain);
1249 if (!job->spoolbuf) {
1250 ERROR("Memory allocation failure!\n");
1251 mitsu70x_cleanup_job(job);
1252 return CUPS_BACKEND_RETRY_CURRENT;
1253 }
1254
1255 /* Read in the BGR data */
1256 while (remain) {
1257 i = read(data_fd, job->spoolbuf + job->spoolbuflen, remain);
1258 if (i == 0) {
1259 mitsu70x_cleanup_job(job);
1260 return CUPS_BACKEND_CANCEL;
1261 }
1262 if (i < 0) {
1263 mitsu70x_cleanup_job(job);
1264 return CUPS_BACKEND_CANCEL;
1265 }
1266 job->spoolbuflen += i;
1267 remain -= i;
1268 }
1269
1270 if (!ctx->dl_handle) {
1271 // XXXFALLBACK write fallback code?
1272 ERROR("!!! Image Processing Library not found, aborting!\n");
1273 mitsu70x_cleanup_job(job);
1274 return CUPS_BACKEND_CANCEL;
1275 }
1276
1277 /* Run through basic LUT, if present and enabled */
1278 if (job->lutfname && !ctx->lut) { /* printer-specific, it is fixed per-job */
1279 uint8_t *buf = malloc(LUT_LEN);
1280 if (!buf) {
1281 ERROR("Memory allocation failure!\n");
1282 mitsu70x_cleanup_job(job);
1283 return CUPS_BACKEND_RETRY_CURRENT;
1284 }
1285 if (ctx->Get3DColorTable(buf, job->lutfname)) {
1286 ERROR("Unable to open LUT file '%s'\n", job->lutfname);
1287 mitsu70x_cleanup_job(job);
1288 return CUPS_BACKEND_CANCEL;
1289 }
1290 ctx->lut = ctx->Load3DColorTable(buf);
1291 free(buf);
1292 if (!ctx->lut) {
1293 ERROR("Unable to parse LUT file '%s'!\n", job->lutfname);
1294 mitsu70x_cleanup_job(job);
1295 return CUPS_BACKEND_CANCEL;
1296 }
1297 }
1298
1299 if (job->lutfname && ctx->lut) {
1300 DEBUG("Running print data through 3D LUT\n");
1301 ctx->DoColorConv(ctx->lut, job->spoolbuf, job->cols, job->rows, job->cols * 3, COLORCONV_BGR);
1302 }
1303
1304 done:
1305 list = dyesub_joblist_create(&mitsu70x_backend, ctx);
1306
1307 for (i = 0 ; i < ctx->num_decks ; i++) {
1308 switch (ctx->medias[i]) {
1309 case 0x1: // 5x3.5
1310 if (job->rows == 1076)
1311 job->decks_ok[i] = 1;
1312 if (job->rows == 1076)
1313 job->decks_exact[i] = 1;
1314 break;
1315 case 0x2: // 4x6
1316 if (job->rows == 1218 ||
1317 job->rows == 1228)
1318 job->decks_ok[i] = 1;
1319 if (job->rows == 1218 ||
1320 job->rows == 1228)
1321 job->decks_exact[i] = 1;
1322 break;
1323 case 0x4: // 5x7
1324 if (job->rows == 1076 ||
1325 job->rows == 1524 ||
1326 job->rows == 2128)
1327 job->decks_ok[i] = 1;
1328 if (job->rows == 1524 ||
1329 job->rows == 2128)
1330 job->decks_exact[i] = 1;
1331 break;
1332 case 0x5: // 6x9
1333 case 0xf: // 6x8
1334 /* This is made more complicated:
1335 some 6x8" jobs are 6x9" sized. Let printer
1336 sort these out. It's unlikely we'll have
1337 6x8" in one deck and 6x9" in the other!
1338 */
1339 if (job->rows == 1218 ||
1340 job->rows == 1228 ||
1341 job->rows == 1820 ||
1342 job->rows == 2422 ||
1343 job->rows == 2564 ||
1344 job->rows == 2730)
1345 job->decks_ok[i] = 1;
1346 if (job->rows == 2422 ||
1347 job->rows == 2564 ||
1348 job->rows == 2730)
1349 job->decks_exact[i] = 1;
1350 break;
1351 default:
1352 job->decks_ok[i] = 0;
1353 job->decks_exact[i] = 0;
1354 break;
1355 }
1356 }
1357
1358 /* 6x4 can be combined, only on 6x8/6x9" media. */
1359 can_combine = 0;
1360 if (job->decks_exact[0] ||
1361 job->decks_exact[1]) {
1362 /* Exact media match, don't combine. */
1363 } else if (job->rows == 1218 ||
1364 job->rows == 1228) {
1365 if (ctx->medias[0] == 0xf ||
1366 ctx->medias[0] == 0x5 ||
1367 ctx->medias[1] == 0xf || /* Two decks possible */
1368 ctx->medias[1] == 0x5)
1369 can_combine = !job->raw_format;
1370 } else if (job->rows == 1076) {
1371 if (ctx->type == P_KODAK_305 ||
1372 ctx->type == P_MITSU_K60) {
1373 if (ctx->medias[0] == 0x4) /* Only one deck */
1374 can_combine = !job->raw_format;
1375 }
1376 }
1377
1378 if (copies > 1 && can_combine) {
1379 struct mitsu70x_printjob *combined;
1380 combined = combine_jobs(job, job);
1381 if (combined) {
1382 combined->copies = job->copies / 2;
1383 dyesub_joblist_addjob(list, combined);
1384
1385 if (job->copies & 1) {
1386 job->copies = 1;
1387 } else {
1388 mitsu70x_cleanup_job(job);
1389 job = NULL;
1390 }
1391 }
1392 }
1393
1394 if (job) {
1395 dyesub_joblist_addjob(list, job);
1396 }
1397
1398 /* All further work is in main loop */
1399 if (test_mode >= TEST_MODE_NOPRINT)
1400 dyesub_joblist_print(list);
1401
1402 *vjob = list;
1403
1404 return CUPS_BACKEND_OK;
1405 }
1406
mitsu70x_get_jobstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_jobstatus * resp,uint16_t jobid)1407 static int mitsu70x_get_jobstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_jobstatus *resp, uint16_t jobid)
1408 {
1409 uint8_t cmdbuf[CMDBUF_LEN];
1410 int num, ret;
1411
1412 /* Send Printer Query */
1413 memset(cmdbuf, 0, CMDBUF_LEN);
1414 cmdbuf[0] = 0x1b;
1415 cmdbuf[1] = 0x56;
1416 cmdbuf[2] = 0x31;
1417 cmdbuf[3] = 0x30; // XXX 30 == specific, 31 = "all"
1418
1419 cmdbuf[4] = (jobid >> 8) & 0xff;
1420 cmdbuf[5] = jobid & 0xff;
1421
1422 if ((ret = send_data(ctx->dev, ctx->endp_down,
1423 cmdbuf, 6)))
1424 return ret;
1425
1426 memset(resp, 0, sizeof(*resp));
1427
1428 ret = read_data(ctx->dev, ctx->endp_up,
1429 (uint8_t*) resp, sizeof(*resp), &num);
1430
1431 if (ret < 0)
1432 return ret;
1433 if (num != sizeof(*resp)) {
1434 ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1435 return 4;
1436 }
1437
1438 return 0;
1439 }
1440
1441 #if 0
1442 static int mitsu70x_get_jobs(struct mitsu70x_ctx *ctx, struct mitsu70x_jobs *resp)
1443 {
1444 uint8_t cmdbuf[CMDBUF_LEN];
1445 int num, ret;
1446
1447 /* Send Printer Query */
1448 memset(cmdbuf, 0, CMDBUF_LEN);
1449 cmdbuf[0] = 0x1b;
1450 cmdbuf[1] = 0x56;
1451 cmdbuf[2] = 0x31;
1452 cmdbuf[3] = 0x31;
1453 cmdbuf[4] = 0x00;
1454 cmdbuf[5] = 0x00;
1455
1456 if ((ret = send_data(ctx->dev, ctx->endp_down,
1457 cmdbuf, 6)))
1458 return ret;
1459
1460 memset(resp, 0, sizeof(*resp));
1461
1462 ret = read_data(ctx->dev, ctx->endp_up,
1463 (uint8_t*) resp, sizeof(*resp), &num);
1464
1465 if (ret < 0)
1466 return ret;
1467 if (num != sizeof(*resp)) {
1468 ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1469 return 4;
1470 }
1471
1472 return 0;
1473 }
1474 #endif
1475
mitsu70x_get_memorystatus(struct mitsu70x_ctx * ctx,const struct mitsu70x_printjob * job,uint8_t mcut,struct mitsu70x_memorystatus_resp * resp)1476 static int mitsu70x_get_memorystatus(struct mitsu70x_ctx *ctx, const struct mitsu70x_printjob *job, uint8_t mcut, struct mitsu70x_memorystatus_resp *resp)
1477 {
1478 uint8_t cmdbuf[CMDBUF_LEN];
1479
1480 uint16_t tmp;
1481
1482 int num;
1483 int ret;
1484
1485 memset(cmdbuf, 0, CMDBUF_LEN);
1486 cmdbuf[0] = 0x1b;
1487 cmdbuf[1] = 0x56;
1488 cmdbuf[2] = 0x33;
1489 cmdbuf[3] = 0x00;
1490 tmp = cpu_to_be16(job->cols);
1491 memcpy(cmdbuf + 4, &tmp, 2);
1492
1493 /* We have to lie about print sizes in 4x6*2 multicut modes */
1494 tmp = job->rows;
1495 if (tmp == 2730 && mcut == 1) {
1496 if (ctx->type == P_MITSU_D70X ||
1497 ctx->type == P_FUJI_ASK300) {
1498 tmp = 2422;
1499 }
1500 }
1501
1502 tmp = cpu_to_be16(tmp);
1503 memcpy(cmdbuf + 6, &tmp, 2);
1504 cmdbuf[8] = job->matte ? 0x80 : 0x00;
1505 cmdbuf[9] = 0x00;
1506
1507 if ((ret = send_data(ctx->dev, ctx->endp_down,
1508 cmdbuf, 10)))
1509 return CUPS_BACKEND_FAILED;
1510
1511 /* Read in the printer status */
1512 ret = read_data(ctx->dev, ctx->endp_up,
1513 (uint8_t*) resp, sizeof(*resp), &num);
1514 if (ret < 0)
1515 return CUPS_BACKEND_FAILED;
1516
1517 if (num != sizeof(*resp)) {
1518 ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1519 return CUPS_BACKEND_FAILED;
1520 }
1521
1522 /* Make sure response is sane */
1523 if (resp->hdr[0] != 0xe4 ||
1524 resp->hdr[1] != 0x56 ||
1525 resp->hdr[2] != 0x33) {
1526 ERROR("Unknown response from printer\n");
1527 return CUPS_BACKEND_FAILED;
1528 }
1529
1530 return 0;
1531 }
1532
mitsu70x_get_printerstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_printerstatus_resp * resp)1533 static int mitsu70x_get_printerstatus(struct mitsu70x_ctx *ctx, struct mitsu70x_printerstatus_resp *resp)
1534 {
1535 uint8_t cmdbuf[CMDBUF_LEN];
1536 int num, ret;
1537
1538 /* Send Printer Query */
1539 memset(cmdbuf, 0, CMDBUF_LEN);
1540 cmdbuf[0] = 0x1b;
1541 cmdbuf[1] = 0x56;
1542 cmdbuf[2] = 0x32;
1543 cmdbuf[3] = 0x30; /* or x31 or x32, for SINGLE DECK query!
1544 Results will only have one deck. */
1545 if ((ret = send_data(ctx->dev, ctx->endp_down,
1546 cmdbuf, 4)))
1547 return ret;
1548 memset(resp, 0, sizeof(*resp));
1549 ret = read_data(ctx->dev, ctx->endp_up,
1550 (uint8_t*) resp, sizeof(*resp), &num);
1551
1552 if (ret < 0)
1553 return ret;
1554 if (num != sizeof(*resp)) {
1555 ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp));
1556 return 4;
1557 }
1558
1559 return 0;
1560 }
1561
mitsu70x_cancel_job(struct mitsu70x_ctx * ctx,uint16_t jobid)1562 static int mitsu70x_cancel_job(struct mitsu70x_ctx *ctx, uint16_t jobid)
1563 {
1564 uint8_t cmdbuf[4];
1565 int ret;
1566
1567 /* Send Job cancel. No response. */
1568 memset(cmdbuf, 0, 4);
1569 cmdbuf[0] = 0x1b;
1570 cmdbuf[1] = 0x44;
1571 cmdbuf[2] = (jobid >> 8) & 0xff;
1572 cmdbuf[3] = jobid & 0xff;
1573 if ((ret = send_data(ctx->dev, ctx->endp_down,
1574 cmdbuf, 4)))
1575 return ret;
1576
1577 return 0;
1578 }
1579
mitsu70x_set_sleeptime(struct mitsu70x_ctx * ctx,uint8_t time)1580 static int mitsu70x_set_sleeptime(struct mitsu70x_ctx *ctx, uint8_t time)
1581 {
1582 uint8_t cmdbuf[4];
1583 int ret;
1584
1585 /* 60 minutes max, according to all docs. */
1586 if (time > 60)
1587 time = 60;
1588
1589 /* Send Parameter.. */
1590 memset(cmdbuf, 0, 4);
1591 cmdbuf[0] = 0x1b;
1592 cmdbuf[1] = 0x53;
1593 cmdbuf[2] = 0x53;
1594 cmdbuf[3] = time;
1595
1596 if ((ret = send_data(ctx->dev, ctx->endp_down,
1597 cmdbuf, 4)))
1598 return ret;
1599
1600 return 0;
1601 }
1602
mitsu70x_set_iserial(struct mitsu70x_ctx * ctx,uint8_t enabled)1603 static int mitsu70x_set_iserial(struct mitsu70x_ctx *ctx, uint8_t enabled)
1604 {
1605 uint8_t cmdbuf[4];
1606 int ret;
1607
1608 if (enabled)
1609 enabled = 0;
1610 else
1611 enabled = 0x80;
1612
1613 /* Send Parameter.. */
1614 memset(cmdbuf, 0, 4);
1615 cmdbuf[0] = 0x1b;
1616 cmdbuf[1] = 0x53;
1617 cmdbuf[2] = 0x4e;
1618 cmdbuf[3] = enabled;
1619
1620 if ((ret = send_data(ctx->dev, ctx->endp_down,
1621 cmdbuf, 4)))
1622 return ret;
1623
1624 return 0;
1625 }
1626
1627 #if 0
1628 /* Switches between "Driver" and "SDK" modes.
1629 Single-endpoint vs Multi-Endpoint, essentially.
1630 Not sure about the polarity.
1631 */
1632 static int mitsu70x_set_printermode(struct mitsu70x_ctx *ctx, uint8_t enabled)
1633 {
1634 uint8_t cmdbuf[4];
1635 int ret;
1636
1637 if (enabled)
1638 enabled = 0;
1639 else
1640 enabled = 0x80;
1641
1642 /* Send Parameter.. */
1643 memset(cmdbuf, 0, 4);
1644 cmdbuf[0] = 0x1b;
1645 cmdbuf[1] = 0x53;
1646 cmdbuf[2] = 0x50;
1647 cmdbuf[3] = enabled;
1648
1649 if ((ret = send_data(ctx->dev, ctx->endp_down,
1650 cmdbuf, 4)))
1651 return ret;
1652
1653 return 0;
1654 }
1655 #endif
1656
mitsu70x_wakeup(struct mitsu70x_ctx * ctx,int wait)1657 static int mitsu70x_wakeup(struct mitsu70x_ctx *ctx, int wait)
1658 {
1659 int ret;
1660 uint8_t buf[512];
1661 struct mitsu70x_jobstatus jobstatus;
1662
1663 top:
1664 /* Query job status for jobid 0 (global) */
1665 ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
1666 if (ret)
1667 return CUPS_BACKEND_FAILED;
1668
1669 /* Trigger a wakeup if necessary */
1670 if (jobstatus.power) {
1671 INFO("Waking up printer...\n");
1672
1673 memset(buf, 0, sizeof(buf));
1674 buf[0] = 0x1b;
1675 buf[1] = 0x45;
1676 buf[2] = 0x57; // XXX also, 0x53, 0x54 seen.
1677 buf[3] = 0x55;
1678
1679 if ((ret = send_data(ctx->dev, ctx->endp_down,
1680 buf, sizeof(buf))))
1681 return CUPS_BACKEND_FAILED;
1682
1683 if (wait) {
1684 sleep(1);
1685 goto top;
1686 }
1687 }
1688
1689
1690 return CUPS_BACKEND_OK;
1691 }
1692
d70_library_callback(void * context,void * buffer,uint32_t len)1693 static int d70_library_callback(void *context, void *buffer, uint32_t len)
1694 {
1695 uint32_t chunk = len;
1696 uint32_t offset = 0;
1697 int ret = 0;
1698
1699 struct mitsu70x_ctx *ctx = context;
1700
1701 while (chunk > 0) {
1702 if (chunk > CHUNK_LEN)
1703 chunk = CHUNK_LEN;
1704
1705 ret = send_data(ctx->dev, ctx->endp_down, (uint8_t*)buffer + offset, chunk);
1706 if (ret < 0)
1707 break;
1708
1709 offset += chunk;
1710 chunk = len - offset;
1711 }
1712
1713 return ret;
1714 }
1715
mitsu70x_main_loop(void * vctx,const void * vjob)1716 static int mitsu70x_main_loop(void *vctx, const void *vjob)
1717 {
1718 struct mitsu70x_ctx *ctx = vctx;
1719 struct mitsu70x_jobstatus jobstatus;
1720 struct mitsu70x_printerstatus_resp resp;
1721 struct mitsu70x_hdr *hdr;
1722 uint8_t last_status[4] = {0xff, 0xff, 0xff, 0xff};
1723
1724 int ret;
1725 int copies;
1726 int deck, legal, reqdeck;
1727
1728 struct mitsu70x_printjob *job = (struct mitsu70x_printjob *) vjob; // XXX not clean.
1729 // const struct mitsu70x_printjob *job = vjob;
1730
1731 if (!ctx)
1732 return CUPS_BACKEND_FAILED;
1733 if (!job)
1734 return CUPS_BACKEND_FAILED;
1735
1736 copies = job->copies;
1737 hdr = (struct mitsu70x_hdr*) job->databuf;
1738
1739 /* Keep track of deck requested */
1740 reqdeck = hdr->deck;
1741
1742 if (job->raw_format)
1743 goto bypass;
1744
1745 struct BandImage input;
1746 uint8_t rew[2] = { 1, 1 }; /* 1 for rewind ok (default!) */
1747
1748 /* Load in the CPC file, if needed */
1749 if (job->cpcfname && job->cpcfname != ctx->last_cpcfname) {
1750 ctx->last_cpcfname = job->cpcfname;
1751 if (ctx->cpcdata)
1752 ctx->DestroyCPCData(ctx->cpcdata);
1753 ctx->cpcdata = ctx->GetCPCData(job->cpcfname);
1754 if (!ctx->cpcdata) {
1755 ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
1756 return CUPS_BACKEND_CANCEL;
1757 }
1758 }
1759
1760 /* Load in the secondary CPC, if needed */
1761 if (job->ecpcfname != ctx->last_ecpcfname) {
1762 ctx->last_ecpcfname = job->ecpcfname;
1763 if (ctx->ecpcdata)
1764 ctx->DestroyCPCData(ctx->ecpcdata);
1765 if (job->ecpcfname) {
1766 ctx->ecpcdata = ctx->GetCPCData(job->ecpcfname);
1767 if (!ctx->ecpcdata) {
1768 ERROR("Unable to load CPC file '%s'\n", job->cpcfname);
1769 return CUPS_BACKEND_CANCEL;
1770 }
1771 } else {
1772 ctx->ecpcdata = NULL;
1773 }
1774 }
1775
1776 /* Convert using image processing library */
1777 input.origin_rows = input.origin_cols = 0;
1778 input.rows = job->rows;
1779 input.cols = job->cols;
1780 input.imgbuf = job->spoolbuf;
1781 input.bytes_per_row = job->cols * 3;
1782
1783 ctx->output.origin_rows = ctx->output.origin_cols = 0;
1784 ctx->output.rows = job->rows;
1785 ctx->output.cols = job->cols;
1786 ctx->output.imgbuf = job->databuf + job->datalen;
1787 ctx->output.bytes_per_row = job->cols * 3 * 2;
1788
1789 DEBUG("Running print data through processing library\n");
1790 if (ctx->DoImageEffect(ctx->cpcdata, ctx->ecpcdata,
1791 &input, &ctx->output, job->sharpen, job->reverse, rew)) {
1792 ERROR("Image Processing failed, aborting!\n");
1793 return CUPS_BACKEND_CANCEL;
1794 }
1795
1796 /* Twiddle rewind stuff if needed */
1797 if (ctx->type != P_MITSU_D70X) {
1798 hdr->rewind[0] = !rew[0];
1799 hdr->rewind[1] = !rew[1];
1800 DEBUG("Rewind Inhibit? %02x %02x\n", hdr->rewind[0], hdr->rewind[1]);
1801 }
1802
1803 /* Move up the pointer to after the image data */
1804 job->datalen += 3*job->planelen;
1805
1806 /* Clean up */
1807 // XXX not really necessary.
1808 free(job->spoolbuf);
1809 job->spoolbuf = NULL;
1810 job->spoolbuflen = 0;
1811
1812 /* Now that we've filled everything in, read matte from file */
1813 if (job->matte) {
1814 int fd;
1815 uint32_t j;
1816 DEBUG("Reading %u bytes of matte data from disk (%d/%d)\n", job->matte, job->cols, LAMINATE_STRIDE);
1817 fd = open(job->laminatefname, O_RDONLY);
1818 if (fd < 0) {
1819 ERROR("Unable to open matte lamination data file '%s'\n", job->laminatefname);
1820 return CUPS_BACKEND_CANCEL;
1821 }
1822
1823 for (j = 0 ; j < be16_to_cpu(hdr->lamrows) ; j++) {
1824 int remain = LAMINATE_STRIDE * 2;
1825
1826 /* Read one row of lamination data at a time */
1827 while (remain) {
1828 int i = read(fd, job->databuf + job->datalen, remain);
1829 if (i < 0)
1830 return CUPS_BACKEND_CANCEL;
1831 if (i == 0) {
1832 /* We hit EOF, restart from beginning */
1833 lseek(fd, 0, SEEK_SET);
1834 continue;
1835 }
1836 job->datalen += i;
1837 remain -= i;
1838 }
1839 /* Back off the buffer so we "wrap" on the print row. */
1840 job->datalen -= ((LAMINATE_STRIDE - job->cols) * 2);
1841 }
1842 /* We're done */
1843 close(fd);
1844
1845 /* Zero out the tail end of the buffer. */
1846 j = be16_to_cpu(hdr->lamcols) * be16_to_cpu(hdr->lamrows) * 2;
1847 memset(job->databuf + job->datalen, 0, job->matte - j);
1848 }
1849
1850 bypass:
1851 /* Bypass */
1852 if (test_mode >= TEST_MODE_NOPRINT)
1853 return CUPS_BACKEND_OK;
1854
1855 INFO("Waiting for printer idle...\n");
1856
1857 /* Ensure printer is awake */
1858 ret = mitsu70x_wakeup(ctx, 1);
1859 if (ret)
1860 return CUPS_BACKEND_FAILED;
1861
1862 top:
1863 /* Query job status for jobid 0 (global) */
1864 ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
1865 if (ret)
1866 return CUPS_BACKEND_FAILED;
1867
1868 /* Figure out which deck(s) can be used.
1869 This should be in the main loop due to copy retries */
1870
1871 /* First, try to respect requested deck */
1872 if (ctx->type == P_MITSU_D70X) {
1873 deck = reqdeck; /* Respect D70 deck choice, 0 is automatic. */
1874 } else {
1875 deck = 1; /* All others have one deck only */
1876 }
1877
1878 /* If user requested a specific deck, go with it, if it's legal */
1879 if (deck == 1 && job->decks_ok[0]) {
1880 deck = 1;
1881 } else if (deck == 2 && job->decks_ok[1]) {
1882 deck = 2;
1883 /* If we have an exact match for media, use it exclusively */
1884 } else if (job->decks_exact[0] && job->decks_exact[1]) {
1885 deck = 1 | 2;
1886 } else if (job->decks_exact[0]) {
1887 deck = 1;
1888 } else if (job->decks_exact[1]) {
1889 deck = 2;
1890 /* Use a non-exact match only if we don't have an exact match */
1891 } else if (job->decks_ok[0] && job->decks_ok[1]) {
1892 deck = 1 | 2;
1893 } else if (job->decks_ok[0]) {
1894 deck = 1;
1895 } else if (job->decks_ok[1]) {
1896 deck = 2;
1897 } else {
1898 ERROR("Loaded media does not match job!\n");
1899 return CUPS_BACKEND_CANCEL;
1900 }
1901
1902 if (ctx->num_decks > 1)
1903 DEBUG("Deck selection mask: %d (%d %d %d/%d %d/%d) \n",
1904 deck, hdr->deck, job->rows,
1905 job->decks_exact[0], job->decks_exact[1],
1906 job->decks_ok[0], job->decks_ok[1]);
1907
1908 /* Okay, we know which decks are _legal_, pick one to use */
1909 legal = deck;
1910 if (deck & 1) {
1911 if (jobstatus.temperature == TEMPERATURE_COOLING) {
1912 if (ctx->num_decks == 2)
1913 INFO("Lower deck cooling down...\n");
1914 else
1915 INFO("Printer cooling down...\n");
1916 deck &= ~1;
1917 } else if (jobstatus.error_status[0]) {
1918 ERROR("%s %s/%s -> %s: %02x/%02x/%02x\n",
1919 ctx->num_decks == 2 ? "LOWER:": "",
1920 mitsu70x_errorclass(jobstatus.error_status),
1921 mitsu70x_errors(jobstatus.error_status),
1922 mitsu70x_errorrecovery(jobstatus.error_status),
1923 jobstatus.error_status[0],
1924 jobstatus.error_status[1],
1925 jobstatus.error_status[2]);
1926 deck &= ~1;
1927 legal &= ~1; /* Deck is offline! */
1928 } else if (jobstatus.mecha_status[0] != MECHA_STATUS_IDLE) {
1929 deck &= ~1;
1930 }
1931 }
1932 if (deck & 2) {
1933 if (jobstatus.temperature_up == TEMPERATURE_COOLING) {
1934 INFO("Upper deck cooling down...\n");
1935 deck &= ~2;
1936 } else if (jobstatus.error_status_up[0]) {
1937 ERROR("UPPER: %s/%s -> %s: %02x/%02x/%02x\n",
1938 mitsu70x_errorclass(jobstatus.error_status_up),
1939 mitsu70x_errors(jobstatus.error_status_up),
1940 mitsu70x_errorrecovery(jobstatus.error_status_up),
1941 jobstatus.error_status_up[0],
1942 jobstatus.error_status_up[1],
1943 jobstatus.error_status_up[2]);
1944 deck &= ~2;
1945 legal &= ~2; /* Deck is offline! */
1946 } else if (jobstatus.mecha_status_up[0] != MECHA_STATUS_IDLE) {
1947 deck &= ~2;
1948 }
1949 }
1950
1951 if (deck == 3) {
1952 /* Both decks OK to use, pick one at random */
1953 if (rand() & 1)
1954 deck = 1;
1955 else
1956 deck = 2;
1957 }
1958
1959 if (ctx->num_decks > 1)
1960 DEBUG("Deck selected: %d\n", deck);
1961
1962 /* Great, we have no decks we can currently print this job on.. */
1963 if (deck == 0) {
1964 /* Halt queue if printer is entirely offline */
1965 if (ctx->num_decks == 2) {
1966 if (jobstatus.error_status[0] && jobstatus.error_status_up[0]) {
1967 ERROR("Both decks offline due to errors\n");
1968 return CUPS_BACKEND_STOP;
1969 }
1970 } else {
1971 if (jobstatus.error_status[0]) {
1972 ERROR("Printer offline due to errors\n");
1973 return CUPS_BACKEND_STOP;
1974 }
1975 }
1976
1977 /* Hold job if we have no legal decks for it, but printer is online. */
1978 if (!legal) {
1979 ERROR("Legal deck for printjob has errors, aborting job");
1980 return CUPS_BACKEND_HOLD;
1981 }
1982
1983 /* Legal decks are busy, retry */
1984 sleep(1);
1985 goto top;
1986 }
1987
1988 /* Perform memory status query */
1989 {
1990 struct mitsu70x_memorystatus_resp memory;
1991 INFO("Checking Memory availability\n");
1992
1993 ret = mitsu70x_get_memorystatus(ctx, job, hdr->multicut, &memory);
1994 if (ret)
1995 return CUPS_BACKEND_FAILED;
1996
1997 /* Check size is sane */
1998 if (memory.size || memory.memory == 0xff) {
1999 ERROR("Unsupported print size!\n");
2000 return CUPS_BACKEND_CANCEL;
2001 }
2002 if (memory.memory) {
2003 INFO("Printer buffers full, retrying!\n");
2004 sleep(1);
2005 goto top;
2006 }
2007 }
2008
2009 #if 0
2010 /* Make sure we don't have any jobid collisions */
2011 {
2012 int i;
2013 struct mitsu70x_jobs jobs;
2014
2015 ret = mitsu70x_get_jobs(ctx, &jobs);
2016 if (ret)
2017 return CUPS_BACKEND_FAILED;
2018 for (i = 0 ; i < NUM_JOBS ; i++) {
2019 if (jobs.jobs[0].id == 0)
2020 break;
2021 if (ctx->jobid == be16_to_cpu(jobs.jobs[0].id)) {
2022 ctx->jobid++;
2023 if (!ctx->jobid)
2024 ctx->jobid++;
2025 i = -1;
2026 }
2027 }
2028 }
2029 #endif
2030 while(!ctx->jobid || ctx->jobid == be16_to_cpu(jobstatus.jobid))
2031 ctx->jobid++;
2032
2033 /* Set jobid */
2034 hdr->jobid = cpu_to_be16(ctx->jobid);
2035
2036 /* Set deck */
2037 hdr->deck = deck;
2038
2039 /* K60 and EK305 need the mcut type 1 specified for 4x6 prints! */
2040 if ((ctx->type == P_MITSU_K60 || ctx->type == P_KODAK_305) &&
2041 job->cols == 0x0748 &&
2042 job->rows == 0x04c2 && !hdr->multicut) {
2043 hdr->multicut = 1;
2044 }
2045
2046 /* We're clear to send data over! */
2047 INFO("Sending Print Job (internal id %u)\n", ctx->jobid);
2048
2049 if ((ret = send_data(ctx->dev, ctx->endp_down,
2050 job->databuf,
2051 sizeof(struct mitsu70x_hdr))))
2052 return CUPS_BACKEND_FAILED;
2053
2054 if (ctx->dl_handle && !job->raw_format) {
2055 if (ctx->SendImageData(&ctx->output, ctx, d70_library_callback))
2056 return CUPS_BACKEND_FAILED;
2057
2058 if (job->matte)
2059 if (d70_library_callback(ctx, job->databuf + job->datalen - job->matte, job->matte))
2060 return CUPS_BACKEND_FAILED;
2061 } else { // Fallback code..
2062 /* K60 and 305 need data sent in 256K chunks, but the first
2063 chunk needs to subtract the length of the 512-byte header */
2064
2065 int chunk = CHUNK_LEN - sizeof(struct mitsu70x_hdr);
2066 int sent = 512;
2067 while (chunk > 0) {
2068 if ((ret = send_data(ctx->dev, ctx->endp_down,
2069 job->databuf + sent, chunk)))
2070 return CUPS_BACKEND_FAILED;
2071 sent += chunk;
2072 chunk = job->datalen - sent;
2073 if (chunk > CHUNK_LEN)
2074 chunk = CHUNK_LEN;
2075 }
2076 }
2077
2078 /* Then wait for completion, if so desired.. */
2079 INFO("Waiting for printer to acknowledge completion\n");
2080
2081 do {
2082 sleep(1);
2083
2084 ret = mitsu70x_get_printerstatus(ctx, &resp);
2085 if (ret)
2086 return CUPS_BACKEND_FAILED;
2087
2088 ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
2089 ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
2090 if (ctx->num_decks == 2) {
2091 ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
2092 ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
2093 }
2094 if (ctx->marker[0].levelnow != ctx->last_l ||
2095 ctx->marker[1].levelnow != ctx->last_u) {
2096 dump_markers(ctx->marker, ctx->num_decks, 0);
2097 ctx->last_l = ctx->marker[0].levelnow;
2098 ctx->last_u = ctx->marker[1].levelnow;
2099 }
2100
2101 /* Query job status for our used jobid */
2102 ret = mitsu70x_get_jobstatus(ctx, &jobstatus, ctx->jobid);
2103 if (ret)
2104 return CUPS_BACKEND_FAILED;
2105
2106 /* See if we hit a printer error. */
2107 if (deck == 1) {
2108 if (jobstatus.error_status[0]) {
2109 ERROR("%s/%s -> %s: %02x/%02x/%02x\n",
2110 mitsu70x_errorclass(jobstatus.error_status),
2111 mitsu70x_errors(jobstatus.error_status),
2112 mitsu70x_errorrecovery(jobstatus.error_status),
2113 jobstatus.error_status[0],
2114 jobstatus.error_status[1],
2115 jobstatus.error_status[2]);
2116
2117 /* Retry job on the other deck.. */
2118 if (ctx->num_decks == 2)
2119 goto top;
2120
2121 return CUPS_BACKEND_STOP;
2122 }
2123 } else if (deck == 2) {
2124 if (jobstatus.error_status_up[0]) {
2125 ERROR("UPPER: %s/%s -> %s: %02x/%02x/%02x\n",
2126 mitsu70x_errorclass(jobstatus.error_status_up),
2127 mitsu70x_errors(jobstatus.error_status_up),
2128 mitsu70x_errorrecovery(jobstatus.error_status_up),
2129 jobstatus.error_status_up[0],
2130 jobstatus.error_status_up[1],
2131 jobstatus.error_status_up[2]);
2132
2133 /* Retry job on the other deck.. */
2134 if (ctx->num_decks == 2)
2135 goto top;
2136
2137 return CUPS_BACKEND_STOP;
2138 }
2139 }
2140
2141 /* Only print if job status is changed */
2142 if (jobstatus.job_status[0] != last_status[0] ||
2143 jobstatus.job_status[1] != last_status[1] ||
2144 jobstatus.job_status[2] != last_status[2] ||
2145 jobstatus.job_status[3] != last_status[3])
2146 INFO("%s: %02x/%02x/%02x/%02x\n",
2147 mitsu70x_jobstatuses(jobstatus.job_status),
2148 jobstatus.job_status[0],
2149 jobstatus.job_status[1],
2150 jobstatus.job_status[2],
2151 jobstatus.job_status[3]);
2152
2153 /* Check for job completion */
2154 if (jobstatus.job_status[0] == JOB_STATUS0_END) {
2155 if (jobstatus.job_status[1] ||
2156 jobstatus.job_status[2] ||
2157 jobstatus.job_status[3]) {
2158 ERROR("Abnormal exit: %02x/%02x/%02x\n",
2159 jobstatus.job_status[1],
2160 jobstatus.job_status[2],
2161 jobstatus.job_status[3]);
2162 return CUPS_BACKEND_STOP;
2163 }
2164 /* Job complete */
2165 break;
2166 }
2167
2168 /* See if we can return early, but wait until printing has started! */
2169 if (fast_return && copies <= 1 && /* Copies generated by backend! */
2170 jobstatus.job_status[0] == JOB_STATUS0_PRINT &&
2171 jobstatus.job_status[1] > JOB_STATUS1_PRINT_MEDIALOAD)
2172 {
2173 INFO("Fast return mode enabled.\n");
2174 break;
2175 }
2176
2177 /* On a two deck system, try to use the second deck
2178 for additional copies. If we can't use it, we'll block. */
2179 if (ctx->num_decks > 1 && copies > 1)
2180 break;
2181
2182 /* Update cache for the next round */
2183 memcpy(last_status, jobstatus.job_status, 4);
2184 } while(1);
2185
2186 /* Clean up */
2187 if (terminate)
2188 copies = 1;
2189
2190 INFO("Print complete (%d copies remaining)\n", copies - 1);
2191
2192 if (copies && --copies) {
2193 goto top;
2194 }
2195
2196 return CUPS_BACKEND_OK;
2197 }
2198
mitsu70x_dump_printerstatus(struct mitsu70x_ctx * ctx,struct mitsu70x_printerstatus_resp * resp)2199 static void mitsu70x_dump_printerstatus(struct mitsu70x_ctx *ctx,
2200 struct mitsu70x_printerstatus_resp *resp)
2201 {
2202 uint32_t i;
2203 uint8_t memory = ~resp->memory;
2204
2205 INFO("Model : ");
2206 for (i = 0 ; i < 6 ; i++) {
2207 DEBUG2("%c", le16_to_cpu(resp->model[i]) & 0x7f);
2208 }
2209 DEBUG2("\n");
2210 INFO("Serial Number : ");
2211 for (i = 0 ; i < 6 ; i++) {
2212 DEBUG2("%c", le16_to_cpu(resp->serno[i]) & 0x7f);
2213 }
2214 DEBUG2("\n");
2215 for (i = 0 ; i < 7 ; i++) {
2216 char buf[7];
2217 char type;
2218 if (resp->vers[i].ver[5] == '@') /* "DUMMY@" */
2219 continue;
2220 memcpy(buf, resp->vers[i].ver, 6);
2221 buf[6] = 0;
2222 if (i == 0) type = 'M';
2223 else if (i == 1) type = 'L';
2224 else if (i == 2) type = 'R';
2225 else if (i == 3) type = 'T';
2226 else if (i == 4) type = 'F';
2227 else type = i + 0x30;
2228
2229 INFO("FW Component: %c %s (%04x)\n",
2230 type, buf, be16_to_cpu(resp->vers[i].checksum));
2231 }
2232 INFO("Standby Timeout: %d minutes\n", resp->sleeptime);
2233 INFO("iSerial Reporting: %s\n", resp->iserial ? "No" : "Yes" );
2234 INFO("Power Status: %s\n", resp->power ? "Sleeping" : "Awake");
2235 INFO("Available Memory Banks: %s%s%s%s%s%s%s%s\n",
2236 (memory & 0x01) ? "mem8 " : "",
2237 (memory & 0x02) ? "mem7 " : "",
2238 (memory & 0x04) ? "mem6 " : "",
2239 (memory & 0x08) ? "mem5 " : "",
2240 (memory & 0x10) ? "mem4 " : "",
2241 (memory & 0x20) ? "mem3 " : "",
2242 (memory & 0x40) ? "mem2 " : "",
2243 (memory & 0x80) ? "mem1 " : "");
2244
2245 if (resp->lower.error_status[0]) {
2246 INFO("Lower Error Status: %s/%s -> %s\n",
2247 mitsu70x_errorclass(resp->lower.error_status),
2248 mitsu70x_errors(resp->lower.error_status),
2249 mitsu70x_errorrecovery(resp->lower.error_status));
2250 }
2251 INFO("Lower Temperature: %s\n", mitsu70x_temperatures(resp->lower.temperature));
2252 INFO("Lower Mechanical Status: %s\n",
2253 mitsu70x_mechastatus(resp->lower.mecha_status));
2254 INFO("Lower Media Type: %s (%02x/%02x)\n",
2255 mitsu70x_media_types(resp->lower.media_brand, resp->lower.media_type),
2256 resp->lower.media_brand,
2257 resp->lower.media_type);
2258 INFO("Lower Prints Remaining: %03d/%03d\n",
2259 be16_to_cpu(resp->lower.remain),
2260 be16_to_cpu(resp->lower.capacity));
2261 i = packed_bcd_to_uint32((char*)resp->lower.lifetime_prints, 4);
2262 if (i)
2263 i-= 10;
2264 INFO("Lower Lifetime Prints: %u\n", i);
2265
2266 if (ctx->num_decks == 2) {
2267 if (resp->upper.error_status[0]) {
2268 INFO("Upper Error Status: %s/%s -> %s\n",
2269 mitsu70x_errorclass(resp->upper.error_status),
2270 mitsu70x_errors(resp->upper.error_status),
2271 mitsu70x_errorrecovery(resp->upper.error_status));
2272 }
2273 INFO("Upper Temperature: %s\n", mitsu70x_temperatures(resp->upper.temperature));
2274 INFO("Upper Mechanical Status: %s\n",
2275 mitsu70x_mechastatus(resp->upper.mecha_status));
2276 INFO("Upper Media Type: %s (%02x/%02x)\n",
2277 mitsu70x_media_types(resp->upper.media_brand, resp->upper.media_type),
2278 resp->upper.media_brand,
2279 resp->upper.media_type);
2280 INFO("Upper Prints Remaining: %03d/%03d\n",
2281 be16_to_cpu(resp->upper.remain),
2282 be16_to_cpu(resp->upper.capacity));
2283
2284 i = packed_bcd_to_uint32((char*)resp->upper.lifetime_prints, 4);
2285 if (i)
2286 i-= 10;
2287 INFO("Upper Lifetime Prints: %u\n", i);
2288 }
2289 }
2290
mitsu70x_query_jobs(struct mitsu70x_ctx * ctx)2291 static int mitsu70x_query_jobs(struct mitsu70x_ctx *ctx)
2292 {
2293 #if 0
2294 struct mitsu70x_jobs jobs;
2295 #endif
2296 struct mitsu70x_jobstatus jobstatus;
2297 int ret;
2298
2299 ret = mitsu70x_get_jobstatus(ctx, &jobstatus, 0x0000);
2300 if (ret)
2301 return CUPS_BACKEND_FAILED;
2302
2303 INFO("JOB00 ID : %06u\n", jobstatus.jobid);
2304 INFO("JOB00 status : %s\n", mitsu70x_jobstatuses(jobstatus.job_status));
2305 INFO("Power Status: %s\n", jobstatus.power ? "Sleeping" : "Awake");
2306
2307 if (ctx->num_decks == 2) {
2308 INFO("Lower Deck Mechanical Status: %s\n",
2309 mitsu70x_mechastatus(jobstatus.mecha_status));
2310 if (jobstatus.error_status[0]) {
2311 INFO("%s/%s -> %s\n",
2312 mitsu70x_errorclass(jobstatus.error_status),
2313 mitsu70x_errors(jobstatus.error_status),
2314 mitsu70x_errorrecovery(jobstatus.error_status));
2315 }
2316 INFO("Lower Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
2317
2318 INFO("Upper Deck Mechanical Status: %s\n",
2319 mitsu70x_mechastatus(jobstatus.mecha_status_up));
2320 if (jobstatus.error_status_up[0]) {
2321 INFO("%s/%s -> %s\n",
2322 mitsu70x_errorclass(jobstatus.error_status_up),
2323 mitsu70x_errors(jobstatus.error_status_up),
2324 mitsu70x_errorrecovery(jobstatus.error_status_up));
2325 }
2326 INFO("Upper Deck Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature_up));
2327 } else {
2328 INFO("Mechanical Status: %s\n",
2329 mitsu70x_mechastatus(jobstatus.mecha_status));
2330 if (jobstatus.error_status[0]) {
2331 INFO("%s/%s -> %s\n",
2332 mitsu70x_errorclass(jobstatus.error_status),
2333 mitsu70x_errors(jobstatus.error_status),
2334 mitsu70x_errorrecovery(jobstatus.error_status));
2335 }
2336 INFO("Temperature: %s\n", mitsu70x_temperatures(jobstatus.temperature));
2337 }
2338
2339 // memory status?
2340
2341 #if 0
2342 ret = mitsu70x_get_jobs(ctx, &jobs);
2343 if (!ret) {
2344 int i;
2345 for (i = 0 ; i < NUM_JOBS ; i++) {
2346 if (jobs.jobs[i].id == 0)
2347 break;
2348 INFO("JOB%02d ID : %06u\n", i, jobs.jobs[i].id);
2349 INFO("JOB%02d status : %s\n", i, mitsu70x_jobstatuses(jobs.jobs[i].status));
2350 }
2351 }
2352
2353 done:
2354 #endif
2355 return CUPS_BACKEND_OK;
2356 }
2357
mitsu70x_query_status(struct mitsu70x_ctx * ctx)2358 static int mitsu70x_query_status(struct mitsu70x_ctx *ctx)
2359 {
2360 struct mitsu70x_printerstatus_resp resp;
2361 int ret;
2362
2363 ret = mitsu70x_get_printerstatus(ctx, &resp);
2364 if (!ret)
2365 mitsu70x_dump_printerstatus(ctx, &resp);
2366
2367 return ret;
2368 }
2369
mitsu70x_query_serno(struct libusb_device_handle * dev,uint8_t endp_up,uint8_t endp_down,char * buf,int buf_len)2370 static int mitsu70x_query_serno(struct libusb_device_handle *dev, uint8_t endp_up, uint8_t endp_down, char *buf, int buf_len)
2371 {
2372 int ret, i;
2373 struct mitsu70x_printerstatus_resp resp = { .hdr = { 0 } };
2374
2375 struct mitsu70x_ctx ctx = {
2376 .dev = dev,
2377 .endp_up = endp_up,
2378 .endp_down = endp_down,
2379 };
2380
2381 ret = mitsu70x_get_printerstatus(&ctx, &resp);
2382
2383 if (buf_len > 6) /* Will we ever have a buffer under 6 bytes? */
2384 buf_len = 6;
2385
2386 for (i = 0 ; i < buf_len ; i++) {
2387 *buf++ = le16_to_cpu(resp.serno[i]) & 0x7f;
2388 }
2389 *buf = 0; /* Null-terminate the returned string */
2390
2391 return ret;
2392 }
2393
2394
mitsu70x_cmdline(void)2395 static void mitsu70x_cmdline(void)
2396 {
2397 DEBUG("\t\t[ -s ] # Query printer status\n");
2398 DEBUG("\t\t[ -j ] # Query job status\n");
2399 DEBUG("\t\t[ -w ] # Wake up printer\n");
2400 DEBUG("\t\t[ -W ] # Wake up printer and wait\n");
2401 DEBUG("\t\t[ -k num ] # Set standby time (1-60 minutes, 0 disables)\n");
2402 DEBUG("\t\t[ -x num ] # Set USB iSerialNumber Reporting (1 on, 0 off)\n");
2403 DEBUG("\t\t[ -X jobid ] # Abort a printjob\n");}
2404
mitsu70x_cmdline_arg(void * vctx,int argc,char ** argv)2405 static int mitsu70x_cmdline_arg(void *vctx, int argc, char **argv)
2406 {
2407 struct mitsu70x_ctx *ctx = vctx;
2408 int i, j = 0;
2409
2410 if (!ctx)
2411 return -1;
2412
2413 while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "jk:swWX:x:")) >= 0) {
2414 switch(i) {
2415 GETOPT_PROCESS_GLOBAL
2416 case 'j':
2417 j = mitsu70x_query_jobs(ctx);
2418 break;
2419 case 'k':
2420 j = mitsu70x_set_sleeptime(ctx, atoi(optarg));
2421 break;
2422 case 's':
2423 j = mitsu70x_query_status(ctx);
2424 break;
2425 case 'w':
2426 j = mitsu70x_wakeup(ctx, 0);
2427 break;
2428 case 'W':
2429 j = mitsu70x_wakeup(ctx, 1);
2430 break;
2431 case 'x':
2432 j = mitsu70x_set_iserial(ctx, atoi(optarg));
2433 break;
2434 case 'X':
2435 j = mitsu70x_cancel_job(ctx, atoi(optarg));
2436 break;
2437 default:
2438 break; /* Ignore completely */
2439 }
2440
2441 if (j) return j;
2442 }
2443
2444 return 0;
2445 }
2446
mitsu70x_query_markers(void * vctx,struct marker ** markers,int * count)2447 static int mitsu70x_query_markers(void *vctx, struct marker **markers, int *count)
2448 {
2449 struct mitsu70x_ctx *ctx = vctx;
2450 struct mitsu70x_printerstatus_resp resp;
2451 int ret;
2452
2453 *markers = ctx->marker;
2454 *count = ctx->num_decks;
2455
2456 /* Tell CUPS about the consumables we report */
2457 ret = mitsu70x_get_printerstatus(ctx, &resp);
2458 if (ret)
2459 return CUPS_BACKEND_FAILED;
2460
2461 if (resp.power) {
2462 ret = mitsu70x_wakeup(ctx, 1);
2463 if (ret)
2464 return CUPS_BACKEND_FAILED;
2465
2466 ret = mitsu70x_get_printerstatus(ctx, &resp);
2467 if (ret)
2468 return CUPS_BACKEND_FAILED;
2469 }
2470
2471 ctx->marker[0].levelmax = be16_to_cpu(resp.lower.capacity);
2472 ctx->marker[0].levelnow = be16_to_cpu(resp.lower.remain);
2473 if (ctx->num_decks == 2) {
2474 ctx->marker[1].levelmax = be16_to_cpu(resp.upper.capacity);
2475 ctx->marker[1].levelnow = be16_to_cpu(resp.upper.remain);
2476 }
2477
2478 return CUPS_BACKEND_OK;
2479 }
2480
2481 static const char *mitsu70x_prefixes[] = {
2482 "mitsu70x", // Family entry, do not nuke.
2483 "mitsubishi-d70dw", "mitsubishi-d80dw", "mitsubishi-k60dw", "kodak-305", "fujifilm-ask-300",
2484 // Extras
2485 "mitsubishi-d707dw", "mitsubishi-k60dws",
2486 // backwards compatibility
2487 "mitsud80", "mitsuk60", "kodak305", "fujiask300",
2488 NULL,
2489 };
2490
2491 /* Exported */
2492 struct dyesub_backend mitsu70x_backend = {
2493 .name = "Mitsubishi CP-D70 family",
2494 .version = "0.95",
2495 .uri_prefixes = mitsu70x_prefixes,
2496 .flags = BACKEND_FLAG_JOBLIST,
2497 .cmdline_usage = mitsu70x_cmdline,
2498 .cmdline_arg = mitsu70x_cmdline_arg,
2499 .init = mitsu70x_init,
2500 .attach = mitsu70x_attach,
2501 .teardown = mitsu70x_teardown,
2502 .cleanup_job = mitsu70x_cleanup_job,
2503 .read_parse = mitsu70x_read_parse,
2504 .main_loop = mitsu70x_main_loop,
2505 .query_serno = mitsu70x_query_serno,
2506 .query_markers = mitsu70x_query_markers,
2507 .devices = {
2508 { USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, NULL, "mitsubishi-d70dw"},
2509 { USB_VID_MITSU, USB_PID_MITSU_K60, P_MITSU_K60, NULL, "mitsubishi-k60dw"},
2510 { USB_VID_MITSU, USB_PID_MITSU_D80, P_MITSU_D80, NULL, "mitsubishi-d80dw"},
2511 { USB_VID_KODAK, USB_PID_KODAK305, P_KODAK_305, NULL, "kodak-305"},
2512 { USB_VID_FUJIFILM, USB_PID_FUJI_ASK300, P_FUJI_ASK300, NULL, "fujifilm-ask-300"},
2513 { 0, 0, 0, NULL, NULL}
2514 }
2515 };
2516
2517 /* Mitsubish CP-D70DW/D707DW/K60DW-S/D80DW, Kodak 305, Fujifilm ASK-300
2518 data format:
2519
2520 Spool file consists of two headers followed by three image planes
2521 and an optional lamination data plane. All blocks are rounded up to
2522 a 512-byte boundary.
2523
2524 All multi-byte numbers are big endian, ie MSB first.
2525
2526 Header 1: (AKA Wake Up)
2527
2528 1b 45 57 55 00 00 00 00 00 00 00 00 00 00 00 00
2529 (padded by NULLs to a 512-byte boundary)
2530
2531 Header 2: (Print Header)
2532
2533 1b 5a 54 PP JJ JJ RR RR 00 00 00 00 00 00 00 00
2534 XX XX YY YY QQ QQ ZZ ZZ SS 00 00 00 00 00 00 00
2535 UU 00 00 00 00 00 00 00 LL TT 00 00 00 00 00 00
2536 MM 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2537
2538 (padded by NULLs to a 512-byte boundary)
2539
2540 PP == 0x01 on D70x/D80, 0x00 on K60, 0x90 on K305, 0x80 on ASK300
2541 JJ JJ == Job ID, can leave at 00 00
2542 XX XX == columns
2543 YY YY == rows
2544 QQ QQ == lamination columns (equal to XX XX)
2545 ZZ ZZ == lamination rows (YY YY + 12 on D70x/D80/ASK300, YY YY on others)
2546 RR RR == "rewind inhibit", 01 01 enabled, normally 00 00 (All but D70x/A300)
2547 SS == Print mode: 00 = Fine, 03 = SuperFine (D70x/D80 only), 04 = UltraFine
2548 (Matte requires Superfine or Ultrafine)
2549 UU == 00 = Auto, 01 = Lower Deck (required for !D70x), 02 = Upper Deck
2550 LL == lamination enable, 00 == on, 01 == off
2551 TT == lamination mode: 00 glossy, 02 matte
2552 MM == 00 (normal), 01 = (Double-cut 4x6), 05 = (double-cut 2x6)
2553
2554 Data planes:
2555 16-bit data, rounded up to 512-byte block (XX * YY * 2 bytes)
2556
2557 Lamination plane: (only present if QQ and ZZ are nonzero)
2558 16-byte data, rounded up to 512-byte block (QQ * ZZ * 2 bytes)
2559
2560 */
2561