diff --git a/.gitignore b/.gitignore index 37234fb..6ebd174 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ kodak1400 gutenprint shinkos2145 canonselphy +mitsu70x diff --git a/Makefile b/Makefile index 4800f2d..7f5b6ec 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ LDFLAGS = -lusb-1.0 CUPS_BACKEND_DIR = /usr/lib/cups/backend CUPS_DATA_DIR = /usr/share/cups DEPS = backend_common.h -SOURCES = backend_sonyupdr150.c backend_kodak6800.c backend_common.c backend_kodak1400.c backend_shinkos2145.c backend_canonselphy.c +SOURCES = backend_sonyupdr150.c backend_kodak6800.c backend_common.c backend_kodak1400.c backend_shinkos2145.c backend_canonselphy.c backend_mitsu70x.c -all: gutenprint sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy +all: gutenprint sonyupdr150 kodak6800 kodak1400 shinkos2145 canonselphy mitsu70x gutenprint: $(SOURCES) $(DEPS) gcc -o $@ $(SOURCES) $(LDFLAGS) $(CFLAGS) @@ -26,10 +26,13 @@ shinkos2145: gutenprint canonselphy: gutenprint ln -sf gutenprint $@ +mitsu70x: gutenprint + ln -sf gutenprint $@ + install: install -o root -m 700 gutenprint $(CUPS_BACKEND_DIR)/gutenprint+usb mkdir -p $(CUPS_DATA_DIR)/usb install -o root -m 644 blacklist $(CUPS_DATA_DIR)/usb/net.sf.gimp-print.usb-quirks clean: - rm -f gutenprint canonselphy kodak6800 kodak1400 shinkos2145 sonyupdr150 + rm -f gutenprint canonselphy kodak6800 kodak1400 shinkos2145 sonyupdr150 mitsu70x diff --git a/README b/README index 9166740..b4e0ee9 100644 --- a/README +++ b/README @@ -22,6 +22,7 @@ Kodak 805 Photo Printer Kodak 6800 Photo Printer Kodak 6850 Photo Printer + Mitsubishi CP-D70x series Shinko/Sinfonia CHC-S2145 (aka "S2") Sony UP-DR150 @@ -244,3 +245,13 @@ Sony UP-DR150 This backend does not support additional commands + + *************************************************************************** + BACKEND=mitsu70x + + Theoretically supported printers: (Untested) + + Mitsubishi CP-D70DW + Mitsubishi CP-D707DW + + This backend does not support additional commands diff --git a/backend_common.h b/backend_common.h index b9ddbcb..80bc9e7 100644 --- a/backend_common.h +++ b/backend_common.h @@ -92,6 +92,7 @@ enum { P_KODAK_1400_805, P_SHINKO_S2145, P_SONY_UPDR150, + P_MITSU_D70X, P_END, }; @@ -133,5 +134,6 @@ extern struct dyesub_backend kodak6800_backend; extern struct dyesub_backend kodak1400_backend; extern struct dyesub_backend shinkos2145_backend; extern struct dyesub_backend canonselphy_backend; +extern struct dyesub_backend mitsu70x_backend; #endif /* __BACKEND_COMMON_H */ diff --git a/backend_mitsu70x.c b/backend_mitsu70x.c new file mode 100644 index 0000000..fbeb39e --- /dev/null +++ b/backend_mitsu70x.c @@ -0,0 +1,279 @@ +/* + * Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version + * + * (c) 2013 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_D70X 0x3B30 + +/* Private data stucture */ +struct mitsu70x_ctx { + struct libusb_device_handle *dev; + uint8_t endp_up; + uint8_t endp_down; + + uint8_t *databuf; + int datalen; +}; + +/* Program states */ +enum { + S_IDLE = 0, + S_SENT_ATTN, + S_SENT_HDR, + S_SENT_DATA, + S_FINISHED, +}; + +#define READBACK_LEN 256 + +static void *mitsu70x_init(void) +{ + struct mitsu70x_ctx *ctx = malloc(sizeof(struct mitsu70x_ctx)); + if (!ctx) + return NULL; + memset(ctx, 0, sizeof(struct mitsu70x_ctx)); + + return ctx; +} + +static void mitsu70x_attach(void *vctx, struct libusb_device_handle *dev, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +{ + struct mitsu70x_ctx *ctx = vctx; + struct libusb_device *device; + struct libusb_device_descriptor desc; + + ctx->dev = dev; + ctx->endp_up = endp_up; + ctx->endp_down = endp_down; + + device = libusb_get_device(dev); + libusb_get_device_descriptor(device, &desc); +} + + +static void mitsu70x_teardown(void *vctx) { + struct mitsu70x_ctx *ctx = vctx; + + if (!ctx) + return; + + if (ctx->databuf) + free(ctx->databuf); + free(ctx); +} + +// XXX is this enough? +#define MAX_PRINTJOB_LEN (1024*1024*32) + +static int mitsu70x_read_parse(void *vctx, int data_fd) { + struct mitsu70x_ctx *ctx = vctx; + uint8_t hdr[16]; + int i; + + if (!ctx) + return 1; + + /* Read in initial header to sanity check */ + read(data_fd, hdr, sizeof(hdr)); + if (hdr[0] != 0x1b || + hdr[1] != 0x45 || + hdr[2] != 0x57 || + hdr[3] != 0x55) { + ERROR("Unrecognized data format!\n"); + return(1); + } + + ctx->databuf = malloc(MAX_PRINTJOB_LEN); + if (!ctx->databuf) { + ERROR("Memory allocation failure!\n"); + return 2; + } + + /* Just read teh whole thing in */ + while((i = read(data_fd, ctx->databuf + ctx->datalen, 4096)) > 0) { + ctx->datalen += i; + } + + return 0; +} + +#define CMDBUF_LEN 512 +#define READBACK_LEN 256 + +static int mitsu70x_main_loop(void *vctx, int copies) { + struct mitsu70x_ctx *ctx = vctx; + + uint8_t rdbuf[READBACK_LEN]; + uint8_t rdbuf2[READBACK_LEN]; + uint8_t cmdbuf[CMDBUF_LEN]; + + int last_state = -1, state = S_IDLE; + int i, num, ret; + int pending = 0; + + if (!ctx) + return 1; + +top: + if (state != last_state) { + DEBUG("last_state %d new %d\n", last_state, state); + } + + if (pending) + goto skip_query; + + /* Send Status Query */ + memset(cmdbuf, 0, CMDBUF_LEN); + cmdbuf[0] = 0x1b; + cmdbuf[1] = 0x56; + cmdbuf[2] = 0x31; + cmdbuf[3] = 0x30; + cmdbuf[4] = 0x00; + cmdbuf[5] = 0x00; + + if ((ret = send_data(ctx->dev, ctx->endp_down, + cmdbuf, 6))) + return ret; + +skip_query: + /* Read in the printer status */ + memset(rdbuf, 0, READBACK_LEN); + ret = libusb_bulk_transfer(ctx->dev, ctx->endp_up, + rdbuf, + READBACK_LEN, + &num, + 5000); + + if (ret < 0 || num != 26) { + ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, num, READBACK_LEN, ctx->endp_up); + if (ret < 0) + return ret; + return 4; + } + + if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) { + DEBUG("readback: "); + for (i = 0 ; i < num ; i++) { + DEBUG2("%02x ", rdbuf[i]); + } + DEBUG2("\n"); + memcpy(rdbuf2, rdbuf, READBACK_LEN); + } else if (state == last_state) { + sleep(1); + } + last_state = state; + + fflush(stderr); + + pending = 0; + + switch (state) { + case S_IDLE: + INFO("Waiting for printer idle\n"); + if (rdbuf[7] != 0x00 || + rdbuf[8] != 0x00 || + rdbuf[9] != 0x00) { + break; + } + + INFO("Sending attention sequence\n"); + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf, 512))) + return ret; + + state = S_SENT_ATTN; + case S_SENT_ATTN: + INFO("Sending header sequence\n"); + + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf + 512, 512))) + return ret; + + state = S_SENT_HDR; + break; + case S_SENT_HDR: + INFO("Sending data\n"); + + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf + 1024, ctx->datalen - 1024))) + return ret; + + state = S_SENT_DATA; + break; + case S_SENT_DATA: + INFO("Waiting for printer to acknowledge completion\n"); + + state = S_FINISHED; + break; + default: + break; + }; + + if (state != S_FINISHED) + goto top; + + /* Clean up */ + if (terminate) + copies = 1; + + INFO("Print complete (%d remaining)\n", copies - 1); + + if (copies && --copies) { + state = S_IDLE; + goto top; + } + + return 0; +} + +/* Exported */ +struct dyesub_backend mitsu70x_backend = { + .name = "Mitsubishi CP-D70/D707", + .version = "0.01", + .uri_prefix = "mitsu70x", + .init = mitsu70x_init, + .attach = mitsu70x_attach, + .teardown = mitsu70x_teardown, + .read_parse = mitsu70x_read_parse, + .main_loop = mitsu70x_main_loop, + .devices = { + { USB_VID_MITSU, USB_PID_MITSU_D70X, P_MITSU_D70X, "Mitsubishi"}, + { 0, 0, 0, ""} + } +};