2014-12-11 16:16:56 -05:00
|
|
|
/*
|
2016-10-13 12:50:30 -04:00
|
|
|
* Mitsubishi CP-9xxx Photo Printer Family CUPS backend
|
2014-12-11 16:16:56 -05:00
|
|
|
*
|
2020-01-26 00:24:33 -05:00
|
|
|
* (c) 2014-2020 Solomon Peachy <pizza@shaftnet.org>
|
2014-12-11 16:16:56 -05:00
|
|
|
*
|
|
|
|
* The latest version of this program can be found at:
|
|
|
|
*
|
|
|
|
* http://git.shaftnet.org/cgit/selphy_print.git
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 3 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2020-01-17 16:50:56 -05:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2014-12-11 16:16:56 -05:00
|
|
|
*
|
2017-11-17 13:34:26 -05:00
|
|
|
* SPDX-License-Identifier: GPL-3.0+
|
|
|
|
*
|
2014-12-11 16:16:56 -05:00
|
|
|
*/
|
|
|
|
|
2019-09-28 11:05:42 -04:00
|
|
|
#define BACKEND mitsu9550_backend
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2019-09-28 11:05:42 -04:00
|
|
|
#include "backend_common.h"
|
2020-02-05 13:22:26 -05:00
|
|
|
#include "backend_mitsu.h"
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2020-02-16 16:19:44 -05:00
|
|
|
#define MITSU_M98xx_LAMINATE_FILE "M98MATTE.raw"
|
|
|
|
#define MITSU_M98xx_DATATABLE_FILE "M98TABLE.dat"
|
|
|
|
#define MITSU_M98xx_LUT_FILE "M98XXL01.lut"
|
2020-06-03 23:15:04 -04:00
|
|
|
#define MITSU_CP30D_LUT_FILE "CP30LT_1.lut"
|
2018-01-21 21:36:29 -05:00
|
|
|
#define LAMINATE_STRIDE 1868
|
|
|
|
|
2019-02-26 07:23:14 -05:00
|
|
|
/* USB VIDs and PIDs */
|
|
|
|
|
|
|
|
#define USB_VID_MITSU 0x06D3
|
|
|
|
#define USB_PID_MITSU_9500D 0x0393
|
|
|
|
#define USB_PID_MITSU_9000D 0x0394
|
|
|
|
#define USB_PID_MITSU_9000AM 0x0395
|
|
|
|
#define USB_PID_MITSU_9550D 0x03A1
|
|
|
|
#define USB_PID_MITSU_9550DS 0x03A5 // or DZ/DZS/DZU
|
|
|
|
#define USB_PID_MITSU_9600D 0x03A9
|
|
|
|
//#define USB_PID_MITSU_9600DS XXXXXX
|
2020-12-03 21:40:10 -05:00
|
|
|
#define USB_PID_MITSU_CP30D 0x03AB
|
2019-02-26 07:23:14 -05:00
|
|
|
#define USB_PID_MITSU_9800D 0x03AD
|
|
|
|
#define USB_PID_MITSU_9800DS 0x03AE
|
|
|
|
#define USB_PID_MITSU_98__D 0x3B21
|
|
|
|
//#define USB_PID_MITSU_9810D XXXXXX
|
|
|
|
//#define USB_PID_MITSU_9820DS XXXXXX
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
/* Spool file structures */
|
2016-10-12 23:28:54 -04:00
|
|
|
|
|
|
|
/* Print parameters1 */
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_hdr1 {
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cmd[4]; /* 1b 57 20 2e */
|
2016-10-12 23:28:54 -04:00
|
|
|
uint8_t unk[10]; /* 00 0a 10 00 [...] */
|
2019-03-08 13:59:45 -05:00
|
|
|
uint16_t cols; /* BE */
|
|
|
|
uint16_t rows; /* BE */
|
|
|
|
uint8_t matte; /* CP9810/9820 only. 01 for matte, 00 glossy */
|
2016-10-12 20:29:02 -04:00
|
|
|
uint8_t null[31];
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
/* Print parameters2 */
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_hdr2 {
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cmd[4]; /* 1b 57 21 2e */
|
|
|
|
uint8_t unk[24]; /* 00 80 00 22 08 03 [...] */
|
|
|
|
uint16_t copies; /* BE, 1-680 */
|
2014-12-14 18:10:01 -05:00
|
|
|
uint8_t null[2];
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cut; /* 00 == normal, 83 == 2x6*2 */
|
2014-12-25 08:23:18 -05:00
|
|
|
uint8_t unkb[5];
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t mode; /* 00 == fine, 80 == superfine */
|
2020-03-01 08:50:15 -05:00
|
|
|
uint8_t unkc[11]; /* 00 [...] 00 01 ; note [7][8][9] are cp98xx extensions for sharpness/reversed/lut */
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
/* Fine Deep selection (9550 only) */
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_hdr3 {
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cmd[4]; /* 1b 57 22 2e */
|
|
|
|
uint8_t unk[7]; /* 00 40 00 [...] */
|
|
|
|
uint8_t mode2; /* 00 == normal, 01 == finedeep */
|
2016-09-28 14:15:04 -04:00
|
|
|
uint8_t null[38];
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
/* Error policy? */
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_hdr4 {
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cmd[4]; /* 1b 57 26 2e */
|
|
|
|
uint8_t unk[46]; /* 00 70 00 00 00 00 00 00 01 01 00 [...] */
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
/* Data plane header */
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_plane {
|
2019-03-08 13:59:45 -05:00
|
|
|
uint8_t cmd[4]; /* 1b 5a 54 XX */ /* XX == 0x10 if 16bpp, 0x00 for 8bpp */
|
2018-04-19 08:15:01 -04:00
|
|
|
uint16_t col_offset; /* BE, normally 0, where we start dumping data */
|
2016-10-23 09:32:43 -04:00
|
|
|
uint16_t row_offset; /* BE, normally 0, where we start dumping data */
|
|
|
|
uint16_t cols; /* BE */
|
|
|
|
uint16_t rows; /* BE */
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2018-04-18 20:52:32 -04:00
|
|
|
/* Command header */
|
2014-12-14 19:09:32 -05:00
|
|
|
struct mitsu9550_cmd {
|
|
|
|
uint8_t cmd[4];
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2017-05-05 08:06:28 -04:00
|
|
|
/* Private data structure */
|
2018-06-15 14:55:03 -04:00
|
|
|
struct mitsu9550_printjob {
|
2020-02-11 17:22:39 -05:00
|
|
|
size_t jobsize;
|
|
|
|
int copies;
|
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
uint8_t *databuf;
|
|
|
|
uint32_t datalen;
|
|
|
|
|
|
|
|
uint16_t rows;
|
|
|
|
uint16_t cols;
|
|
|
|
uint32_t plane_len;
|
2018-06-17 22:24:15 -04:00
|
|
|
int is_raw;
|
2016-10-13 08:12:20 -04:00
|
|
|
|
|
|
|
/* Parse headers separately */
|
|
|
|
struct mitsu9550_hdr1 hdr1;
|
|
|
|
int hdr1_present;
|
|
|
|
struct mitsu9550_hdr2 hdr2;
|
|
|
|
int hdr2_present;
|
|
|
|
struct mitsu9550_hdr3 hdr3;
|
|
|
|
int hdr3_present;
|
|
|
|
struct mitsu9550_hdr4 hdr4;
|
|
|
|
int hdr4_present;
|
2018-06-15 14:55:03 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct mitsu9550_ctx {
|
2020-08-11 20:27:26 -04:00
|
|
|
struct dyesub_connection *conn;
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
int is_s;
|
|
|
|
int is_98xx;
|
2020-05-18 14:00:49 -04:00
|
|
|
int footer_len;
|
2020-06-03 23:15:04 -04:00
|
|
|
const char *lut_fname;
|
2018-06-15 14:55:03 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
char fwver[7]; /* 6 + null */
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
struct marker marker;
|
2018-04-18 20:52:32 -04:00
|
|
|
|
|
|
|
/* CP98xx stuff */
|
2020-02-05 13:22:26 -05:00
|
|
|
struct mitsu_lib lib;
|
2020-02-08 22:38:27 -05:00
|
|
|
const struct mitsu98xx_data *m98xxdata;
|
2016-10-13 08:12:20 -04:00
|
|
|
};
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
/* Printer data structures */
|
2020-12-03 21:40:10 -05:00
|
|
|
#define CP9XXXX_STS_STS3 0x20
|
|
|
|
#define CP9XXXX_STS_STS2 0x21 /* mitsu9550_status2 */
|
|
|
|
#define CP9XXXX_STS_STS5 0x22
|
2020-12-04 20:02:44 -05:00
|
|
|
#define CP9XXXX_STS_FWVER 0x23
|
2020-12-03 21:40:10 -05:00
|
|
|
#define CP9XXXX_STS_MEDIA 0x24 /* mitsu9550_media */
|
|
|
|
#define CP9XXXX_STS_STS1 0x30 /* mitsu9550_status */
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_media {
|
2014-12-14 20:52:21 -05:00
|
|
|
uint8_t hdr[2]; /* 24 2e */
|
|
|
|
uint8_t unk[12];
|
|
|
|
uint8_t type;
|
|
|
|
uint8_t unka[13];
|
|
|
|
uint16_t max; /* BE, prints per media */
|
2020-12-03 21:40:10 -05:00
|
|
|
uint16_t remain2; /* BE, prints remaining (CP30)*/
|
|
|
|
uint16_t remain; /* BE, prints remaining (Everything else) */
|
2014-12-14 20:52:21 -05:00
|
|
|
uint8_t unkc[14];
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
struct mitsu9550_status {
|
2014-12-14 20:52:21 -05:00
|
|
|
uint8_t hdr[2]; /* 30 2e */
|
|
|
|
uint8_t null[4];
|
2014-12-15 09:11:41 -05:00
|
|
|
uint8_t sts1; // MM
|
2014-12-20 12:43:22 -05:00
|
|
|
uint8_t nullb[1];
|
2016-09-28 14:15:04 -04:00
|
|
|
uint16_t copies; // BE, NN
|
2016-10-31 14:02:23 -04:00
|
|
|
uint8_t sts2; // ZZ (9600 only?)
|
|
|
|
uint8_t nullc[5];
|
2014-12-15 09:11:41 -05:00
|
|
|
uint8_t sts3; // QQ
|
|
|
|
uint8_t sts4; // RR
|
|
|
|
uint8_t sts5; // SS
|
2014-12-14 20:52:21 -05:00
|
|
|
uint8_t nulld[25];
|
2014-12-15 09:11:41 -05:00
|
|
|
uint8_t sts6; // TT
|
|
|
|
uint8_t sts7; // UU
|
2014-12-14 20:52:21 -05:00
|
|
|
uint8_t nulle[2];
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
struct mitsu9550_status2 {
|
2018-05-01 14:40:17 -04:00
|
|
|
uint8_t hdr[2]; /* 21 2e / 24 2e on 9550/9800 */
|
2018-05-04 08:34:57 -04:00
|
|
|
uint8_t unk[40];
|
2016-10-31 13:44:56 -04:00
|
|
|
uint16_t remain; /* BE, media remaining */
|
2016-10-31 14:02:23 -04:00
|
|
|
uint8_t unkb[4]; /* 0a 00 00 01 */
|
2014-12-11 16:16:56 -05:00
|
|
|
} __attribute__((packed));
|
|
|
|
|
2018-06-19 09:04:17 -04:00
|
|
|
static int mitsu9550_main_loop(void *vctx, const void *vjob);
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
#define CMDBUF_LEN 64
|
|
|
|
#define READBACK_LEN 128
|
|
|
|
|
2016-08-17 21:16:15 -04:00
|
|
|
#define QUERY_STATUS() \
|
|
|
|
do {\
|
|
|
|
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;\
|
|
|
|
/* struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf; */ \
|
|
|
|
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf; \
|
2018-04-27 15:40:09 -04:00
|
|
|
uint16_t donor; \
|
2016-08-17 21:16:15 -04:00
|
|
|
/* media */ \
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_MEDIA); \
|
2016-08-17 21:16:15 -04:00
|
|
|
if (ret < 0) \
|
|
|
|
return CUPS_BACKEND_FAILED; \
|
|
|
|
\
|
2020-12-03 21:40:10 -05:00
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) { \
|
|
|
|
donor = be16_to_cpu(media->remain2); \
|
|
|
|
} else { \
|
|
|
|
donor = be16_to_cpu(media->remain); \
|
|
|
|
} \
|
2018-04-27 15:40:09 -04:00
|
|
|
if (donor != ctx->marker.levelnow) { \
|
|
|
|
ctx->marker.levelnow = donor; \
|
|
|
|
dump_markers(&ctx->marker, 1, 0); \
|
2016-08-19 17:40:12 -04:00
|
|
|
} \
|
2016-08-17 21:16:15 -04:00
|
|
|
/* Sanity-check media response */ \
|
2020-12-03 21:40:10 -05:00
|
|
|
if ((media->remain == 0 && media->remain2 == 0) || media->max == 0) { \
|
2016-08-17 21:16:15 -04:00
|
|
|
ERROR("Printer out of media!\n"); \
|
|
|
|
return CUPS_BACKEND_HOLD; \
|
|
|
|
} \
|
2020-08-11 20:27:26 -04:00
|
|
|
if (validate_media(ctx->conn->type, media->type, job->cols, job->rows)) { \
|
2018-06-15 14:55:03 -04:00
|
|
|
ERROR("Incorrect media (%u) type for printjob (%ux%u)!\n", media->type, job->cols, job->rows); \
|
2016-08-17 21:16:15 -04:00
|
|
|
return CUPS_BACKEND_HOLD; \
|
|
|
|
} \
|
|
|
|
/* status2 */ \
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS2); \
|
2016-08-17 21:16:15 -04:00
|
|
|
if (ret < 0) \
|
|
|
|
return CUPS_BACKEND_FAILED; \
|
|
|
|
/* status */ \
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS1); \
|
2016-08-17 21:16:15 -04:00
|
|
|
if (ret < 0) \
|
|
|
|
return CUPS_BACKEND_FAILED; \
|
|
|
|
\
|
|
|
|
/* Make sure we're idle */ \
|
|
|
|
if (sts->sts5 != 0) { /* Printer ready for another job */ \
|
|
|
|
sleep(1); \
|
|
|
|
goto top; \
|
|
|
|
} \
|
2016-10-31 14:02:23 -04:00
|
|
|
/* Check for known errors */ \
|
|
|
|
if (sts->sts2 != 0) { \
|
|
|
|
ERROR("Printer cover open!\n"); \
|
|
|
|
return CUPS_BACKEND_STOP; \
|
|
|
|
} \
|
2016-08-17 21:16:15 -04:00
|
|
|
} while (0);
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
static int mitsu98xx_fillmatte(struct mitsu9550_printjob *job)
|
2018-04-19 08:15:01 -04:00
|
|
|
{
|
2020-02-05 13:22:26 -05:00
|
|
|
int ret;
|
2018-04-19 08:15:01 -04:00
|
|
|
|
|
|
|
/* Fill in the lamination plane header */
|
2018-06-15 14:55:03 -04:00
|
|
|
struct mitsu9550_plane *matte = (struct mitsu9550_plane *)(job->databuf + job->datalen);
|
2018-04-19 08:15:01 -04:00
|
|
|
matte->cmd[0] = 0x1b;
|
|
|
|
matte->cmd[1] = 0x5a;
|
|
|
|
matte->cmd[2] = 0x54;
|
|
|
|
matte->cmd[3] = 0x10;
|
|
|
|
matte->row_offset = 0;
|
|
|
|
matte->col_offset = 0;
|
2018-09-26 21:05:47 -04:00
|
|
|
matte->cols = cpu_to_be16(job->hdr1.cols);
|
|
|
|
matte->rows = cpu_to_be16(job->hdr1.rows);
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sizeof(struct mitsu9550_plane);
|
2018-04-19 08:15:01 -04:00
|
|
|
|
2020-02-05 13:22:26 -05:00
|
|
|
ret = mitsu_readlamdata(MITSU_M98xx_LAMINATE_FILE, LAMINATE_STRIDE,
|
|
|
|
job->databuf, &job->datalen,
|
|
|
|
job->rows, job->cols, 2);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2018-04-19 08:15:01 -04:00
|
|
|
|
|
|
|
/* Fill in the lamination plane footer */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->databuf[job->datalen++] = 0x1b;
|
|
|
|
job->databuf[job->datalen++] = 0x50;
|
|
|
|
job->databuf[job->datalen++] = 0x56;
|
|
|
|
job->databuf[job->datalen++] = 0x00;
|
2018-04-19 08:15:01 -04:00
|
|
|
|
|
|
|
return CUPS_BACKEND_OK;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int type);
|
2020-03-24 18:22:39 -04:00
|
|
|
static const char *mitsu9550_media_types(uint8_t type, uint8_t is_s);
|
2018-04-19 08:15:01 -04:00
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
static void *mitsu9550_init(void)
|
|
|
|
{
|
|
|
|
struct mitsu9550_ctx *ctx = malloc(sizeof(struct mitsu9550_ctx));
|
2015-06-23 20:32:41 -04:00
|
|
|
if (!ctx) {
|
|
|
|
ERROR("Memory Allocation Failure!\n");
|
2014-12-11 16:16:56 -05:00
|
|
|
return NULL;
|
2015-06-23 20:32:41 -04:00
|
|
|
}
|
2014-12-11 16:16:56 -05:00
|
|
|
memset(ctx, 0, sizeof(struct mitsu9550_ctx));
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
static int mitsu9550_attach(void *vctx, struct dyesub_connection *conn, uint8_t jobid)
|
2014-12-11 16:16:56 -05:00
|
|
|
{
|
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
2018-04-27 15:40:09 -04:00
|
|
|
struct mitsu9550_media media;
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
UNUSED(jobid);
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
ctx->conn = conn;
|
2016-08-17 21:16:15 -04:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9550S ||
|
|
|
|
ctx->conn->type == P_MITSU_9800S)
|
2016-10-14 07:42:24 -04:00
|
|
|
ctx->is_s = 1;
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9800 ||
|
|
|
|
ctx->conn->type == P_MITSU_9800S ||
|
|
|
|
ctx->conn->type == P_MITSU_9810) {
|
2018-04-18 20:52:32 -04:00
|
|
|
ctx->is_98xx = 1;
|
2020-06-03 23:15:04 -04:00
|
|
|
ctx->lut_fname = MITSU_M98xx_LUT_FILE;
|
|
|
|
}
|
2018-04-18 20:52:32 -04:00
|
|
|
|
2020-02-27 11:53:31 -05:00
|
|
|
if (ctx->is_98xx) {
|
2020-02-05 13:22:26 -05:00
|
|
|
#if defined(WITH_DYNAMIC)
|
2020-02-27 11:53:31 -05:00
|
|
|
/* Attempt to open the library */
|
2020-08-11 20:27:26 -04:00
|
|
|
if (mitsu_loadlib(&ctx->lib, ctx->conn->type))
|
2019-02-26 07:23:14 -05:00
|
|
|
#endif
|
2020-02-27 11:53:31 -05:00
|
|
|
WARNING("Dynamic library support not loaded, will be unable to print.");
|
|
|
|
}
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) {
|
2020-05-18 14:00:49 -04:00
|
|
|
ctx->footer_len = 6;
|
2020-06-03 23:15:04 -04:00
|
|
|
ctx->lut_fname = MITSU_CP30D_LUT_FILE;
|
|
|
|
} else {
|
2020-05-18 14:00:49 -04:00
|
|
|
ctx->footer_len = 4;
|
2020-06-03 23:15:04 -04:00
|
|
|
}
|
2020-05-18 14:00:49 -04:00
|
|
|
|
2018-05-12 12:17:24 -04:00
|
|
|
if (test_mode < TEST_MODE_NOATTACH) {
|
2020-12-04 20:02:44 -05:00
|
|
|
uint8_t buf[48];
|
2020-12-03 21:40:10 -05:00
|
|
|
if (mitsu9550_get_status(ctx, (uint8_t*) &media, CP9XXXX_STS_MEDIA))
|
2018-05-12 12:17:24 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2020-12-04 20:02:44 -05:00
|
|
|
|
|
|
|
/* Get FW Version */
|
|
|
|
if (mitsu9550_get_status(ctx, buf, CP9XXXX_STS_FWVER))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
memcpy(ctx->fwver, &buf[6], 6);
|
|
|
|
ctx->fwver[6] = 0;
|
|
|
|
// XXX get serial number too?
|
2018-05-12 12:17:24 -04:00
|
|
|
} else {
|
2018-09-21 15:20:38 -04:00
|
|
|
int media_code = 0x2;
|
|
|
|
if (getenv("MEDIA_CODE"))
|
|
|
|
media_code = atoi(getenv("MEDIA_CODE")) & 0xf;
|
|
|
|
|
2018-05-12 12:17:24 -04:00
|
|
|
media.max = cpu_to_be16(400);
|
2018-05-12 18:33:39 -04:00
|
|
|
media.remain = cpu_to_be16(330);
|
2020-12-03 21:40:10 -05:00
|
|
|
media.remain2 = cpu_to_be16(330);
|
2018-09-21 15:20:38 -04:00
|
|
|
media.type = media_code;
|
2020-12-04 20:02:44 -05:00
|
|
|
ctx->fwver[0] = 0;
|
2018-05-12 12:17:24 -04:00
|
|
|
}
|
|
|
|
|
2018-04-27 15:40:09 -04:00
|
|
|
ctx->marker.color = "#00FFFF#FF00FF#FFFF00";
|
|
|
|
ctx->marker.name = mitsu9550_media_types(media.type, ctx->is_s);
|
2019-09-28 10:54:10 -04:00
|
|
|
ctx->marker.numtype = media.type;
|
2018-04-27 15:40:09 -04:00
|
|
|
ctx->marker.levelmax = be16_to_cpu(media.max);
|
2020-12-03 21:40:10 -05:00
|
|
|
|
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) {
|
|
|
|
ctx->marker.levelnow = be16_to_cpu(media.remain2);
|
|
|
|
} else {
|
|
|
|
ctx->marker.levelnow = be16_to_cpu(media.remain);
|
|
|
|
}
|
2018-04-27 15:07:43 -04:00
|
|
|
|
|
|
|
return CUPS_BACKEND_OK;
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
static void mitsu9550_cleanup_job(const void *vjob)
|
|
|
|
{
|
|
|
|
const struct mitsu9550_printjob *job = vjob;
|
|
|
|
|
|
|
|
if (job->databuf)
|
|
|
|
free(job->databuf);
|
|
|
|
|
|
|
|
free((void*)job);
|
|
|
|
}
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
static void mitsu9550_teardown(void *vctx) {
|
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return;
|
|
|
|
|
2020-02-05 13:22:26 -05:00
|
|
|
if (ctx->m98xxdata)
|
2020-02-08 22:38:27 -05:00
|
|
|
ctx->lib.CP98xx_DestroyData(ctx->m98xxdata);
|
2020-02-05 13:22:26 -05:00
|
|
|
|
|
|
|
mitsu_destroylib(&ctx->lib);
|
2019-02-26 07:23:14 -05:00
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
static int mitsu9550_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
2016-10-13 08:12:20 -04:00
|
|
|
uint8_t buf[sizeof(struct mitsu9550_hdr1)];
|
2014-12-11 16:16:56 -05:00
|
|
|
int remain, i;
|
2016-10-23 09:32:43 -04:00
|
|
|
uint32_t planelen = 0;
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
struct mitsu9550_printjob *job = NULL;
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
if (!ctx)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
job = malloc(sizeof(*job));
|
|
|
|
if (!job) {
|
|
|
|
ERROR("Memory allocation failure!\n");
|
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
2018-06-15 14:55:03 -04:00
|
|
|
memset(job, 0, sizeof(*job));
|
2018-06-17 22:24:15 -04:00
|
|
|
job->is_raw = 1;
|
2020-02-11 17:22:39 -05:00
|
|
|
job->jobsize = sizeof(*job);
|
|
|
|
job->copies = copies;
|
2016-10-13 08:12:20 -04:00
|
|
|
|
|
|
|
top:
|
2014-12-11 16:16:56 -05:00
|
|
|
/* Read in initial header */
|
2016-10-13 08:12:20 -04:00
|
|
|
remain = sizeof(buf);
|
2014-12-11 16:16:56 -05:00
|
|
|
while (remain > 0) {
|
2016-10-13 08:12:20 -04:00
|
|
|
i = read(data_fd, buf + sizeof(buf) - remain, remain);
|
2018-06-17 21:08:17 -04:00
|
|
|
if (i == 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
|
|
|
if (i < 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
2014-12-11 16:16:56 -05:00
|
|
|
remain -= i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity check */
|
2016-10-13 08:12:20 -04:00
|
|
|
if (buf[0] != 0x1b || buf[1] != 0x57 || buf[3] != 0x2e) {
|
2018-06-15 14:55:03 -04:00
|
|
|
if (!job->hdr1_present || !job->hdr2_present) {
|
2018-05-02 15:45:46 -04:00
|
|
|
ERROR("Unrecognized data format (%02x%02x%02x%02x)!\n",
|
|
|
|
buf[0], buf[1], buf[2], buf[3]);
|
2018-06-17 21:08:17 -04:00
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-13 08:12:20 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-05-02 15:45:46 -04:00
|
|
|
} else if (buf[0] == 0x1b &&
|
|
|
|
buf[1] == 0x5a &&
|
2016-10-14 07:42:24 -04:00
|
|
|
buf[2] == 0x54) {
|
2016-10-23 09:32:43 -04:00
|
|
|
|
|
|
|
/* We're in the data portion now */
|
|
|
|
if (buf[3] == 0x10)
|
|
|
|
planelen *= 2;
|
2018-04-19 08:15:01 -04:00
|
|
|
else if (ctx->is_98xx && buf[3] == 0x80)
|
2018-06-17 22:24:15 -04:00
|
|
|
job->is_raw = 0;
|
2016-10-23 09:32:43 -04:00
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
goto hdr_done;
|
|
|
|
} else {
|
2018-05-02 15:45:46 -04:00
|
|
|
ERROR("Unrecognized data block (%02x%02x%02x%02x)!\n",
|
|
|
|
buf[0], buf[1], buf[2], buf[3]);
|
2018-06-17 21:08:17 -04:00
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-13 08:12:20 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(buf[2]) {
|
|
|
|
case 0x20: /* header 1 */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(&job->hdr1, buf, sizeof(job->hdr1));
|
|
|
|
job->hdr1_present = 1;
|
2016-10-23 09:32:43 -04:00
|
|
|
|
|
|
|
/* Work out printjob size */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->rows = be16_to_cpu(job->hdr1.rows);
|
|
|
|
job->cols = be16_to_cpu(job->hdr1.cols);
|
|
|
|
planelen = job->rows * job->cols;
|
2016-10-23 09:32:43 -04:00
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
break;
|
|
|
|
case 0x21: /* header 2 */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(&job->hdr2, buf, sizeof(job->hdr2));
|
|
|
|
job->hdr2_present = 1;
|
2016-10-13 08:12:20 -04:00
|
|
|
break;
|
|
|
|
case 0x22: /* header 3 */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(&job->hdr3, buf, sizeof(job->hdr3));
|
|
|
|
job->hdr3_present = 1;
|
2016-10-13 08:12:20 -04:00
|
|
|
break;
|
|
|
|
case 0x26: /* header 4 */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(&job->hdr4, buf, sizeof(job->hdr4));
|
|
|
|
job->hdr4_present = 1;
|
2016-10-13 08:12:20 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ERROR("Unrecognized header format (%02x)!\n", buf[2]);
|
2018-06-17 21:08:17 -04:00
|
|
|
mitsu9550_cleanup_job(job);
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
/* Read in the next chunk */
|
|
|
|
goto top;
|
|
|
|
|
|
|
|
hdr_done:
|
|
|
|
|
2018-04-18 20:52:32 -04:00
|
|
|
/* Read in CP98xx data tables if necessary */
|
2018-06-17 22:24:15 -04:00
|
|
|
if (ctx->is_98xx && !job->is_raw && !ctx->m98xxdata) {
|
2020-02-16 16:19:44 -05:00
|
|
|
char full[2048];
|
2020-02-27 11:53:31 -05:00
|
|
|
|
|
|
|
if (!ctx->lib.dl_handle) {
|
|
|
|
ERROR("!!! Image Processing Library not found, aborting!\n");
|
|
|
|
mitsu9550_cleanup_job(job);
|
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2020-02-16 16:19:44 -05:00
|
|
|
snprintf(full, sizeof(full), "%s/%s", corrtable_path, MITSU_M98xx_DATATABLE_FILE);
|
|
|
|
|
2019-01-13 15:44:29 -05:00
|
|
|
DEBUG("Reading in 98xx data from disk\n");
|
2020-02-16 16:19:44 -05:00
|
|
|
ctx->m98xxdata = ctx->lib.CP98xx_GetData(full);
|
2020-02-08 22:38:27 -05:00
|
|
|
if (!ctx->m98xxdata) {
|
2020-02-17 10:33:37 -05:00
|
|
|
ERROR("Unable to read 98xx data table file '%s'\n", full);
|
2019-03-08 13:59:45 -05:00
|
|
|
}
|
2018-04-18 20:52:32 -04:00
|
|
|
}
|
|
|
|
|
2018-06-17 22:24:15 -04:00
|
|
|
if (job->is_raw) {
|
2018-05-02 15:45:46 -04:00
|
|
|
/* We have three planes + headers and the final terminator to read */
|
2018-05-01 17:51:13 -04:00
|
|
|
remain = 3 * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd);
|
|
|
|
} else {
|
2018-05-02 15:45:46 -04:00
|
|
|
/* We have one plane + header and the final terminator to read */
|
2018-05-01 17:51:13 -04:00
|
|
|
remain = planelen * 3 + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mitsu9600 windows spool uses more, smaller blocks, but plane data is the same */
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9600) {
|
2018-05-01 17:51:13 -04:00
|
|
|
remain += 128 * sizeof(struct mitsu9550_plane); /* 39 extra seen on 4x6" */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 9550S/9800S doesn't typically sent over hdr4! */
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9550S ||
|
|
|
|
ctx->conn->type == P_MITSU_9800S) {
|
2018-05-01 17:51:13 -04:00
|
|
|
/* XXX Has to do with error policy, but not sure what.
|
|
|
|
Mitsu9550-S/9800-S will set this based on a command,
|
|
|
|
but it's not part of the standard job spool */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->hdr4_present = 0;
|
2018-05-01 17:51:13 -04:00
|
|
|
}
|
|
|
|
|
2018-04-19 08:15:01 -04:00
|
|
|
/* Disable matte if the printer doesn't support it */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr1.matte) {
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type != P_MITSU_9810) {
|
2018-04-19 08:15:01 -04:00
|
|
|
WARNING("Matte not supported on this printer, disabling\n");
|
2018-06-15 14:55:03 -04:00
|
|
|
job->hdr1.matte = 0;
|
2018-06-17 22:24:15 -04:00
|
|
|
} else if (job->is_raw) {
|
2018-04-19 08:15:01 -04:00
|
|
|
remain += planelen + sizeof(struct mitsu9550_plane) + sizeof(struct mitsu9550_cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-23 09:32:43 -04:00
|
|
|
/* Allocate buffer for the payload */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen = 0;
|
|
|
|
job->databuf = malloc(remain);
|
|
|
|
if (!job->databuf) {
|
2014-12-11 16:16:56 -05:00
|
|
|
ERROR("Memory allocation failure!\n");
|
2018-06-17 21:08:17 -04:00
|
|
|
mitsu9550_cleanup_job(job);
|
2018-02-16 10:49:21 -05:00
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
|
2016-10-23 09:32:43 -04:00
|
|
|
/* Load up the data blocks.*/
|
|
|
|
while(1) {
|
2016-10-23 11:59:29 -04:00
|
|
|
/* Note that 'buf' needs to be already filled here! */
|
2016-10-23 09:32:43 -04:00
|
|
|
struct mitsu9550_plane *plane = (struct mitsu9550_plane *)buf;
|
|
|
|
|
|
|
|
/* Sanity check header... */
|
|
|
|
if (plane->cmd[0] != 0x1b ||
|
|
|
|
plane->cmd[1] != 0x5a ||
|
|
|
|
plane->cmd[2] != 0x54) {
|
2018-05-09 10:47:19 -04:00
|
|
|
ERROR("Unrecognized data read (%02x%02x%02x%02x)!\n",
|
|
|
|
plane->cmd[0], plane->cmd[1], plane->cmd[2], plane->cmd[3]);
|
2018-06-17 21:08:17 -04:00
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-23 09:32:43 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Work out the length of this block */
|
|
|
|
planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
|
|
|
|
if (plane->cmd[3] == 0x10)
|
|
|
|
planelen *= 2;
|
2018-05-09 11:04:57 -04:00
|
|
|
if (plane->cmd[3] == 0x80)
|
|
|
|
planelen *= 3;
|
2016-10-23 09:32:43 -04:00
|
|
|
|
|
|
|
/* Copy plane header into buffer */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(job->databuf + job->datalen, buf, sizeof(buf));
|
|
|
|
job->datalen += sizeof(buf);
|
2016-10-23 11:59:29 -04:00
|
|
|
planelen -= sizeof(buf) - sizeof(struct mitsu9550_plane);
|
2016-10-23 09:32:43 -04:00
|
|
|
|
|
|
|
/* Read in the spool data */
|
|
|
|
while(planelen > 0) {
|
2018-06-15 14:55:03 -04:00
|
|
|
i = read(data_fd, job->databuf + job->datalen, planelen);
|
2018-06-17 21:08:17 -04:00
|
|
|
if (i == 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-23 09:32:43 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
|
|
|
if (i < 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-23 09:32:43 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += i;
|
2016-10-23 09:32:43 -04:00
|
|
|
planelen -= i;
|
|
|
|
}
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-23 09:32:43 -04:00
|
|
|
/* Try to read in the next chunk. It will be one of:
|
|
|
|
- Additional block header (12B)
|
|
|
|
- Job footer (4B)
|
|
|
|
*/
|
2020-05-18 14:00:49 -04:00
|
|
|
i = read(data_fd, buf, ctx->footer_len);
|
2018-06-17 21:08:17 -04:00
|
|
|
if (i == 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
|
|
|
if (i < 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-23 09:32:43 -04:00
|
|
|
/* Is this a "job end" marker? */
|
2018-05-02 15:45:46 -04:00
|
|
|
if (plane->cmd[0] == 0x1b &&
|
|
|
|
plane->cmd[1] == 0x50 &&
|
|
|
|
plane->cmd[3] == 0x00) {
|
2016-10-23 09:32:43 -04:00
|
|
|
/* store it in the buffer */
|
2020-05-18 14:00:49 -04:00
|
|
|
memcpy(job->databuf + job->datalen, buf, ctx->footer_len);
|
|
|
|
job->datalen += ctx->footer_len;
|
2016-10-23 09:32:43 -04:00
|
|
|
|
2018-09-26 21:05:47 -04:00
|
|
|
/* Unless we have a raw matte plane following,
|
|
|
|
we're done */
|
|
|
|
if (job->hdr1.matte != 0x01 ||
|
|
|
|
!job->is_raw)
|
2016-10-23 09:32:43 -04:00
|
|
|
break;
|
2018-05-15 08:48:39 -04:00
|
|
|
remain = sizeof(buf);
|
2016-10-23 09:32:43 -04:00
|
|
|
} else {
|
|
|
|
/* It's part of a block header, mark what we've read */
|
2020-05-18 14:00:49 -04:00
|
|
|
remain = sizeof(buf) - ctx->footer_len;
|
2016-10-23 09:32:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in the rest of the header */
|
2018-05-15 08:48:39 -04:00
|
|
|
while (remain > 0) {
|
|
|
|
i = read(data_fd, buf + sizeof(buf) - remain, remain);
|
2018-06-17 21:08:17 -04:00
|
|
|
if (i == 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-23 09:32:43 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
|
|
|
if (i < 0) {
|
|
|
|
mitsu9550_cleanup_job(job);
|
2016-10-23 09:32:43 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2018-06-17 21:08:17 -04:00
|
|
|
}
|
2018-05-15 08:48:39 -04:00
|
|
|
remain -= i;
|
2016-10-23 09:32:43 -04:00
|
|
|
}
|
2016-10-13 08:12:20 -04:00
|
|
|
}
|
|
|
|
|
2019-02-26 07:23:14 -05:00
|
|
|
/* Apply LUT, if job calls for it.. */
|
2020-06-03 23:15:04 -04:00
|
|
|
if (ctx->lut_fname && !job->is_raw && job->hdr2.unkc[9]) {
|
|
|
|
int ret = mitsu_apply3dlut(&ctx->lib, ctx->lut_fname,
|
2020-02-05 13:22:26 -05:00
|
|
|
job->databuf + sizeof(struct mitsu9550_plane),
|
|
|
|
job->cols, job->rows,
|
2020-06-04 13:20:51 -04:00
|
|
|
job->cols * 3, COLORCONV_BGR);
|
2020-02-05 13:22:26 -05:00
|
|
|
if (ret) {
|
2019-02-26 07:23:14 -05:00
|
|
|
mitsu9550_cleanup_job(job);
|
2020-02-05 13:22:26 -05:00
|
|
|
return ret;
|
2018-01-21 21:36:29 -05:00
|
|
|
}
|
2019-02-26 07:23:14 -05:00
|
|
|
|
2018-06-17 22:24:15 -04:00
|
|
|
job->hdr2.unkc[9] = 0;
|
2018-01-21 21:36:29 -05:00
|
|
|
}
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
/* Update printjob header to reflect number of requested copies */
|
|
|
|
if (job->hdr2_present) {
|
|
|
|
copies = 1;
|
2019-10-18 14:17:51 -04:00
|
|
|
if (be16_to_cpu(job->hdr2.copies) < copies)
|
|
|
|
job->hdr2.copies = cpu_to_be16(copies);
|
2018-06-15 14:55:03 -04:00
|
|
|
}
|
|
|
|
job->copies = copies;
|
|
|
|
|
2018-06-19 09:04:17 -04:00
|
|
|
/* All further work is in main loop */
|
|
|
|
if (test_mode >= TEST_MODE_NOPRINT)
|
|
|
|
mitsu9550_main_loop(ctx, job);
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
*vjob = job;
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, uint8_t *resp, int type)
|
2014-12-11 16:16:56 -05:00
|
|
|
{
|
2014-12-15 09:11:41 -05:00
|
|
|
struct mitsu9550_cmd cmd;
|
2014-12-14 20:52:21 -05:00
|
|
|
int num, ret;
|
|
|
|
|
|
|
|
/* Send Printer Query */
|
2014-12-15 09:11:41 -05:00
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x56;
|
2020-12-03 21:40:10 -05:00
|
|
|
cmd.cmd[2] = type;
|
2014-12-15 09:11:41 -05:00
|
|
|
cmd.cmd[3] = 0x00;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2014-12-15 09:11:41 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
2014-12-14 20:52:21 -05:00
|
|
|
return ret;
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = read_data(ctx->conn,
|
2014-12-17 11:43:38 -05:00
|
|
|
resp, sizeof(struct mitsu9550_status), &num);
|
2014-12-14 20:52:21 -05:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2014-12-15 09:11:41 -05:00
|
|
|
if (num != sizeof(struct mitsu9550_status)) {
|
|
|
|
ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(struct mitsu9550_status));
|
2014-12-14 20:52:21 -05:00
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2019-12-12 07:15:25 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
2014-12-14 20:52:21 -05:00
|
|
|
}
|
|
|
|
|
2020-03-24 18:22:39 -04:00
|
|
|
static const char *mitsu9550_media_types(uint8_t type, uint8_t is_s)
|
2016-08-19 17:40:12 -04:00
|
|
|
{
|
2016-10-14 07:42:24 -04:00
|
|
|
if (is_s) {
|
|
|
|
switch (type & 0xf) { /* values can be 0x0? or 0x4? */
|
|
|
|
case 0x02:
|
|
|
|
return "CK9015 (4x6)";
|
|
|
|
case 0x04:
|
|
|
|
return "CK9318 (5x7)";
|
|
|
|
case 0x05:
|
|
|
|
return "CK9523 (6x9)";
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2016-09-28 14:15:04 -04:00
|
|
|
switch (type & 0xf) { /* values can be 0x0? or 0x4? */
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x01:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9035 (3.5x5)";
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x02:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9046 (4x6)";
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x03:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9046PST (4x6)";
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x04:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9057 (5x7)";
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x05:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9069 (6x9)";
|
2016-08-19 17:40:12 -04:00
|
|
|
case 0x06:
|
2016-09-28 14:15:04 -04:00
|
|
|
return "CK9068 (6x8)";
|
2016-08-19 17:40:12 -04:00
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-14 13:25:25 -04:00
|
|
|
static int validate_media(int type, int media, int cols, int rows)
|
|
|
|
{
|
2015-01-17 08:46:50 -05:00
|
|
|
switch(type) {
|
2016-10-14 13:25:25 -04:00
|
|
|
case P_MITSU_9550:
|
|
|
|
switch(media & 0xf) {
|
|
|
|
case 0x01: /* 3.5x5 */
|
|
|
|
if (cols != 1812 && rows != 1240)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x02: /* 4x6 */
|
2017-07-10 20:15:56 -04:00
|
|
|
case 0x03: /* 4x6 postcard */
|
2016-10-14 13:25:25 -04:00
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 1184 && rows != 1240)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x04: /* 5x7 */
|
|
|
|
if (cols != 1812)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1240 && rows != 2452)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x05: /* 6x9 */
|
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 2792 &&
|
|
|
|
rows != 2956 && rows != 3146)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x06: /* V (6x8??) */
|
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 2792)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default: /* Unknown */
|
|
|
|
WARNING("Unknown media type %02x\n", media);
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
break;
|
2016-10-17 14:59:44 -04:00
|
|
|
case P_MITSU_9550S:
|
|
|
|
switch(media & 0xf) {
|
|
|
|
case 0x02: /* 4x6 */
|
|
|
|
case 0x03: /* 4x6 postcard */
|
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 1184 && rows != 1240)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x04: /* 5x7 */
|
|
|
|
if (cols != 1812 && rows != 2452)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x05: /* 6x9 */
|
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 2792 &&
|
|
|
|
rows != 2956 && rows != 3146)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x06: /* V (6x8??) */
|
|
|
|
if (cols != 2152)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1416 && rows != 2792)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default: /* Unknown */
|
|
|
|
WARNING("Unknown media type %02x\n", media);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case P_MITSU_9600: // XXX 9600S doesn't support 5" media at all!
|
2016-10-14 13:25:25 -04:00
|
|
|
switch(media & 0xf) {
|
|
|
|
case 0x01: /* 3.5x5 */
|
|
|
|
if (cols == 1572) {
|
|
|
|
if (rows == 1076)
|
|
|
|
break;
|
|
|
|
} else if (cols == 3144) {
|
|
|
|
if (rows == 2152)
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
return 1;
|
2016-10-14 13:25:25 -04:00
|
|
|
case 0x02: /* 4x6 */
|
|
|
|
case 0x03: /* 4x6 postcard */
|
|
|
|
if (cols == 1868) {
|
|
|
|
if (rows == 1228)
|
|
|
|
break;
|
|
|
|
} else if (cols == 3736) {
|
|
|
|
if (rows == 2458)
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
return 1;
|
2016-10-14 13:25:25 -04:00
|
|
|
case 0x04: /* 5x7 */
|
|
|
|
if (cols == 1572) {
|
|
|
|
if (rows == 1076 || rows == 2128)
|
|
|
|
break;
|
|
|
|
} else if (cols == 3144) {
|
|
|
|
if (rows == 2152 || rows == 4256)
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
return 1;
|
2016-10-14 13:25:25 -04:00
|
|
|
case 0x05: /* 6x9 */
|
|
|
|
if (cols == 1868) {
|
|
|
|
if (rows == 1228 || rows == 2442 || rows == 2564 || rows == 2730)
|
|
|
|
break;
|
|
|
|
} else if (cols == 3736) {
|
|
|
|
if (rows == 2458 || rows == 4846 || rows == 5130 || rows == 5462)
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
return 1;
|
2016-10-14 13:25:25 -04:00
|
|
|
case 0x06: /* V (6x8??) */
|
|
|
|
if (cols == 1868) {
|
|
|
|
if (rows == 1228 || rows == 2442)
|
|
|
|
break;
|
|
|
|
} else if (cols == 3736) {
|
|
|
|
if (rows == 2458 || rows == 4846)
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
return 1;
|
2016-10-14 13:25:25 -04:00
|
|
|
default: /* Unknown */
|
|
|
|
WARNING("Unknown media type %02x\n", media);
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
break;
|
2016-10-14 13:25:25 -04:00
|
|
|
case P_MITSU_9800:
|
2019-10-28 20:32:09 -04:00
|
|
|
case P_MITSU_9810:
|
|
|
|
// case P_MITSU_9820S:
|
2016-10-14 13:25:25 -04:00
|
|
|
switch(media & 0xf) {
|
|
|
|
case 0x01: /* 3.5x5 */
|
|
|
|
if (cols != 1572 && rows != 1076)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x02: /* 4x6 */
|
2016-10-17 14:59:44 -04:00
|
|
|
case 0x03: /* 4x6 postcard */
|
2016-10-14 13:25:25 -04:00
|
|
|
if (cols != 1868 && rows != 1228)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x04: /* 5x7 */
|
2016-10-17 14:59:44 -04:00
|
|
|
if (cols != 1572 && rows != 2128)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x05: /* 6x9 */
|
|
|
|
if (cols != 1868)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1228 && rows != 2442 &&
|
|
|
|
rows != 2564 && rows != 2730)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x06: /* V (6x8??) */
|
|
|
|
if (cols != 1868)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1228 && rows != 2442)
|
2016-10-14 13:25:25 -04:00
|
|
|
return 1;
|
2016-10-17 14:59:44 -04:00
|
|
|
break;
|
|
|
|
default: /* Unknown */
|
|
|
|
WARNING("Unknown media type %02x\n", media);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case P_MITSU_9800S:
|
|
|
|
switch(media & 0xf) {
|
|
|
|
case 0x02: /* 4x6 */
|
2017-07-10 20:15:56 -04:00
|
|
|
case 0x03: /* 4x6 postcard */
|
2016-10-17 14:59:44 -04:00
|
|
|
if (cols != 1868 && rows != 1228)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x04: /* 5x7 */
|
|
|
|
if (cols != 1572 && rows != 2128)
|
2016-10-14 13:25:25 -04:00
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x05: /* 6x9 */
|
|
|
|
if (cols != 1868)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1228 && rows != 2442 &&
|
|
|
|
rows != 2564 && rows != 2730)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case 0x06: /* V (6x8??) */
|
|
|
|
if (cols != 1868)
|
|
|
|
return 1;
|
|
|
|
if (rows != 1228 && rows != 2442)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default: /* Unknown */
|
|
|
|
WARNING("Unknown media type %02x\n", media);
|
|
|
|
break;
|
|
|
|
}
|
2015-01-17 08:46:50 -05:00
|
|
|
break;
|
2020-05-18 14:00:49 -04:00
|
|
|
case P_MITSU_CP30D:
|
|
|
|
if (cols != 1600)
|
|
|
|
return 1;
|
|
|
|
// XXX validate media type vs job size. Don't know readback codes.
|
|
|
|
// S == 1600x1200
|
2020-12-03 21:40:10 -05:00
|
|
|
// L == 1600x2100 ( type 00 ?)
|
2020-05-18 14:00:49 -04:00
|
|
|
break;
|
2016-10-14 13:25:25 -04:00
|
|
|
default:
|
|
|
|
WARNING("Unknown printer type %d\n", type);
|
2015-01-17 08:46:50 -05:00
|
|
|
break;
|
|
|
|
}
|
2019-12-12 07:15:25 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
2015-01-17 08:46:50 -05:00
|
|
|
}
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
static int mitsu9550_main_loop(void *vctx, const void *vjob) {
|
2014-12-11 16:16:56 -05:00
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
2014-12-15 08:25:05 -05:00
|
|
|
struct mitsu9550_cmd cmd;
|
|
|
|
uint8_t rdbuf[READBACK_LEN];
|
|
|
|
uint8_t *ptr;
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
int ret;
|
2018-06-15 14:55:03 -04:00
|
|
|
#if 0
|
2019-10-18 14:17:51 -04:00
|
|
|
int copies = 1;
|
2018-06-15 14:55:03 -04:00
|
|
|
#endif
|
|
|
|
|
2019-10-28 20:32:09 -04:00
|
|
|
struct mitsu9550_printjob *job = (struct mitsu9550_printjob*) vjob;
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2018-06-15 14:55:03 -04:00
|
|
|
if (!job)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2014-12-15 08:25:05 -05:00
|
|
|
|
2016-10-13 08:12:20 -04:00
|
|
|
/* Okay, let's do this thing */
|
2018-06-15 14:55:03 -04:00
|
|
|
ptr = job->databuf;
|
|
|
|
|
2018-06-17 22:24:15 -04:00
|
|
|
/* Do the 98xx processing here */
|
2018-06-19 09:04:17 -04:00
|
|
|
if (!ctx->is_98xx || job->is_raw)
|
2020-02-08 22:38:27 -05:00
|
|
|
goto non_98xx;
|
2018-06-19 09:04:17 -04:00
|
|
|
|
2020-02-08 22:38:27 -05:00
|
|
|
/* Special CP98xx handling code */
|
2018-06-19 09:04:17 -04:00
|
|
|
uint8_t *newbuf;
|
|
|
|
uint32_t newlen = 0;
|
|
|
|
int i, remain, planelen;
|
|
|
|
|
|
|
|
planelen = job->rows * job->cols * 2;
|
2018-09-30 10:40:20 -04:00
|
|
|
remain = (job->hdr1.matte ? 4 : 3) * (planelen + sizeof(struct mitsu9550_plane)) + sizeof(struct mitsu9550_cmd) * (job->hdr1.matte? 2 : 1) + LAMINATE_STRIDE * 2;
|
2018-06-19 09:04:17 -04:00
|
|
|
newbuf = malloc(remain);
|
|
|
|
if (!newbuf) {
|
|
|
|
ERROR("Memory allocation Failure!\n");
|
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
|
|
|
}
|
2020-02-08 22:38:27 -05:00
|
|
|
|
|
|
|
DEBUG("Running print data through processing library\n");
|
|
|
|
|
|
|
|
/* Create band images for input and output */
|
|
|
|
struct BandImage input;
|
|
|
|
struct BandImage output;
|
|
|
|
|
|
|
|
uint8_t *convbuf = malloc(planelen * 3);
|
|
|
|
if (!convbuf) {
|
|
|
|
free(newbuf);
|
|
|
|
ERROR("Memory allocation Failure!\n");
|
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
2018-06-19 09:04:17 -04:00
|
|
|
}
|
2018-06-17 22:24:15 -04:00
|
|
|
|
2020-02-08 22:38:27 -05:00
|
|
|
input.origin_rows = input.origin_cols = 0;
|
|
|
|
input.rows = job->rows;
|
|
|
|
input.cols = job->cols;
|
|
|
|
input.imgbuf = job->databuf + sizeof(struct mitsu9550_plane);
|
|
|
|
input.bytes_per_row = job->cols * 3;
|
|
|
|
|
|
|
|
output.origin_rows = output.origin_cols = 0;
|
|
|
|
output.rows = job->rows;
|
|
|
|
output.cols = job->cols;
|
|
|
|
output.imgbuf = convbuf;
|
2020-02-12 20:07:03 -05:00
|
|
|
output.bytes_per_row = job->cols * 3 * sizeof(uint16_t);
|
2020-02-08 22:38:27 -05:00
|
|
|
|
2020-02-12 20:07:03 -05:00
|
|
|
int sharpness = job->hdr2.unkc[7];
|
2020-02-08 22:38:27 -05:00
|
|
|
|
2020-02-12 20:07:03 -05:00
|
|
|
if (!ctx->lib.CP98xx_DoConvert(ctx->m98xxdata, &input, &output, job->hdr2.mode, sharpness, job->hdr2.unkc[8])) {
|
2020-02-08 22:38:27 -05:00
|
|
|
free(convbuf);
|
|
|
|
free(newbuf);
|
|
|
|
ERROR("CP98xx_DoConvert() failed!\n");
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
}
|
2020-02-12 20:07:03 -05:00
|
|
|
|
|
|
|
/* Clear special extension flags used by our backend */
|
2020-02-08 22:38:27 -05:00
|
|
|
if (job->hdr2.mode == 0x11)
|
|
|
|
job->hdr2.mode = 0x10;
|
2020-02-12 20:07:03 -05:00
|
|
|
job->hdr2.unkc[8] = 0; /* Clear "already reversed" flag */
|
|
|
|
job->hdr2.unkc[7] = 0; /* Clear "sharpness" parameter */
|
|
|
|
|
2020-06-05 21:06:41 -04:00
|
|
|
/* Library is done, but its output is packed YMC16.
|
|
|
|
We need to convert this to planar YMC16, with a header for
|
|
|
|
each plane. */
|
2020-02-12 20:07:03 -05:00
|
|
|
uint8_t *yPtr, *mPtr, *cPtr;
|
|
|
|
int j, offset;
|
|
|
|
|
|
|
|
yPtr = newbuf + newlen;
|
|
|
|
memcpy(yPtr, job->databuf, sizeof(struct mitsu9550_plane));
|
|
|
|
yPtr[3] = 0x10; /* ie 16bpp data */
|
|
|
|
yPtr += sizeof(struct mitsu9550_plane);
|
|
|
|
newlen += sizeof(struct mitsu9550_plane) + planelen;
|
|
|
|
|
|
|
|
mPtr = newbuf + newlen;
|
|
|
|
memcpy(mPtr, job->databuf, sizeof(struct mitsu9550_plane));
|
|
|
|
mPtr[3] = 0x10; /* ie 16bpp data */
|
|
|
|
mPtr += sizeof(struct mitsu9550_plane);
|
|
|
|
newlen += sizeof(struct mitsu9550_plane) + planelen;
|
|
|
|
|
|
|
|
cPtr = newbuf + newlen;
|
|
|
|
memcpy(cPtr, job->databuf, sizeof(struct mitsu9550_plane));
|
|
|
|
cPtr[3] = 0x10; /* ie 16bpp data */
|
|
|
|
cPtr += sizeof(struct mitsu9550_plane);
|
|
|
|
newlen += sizeof(struct mitsu9550_plane) + planelen;
|
|
|
|
|
2020-06-05 21:06:41 -04:00
|
|
|
for (offset = 0, i = 0; i < output.rows ; i++) {
|
|
|
|
for (j = 0 ; j < output.cols ; j ++, offset += 3) {
|
|
|
|
yPtr[i*output.cols + j] = convbuf[0 + offset];
|
|
|
|
mPtr[i*output.cols + j] = convbuf[1 + offset];
|
|
|
|
cPtr[i*output.cols + j] = convbuf[2 + offset];
|
2020-02-12 20:07:03 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-08 22:38:27 -05:00
|
|
|
|
|
|
|
/* All done with conversion buffer, nuke it */
|
|
|
|
free(convbuf);
|
2018-06-19 09:04:17 -04:00
|
|
|
|
2020-06-05 21:06:41 -04:00
|
|
|
/* And finally, append the job footer. */
|
2020-05-18 14:00:49 -04:00
|
|
|
memcpy(newbuf + newlen, job->databuf + sizeof(struct mitsu9550_plane) + planelen/2 * 3, ctx->footer_len);
|
2018-06-19 09:04:17 -04:00
|
|
|
newlen += sizeof(struct mitsu9550_cmd);
|
|
|
|
|
2018-06-20 11:39:40 -04:00
|
|
|
/* Clean up, and move pointer to new buffer; */
|
2018-06-19 09:04:17 -04:00
|
|
|
free(job->databuf);
|
|
|
|
job->databuf = newbuf;
|
|
|
|
job->datalen = newlen;
|
2018-06-20 11:39:40 -04:00
|
|
|
ptr = job->databuf;
|
2018-06-19 09:04:17 -04:00
|
|
|
|
|
|
|
/* Now handle the matte plane generation */
|
|
|
|
if (job->hdr1.matte) {
|
|
|
|
if ((i = mitsu98xx_fillmatte(job))) {
|
|
|
|
return i;
|
2018-06-17 22:24:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-08 22:38:27 -05:00
|
|
|
non_98xx:
|
2018-06-19 09:04:17 -04:00
|
|
|
/* Bypass */
|
|
|
|
if (test_mode >= TEST_MODE_NOPRINT)
|
|
|
|
return CUPS_BACKEND_OK;
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
top:
|
2016-10-14 07:42:24 -04:00
|
|
|
if (ctx->is_s) {
|
2014-12-15 08:25:05 -05:00
|
|
|
int num;
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2014-12-15 08:25:05 -05:00
|
|
|
/* Send "unknown 1" command */
|
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x53;
|
|
|
|
cmd.cmd[2] = 0xc5;
|
|
|
|
cmd.cmd[3] = 0x9d;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2014-12-15 08:25:05 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2014-12-15 08:25:05 -05:00
|
|
|
/* Send "unknown 2" command */
|
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x4b;
|
|
|
|
cmd.cmd[2] = 0x7f;
|
|
|
|
cmd.cmd[3] = 0x00;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2014-12-15 08:25:05 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = read_data(ctx->conn,
|
2014-12-15 08:25:05 -05:00
|
|
|
rdbuf, READBACK_LEN, &num);
|
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
// seen so far: eb 4b 7f 00 02 00 5e
|
|
|
|
}
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9800S) {
|
2016-10-13 19:44:09 -04:00
|
|
|
int num;
|
|
|
|
|
|
|
|
/* Send "unknown 3" command */
|
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x4b;
|
|
|
|
cmd.cmd[2] = 0x01;
|
|
|
|
cmd.cmd[3] = 0x00;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-13 19:44:09 -04:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = read_data(ctx->conn,
|
2016-10-13 19:44:09 -04:00
|
|
|
rdbuf, READBACK_LEN, &num);
|
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
// seen so far: e4 4b 01 00 02 00 78
|
|
|
|
}
|
|
|
|
|
2016-08-17 21:16:15 -04:00
|
|
|
QUERY_STATUS();
|
2014-12-15 08:25:05 -05:00
|
|
|
|
2014-12-16 21:51:14 -05:00
|
|
|
/* Now it's time for the actual print job! */
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2016-08-17 21:16:15 -04:00
|
|
|
QUERY_STATUS();
|
2014-12-15 08:25:05 -05:00
|
|
|
|
|
|
|
/* Send printjob headers from spool data */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr1_present)
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2018-06-15 14:55:03 -04:00
|
|
|
(uint8_t*) &job->hdr1, sizeof(job->hdr1))))
|
2016-10-13 08:12:20 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr2_present)
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2018-06-15 14:55:03 -04:00
|
|
|
(uint8_t*) &job->hdr2, sizeof(job->hdr2))))
|
2016-10-13 08:12:20 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr3_present)
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2018-06-15 14:55:03 -04:00
|
|
|
(uint8_t*) &job->hdr3, sizeof(job->hdr3))))
|
2016-10-13 08:12:20 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr4_present)
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2018-06-15 14:55:03 -04:00
|
|
|
(uint8_t*) &job->hdr4, sizeof(struct mitsu9550_hdr4))))
|
2017-07-10 20:15:56 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2016-10-14 07:42:24 -04:00
|
|
|
if (ctx->is_s) {
|
2018-04-20 16:17:47 -04:00
|
|
|
/* I think this a "clear memory' command...? */
|
2014-12-15 08:25:05 -05:00
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x5a;
|
|
|
|
cmd.cmd[2] = 0x43;
|
|
|
|
cmd.cmd[3] = 0x00;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2014-12-15 08:25:05 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
}
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2016-10-23 09:32:43 -04:00
|
|
|
/* Send over plane data */
|
2018-06-20 11:39:40 -04:00
|
|
|
while(ptr < (job->databuf + job->datalen)) {
|
2016-10-23 09:32:43 -04:00
|
|
|
struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
|
|
|
|
if (plane->cmd[0] != 0x1b ||
|
|
|
|
plane->cmd[1] != 0x5a ||
|
|
|
|
plane->cmd[2] != 0x54)
|
|
|
|
break;
|
2018-06-20 11:39:40 -04:00
|
|
|
|
|
|
|
planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
|
2016-10-23 09:32:43 -04:00
|
|
|
if (plane->cmd[3] == 0x10)
|
|
|
|
planelen *= 2;
|
2016-10-13 08:12:20 -04:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-23 09:32:43 -04:00
|
|
|
(uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
ptr += sizeof(struct mitsu9550_plane);
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-23 09:32:43 -04:00
|
|
|
(uint8_t*) ptr, planelen)))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
ptr += planelen;
|
|
|
|
}
|
2014-12-15 09:11:41 -05:00
|
|
|
|
|
|
|
/* Query statuses */
|
|
|
|
{
|
|
|
|
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
|
|
|
|
// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
|
|
|
|
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
|
2018-04-27 15:40:09 -04:00
|
|
|
uint16_t donor;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_MEDIA);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) {
|
|
|
|
donor = be16_to_cpu(media->remain2);
|
|
|
|
} else {
|
|
|
|
donor = be16_to_cpu(media->remain);
|
|
|
|
}
|
2018-04-27 15:40:09 -04:00
|
|
|
if (donor != ctx->marker.levelnow) {
|
|
|
|
ctx->marker.levelnow = donor;
|
|
|
|
dump_markers(&ctx->marker, 1, 0);
|
|
|
|
}
|
2014-12-15 09:11:41 -05:00
|
|
|
/* Sanity-check media response */
|
2020-12-03 21:40:10 -05:00
|
|
|
if ((media->remain == 0 && media->remain2 == 0) || media->max == 0) {
|
2014-12-15 09:11:41 -05:00
|
|
|
ERROR("Printer out of media!\n");
|
|
|
|
return CUPS_BACKEND_HOLD;
|
|
|
|
}
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS2);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS1);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2014-12-15 09:11:41 -05:00
|
|
|
/* Make sure we're ready to proceed */
|
|
|
|
if (sts->sts5 != 0) {
|
2015-01-07 21:58:11 -05:00
|
|
|
ERROR("Unexpected response (sts5 %02x)\n", sts->sts5);
|
2014-12-15 09:11:41 -05:00
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
}
|
2015-01-07 21:58:11 -05:00
|
|
|
if (!(sts->sts3 & 0xc0)) {
|
|
|
|
ERROR("Unexpected response (sts3 %02x)\n", sts->sts3);
|
2014-12-15 09:11:41 -05:00
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
}
|
2016-10-31 14:02:23 -04:00
|
|
|
/* Check for known errors */
|
|
|
|
if (sts->sts2 != 0) {
|
|
|
|
ERROR("Printer cover open!\n");
|
|
|
|
return CUPS_BACKEND_STOP;
|
|
|
|
}
|
2014-12-15 09:11:41 -05:00
|
|
|
}
|
2016-10-14 13:59:31 -04:00
|
|
|
|
|
|
|
/* Send "end data" command */
|
2020-08-11 20:27:26 -04:00
|
|
|
if (ctx->conn->type == P_MITSU_9550S) {
|
2016-10-14 13:59:31 -04:00
|
|
|
/* Override spool, which may be wrong */
|
2014-12-15 08:25:05 -05:00
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x50;
|
|
|
|
cmd.cmd[2] = 0x47;
|
2016-10-13 19:44:09 -04:00
|
|
|
cmd.cmd[3] = 0x00;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-13 19:44:09 -04:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2020-08-11 20:27:26 -04:00
|
|
|
} else if (ctx->conn->type == P_MITSU_9800S) {
|
2016-10-14 13:59:31 -04:00
|
|
|
/* Override spool, which may be wrong */
|
2016-10-13 19:44:09 -04:00
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x50;
|
|
|
|
cmd.cmd[2] = 0x4e;
|
|
|
|
cmd.cmd[3] = 0x00;
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2014-12-15 08:25:05 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
} else {
|
2016-10-14 13:59:31 -04:00
|
|
|
/* Send from spool file */
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2020-05-18 14:00:49 -04:00
|
|
|
ptr, ctx->footer_len)))
|
2016-10-16 09:52:02 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2020-05-18 14:00:49 -04:00
|
|
|
ptr += ctx->footer_len;
|
2016-10-16 09:52:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't forget the 9810's matte plane */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->hdr1.matte) {
|
2016-10-23 09:32:43 -04:00
|
|
|
struct mitsu9550_plane *plane = (struct mitsu9550_plane *)ptr;
|
2019-05-06 21:10:43 -04:00
|
|
|
planelen = be16_to_cpu(plane->rows) * be16_to_cpu(plane->cols);
|
2016-10-23 09:32:43 -04:00
|
|
|
|
|
|
|
if (plane->cmd[3] == 0x10)
|
|
|
|
planelen *= 2;
|
|
|
|
|
2016-10-16 09:52:02 -04:00
|
|
|
// XXX include a status loop here too?
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-16 09:52:02 -04:00
|
|
|
(uint8_t*) ptr, sizeof(struct mitsu9550_plane))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
ptr += sizeof(struct mitsu9550_plane);
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-23 09:32:43 -04:00
|
|
|
(uint8_t*) ptr, planelen)))
|
2016-10-16 09:52:02 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2016-10-23 09:32:43 -04:00
|
|
|
ptr += planelen;
|
2016-10-16 09:52:02 -04:00
|
|
|
|
|
|
|
/* Send "lamination end data" command from spool file */
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(ctx->conn,
|
2016-10-13 08:12:20 -04:00
|
|
|
ptr, sizeof(cmd))))
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2018-09-20 08:42:30 -04:00
|
|
|
// ptr += sizeof(cmd);
|
2016-10-13 08:12:20 -04:00
|
|
|
}
|
|
|
|
|
2014-12-15 09:11:41 -05:00
|
|
|
/* Status loop, run until printer reports completion */
|
|
|
|
while(1) {
|
|
|
|
struct mitsu9550_status *sts = (struct mitsu9550_status*) rdbuf;
|
|
|
|
// struct mitsu9550_status2 *sts2 = (struct mitsu9550_status2*) rdbuf;
|
|
|
|
struct mitsu9550_media *media = (struct mitsu9550_media *) rdbuf;
|
2018-04-27 15:40:09 -04:00
|
|
|
uint16_t donor;
|
2016-08-17 21:16:15 -04:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_MEDIA);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) {
|
|
|
|
donor = be16_to_cpu(media->remain2);
|
|
|
|
} else {
|
|
|
|
donor = be16_to_cpu(media->remain);
|
|
|
|
}
|
2018-04-27 15:40:09 -04:00
|
|
|
if (donor != ctx->marker.levelnow) {
|
|
|
|
ctx->marker.levelnow = donor;
|
|
|
|
dump_markers(&ctx->marker, 1, 0);
|
|
|
|
}
|
2014-12-15 09:11:41 -05:00
|
|
|
/* Sanity-check media response */
|
2020-12-03 21:40:10 -05:00
|
|
|
if ((media->remain == 0 && media->remain2 == 0) || media->max == 0) {
|
2014-12-15 09:11:41 -05:00
|
|
|
ERROR("Printer out of media!\n");
|
|
|
|
return CUPS_BACKEND_HOLD;
|
|
|
|
}
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS2);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, rdbuf, CP9XXXX_STS_STS1);
|
2014-12-15 09:11:41 -05:00
|
|
|
if (ret < 0)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2014-12-20 12:43:22 -05:00
|
|
|
INFO("%03d copies remaining\n", be16_to_cpu(sts->copies));
|
2014-12-15 09:11:41 -05:00
|
|
|
|
|
|
|
if (!sts->sts1) /* If printer transitions to idle */
|
|
|
|
break;
|
|
|
|
|
2015-08-12 20:56:51 -04:00
|
|
|
if (fast_return && !be16_to_cpu(sts->copies)) { /* No remaining prints */
|
2014-12-16 21:51:14 -05:00
|
|
|
INFO("Fast return mode enabled.\n");
|
2014-12-15 09:11:41 -05:00
|
|
|
break;
|
2014-12-16 21:51:14 -05:00
|
|
|
}
|
|
|
|
|
2015-08-12 20:56:51 -04:00
|
|
|
if (fast_return && !sts->sts5) { /* Ready for another job */
|
2014-12-16 21:51:14 -05:00
|
|
|
INFO("Fast return mode enabled.\n");
|
2014-12-15 09:11:41 -05:00
|
|
|
break;
|
2014-12-16 21:51:14 -05:00
|
|
|
}
|
2016-10-31 14:02:23 -04:00
|
|
|
/* Check for known errors */
|
|
|
|
if (sts->sts2 != 0) {
|
|
|
|
ERROR("Printer cover open!\n");
|
|
|
|
return CUPS_BACKEND_STOP;
|
|
|
|
}
|
2014-12-15 09:11:41 -05:00
|
|
|
sleep(1);
|
|
|
|
}
|
2016-08-19 17:40:12 -04:00
|
|
|
|
2015-08-20 23:13:52 -04:00
|
|
|
INFO("Print complete\n");
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
return CUPS_BACKEND_OK;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
static void mitsu9550_dump_media(struct mitsu9550_ctx *ctx, struct mitsu9550_media *resp)
|
2014-12-14 20:52:21 -05:00
|
|
|
{
|
2014-12-20 15:15:33 -05:00
|
|
|
INFO("Media type : %02x (%s)\n",
|
2020-12-03 21:40:10 -05:00
|
|
|
resp->type, mitsu9550_media_types(resp->type, ctx->is_s));
|
2014-12-20 15:15:33 -05:00
|
|
|
INFO("Media remaining : %03d/%03d\n",
|
2020-12-03 21:40:10 -05:00
|
|
|
(ctx->conn->type == P_MITSU_CP30D) ? be16_to_cpu(resp->remain2) : be16_to_cpu(resp->remain), be16_to_cpu(resp->max));
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
|
2014-12-20 12:43:22 -05:00
|
|
|
static void mitsu9550_dump_status(struct mitsu9550_status *resp)
|
|
|
|
{
|
|
|
|
INFO("Printer status : %02x (%s)\n",
|
|
|
|
resp->sts1, resp->sts1 ? "Printing": "Idle");
|
|
|
|
INFO("Pages remaining : %03d\n",
|
|
|
|
be16_to_cpu(resp->copies));
|
2016-10-31 14:02:23 -04:00
|
|
|
INFO("Other status : %02x %02x %02x %02x %02x %02x\n",
|
|
|
|
resp->sts2, resp->sts3, resp->sts4,
|
|
|
|
resp->sts5, resp->sts6, resp->sts7);
|
2014-12-20 12:43:22 -05:00
|
|
|
}
|
|
|
|
|
2016-10-27 16:30:48 -04:00
|
|
|
static void mitsu9550_dump_status2(struct mitsu9550_status2 *resp)
|
|
|
|
{
|
2016-10-31 14:02:23 -04:00
|
|
|
INFO("Prints remaining on media : %03d\n",
|
|
|
|
be16_to_cpu(resp->remain));
|
2016-10-27 16:30:48 -04:00
|
|
|
}
|
|
|
|
|
2014-12-14 20:52:21 -05:00
|
|
|
static int mitsu9550_query_media(struct mitsu9550_ctx *ctx)
|
2014-12-11 16:16:56 -05:00
|
|
|
{
|
2014-12-14 20:52:21 -05:00
|
|
|
struct mitsu9550_media resp;
|
2014-12-11 16:16:56 -05:00
|
|
|
int ret;
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_MEDIA);
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
if (!ret)
|
2020-12-03 21:40:10 -05:00
|
|
|
mitsu9550_dump_media(ctx, &resp);
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-20 12:43:22 -05:00
|
|
|
static int mitsu9550_query_status(struct mitsu9550_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct mitsu9550_status resp;
|
|
|
|
int ret;
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_STS1);
|
2014-12-20 12:43:22 -05:00
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
mitsu9550_dump_status(&resp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-10-27 16:30:48 -04:00
|
|
|
static int mitsu9550_query_status2(struct mitsu9550_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct mitsu9550_status2 resp;
|
|
|
|
int ret;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_STS2);
|
2016-10-27 16:30:48 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
if (!ret && ctx->conn->type != P_MITSU_CP30D)
|
2016-10-27 16:30:48 -04:00
|
|
|
mitsu9550_dump_status2(&resp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
static int mitsu9550_query_statusX(struct mitsu9550_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct mitsu9550_status2 resp;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_STS3);
|
2020-12-04 20:02:44 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_FWVER);
|
2020-12-03 21:40:10 -05:00
|
|
|
ret = mitsu9550_get_status(ctx, (uint8_t*) &resp, CP9XXXX_STS_STS5);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
static int mitsu9550_query_serno(struct dyesub_connection *conn, char *buf, int buf_len)
|
2014-12-14 19:09:32 -05:00
|
|
|
{
|
|
|
|
struct mitsu9550_cmd cmd;
|
|
|
|
uint8_t rdbuf[READBACK_LEN];
|
2014-12-19 14:45:49 -05:00
|
|
|
uint8_t *ptr;
|
2014-12-14 19:09:32 -05:00
|
|
|
int ret, num, i;
|
|
|
|
|
|
|
|
cmd.cmd[0] = 0x1b;
|
|
|
|
cmd.cmd[1] = 0x72;
|
|
|
|
cmd.cmd[2] = 0x6e;
|
|
|
|
cmd.cmd[3] = 0x00;
|
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
if ((ret = send_data(conn,
|
2014-12-14 19:09:32 -05:00
|
|
|
(uint8_t*) &cmd, sizeof(cmd))))
|
2014-12-17 07:33:51 -05:00
|
|
|
return (ret < 0) ? ret : CUPS_BACKEND_FAILED;
|
2014-12-14 19:09:32 -05:00
|
|
|
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = read_data(conn,
|
2014-12-14 19:09:32 -05:00
|
|
|
rdbuf, READBACK_LEN, &num);
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2014-12-14 19:09:32 -05:00
|
|
|
if (ret < 0)
|
2014-12-17 07:33:51 -05:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2014-12-14 19:09:32 -05:00
|
|
|
|
2014-12-25 08:23:18 -05:00
|
|
|
if ((unsigned int)num < sizeof(cmd) + 1) /* Short read */
|
2014-12-17 07:33:51 -05:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2014-12-14 19:09:32 -05:00
|
|
|
if (rdbuf[0] != 0xe4 ||
|
|
|
|
rdbuf[1] != 0x72 ||
|
|
|
|
rdbuf[2] != 0x6e ||
|
|
|
|
rdbuf[3] != 0x00) /* Bad response */
|
2014-12-17 07:33:51 -05:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2014-12-14 19:09:32 -05:00
|
|
|
|
|
|
|
/* If response is truncated, handle it */
|
2014-12-25 08:23:18 -05:00
|
|
|
num -= (sizeof(cmd) + 1);
|
|
|
|
if ((unsigned int) num != rdbuf[4])
|
2016-08-21 10:23:00 -04:00
|
|
|
WARNING("Short serno read! (%d vs %u)\r\n",
|
2014-12-25 08:23:18 -05:00
|
|
|
num, rdbuf[4]);
|
2014-12-14 19:09:32 -05:00
|
|
|
|
2017-07-10 20:15:56 -04:00
|
|
|
/* model and serial number are encoded as 16-bit unicode,
|
2014-12-19 14:45:49 -05:00
|
|
|
little endian, separated by spaces. */
|
2014-12-25 08:23:18 -05:00
|
|
|
i = num;
|
2014-12-19 14:45:49 -05:00
|
|
|
ptr = rdbuf + 5;
|
2014-12-25 08:23:18 -05:00
|
|
|
while (i > 0 && buf_len > 1) {
|
|
|
|
if (*ptr != 0x20)
|
|
|
|
*buf++ = *ptr;
|
|
|
|
buf_len--;
|
2014-12-19 14:45:49 -05:00
|
|
|
ptr += 2;
|
|
|
|
i -= 2;
|
2014-12-14 19:09:32 -05:00
|
|
|
}
|
|
|
|
*buf = 0; /* Null-terminate the returned string */
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2014-12-14 19:09:32 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-04-20 16:17:47 -04:00
|
|
|
static int mitsu9550_cancel_job(struct mitsu9550_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret;
|
2018-04-23 22:01:35 -04:00
|
|
|
|
2018-04-20 16:17:47 -04:00
|
|
|
uint8_t buf[2] = { 0x1b, 0x44 };
|
2020-08-11 20:27:26 -04:00
|
|
|
ret = send_data(ctx->conn, buf, sizeof(buf));
|
2018-04-20 16:17:47 -04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
static void mitsu9550_cmdline(void)
|
|
|
|
{
|
2014-12-14 20:52:21 -05:00
|
|
|
DEBUG("\t\t[ -m ] # Query media\n");
|
2014-12-20 12:43:22 -05:00
|
|
|
DEBUG("\t\t[ -s ] # Query status\n");
|
2018-04-20 16:17:47 -04:00
|
|
|
DEBUG("\t\t[ -X ] # Cancel current job\n");
|
2020-12-04 20:02:44 -05:00
|
|
|
// DEBUG("\t\t[ -Z ] # Dump all parameters\n");
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
|
|
|
int i, j = 0;
|
|
|
|
|
2015-08-24 17:28:10 -04:00
|
|
|
if (!ctx)
|
|
|
|
return -1;
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "msXZ")) >= 0) {
|
2014-12-11 16:16:56 -05:00
|
|
|
switch(i) {
|
2015-08-25 22:47:26 -04:00
|
|
|
GETOPT_PROCESS_GLOBAL
|
2015-08-13 21:09:56 -04:00
|
|
|
case 'm':
|
2015-08-24 17:28:10 -04:00
|
|
|
j = mitsu9550_query_media(ctx);
|
|
|
|
break;
|
2014-12-20 12:43:22 -05:00
|
|
|
case 's':
|
2020-12-04 20:02:44 -05:00
|
|
|
if (ctx->conn->type != P_MITSU_CP30D)
|
2020-12-03 21:40:10 -05:00
|
|
|
j = mitsu9550_query_status(ctx);
|
2016-10-27 16:30:48 -04:00
|
|
|
if (!j)
|
|
|
|
j = mitsu9550_query_status2(ctx);
|
2020-12-04 20:02:44 -05:00
|
|
|
INFO("Firmware Version: %s\n", ctx->fwver);
|
2015-08-24 17:28:10 -04:00
|
|
|
break;
|
2018-04-20 16:17:47 -04:00
|
|
|
case 'X':
|
|
|
|
j = mitsu9550_cancel_job(ctx);
|
2018-04-23 22:01:35 -04:00
|
|
|
break;
|
2020-12-04 20:02:44 -05:00
|
|
|
case 'Z':
|
|
|
|
j = mitsu9550_query_statusX(ctx);
|
|
|
|
break;
|
2014-12-11 16:16:56 -05:00
|
|
|
default:
|
|
|
|
break; /* Ignore completely */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j) return j;
|
|
|
|
}
|
|
|
|
|
2019-12-12 07:15:25 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
|
2018-04-27 15:40:09 -04:00
|
|
|
static int mitsu9550_query_markers(void *vctx, struct marker **markers, int *count)
|
|
|
|
{
|
|
|
|
struct mitsu9550_ctx *ctx = vctx;
|
|
|
|
struct mitsu9550_media media;
|
|
|
|
|
|
|
|
/* Query printer status */
|
2020-12-03 21:40:10 -05:00
|
|
|
if (mitsu9550_get_status(ctx, (uint8_t*) &media, CP9XXXX_STS_MEDIA))
|
2018-04-27 15:40:09 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
if (ctx->conn->type == P_MITSU_CP30D) {
|
|
|
|
ctx->marker.levelnow = be16_to_cpu(media.remain);
|
|
|
|
} else {
|
|
|
|
ctx->marker.levelnow = be16_to_cpu(media.remain2);
|
|
|
|
}
|
2018-04-27 15:40:09 -04:00
|
|
|
|
|
|
|
*markers = &ctx->marker;
|
|
|
|
*count = 1;
|
|
|
|
|
|
|
|
return CUPS_BACKEND_OK;
|
|
|
|
}
|
|
|
|
|
2018-03-16 15:35:00 -04:00
|
|
|
static const char *mitsu9550_prefixes[] = {
|
2018-09-22 09:11:14 -04:00
|
|
|
"mitsu9xxx", // Family driver, do not nuke.
|
|
|
|
// Backwards compatibility
|
2018-05-15 18:35:20 -04:00
|
|
|
"mitsu9000", "mitsu9500", "mitsu9550", "mitsu9600", "mitsu9800", "mitsu9810",
|
2018-03-16 13:35:17 -04:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2014-12-11 16:16:56 -05:00
|
|
|
/* Exported */
|
2020-10-05 22:26:39 -04:00
|
|
|
const struct dyesub_backend mitsu9550_backend = {
|
2018-03-16 13:35:17 -04:00
|
|
|
.name = "Mitsubishi CP9xxx family",
|
2020-12-03 21:40:10 -05:00
|
|
|
.version = "0.57" " (lib " LIBMITSU_VER ")",
|
2018-03-16 15:35:00 -04:00
|
|
|
.uri_prefixes = mitsu9550_prefixes,
|
2014-12-11 16:16:56 -05:00
|
|
|
.cmdline_usage = mitsu9550_cmdline,
|
|
|
|
.cmdline_arg = mitsu9550_cmdline_arg,
|
|
|
|
.init = mitsu9550_init,
|
|
|
|
.attach = mitsu9550_attach,
|
|
|
|
.teardown = mitsu9550_teardown,
|
2018-06-15 14:55:03 -04:00
|
|
|
.cleanup_job = mitsu9550_cleanup_job,
|
2014-12-11 16:16:56 -05:00
|
|
|
.read_parse = mitsu9550_read_parse,
|
|
|
|
.main_loop = mitsu9550_main_loop,
|
2014-12-14 19:09:32 -05:00
|
|
|
.query_serno = mitsu9550_query_serno,
|
2018-04-27 15:40:09 -04:00
|
|
|
.query_markers = mitsu9550_query_markers,
|
2014-12-11 16:16:56 -05:00
|
|
|
.devices = {
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9000AM, P_MITSU_9550, NULL, "mitsubishi-9000dw"}, // XXX -am instead?
|
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9000D, P_MITSU_9550, NULL, "mitsubishi-9000dw"},
|
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9500D, P_MITSU_9550, NULL, "mitsubishi-9500dw"},
|
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, NULL, "mitsubishi-9550dw"},
|
2020-01-30 22:08:55 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, NULL, "mitsubishi-9550d"}, /* Duplicate */
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, NULL, "mitsubishi-9550dw-s"},
|
2020-01-30 22:08:55 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9550DS, P_MITSU_9550S, NULL, "mitsubishi-9550dz"}, /* Duplicate */
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600, NULL, "mitsubishi-9600dw"},
|
|
|
|
// { USB_VID_MITSU, USB_PID_MITSU_9600D, P_MITSU_9600S, NULL, "mitsubishi-9600dw-s"},
|
2020-12-03 21:40:10 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_CP30D, P_MITSU_CP30D, NULL, "mitsubishi-cp30dw"},
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9800D, P_MITSU_9800, NULL, "mitsubishi-9800dw"},
|
2020-01-30 22:08:55 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9800D, P_MITSU_9800, NULL, "mitsubishi-9800d"}, /* Duplicate */
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9800DS, P_MITSU_9800S, NULL, "mitsubishi-9800dw-s"},
|
2020-01-30 22:08:55 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_9800DS, P_MITSU_9800S, NULL, "mitsubishi-9800dz"}, /* Duplicate */
|
2018-09-22 09:11:14 -04:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_98__D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
|
2020-01-30 22:08:55 -05:00
|
|
|
{ USB_VID_MITSU, USB_PID_MITSU_98__D, P_MITSU_9810, NULL, "mitsubishi-9810d"}, /* Duplicate */
|
2018-09-22 09:11:14 -04:00
|
|
|
// { USB_VID_MITSU, USB_PID_MITSU_9810D, P_MITSU_9810, NULL, "mitsubishi-9810dw"},
|
|
|
|
// { USB_VID_MITSU, USB_PID_MITSU_9820DS, P_MITSU_9820S, NULL, "mitsubishi-9820dw-s"},
|
2018-03-16 15:35:00 -04:00
|
|
|
{ 0, 0, 0, NULL, NULL}
|
2014-12-11 16:16:56 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-18 14:00:49 -04:00
|
|
|
/* Mitsubish CP-30/9500/9550/9600/9800/9810/9820 spool format:
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2020-05-18 14:00:49 -04:00
|
|
|
Spool file consists of 3 or 4 50-byte headers, followed by three
|
|
|
|
image planes, each with a 12-byte header, then a 4 or 6-byte footer.
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
All multi-byte numbers are big endian.
|
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
~~~ Header 1
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
1b 57 20 2e 00 QQ QQ 00 00 00 00 00 00 00 XX XX :: XX XX == columns
|
|
|
|
YY YY 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: YY YY == rows
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ == 0x0a90 on 9810, 0x0a10 on all others.
|
2017-07-10 20:15:56 -04:00
|
|
|
00 00
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
~~~ Header 2
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2020-06-03 23:15:04 -04:00
|
|
|
1b 57 21 2e 00 GG 00 HH QQ QQ 00 00 00 00 00 00 :: ZZ ZZ = num copies (>= 0x01)
|
2020-05-18 14:00:49 -04:00
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 ZZ ZZ 00 00 :: YY = 00/80 Fine/SuperFine (9550), 10/80 Fine/Superfine (98x0), 00 (9600), 0x80/0x00 Powersave/Normal (CP30)
|
2020-02-12 20:07:03 -05:00
|
|
|
XX 00 00 00 00 00 YY 00 00 00 00 00 00 00 SS TT :: XX = 00 normal, 83 Cut 2x6 (9550 only!)
|
2020-06-03 23:15:04 -04:00
|
|
|
RR II :: QQ QQ = 0x0803 on 9550, 0x0801 on 98x0, 0x0003 on 9600, 0xa803 on 9500, 0x0802 on CP30
|
2018-04-19 08:15:01 -04:00
|
|
|
:: RR = 01 for "use LUT" on 98xx, 0x00 otherwise. Extension to stock.
|
2020-02-12 20:07:03 -05:00
|
|
|
:: TT = 01 for "already reversed". Extension to stock.
|
|
|
|
:: SS == sharpening level, 0 for off, 1-10 otherwise. Extesion to stock.
|
2020-06-03 23:15:04 -04:00
|
|
|
:: GG == 0x00 on CP30, 0x80 on others
|
|
|
|
:: HH == 0x20 on CP30, 0x22 on others
|
|
|
|
:: II == 0x00 on CP30, 0x01 on others.
|
2016-10-12 23:28:54 -04:00
|
|
|
|
2020-05-18 14:00:49 -04:00
|
|
|
~~~ Header 3 (9550, 9800-S, and CP30 only..)
|
2016-10-12 23:28:54 -04:00
|
|
|
|
2016-12-20 11:22:48 -05:00
|
|
|
1b 57 22 2e 00 QQ 00 00 00 00 00 XX 00 00 00 00 :: XX = 00 normal, 01 FineDeep
|
2020-11-28 17:50:30 -05:00
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ = 0xf0 on 9500, 0x40 on the rest
|
2017-07-10 20:15:56 -04:00
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-13 19:44:09 -04:00
|
|
|
~~~ Header 4 (all but 9550-S and 9800-S, involves error policy?)
|
2016-10-12 23:28:54 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
1b 57 26 2e 00 QQ TT 00 00 00 00 SS RR ZZ VV WW :: QQ = 0x70 on 9550/98x0, 0x60 on 9600 or 9800S, 0x3f on CP30 [also seen 0x20 & 0x00 on 9550S]
|
|
|
|
WW 00 WW 00 00 00 00 00 00 00 00 00 00 00 00 00 :: RR = 0x01 on 9550/98x0/CP30, 0x00 on 9600 [ "ignore errors? ]
|
2017-04-04 08:15:37 -04:00
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: SS = 0x01 on 9800S, 0x00 otherwise.
|
2017-07-10 20:15:56 -04:00
|
|
|
00 00
|
2020-12-04 20:02:44 -05:00
|
|
|
:: ZZ = Unknown; 0x01 [9550S] & 0x00 [9500].
|
2020-05-18 14:00:49 -04:00
|
|
|
:: TT = 0x80 on CP30, 0x00 otherwise
|
|
|
|
:: VV = 0x80 on CP30, 0x00 otherwise
|
|
|
|
:: WW = 0x10 on CP30, 0x00 otherwise
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2016-10-25 15:10:42 -04:00
|
|
|
~~~~ Data follows:
|
2014-12-11 16:16:56 -05:00
|
|
|
|
2018-04-19 08:15:01 -04:00
|
|
|
Format is: planar YMC16 for 98x0 (but only 12 bits used, BIG endian)
|
|
|
|
planar RGB for all others
|
2016-10-25 15:10:42 -04:00
|
|
|
|
2018-05-09 10:47:19 -04:00
|
|
|
1b 5a 54 ?? RR RR CC CC 07 14 04 d8 :: 0714 == columns, 04d8 == rows
|
2018-04-19 08:15:01 -04:00
|
|
|
:: RRRR == row offset for data, CCCC == col offset for data
|
2016-10-14 07:42:24 -04:00
|
|
|
:: ?? == 0x00 for 8bpp, 0x10 for 16/12bpp.
|
2018-04-19 08:15:01 -04:00
|
|
|
:: 0x80 for PACKED BGR!
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
Data follows immediately, no padding.
|
|
|
|
|
|
|
|
1b 5a 54 00 00 00 00 00 07 14 04 d8 :: Another plane.
|
|
|
|
|
|
|
|
Data follows immediately, no padding.
|
|
|
|
|
|
|
|
1b 5a 54 00 00 00 00 00 07 14 04 d8 :: Another plane.
|
|
|
|
|
|
|
|
Data follows immediately, no padding.
|
|
|
|
|
|
|
|
~~~~ Footer:
|
|
|
|
|
2019-12-20 23:06:09 -05:00
|
|
|
1b 50 41 00 (9500AM)
|
2016-10-12 23:28:54 -04:00
|
|
|
1b 50 46 00 (9550)
|
|
|
|
1b 50 47 00 (9550-S)
|
|
|
|
1b 50 48 00 (9600)
|
2017-04-04 08:15:37 -04:00
|
|
|
1b 50 4c 00 (9800/9810)
|
2019-12-20 23:06:09 -05:00
|
|
|
1b 50 4d 00 (9000)
|
2016-10-13 19:58:16 -04:00
|
|
|
1b 50 4e 00 (9800-S)
|
2019-12-20 23:06:09 -05:00
|
|
|
1b 50 51 00 (CP3020DA)
|
|
|
|
1b 50 57 00 (9500)
|
2020-06-03 23:15:04 -04:00
|
|
|
1b 50 52 00 00 00 (CP30)
|
2016-10-12 23:28:54 -04:00
|
|
|
|
2019-12-20 23:06:09 -05:00
|
|
|
Unknown: 9600-S, 9820-S, 1 other..
|
2017-04-04 08:15:37 -04:00
|
|
|
|
2016-10-12 23:28:54 -04:00
|
|
|
~~~~ Lamination data follows (on 9810 only, if matte selected)
|
|
|
|
|
|
|
|
1b 5a 54 10 00 00 00 00 06 24 04 34
|
|
|
|
|
|
|
|
Data follows immediately, no padding.
|
|
|
|
|
|
|
|
1b 50 56 00 (Lamination footer)
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
~~~~ QUESTIONS:
|
|
|
|
|
2014-12-14 18:10:01 -05:00
|
|
|
* Lamination control?
|
2016-10-12 23:28:54 -04:00
|
|
|
* Other 9550 multi-cut modes (on 6x9 media: 4x6*2, 4.4x6*2, 3x6*3, 2x6*4)
|
|
|
|
* 9600/98x0 multi-cut modes?
|
|
|
|
|
2014-12-14 20:52:21 -05:00
|
|
|
***********************************************************************
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
* Mitsubishi CP-9xxx Communications Protocol:
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
JOB CANCEL
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 44
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Unknown query ]]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
|
|
|
-> 1b 4b 7f 00
|
2020-12-04 20:02:44 -05:00
|
|
|
<- eb 4b 8f 00 02 00 5e [[ '02' seems to be a length ]]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ unknown query, 9800-only ]]
|
2019-12-25 23:41:31 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 4b 01 00
|
|
|
|
<- e4 4b 01 00 02 00 78
|
2019-12-25 23:41:31 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
PRINT START
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 50 47 00 [9550S]
|
|
|
|
-> 1b 50 4e 00 [9800S]
|
|
|
|
-> 1b 50 56 00 [9810 Lamination]
|
|
|
|
[[ see "footer" above for other models ]]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Unknown ]]
|
2016-10-13 19:44:09 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 51 c5 9d
|
2016-10-13 19:44:09 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Unknown ]]
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 53 00 00
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Unknown ]]
|
2017-07-10 20:15:56 -04:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 53 c5 9d
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Status Query B ]]
|
2020-12-03 21:40:10 -05:00
|
|
|
|
|
|
|
-> 1b 56 20 00 [ CP30 ]
|
|
|
|
<- 20 2e 00 0a 10 00 00 00 00 00 00 00 CC CC RR RR :: CC == cols
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: RR == rows (04b0 for L??)
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Status Query C ]]
|
2020-12-03 21:40:10 -05:00
|
|
|
|
|
|
|
-> 1b 56 21 00 [ Most models ]
|
2014-12-14 20:52:21 -05:00
|
|
|
<- 21 2e 00 80 00 22 a8 0b 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 QQ 00 00 00 00 :: QQ == Prints in job?
|
|
|
|
00 00 00 00 00 00 00 00 00 00 NN NN 0A 00 00 01 :: NN NN = Remaining media
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
21 2e 00 00 00 20 08 02 00 00 00 00 00 00 00 00 [ CP30 ]
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Status Query D (unknown, possibly lifetime print count?) ]]
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
-> 1b 56 22 00 [ CP30 ]
|
2020-12-04 20:02:44 -05:00
|
|
|
<- 22 2e 00 40 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
FIRWARE VERSIONS
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-03 21:40:10 -05:00
|
|
|
-> 1b 56 23 00 [ CP30 ]
|
2020-12-04 20:02:44 -05:00
|
|
|
<- 23 2e 00 00 00 00 32 32 33 46 31 30 32 32 34 42 223F10 224B10 ... 222A10
|
|
|
|
31 30 00 00 00 00 00 00 32 32 32 41 31 30 00 00
|
|
|
|
00 00 00 05 d9 3f 79 20 00 00 13 97 00 00 00 00
|
2019-12-20 23:06:09 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
MEDIA INFO
|
2020-12-03 21:40:10 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 56 24 00
|
|
|
|
<- 24 2e 00 00 00 00 00 00 00 00 00 00 00 00 TT 00 :: TT = Type (!CP30)
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 MM MM N1 N1 :: MM MM = Max prints
|
|
|
|
NN NN 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: NN NN = Remaining (!CP30) ; N1 N1 = Remaining (CP30)
|
2019-12-25 23:41:31 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
Status Query [All models except CP30]
|
2019-12-25 23:41:31 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 56 30 00
|
|
|
|
-> 30 2e 00 00 00 00 MM 00 NN NN ZZ 00 00 00 00 00 :: MM, NN, ZZ
|
|
|
|
QQ RR SS 00 00 00 00 00 00 00 00 00 00 00 00 00 :: QQ, RR, SS
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 TT UU 00 00 :: TT, UU
|
|
|
|
|
|
|
|
Status Query X (unknown)
|
2020-12-03 21:40:10 -05:00
|
|
|
|
|
|
|
-> 1b 56 33 00
|
2019-12-20 23:06:09 -05:00
|
|
|
<- ??? 48 bytes?
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
Status Query Y (unknown)
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 56 36 00
|
|
|
|
<- ??? 48 bytes?
|
2014-12-14 20:52:21 -05:00
|
|
|
|
|
|
|
[[ Header 1 -- See above ]]
|
|
|
|
|
|
|
|
-> 1b 57 20 2e ....
|
|
|
|
|
|
|
|
[[ Header 2 -- See above ]]
|
|
|
|
|
|
|
|
-> 1b 57 21 2e ....
|
|
|
|
|
|
|
|
[[ Header 3 -- See above ]]
|
|
|
|
|
|
|
|
-> 1b 57 22 2e ....
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Header 4 -- See above ]]
|
|
|
|
|
|
|
|
-> 1b 57 26 2e ....
|
|
|
|
|
|
|
|
DATA Start [[ Or maybe it's "DATA Clear" ? ]]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
|
|
|
-> 1b 5a 43 00
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
PLANE Data
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 5a 54 ?? 00 00 00 00 XX XX YY YY :: XX XX == Columns, YY YY == Rows
|
|
|
|
:: ?? == x00 8bpp, x10 16bpp
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
Followed by image plane data, XXXX * YYYY [ * 2 ] bytes
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[ Three planes are needed! ]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
Query Model & FW Version (XXX Confirm this!)
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 72 01 00
|
|
|
|
<- e4 82 01 00 LL 39 00 35 00 35 00 30 00 5a 00 20
|
|
|
|
00 41 00 32 00 30 00 30 00 36 00 37 00
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
'LL' is length. Data is returned in 16-bit unicode, LE.
|
|
|
|
Contents are model ('9550Z'), then space, then serialnum ('A20067')
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
[[ Unknown query.. "Printer number" related? Seen in driver dump ]]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 72 10 00
|
|
|
|
<- e4 82 10 00 LL [ 10 unknown bytes. guess. ]
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
Query Model & Serial number
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 72 6e 00
|
|
|
|
<- e4 82 6e 00 LL 39 00 35 00 35 00 30 00 5a 00 20
|
|
|
|
00 41 00 32 00 30 00 30 00 36 00 37 00
|
|
|
|
|
|
|
|
'LL' is length. Data is returned in 16-bit unicode, LE.
|
|
|
|
Contents are model ('9550Z'), then space, then serialnum ('A20067')
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
|
|
|
|
**** After print starts, loop status/status b/media queries until printer idle
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2016-10-26 16:28:20 -04:00
|
|
|
MM, QQ RR SS, TT UU
|
|
|
|
|
|
|
|
<- 00 3e 00 00 8a 44 :: Idle.
|
|
|
|
00 7e 00 00 8a 44 :: Plane data submitted, pre "end data" cmd
|
|
|
|
00 7e 40 01 8a 44 :: "end data" sent
|
|
|
|
30 7e 40 01 8a 44
|
|
|
|
38 7e 40 01 8a 44
|
|
|
|
59 7e 40 01 8a 44
|
|
|
|
59 7e 40 00 8a 44
|
|
|
|
4d 7e 40 00 8a 44
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
43 7e 40 00 82 44
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
50 7e 40 00 80 44
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
31 7e 40 00 7d 44
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
00 3e 00 00 80 44 :: Idle.
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2017-07-10 20:15:56 -04:00
|
|
|
Also seen:
|
2014-12-14 20:52:21 -05:00
|
|
|
|
2016-10-26 16:28:20 -04:00
|
|
|
00 3e 00 00 96 4b :: Idle
|
|
|
|
00 be 00 00 96 4b :: Data submitted, pre "start"
|
|
|
|
00 be 80 01 96 4b :: print start sent
|
|
|
|
30 be 80 01 96 4c
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
30 be 80 01 89 4b
|
|
|
|
38 be 80 01 8a 4b
|
|
|
|
59 be 80 01 8b 4b
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
4d be 80 01 89 4b
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
43 be 80 01 89 4b
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
50 be 80 01 82 4b
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
2016-10-26 16:28:20 -04:00
|
|
|
31 be 80 01 80 4b
|
2014-12-14 20:52:21 -05:00
|
|
|
[...]
|
|
|
|
|
|
|
|
Working theory of interpreting the status flags:
|
|
|
|
|
|
|
|
MM :: 00 is idle, else mechanical printer state.
|
2014-12-20 12:43:22 -05:00
|
|
|
NN :: Remaining prints in job, or 0x00 0x00 when idle.
|
2014-12-14 20:52:21 -05:00
|
|
|
QQ :: ?? 0x3e + 0x40 or 0x80 (see below)
|
|
|
|
RR :: ?? 0x00 is idle, 0x40 or 0x80 is "printing"?
|
|
|
|
SS :: ?? 0x00 means "ready for another print" but 0x01 is "busy"
|
|
|
|
TT :: ?? seen values between 0x7c through 0x96)
|
2016-10-26 16:28:20 -04:00
|
|
|
UU :: ?? seen values between 0x43 and 0x4c -- temperature?
|
2020-12-04 20:02:44 -05:00
|
|
|
ZZ :: ?? Error code (08 = Door open on 9600)
|
2017-07-10 20:15:56 -04:00
|
|
|
|
|
|
|
***
|
2014-12-14 20:52:21 -05:00
|
|
|
|
|
|
|
Other printer commands seen:
|
|
|
|
|
|
|
|
[[ Set error policy ?? aka "header 4" ]]
|
|
|
|
|
2020-12-04 20:02:44 -05:00
|
|
|
-> 1b 57 26 2e 00 QQ 00 00 00 00 00 00 RR ZZ 00 00 :: QQ/RR/ZZ 00 00 00 [9550S]
|
2016-10-12 23:28:54 -04:00
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 20 01 00 [9550S w/ ignore failures on]
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 70 01 01 [9550]
|
2014-12-14 20:52:21 -05:00
|
|
|
00 00
|
2014-12-11 16:16:56 -05:00
|
|
|
|
|
|
|
*/
|