From da5ae0e152488824041ffe17a78faa7677548705 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Thu, 11 Dec 2014 16:16:56 -0500 Subject: [PATCH] mitsu9550: Initial WIP of the Mitsubishi CP-9550DW-S backend. Just committing it so I don't lose it. --- .gitignore | 1 + Makefile | 2 +- backend_common.c | 1 + backend_common.h | 2 + backend_mitsu9550.c | 430 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 backend_mitsu9550.c diff --git a/.gitignore b/.gitignore index 905553e..4a78e04 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ mitsu70x dnpds40 citizencw01 dyesub_backend +mitsu9550 diff --git a/Makefile b/Makefile index 05cd9e4..3268ff3 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CPPFLAGS = `pkg-config --cflags libusb-1.0` CUPS_BACKEND_DIR = /usr/lib/cups/backend CUPS_DATA_DIR = /usr/share/cups -BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy mitsu70x kodak605 dnpds40 citizencw01 +BACKENDS = sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy mitsu70x kodak605 dnpds40 citizencw01 mitsu9550 DEPS = backend_common.h diff --git a/backend_common.c b/backend_common.c index e5cc31a..ea6d43d 100644 --- a/backend_common.c +++ b/backend_common.c @@ -487,6 +487,7 @@ static struct dyesub_backend *backends[] = { &shinkos2145_backend, &updr150_backend, &mitsu70x_backend, + &mitsu9550_backend, &dnpds40_backend, &cw01_backend, NULL, diff --git a/backend_common.h b/backend_common.h index 23a3a6b..4a84ed7 100644 --- a/backend_common.h +++ b/backend_common.h @@ -105,6 +105,7 @@ enum { P_SONY_UPDR150, P_SONY_UPCR10, P_MITSU_D70X, + P_MITSU_9550, P_DNP_DS40, P_DNP_DS80, P_CITIZEN_CW01, @@ -154,6 +155,7 @@ extern struct dyesub_backend kodak1400_backend; extern struct dyesub_backend shinkos2145_backend; extern struct dyesub_backend canonselphy_backend; extern struct dyesub_backend mitsu70x_backend; +extern struct dyesub_backend mitsu9550_backend; extern struct dyesub_backend dnpds40_backend; extern struct dyesub_backend cw01_backend; diff --git a/backend_mitsu9550.c b/backend_mitsu9550.c new file mode 100644 index 0000000..2a1d7e2 --- /dev/null +++ b/backend_mitsu9550.c @@ -0,0 +1,430 @@ +/* + * Mitsubishi CP-9550DW[-S] Photo Printer CUPS backend + * + * (c) 2014 Solomon Peachy + * + * 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 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * [http://www.gnu.org/licenses/gpl-3.0.html] + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "backend_common.h" + +#define USB_VID_MITSU 0x06D3 +#define USB_PID_MITSU_9550D 0x03A1 +#define USB_PID_MITSU_9550DZ 0x03A5 + +/* Private data stucture */ +struct mitsu9550_ctx { + struct libusb_device_handle *dev; + uint8_t endp_up; + uint8_t endp_down; + + uint8_t *databuf; + int datalen; + + uint16_t rows; + uint16_t cols; +}; + +/* Spool file structures */ +struct mitsu9550_hdr1 { + uint8_t cmd[4]; /* 1b 57 20 2e */ + uint8_t unk[10]; + uint16_t rows; /* BE */ + uint16_t cols; /* BE */ + uint8_t null[32]; +} __attribute__((packed)); + +struct mitsu9550_hdr2 { + uint8_t cmd[4]; /* 1b 57 22 2e */ + uint8_t unk[28]; + uint8_t cut; /* 00 == normal, 83 == 2x6*2 */ + uint8_t unkb[6]; + uint8_t mode; /* 00 == normal, 80 == fine */ + uint8_t unkc[11]; +} __attribute__((packed)); + +struct mitsu9550_hdr3 { + uint8_t cmd[4]; /* 1b 57 22 2e */ + uint8_t unk[7]; + uint8_t mode2; /* 00 == normal, 01 == finedeep */ + uint8_t unkb[38]; +} __attribute__((packed)); + +struct mitsu9550_hdr4 { + uint8_t cmd[4]; /* 1b 57 26 2e */ + uint8_t unk[46]; +} __attribute__((packed)); + +struct mitsu9550_plane { + uint8_t cmd[4]; /* 1b 5a 54 00 */ + uint8_t null[2]; + uint16_t rem_rows; /* BE, normally 0 */ + uint16_t columns; /* BE */ + uint16_t rows; /* BE */ +} __attribute__((packed)); + +struct mitsu9550_footer { + uint8_t cmd[4]; /* 1b 50 46 00 */ +} __attribute__((packed)); + +/* Printer data structures */ +struct mitsu9550_media { + +} __attribute__((packed)); + +struct mitsu9550_status { + +} __attribute__((packed)); + +struct mitsu9550_status2 { + +} __attribute__((packed)); + +#define CMDBUF_LEN 64 +#define READBACK_LEN 128 + +static void *mitsu9550_init(void) +{ + struct mitsu9550_ctx *ctx = malloc(sizeof(struct mitsu9550_ctx)); + if (!ctx) + return NULL; + memset(ctx, 0, sizeof(struct mitsu9550_ctx)); + + return ctx; +} + +static void mitsu9550_attach(void *vctx, struct libusb_device_handle *dev, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +{ + struct mitsu9550_ctx *ctx = vctx; + + UNUSED(jobid); + + ctx->dev = dev; + ctx->endp_up = endp_up; + ctx->endp_down = endp_down; +} + + +static void mitsu9550_teardown(void *vctx) { + struct mitsu9550_ctx *ctx = vctx; + + if (!ctx) + return; + + if (ctx->databuf) + free(ctx->databuf); + free(ctx); +} + +static int mitsu9550_read_parse(void *vctx, int data_fd) { + struct mitsu9550_ctx *ctx = vctx; + struct mitsu9550_hdr1 hdr; + + int remain, i; + + if (!ctx) + return CUPS_BACKEND_FAILED; + + if (ctx->databuf) { + free(ctx->databuf); + ctx->databuf = NULL; + } + + /* Read in initial header */ + remain = sizeof(hdr); + while (remain > 0) { + i = read(data_fd, ((uint8_t*)&hdr) + sizeof(hdr) - remain, remain); + if (i == 0) + return CUPS_BACKEND_CANCEL; + if (i < 0) + return CUPS_BACKEND_CANCEL; + remain -= i; + } + + /* Sanity check */ + if (hdr.cmd[0] != 0x1b || + hdr.cmd[1] != 0x57 || + hdr.cmd[2] != 0x20 || + hdr.cmd[3] != 0x2e) { + ERROR("Unrecognized data format!\n"); + return CUPS_BACKEND_CANCEL; + } + + /* Work out printjob size */ + ctx->rows = be16_to_cpu(hdr.rows); + ctx->cols = be16_to_cpu(hdr.cols); + + remain = ctx->rows * ctx->cols + sizeof(struct mitsu9550_plane); + remain *= 3; + remain += sizeof(struct mitsu9550_hdr2) + sizeof(struct mitsu9550_hdr3)+ sizeof(struct mitsu9550_hdr4) + sizeof(struct mitsu9550_footer); + + /* Allocate buffer */ + ctx->databuf = malloc(remain + sizeof(struct mitsu9550_hdr1)); + if (!ctx->databuf) { + ERROR("Memory allocation failure!\n"); + return CUPS_BACKEND_FAILED; + } + + memcpy(ctx->databuf, &hdr, sizeof(struct mitsu9550_hdr1)); + ctx->datalen = sizeof(struct mitsu9550_hdr1); + + /* Read in the spool data */ + while(remain) { + i = read(data_fd, ctx->databuf + ctx->datalen, remain); + if (i == 0) + return CUPS_BACKEND_CANCEL; + if (i < 0) + return CUPS_BACKEND_CANCEL; + ctx->datalen += i; + remain -= i; + } + + return CUPS_BACKEND_OK; +} + +static int mitsu9550_get_status(struct mitsu9550_ctx *ctx, struct mitsu9550_status *resp) +{ + uint8_t cmdbuf[CMDBUF_LEN]; + int num, ret; + + /* Send Printer Query */ + memset(cmdbuf, 0, CMDBUF_LEN); + cmdbuf[0] = 0x1b; + cmdbuf[1] = 0x56; + cmdbuf[2] = 0x32; + cmdbuf[3] = 0x30; + if ((ret = send_data(ctx->dev, ctx->endp_down, + cmdbuf, 4))) + return ret; + memset(resp, 0, sizeof(*resp)); + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) resp, sizeof(*resp), &num); + + if (ret < 0) + return ret; + if (num != sizeof(*resp)) { + ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*resp)); + return 4; + } + + return 0; +} + +static int mitsu9550_main_loop(void *vctx, int copies) { + struct mitsu9550_ctx *ctx = vctx; + + int ret; + + if (!ctx) + return CUPS_BACKEND_FAILED; + +top: + + // query state, start streaming over chunks...? + // blablabla + +#if 0 + /* This printer handles copies internally */ + copies = 1; +#endif + + /* Clean up */ + if (terminate) + copies = 1; + + INFO("Print complete (%d copies remaining)\n", copies - 1); + + if (copies && --copies) { + goto top; + } + + return CUPS_BACKEND_OK; +} + +static void mitsu9550_dump_status(struct mitsu9550_status *resp) +{ + if (dyesub_debug) { +#if 0 + uint8_t *ptr; + unsigned int i; + + DEBUG("Status Dump:\n"); + for (i = 0 ; i < sizeof(resp->unk) ; i++) { + DEBUG2("%02x ", resp->unk[i]); + } + DEBUG2("\n"); + DEBUG("Lower Deck:\n"); + ptr = (uint8_t*) &resp->lower; + for (i = 0 ; i < sizeof(resp->lower) ; i++) { + DEBUG2("%02x ", *ptr++); + } + DEBUG2("\n"); + ptr = (uint8_t*) &resp->upper; + DEBUG("Upper Deck:\n"); + for (i = 0 ; i < sizeof(resp->upper) ; i++) { + DEBUG2("%02x ", *ptr++); + } + DEBUG2("\n"); +#endif + } +#if 0 + if (resp->upper.present & 0x80) { /* Not present */ + INFO("Prints remaining: %d\n", + be16_to_cpu(resp->lower.remain)); + } else { + INFO("Prints remaining: Lower: %d Upper: %d\n", + be16_to_cpu(resp->lower.remain), + be16_to_cpu(resp->upper.remain)); + } +#endif +} + +static int mitsu9550_query_status(struct mitsu9550_ctx *ctx) +{ + struct mitsu9550_status resp; + int ret; + + ret = mitsu9550_get_status(ctx, &resp); + + if (!ret) + mitsu9550_dump_status(&resp); + + return ret; +} + +static void mitsu9550_cmdline(void) +{ + DEBUG("\t\t[ -s ] # Query status\n"); +} + +static int mitsu9550_cmdline_arg(void *vctx, int argc, char **argv) +{ + struct mitsu9550_ctx *ctx = vctx; + int i, j = 0; + + /* Reset arg parsing */ + optind = 1; + opterr = 0; + while ((i = getopt(argc, argv, "s")) >= 0) { + switch(i) { + case 's': + if (ctx) { + j = mitsu9550_query_status(ctx); + break; + } + return 1; + default: + break; /* Ignore completely */ + } + + if (j) return j; + } + + return 0; +} + +/* Exported */ +struct dyesub_backend mitsu9550_backend = { + .name = "Mitsubishi CP-9550DW-S ***WIP***", + .version = "-0.001WIP", + .uri_prefix = "mitsu9550", + .cmdline_usage = mitsu9550_cmdline, + .cmdline_arg = mitsu9550_cmdline_arg, + .init = mitsu9550_init, + .attach = mitsu9550_attach, + .teardown = mitsu9550_teardown, + .read_parse = mitsu9550_read_parse, + .main_loop = mitsu9550_main_loop, + .devices = { + { USB_VID_MITSU, USB_PID_MITSU_9550DZ, P_MITSU_9550, ""}, + { USB_VID_MITSU, USB_PID_MITSU_9550D, P_MITSU_9550, ""}, + { 0, 0, 0, ""} + } +}; + +/* Mitsubish CP-9550D/DW spool data format + + Spool file consists of four 50-byte headers, followed by three image + planes (BGR, each with a 12-byte header), and a 4-byte footer. + + All multi-byte numbers are big endian. + + ~~~ Printer Init: 4x 50-byte blocks: + + 1b 57 20 2e 00 0a 10 00 00 00 00 00 00 00 07 14 :: 0714 = 1812 = X res + 04 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :: 04d8 = 1240 = Y res + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + + 1b 57 21 2e 00 80 00 22 08 03 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 :: YY 00 = normal, 80 = Fine + XX 00 00 00 00 00 YY 00 00 00 00 00 00 00 00 00 :: XX 00 = normal, 83 = Cut 2x6 + 00 01 + + 1b 57 22 2e 00 40 00 00 00 00 00 XX 00 00 00 00 :: 00 = normal, 01 = FineDeep + 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 + + 1b 57 26 2e 00 70 00 00 00 00 00 00 01 01 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 + + ~~~~ Data follows: Appears to be RGB (or BGR?) + + 1b 5a 54 00 00 00 00 00 07 14 04 d8 :: 0714 == row len, 04d8 == rows + ^^ ^^ :: 0000 == remaining rows + + 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: + + 1b 50 46 00 + + + ~~~~ QUESTIONS: + + * Lamination? + * Other multi-cut modes (6x9 media, 4x6*2, 4.4x6*2, 3x6*3, 2x6*4) + * Printer-generated copies (the "first 01" in hdr2?) + + */