mitsu70x: Add an experimental backend for the Mitsubishi CP-D70x series.
This as of yet untested, but guinea pigs welcome.master
parent
a1cf040437
commit
3d6021d59a
|
@ -5,3 +5,4 @@ kodak1400
|
|||
gutenprint
|
||||
shinkos2145
|
||||
canonselphy
|
||||
mitsu70x
|
||||
|
|
9
Makefile
9
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
|
||||
|
|
11
README
11
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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, ""}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue