|
|
|
@ -35,11 +35,195 @@
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
|
|
#define VERSION "0.14"
|
|
|
|
|
#define URI_PREFIX "kodak6800://"
|
|
|
|
|
#define STR_LEN_MAX 64
|
|
|
|
|
#include "backend_common.h"
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
int main (int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
struct libusb_context *ctx;
|
|
|
|
|
struct libusb_device **list;
|
|
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
|
struct libusb_config_descriptor *config;
|
|
|
|
|
|
|
|
|
|
uint8_t endp_up = 0;
|
|
|
|
|
uint8_t endp_down = 0;
|
|
|
|
|
|
|
|
|
|
int data_fd = fileno(stdin);
|
|
|
|
|
|
|
|
|
|
int i, num;
|
|
|
|
|
int claimed;
|
|
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int iface = 0;
|
|
|
|
|
int found = -1;
|
|
|
|
|
int copies = 1;
|
|
|
|
|
char *uri = getenv("DEVICE_URI");;
|
|
|
|
|
char *use_serno = NULL;
|
|
|
|
|
|
|
|
|
|
uint8_t rdbuf[READBACK_LEN];
|
|
|
|
|
uint8_t rdbuf2[READBACK_LEN];
|
|
|
|
|
int last_state = -1, state = S_IDLE;
|
|
|
|
|
|
|
|
|
|
/* Time for the main processing loop */
|
|
|
|
|
|
|
|
|
|
top:
|
|
|
|
|
if (state != last_state) {
|
|
|
|
|
DEBUG("last_state %d new %d\n", last_state, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send Status Query */
|
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
|
cmdbuf[0] = 0x03;
|
|
|
|
|
cmdbuf[1] = 0x1b;
|
|
|
|
|
cmdbuf[2] = 0x43;
|
|
|
|
|
cmdbuf[3] = 0x48;
|
|
|
|
|
cmdbuf[4] = 0x43;
|
|
|
|
|
cmdbuf[5] = 0x03;
|
|
|
|
|
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN - 1)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
/* Read in the printer status */
|
|
|
|
|
memset(rdbuf, 0, READBACK_LEN);
|
|
|
|
|
ret = libusb_bulk_transfer(dev, endp_up,
|
|
|
|
|
rdbuf,
|
|
|
|
|
READBACK_LEN,
|
|
|
|
|
&num,
|
|
|
|
|
5000);
|
|
|
|
|
|
|
|
|
|
if (ret < 0 || ((num != 51) && (num != 58))) {
|
|
|
|
|
ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, num, READBACK_LEN, endp_up);
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
|
|
|
|
|
DEBUG("readback: ");
|
|
|
|
|
for (i = 0 ; i < num ; i++) {
|
|
|
|
|
DEBUG2("%02x ", rdbuf[i]);
|
|
|
|
|
}
|
|
|
|
|
DEBUG2("\n");
|
|
|
|
|
} else if (state == last_state) {
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
last_state = state;
|
|
|
|
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case S_IDLE:
|
|
|
|
|
INFO("Waiting for printer idle\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = S_PRINTER_READY_HDR;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_READY_HDR:
|
|
|
|
|
INFO("Printing started; Sending init sequence\n");
|
|
|
|
|
/* Send reset/attention */
|
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
|
cmdbuf[0] = 0x03;
|
|
|
|
|
cmdbuf[1] = 0x1b;
|
|
|
|
|
cmdbuf[2] = 0x43;
|
|
|
|
|
cmdbuf[3] = 0x48;
|
|
|
|
|
cmdbuf[4] = 0x43;
|
|
|
|
|
cmdbuf[5] = 0x1a;
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN -1)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
state = S_PRINTER_SENT_HDR;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_HDR:
|
|
|
|
|
INFO("Waiting for printer to acknowledge start\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x03 ||
|
|
|
|
|
rdbuf[2] != 0x00) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(cmdbuf, &hdr, CMDBUF_LEN);
|
|
|
|
|
|
|
|
|
|
/* If we're printing a 4x6 on 8x6 media... */
|
|
|
|
|
if (hdr.media == 0x00 &&
|
|
|
|
|
rdbuf[11] == 0x09 &&
|
|
|
|
|
rdbuf[12] == 0x82) {
|
|
|
|
|
cmdbuf[14] = 0x06;
|
|
|
|
|
cmdbuf[16] = 0x01;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INFO("Sending image header\n");
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
state = S_PRINTER_SENT_HDR2;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_HDR2:
|
|
|
|
|
INFO("Waiting for printer to accept data\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INFO("Sending image data\n");
|
|
|
|
|
if ((ret = send_data(dev, endp_down, planedata, datasize)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
INFO("Image data sent\n");
|
|
|
|
|
state = S_PRINTER_SENT_DATA;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_DATA:
|
|
|
|
|
INFO("Waiting for printer to acknowledge completion\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done printing */
|
|
|
|
|
INFO("All printing done\n");
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define CMDBUF_LEN 17
|
|
|
|
|
|
|
|
|
|
/* Private data stucture */
|
|
|
|
|
struct kodak6800_ctx {
|
|
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
|
uint8_t endp_up;
|
|
|
|
|
uint8_t endp_down;
|
|
|
|
|
|
|
|
|
|
uint8_t *databuf;
|
|
|
|
|
uint8_t cmdbuf[CMDBUF_LEN];
|
|
|
|
|
int datalen;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#include "backend_common.c"
|
|
|
|
|
|
|
|
|
|
/* Program states */
|
|
|
|
|
enum {
|
|
|
|
@ -51,6 +235,8 @@ enum {
|
|
|
|
|
S_FINISHED,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define READBACK_LEN 58
|
|
|
|
|
|
|
|
|
|
struct kodak6800_hdr {
|
|
|
|
|
uint8_t hdr[9];
|
|
|
|
|
uint8_t copies;
|
|
|
|
@ -61,13 +247,13 @@ struct kodak6800_hdr {
|
|
|
|
|
uint8_t unk1; /* 0x00, 0x01 [may be print mode] */
|
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
|
|
#define CMDBUF_LEN 17
|
|
|
|
|
#define READBACK_LEN 58
|
|
|
|
|
|
|
|
|
|
#define UPDATE_SIZE 1536
|
|
|
|
|
static int get_tonecurve(char *fname, libusb_device_handle *dev,
|
|
|
|
|
uint8_t endp_down, uint8_t endp_up)
|
|
|
|
|
static int kodak6800_get_tonecurve(struct kodak6800_ctx *ctx, char *fname)
|
|
|
|
|
{
|
|
|
|
|
libusb_device_handle *dev = ctx->dev;
|
|
|
|
|
uint8_t endp_down = ctx->endp_down;
|
|
|
|
|
uint8_t endp_up = ctx->endp_up;
|
|
|
|
|
|
|
|
|
|
uint8_t cmdbuf[16];
|
|
|
|
|
uint8_t respbuf[64];
|
|
|
|
|
int ret, num = 0;
|
|
|
|
@ -162,9 +348,12 @@ static int get_tonecurve(char *fname, libusb_device_handle *dev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int set_tonecurve(char *fname, libusb_device_handle *dev,
|
|
|
|
|
uint8_t endp_down, uint8_t endp_up)
|
|
|
|
|
static int kodak6800_set_tonecurve(struct kodak6800_ctx *ctx, char *fname)
|
|
|
|
|
{
|
|
|
|
|
libusb_device_handle *dev = ctx->dev;
|
|
|
|
|
uint8_t endp_down = ctx->endp_down;
|
|
|
|
|
uint8_t endp_up = ctx->endp_up;
|
|
|
|
|
|
|
|
|
|
uint8_t cmdbuf[64];
|
|
|
|
|
uint8_t respbuf[64];
|
|
|
|
|
int ret, num = 0;
|
|
|
|
@ -253,107 +442,58 @@ static int set_tonecurve(char *fname, libusb_device_handle *dev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char **argv)
|
|
|
|
|
static void kodak6800_cmdline(char *caller)
|
|
|
|
|
{
|
|
|
|
|
struct libusb_context *ctx;
|
|
|
|
|
struct libusb_device **list;
|
|
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
|
struct libusb_config_descriptor *config;
|
|
|
|
|
|
|
|
|
|
uint8_t endp_up = 0;
|
|
|
|
|
uint8_t endp_down = 0;
|
|
|
|
|
DEBUG("\t\t%s [ -qtc filename | -stc filename ]\n", caller);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int data_fd = fileno(stdin);
|
|
|
|
|
int kodak6800_cmdline_arg(void *vctx, int run, char *arg1, char *arg2)
|
|
|
|
|
{
|
|
|
|
|
struct kodak6800_ctx *ctx = vctx;
|
|
|
|
|
|
|
|
|
|
int i, num;
|
|
|
|
|
int claimed;
|
|
|
|
|
if (!run || !ctx)
|
|
|
|
|
return (!strcmp("-qtc", arg1) ||
|
|
|
|
|
!strcmp("-stc", arg1));
|
|
|
|
|
|
|
|
|
|
if (!strcmp("-qtc", arg1))
|
|
|
|
|
return kodak6800_get_tonecurve(ctx, arg2);
|
|
|
|
|
if (!strcmp("-stc", arg1))
|
|
|
|
|
return kodak6800_set_tonecurve(ctx, arg2);
|
|
|
|
|
|
|
|
|
|
int query_only = 0;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int iface = 0;
|
|
|
|
|
int found = -1;
|
|
|
|
|
int copies = 1;
|
|
|
|
|
char *uri = getenv("DEVICE_URI");;
|
|
|
|
|
char *use_serno = NULL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct kodak6800_hdr hdr;
|
|
|
|
|
uint8_t *planedata, *cmdbuf;
|
|
|
|
|
uint32_t datasize;
|
|
|
|
|
|
|
|
|
|
uint8_t rdbuf[READBACK_LEN];
|
|
|
|
|
uint8_t rdbuf2[READBACK_LEN];
|
|
|
|
|
int last_state = -1, state = S_IDLE;
|
|
|
|
|
static void *kodak6800_init(struct libusb_device_handle *dev,
|
|
|
|
|
uint8_t endp_up, uint8_t endp_down)
|
|
|
|
|
{
|
|
|
|
|
struct kodak6800_ctx *ctx = malloc(sizeof(struct kodak6800_ctx));
|
|
|
|
|
if (!ctx)
|
|
|
|
|
return NULL;
|
|
|
|
|
memset(ctx, 0, sizeof(struct kodak6800_ctx));
|
|
|
|
|
|
|
|
|
|
ctx->endp_up = endp_up;
|
|
|
|
|
ctx->endp_down = endp_down;
|
|
|
|
|
return ctx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEBUG("Kodak 6800 CUPS backend version " VERSION "/" BACKEND_VERSION " \n");
|
|
|
|
|
|
|
|
|
|
/* Cmdline help */
|
|
|
|
|
if (argc < 2) {
|
|
|
|
|
DEBUG("Usage:\n\t%s [ infile | - ]\n\t%s job user title num-copies options [ filename ]\n\t%s [ -qtc filename | -stc filename ] \n\n",
|
|
|
|
|
argv[0], argv[0], argv[0]);
|
|
|
|
|
libusb_init(&ctx);
|
|
|
|
|
find_and_enumerate(ctx, &list, NULL, P_KODAK_6800, 1);
|
|
|
|
|
libusb_free_device_list(list, 1);
|
|
|
|
|
libusb_exit(ctx);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
static void kodak6800_teardown(void *vctx) {
|
|
|
|
|
struct kodak6800_ctx *ctx = vctx;
|
|
|
|
|
|
|
|
|
|
/* Are we running as a CUPS backend? */
|
|
|
|
|
if (uri) {
|
|
|
|
|
if (argv[4])
|
|
|
|
|
copies = atoi(argv[4]);
|
|
|
|
|
if (argv[6]) { /* IOW, is it specified? */
|
|
|
|
|
data_fd = open(argv[6], O_RDONLY);
|
|
|
|
|
if (data_fd < 0) {
|
|
|
|
|
perror("ERROR:Can't open input file");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!ctx)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Ensure we're using BLOCKING I/O */
|
|
|
|
|
i = fcntl(data_fd, F_GETFL, 0);
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
perror("ERROR:Can't open input");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
i &= ~O_NONBLOCK;
|
|
|
|
|
i = fcntl(data_fd, F_SETFL, 0);
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
perror("ERROR:Can't open input");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
/* Start parsing URI 'selphy://PID/SERIAL' */
|
|
|
|
|
if (strncmp(URI_PREFIX, uri, strlen(URI_PREFIX))) {
|
|
|
|
|
ERROR("Invalid URI prefix (%s)\n", uri);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
use_serno = strchr(uri, '=');
|
|
|
|
|
if (!use_serno || !*(use_serno+1)) {
|
|
|
|
|
ERROR("Invalid URI (%s)\n", uri);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
use_serno++;
|
|
|
|
|
} else {
|
|
|
|
|
use_serno = getenv("DEVICE");
|
|
|
|
|
|
|
|
|
|
if (!strcmp("-qtc", argv[1]) ||
|
|
|
|
|
!strcmp("-stc", argv[1])) {
|
|
|
|
|
query_only = 1;
|
|
|
|
|
goto skip_read;
|
|
|
|
|
}
|
|
|
|
|
if (ctx->databuf)
|
|
|
|
|
free(ctx->databuf);
|
|
|
|
|
free(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open Input File */
|
|
|
|
|
if (strcmp("-", argv[1])) {
|
|
|
|
|
data_fd = open(argv[1], O_RDONLY);
|
|
|
|
|
if (data_fd < 0) {
|
|
|
|
|
perror("ERROR:Can't open input file");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static int kodak6800_read_parse(void *vctx, int data_fd) {
|
|
|
|
|
struct kodak6800_ctx *ctx = vctx;
|
|
|
|
|
struct kodak6800_hdr hdr;
|
|
|
|
|
|
|
|
|
|
/* Ignore SIGPIPE */
|
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
signal(SIGTERM, sigterm_handler);
|
|
|
|
|
if (!ctx)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* Read in then validate header */
|
|
|
|
|
read(data_fd, &hdr, sizeof(hdr));
|
|
|
|
@ -363,27 +503,25 @@ int main (int argc, char **argv)
|
|
|
|
|
hdr.hdr[3] != 0x48 ||
|
|
|
|
|
hdr.hdr[4] != 0x43) {
|
|
|
|
|
ERROR("Unrecognized data format!\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read in image data */
|
|
|
|
|
cmdbuf = malloc(CMDBUF_LEN);
|
|
|
|
|
datasize = be16_to_cpu(hdr.rows) * be16_to_cpu(hdr.columns) * 3;
|
|
|
|
|
planedata = malloc(datasize);
|
|
|
|
|
if (!cmdbuf || !planedata) {
|
|
|
|
|
ctx->datalen = be16_to_cpu(hdr.rows) * be16_to_cpu(hdr.columns) * 3;
|
|
|
|
|
ctx->databuf = malloc(ctx->datalen);
|
|
|
|
|
if (!ctx->databuf) {
|
|
|
|
|
ERROR("Memory allocation failure!\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
int remain;
|
|
|
|
|
uint8_t *ptr = planedata;
|
|
|
|
|
remain = datasize;
|
|
|
|
|
int remain = ctx->datalen;
|
|
|
|
|
uint8_t *ptr = ctx->databuf;
|
|
|
|
|
int ret;
|
|
|
|
|
do {
|
|
|
|
|
ret = read(data_fd, ptr, remain);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
ERROR("Read failed (%d/%d/%d)\n",
|
|
|
|
|
ret, remain, datasize);
|
|
|
|
|
ret, remain, ctx->datalen);
|
|
|
|
|
perror("ERROR: Read failed");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
@ -391,232 +529,24 @@ int main (int argc, char **argv)
|
|
|
|
|
remain -= ret;
|
|
|
|
|
} while (remain);
|
|
|
|
|
}
|
|
|
|
|
close(data_fd); /* We're done reading! */
|
|
|
|
|
|
|
|
|
|
skip_read:
|
|
|
|
|
/* Libusb setup */
|
|
|
|
|
libusb_init(&ctx);
|
|
|
|
|
found = find_and_enumerate(ctx, &list, use_serno, P_KODAK_6800, 0);
|
|
|
|
|
|
|
|
|
|
if (found == -1) {
|
|
|
|
|
ERROR("Printer open failure (No suitable printers found!)\n");
|
|
|
|
|
ret = 3;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = libusb_open(list[found], &dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
claimed = libusb_kernel_driver_active(dev, iface);
|
|
|
|
|
if (claimed) {
|
|
|
|
|
ret = libusb_detach_kernel_driver(dev, iface);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ERROR("Printer open failure (Could not detach printer from kernel)\n");
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done_close;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = libusb_claim_interface(dev, iface);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ERROR("Printer open failure (Could not claim printer interface)\n");
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done_close;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = libusb_get_active_config_descriptor(list[found], &config);
|
|
|
|
|
if (ret) {
|
|
|
|
|
ERROR("Printer open failure (Could not fetch config descriptor)\n");
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done_close;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0 ; i < config->interface[0].altsetting[0].bNumEndpoints ; i++) {
|
|
|
|
|
if ((config->interface[0].altsetting[0].endpoint[i].bmAttributes & 3) == LIBUSB_TRANSFER_TYPE_BULK) {
|
|
|
|
|
if (config->interface[0].altsetting[0].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
|
|
|
|
|
endp_up = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
|
|
|
|
|
else
|
|
|
|
|
endp_down = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (query_only) {
|
|
|
|
|
if (!strcmp("-qtc", argv[1]))
|
|
|
|
|
get_tonecurve(argv[2], dev, endp_down, endp_up);
|
|
|
|
|
if (!strcmp("-stc", argv[1]))
|
|
|
|
|
set_tonecurve(argv[2], dev, endp_down, endp_up);
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Time for the main processing loop */
|
|
|
|
|
|
|
|
|
|
top:
|
|
|
|
|
if (state != last_state) {
|
|
|
|
|
DEBUG("last_state %d new %d\n", last_state, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send Status Query */
|
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
|
cmdbuf[0] = 0x03;
|
|
|
|
|
cmdbuf[1] = 0x1b;
|
|
|
|
|
cmdbuf[2] = 0x43;
|
|
|
|
|
cmdbuf[3] = 0x48;
|
|
|
|
|
cmdbuf[4] = 0x43;
|
|
|
|
|
cmdbuf[5] = 0x03;
|
|
|
|
|
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN - 1)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
/* Read in the printer status */
|
|
|
|
|
memset(rdbuf, 0, READBACK_LEN);
|
|
|
|
|
ret = libusb_bulk_transfer(dev, endp_up,
|
|
|
|
|
rdbuf,
|
|
|
|
|
READBACK_LEN,
|
|
|
|
|
&num,
|
|
|
|
|
5000);
|
|
|
|
|
|
|
|
|
|
if (ret < 0 || ((num != 51) && (num != 58))) {
|
|
|
|
|
ERROR("Failure to receive data from printer (libusb error %d: (%d/%d from 0x%02x))\n", ret, num, READBACK_LEN, endp_up);
|
|
|
|
|
ret = 4;
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
|
|
|
|
|
DEBUG("readback: ");
|
|
|
|
|
for (i = 0 ; i < num ; i++) {
|
|
|
|
|
DEBUG2("%02x ", rdbuf[i]);
|
|
|
|
|
}
|
|
|
|
|
DEBUG2("\n");
|
|
|
|
|
} else if (state == last_state) {
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
last_state = state;
|
|
|
|
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case S_IDLE:
|
|
|
|
|
INFO("Waiting for printer idle\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = S_PRINTER_READY_HDR;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_READY_HDR:
|
|
|
|
|
INFO("Printing started; Sending init sequence\n");
|
|
|
|
|
/* Send reset/attention */
|
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
|
cmdbuf[0] = 0x03;
|
|
|
|
|
cmdbuf[1] = 0x1b;
|
|
|
|
|
cmdbuf[2] = 0x43;
|
|
|
|
|
cmdbuf[3] = 0x48;
|
|
|
|
|
cmdbuf[4] = 0x43;
|
|
|
|
|
cmdbuf[5] = 0x1a;
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN -1)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
state = S_PRINTER_SENT_HDR;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_HDR:
|
|
|
|
|
INFO("Waiting for printer to acknowledge start\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x03 ||
|
|
|
|
|
rdbuf[2] != 0x00) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(cmdbuf, &hdr, CMDBUF_LEN);
|
|
|
|
|
|
|
|
|
|
/* If we're printing a 4x6 on 8x6 media... */
|
|
|
|
|
if (hdr.media == 0x00 &&
|
|
|
|
|
rdbuf[11] == 0x09 &&
|
|
|
|
|
rdbuf[12] == 0x82) {
|
|
|
|
|
cmdbuf[14] = 0x06;
|
|
|
|
|
cmdbuf[16] = 0x01;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INFO("Sending image header\n");
|
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
|
cmdbuf, CMDBUF_LEN)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
state = S_PRINTER_SENT_HDR2;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_HDR2:
|
|
|
|
|
INFO("Waiting for printer to accept data\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
INFO("Sending image data\n");
|
|
|
|
|
if ((ret = send_data(dev, endp_down, planedata, datasize)))
|
|
|
|
|
goto done_claimed;
|
|
|
|
|
|
|
|
|
|
INFO("Image data sent\n");
|
|
|
|
|
state = S_PRINTER_SENT_DATA;
|
|
|
|
|
break;
|
|
|
|
|
case S_PRINTER_SENT_DATA:
|
|
|
|
|
INFO("Waiting for printer to acknowledge completion\n");
|
|
|
|
|
if (rdbuf[0] != 0x01 ||
|
|
|
|
|
rdbuf[1] != 0x02 ||
|
|
|
|
|
rdbuf[2] != 0x01) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done printing */
|
|
|
|
|
INFO("All printing done\n");
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
done_claimed:
|
|
|
|
|
libusb_release_interface(dev, iface);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done_close:
|
|
|
|
|
/* Exported */
|
|
|
|
|
struct dyesub_backend kodak6800_backend = {
|
|
|
|
|
.name = "Kodak 6800",
|
|
|
|
|
.version = "0.14",
|
|
|
|
|
.uri_prefix = "kodak6800",
|
|
|
|
|
.cmdline_usage = kodak6800_cmdline,
|
|
|
|
|
.cmdline_arg = kodak6800_cmdline_arg,
|
|
|
|
|
.init = kodak6800_init,
|
|
|
|
|
.teardown = kodak6800_teardown,
|
|
|
|
|
.read_parse = kodak6800_read_parse,
|
|
|
|
|
#if 0
|
|
|
|
|
if (claimed)
|
|
|
|
|
libusb_attach_kernel_driver(dev, iface);
|
|
|
|
|
.main_loop = kodak6800_main_loop,
|
|
|
|
|
#endif
|
|
|
|
|
libusb_close(dev);
|
|
|
|
|
done:
|
|
|
|
|
if (planedata)
|
|
|
|
|
free(planedata);
|
|
|
|
|
if (cmdbuf)
|
|
|
|
|
free(cmdbuf);
|
|
|
|
|
|
|
|
|
|
libusb_free_device_list(list, 1);
|
|
|
|
|
libusb_exit(ctx);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Kodak 6800/6850 data format
|
|
|
|
|
|
|
|
|
|