mitsu70x: Add an experimental backend for the Mitsubishi CP-D70x series.

This as of yet untested, but guinea pigs welcome.
This commit is contained in:
Solomon Peachy 2013-10-05 09:55:29 -04:00
parent a1cf040437
commit 3d6021d59a
5 changed files with 299 additions and 3 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ kodak1400
gutenprint
shinkos2145
canonselphy
mitsu70x

View File

@ -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

11
README
View File

@ -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

View File

@ -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 */

279
backend_mitsu70x.c Normal file
View File

@ -0,0 +1,279 @@
/*
* Mitsubishi CP-D70/D707 Photo Printer CUPS backend -- libusb-1.0 version
*
* (c) 2013 Solomon Peachy <pizza@shaftnet.org>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#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, ""}
}
};