diff options
Diffstat (limited to 'src/cups/kodak605_print.c')
-rw-r--r-- | src/cups/kodak605_print.c | 548 |
1 files changed, 276 insertions, 272 deletions
diff --git a/src/cups/kodak605_print.c b/src/cups/kodak605_print.c index 544eb72..ad2e6bf 100644 --- a/src/cups/kodak605_print.c +++ b/src/cups/kodak605_print.c @@ -35,38 +35,116 @@ #include <fcntl.h> #include <signal.h> +#define BACKEND kodak605_backend + #include "backend_common.h" #define USB_VID_KODAK 0x040A #define USB_PID_KODAK_605 0x402E +/* Command Header */ +struct kodak605_cmd { + uint16_t cmd; /* LE */ + uint16_t len; /* LE, not counting this header */ +} __attribute__((packed)); + +struct kodak605_sts_hdr { + uint8_t result; /* RESULT_* */ + uint8_t unk_1[5]; /* 00 00 00 00 00 */ + uint8_t sts_1; /* 01/02 */ + uint8_t sts_2; /* 00/61->6b ?? temperature? */ + uint16_t length; /* LE, not counting this header */ +} __attribute__((packed)); + +#define RESULT_SUCCESS 0x01 +#define RESULT_FAIL 0x02 + /* Media structure */ struct kodak605_medium { uint8_t index; uint16_t cols; /* LE */ uint16_t rows; /* LE */ - uint8_t unk[5]; /* 01 00 00 00 00 */ + uint8_t type; /* MEDIA_TYPE_* */ + uint8_t unk[4]; /* 00 00 00 00 */ } __attribute__((packed)); +#define MEDIA_TYPE_UNKNOWN 0x00 +#define MEDIA_TYPE_PAPER 0x01 + struct kodak605_media_list { - uint8_t unk[12]; /* 01 00 00 00 00 00 02 00 67 00 02 0b */ + struct kodak605_sts_hdr hdr; + uint8_t unk; /* always seen 02 */ + uint8_t type; /* KODAK_MEDIA_* */ uint8_t count; struct kodak605_medium entries[]; } __attribute__((packed)); +#define KODAK_MEDIA_6R 0x0b +#define KODAK_MEDIA_NONE 0x00 + +#define MAX_MEDIA_LEN 128 + +/* Status response */ +struct kodak605_status { + struct kodak605_sts_hdr hdr; +/*@10*/ uint32_t ctr_life; /* Lifetime Prints */ + uint32_t ctr_maint; /* Prints since last maintainence */ + uint32_t ctr_media; /* Prints on current media */ + uint32_t ctr_cut; /* Cutter Actuations */ + uint32_t ctr_head; /* Prints on current head */ +/*@30*/ uint8_t donor; /* Donor Percentage remaining */ +/*@31*/ uint8_t null_1[7]; /* 00 00 00 00 00 00 00 */ +/*@38*/ uint8_t b1_id; /* 00/01/02 */ + uint16_t b1_remain; + uint16_t b1_complete; + uint16_t b1_total; +/*@45*/ uint8_t b1_sts; /* See BANK_STATUS_* */ + uint8_t b2_id; /* 00/01/02 */ + uint16_t b2_remain; + uint16_t b2_complete; + uint16_t b2_total; +/*@53*/ uint8_t b2_sts; /* see BANK_STATUS_* */ +/*@54*/ uint8_t id; /* current job id ( 00/01/02 seen ) */ +/*@55*/ uint16_t remain; /* in current job */ +/*@57*/ uint16_t complete; /* in current job */ +/*@59*/ uint16_t total; /* in current job */ +/*@61*/ uint8_t null_2[9]; /* 00 00 00 00 00 00 00 00 00 */ +/*@70*/ uint8_t unk_12[6]; /* 01 00 00 00 00 00 */ +} __attribute__((packed)); + /* File header */ struct kodak605_hdr { uint8_t hdr[4]; /* 01 40 0a 00 */ - uint8_t unk1; /* 01 or 02 */ - uint8_t copies; /* 01 or more */ - uint8_t unk2; /* always 00 */ - uint16_t columns; /* BE always 0x0734 */ - uint16_t rows; /* BE */ + uint8_t jobid; + uint16_t copies; /* LE, 0x0001 or more */ + uint16_t columns; /* LE, always 0x0734 */ + uint16_t rows; /* LE */ uint8_t media; /* 0x03 for 6x8, 0x01 for 6x4 */ uint8_t laminate; /* 0x02 to laminate, 0x01 for not */ - uint8_t unk3; /* 0x00, 0x01 [may be print mode] */ + uint8_t mode; /* Print mode -- 0x00, 0x01 seen */ } __attribute__((packed)); +#define BANK_STATUS_FREE 0x00 +#define BANK_STATUS_XFER 0x01 +#define BANK_STATUS_FULL 0x02 +#define BANK_STATUS_PRINTING 0x12 + +static char *bank_statuses(uint8_t v) +{ + switch (v) { + case BANK_STATUS_FREE: + return "Free"; + case BANK_STATUS_XFER: + return "Xfer"; + case BANK_STATUS_FULL: + return "Full"; + case BANK_STATUS_PRINTING: + return "Printing"; + default: + return "Unknown"; + } +} + #define CMDBUF_LEN 4 /* Private data stucture */ @@ -74,23 +152,50 @@ struct kodak605_ctx { struct libusb_device_handle *dev; uint8_t endp_up; uint8_t endp_down; + int type; + uint8_t jobid; struct kodak605_hdr hdr; + + struct kodak605_media_list *media; + uint8_t *databuf; int datalen; }; -/* Program states */ -enum { - S_IDLE = 0, - S_READY, - S_STARTED, - S_SENT_HDR, - S_SENT_DATA, - S_FINISHED, -}; +static int kodak605_get_media(struct kodak605_ctx *ctx, struct kodak605_media_list *media) +{ + uint8_t cmdbuf[4]; + + int ret, num = 0; + + /* Send Media Query */ + cmdbuf[0] = 0x02; + cmdbuf[1] = 0x00; + cmdbuf[2] = 0x00; + cmdbuf[3] = 0x00; + if ((ret = send_data(ctx->dev, ctx->endp_down, + cmdbuf, sizeof(cmdbuf)))) + return ret; -#define READBACK_LEN 120 + /* Read in the printer status */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) media, MAX_MEDIA_LEN, &num); + if (ret < 0) + return ret; + + if (num < (int)sizeof(*media)) { + ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*media)); + return CUPS_BACKEND_FAILED; + } + + if (media->hdr.result != RESULT_SUCCESS) { + ERROR("Unexpected response from media query (%x)!\n", media->hdr.result); + return CUPS_BACKEND_FAILED; + } + + return 0; +} static void *kodak605_init(void) { @@ -101,6 +206,10 @@ static void *kodak605_init(void) } memset(ctx, 0, sizeof(struct kodak605_ctx)); + ctx->media = malloc(MAX_MEDIA_LEN); + + ctx->type = P_ANY; + return ctx; } @@ -111,15 +220,23 @@ static void kodak605_attach(void *vctx, struct libusb_device_handle *dev, struct libusb_device *device; struct libusb_device_descriptor desc; - UNUSED(jobid); - - ctx->dev = dev; + ctx->dev = dev; ctx->endp_up = endp_up; ctx->endp_down = endp_down; device = libusb_get_device(dev); libusb_get_device_descriptor(device, &desc); + ctx->type = lookup_printer_type(&kodak605_backend, + desc.idVendor, desc.idProduct); + + /* Make sure jobid is sane */ + ctx->jobid = (jobid & 0x7f) + 1; + + /* Query media info */ + if (kodak605_get_media(ctx, ctx->media)) { + ERROR("Can't query media\n"); + } } static void kodak605_teardown(void *vctx) { @@ -190,236 +307,176 @@ static int kodak605_read_parse(void *vctx, int data_fd) { return CUPS_BACKEND_OK; } -static int kodak605_main_loop(void *vctx, int copies) { - struct kodak605_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 num, ret; - int pending = 0; - - if (!ctx) - return CUPS_BACKEND_FAILED; - - /* Printer handles generating copies.. */ - if (ctx->hdr.copies < copies) - ctx->hdr.copies = copies; - copies = 1; - -top: - if (state != last_state) { - if (dyesub_debug) - DEBUG("last_state %d new %d\n", last_state, state); - } +static int kodak605_get_status(struct kodak605_ctx *ctx, struct kodak605_status *sts) +{ + uint8_t cmdbuf[4]; - if (pending) - goto skip_query; + int ret, num = 0; /* Send Status Query */ cmdbuf[0] = 0x01; cmdbuf[1] = 0x00; cmdbuf[2] = 0x00; cmdbuf[3] = 0x00; - if ((ret = send_data(ctx->dev, ctx->endp_down, - cmdbuf, CMDBUF_LEN))) - return CUPS_BACKEND_FAILED; + cmdbuf, sizeof(cmdbuf)))) + return ret; -skip_query: /* Read in the printer status */ ret = read_data(ctx->dev, ctx->endp_up, - rdbuf, READBACK_LEN, &num); + (uint8_t*) sts, sizeof(*sts), &num); if (ret < 0) return ret; - if (num < 10) { - ERROR("Short read! (%d/%d)\n", num, 10); + if (num < (int)sizeof(*sts)) { + ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(*sts)); return CUPS_BACKEND_FAILED; } - if (num != 10 && num != 76 && num != 113) { - ERROR("Unexpected readback from printer (%d/%d from 0x%02x))\n", - num, READBACK_LEN, ctx->endp_up); + if (sts->hdr.result != RESULT_SUCCESS) { + ERROR("Unexpected response from status query (%x)!\n", sts->hdr.result); return CUPS_BACKEND_FAILED; } - if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) { - memcpy(rdbuf2, rdbuf, READBACK_LEN); - } else if (state == last_state) { - sleep(1); - } - last_state = state; + return 0; +} + +static int kodak605_main_loop(void *vctx, int copies) { + struct kodak605_ctx *ctx = vctx; - fflush(stderr); + struct kodak605_status sts; - pending = 0; + int num, ret; - switch (state) { - case S_IDLE: - INFO("Waiting for printer idle\n"); -#if 0 - if (rdbuf[0] != 0x01 || - rdbuf[1] != 0x02 || - rdbuf[2] != 0x01) { - break; - } -#endif - // XXX detect media type based on readback! + if (!ctx) + return CUPS_BACKEND_FAILED; - INFO("Printing started; Sending init sequence\n"); - state = S_STARTED; + /* Printer handles generating copies.. */ + if (le16_to_cpu(ctx->hdr.copies) < copies) + ctx->hdr.copies = cpu_to_le16(copies); - break; - case S_STARTED: -#if 0 - if (rdbuf[0] != 0x01 || - rdbuf[2] != 0x00) + /* Validate against supported media list */ + for (num = 0 ; num < ctx->media->count; num++) { + if (ctx->media->entries[num].rows == ctx->hdr.rows && + ctx->media->entries[num].cols == ctx->hdr.columns) break; + } + if (num == ctx->media->count) { + ERROR("Print size unsupported by media!\n"); + return CUPS_BACKEND_HOLD; + } - /* Aappears to depend on media */ - if (rdbuf[1] != 0x0b && - rdbuf[1] != 0x03) - break; -#endif + /* Use specified jobid */ + ctx->hdr.jobid = ctx->jobid; - INFO("Sending image header\n"); - if ((ret = send_data(ctx->dev, ctx->endp_down, - (uint8_t*)&ctx->hdr, sizeof(ctx->hdr)))) - return CUPS_BACKEND_FAILED; - pending = 1; - state = S_SENT_HDR; - break; - case S_SENT_HDR: - INFO("Waiting for printer to accept data\n"); - if (rdbuf[0] != 0x01 || - rdbuf[6] == 0x00 || - num != 10) { - break; - } - INFO("Sending image data\n"); - if ((ret = send_data(ctx->dev, ctx->endp_down, - ctx->databuf, ctx->datalen))) + INFO("Waiting for printer idle\n"); + + while(1) { + if ((ret = kodak605_get_status(ctx, &sts))) return CUPS_BACKEND_FAILED; - INFO("Image data sent\n"); - sleep(1); /* An experiment */ - state = S_SENT_DATA; - break; - case S_SENT_DATA: - INFO("Waiting for printer to acknowledge completion\n"); -#if 0 - if (rdbuf[0] != 0x01 || - rdbuf[1] != 0x02 || - rdbuf[2] != 0x01) { + // XXX check for errors + + /* Wait for a free buffer */ + if (sts.b1_sts == BANK_STATUS_FREE || + sts.b2_sts == BANK_STATUS_FREE) { break; } -#endif - state = S_FINISHED; - break; - default: - break; - }; - if (state != S_FINISHED) - goto top; + sleep(1); + } - /* Clean up */ - if (terminate) - copies = 1; + { + INFO("Sending image header\n"); + if ((ret = send_data(ctx->dev, ctx->endp_down, + (uint8_t*)&ctx->hdr, sizeof(ctx->hdr)))) + return CUPS_BACKEND_FAILED; - INFO("Print complete (%d copies remaining)\n", copies - 1); + struct kodak605_sts_hdr resp; + if ((ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &resp, sizeof(resp), &num))) + return CUPS_BACKEND_FAILED; - if (copies && --copies) { - state = S_IDLE; - goto top; + if (resp.result != RESULT_SUCCESS) { + ERROR("Unexpected response from print command (%x)!\n", resp.result); + return CUPS_BACKEND_FAILED; + } + // XXX what about resp.sts1 or resp.sts2? } + sleep(1); - return CUPS_BACKEND_OK; -} + INFO("Sending image data\n"); + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf, ctx->datalen))) + return CUPS_BACKEND_FAILED; -static int kodak605_get_status(struct kodak605_ctx *ctx) -{ - uint8_t cmdbuf[4]; - uint8_t rdbuf[76]; + INFO("Image data sent\n"); - int ret, i, num = 0; + INFO("Waiting for printer to acknowledge completion\n"); + do { + sleep(1); + if ((ret = kodak605_get_status(ctx, &sts))) + return CUPS_BACKEND_FAILED; - /* Send Status Query */ - cmdbuf[0] = 0x01; - cmdbuf[1] = 0x00; - cmdbuf[2] = 0x00; - cmdbuf[3] = 0x00; - if ((ret = send_data(ctx->dev, ctx->endp_down, - cmdbuf, sizeof(cmdbuf)))) - return ret; + // XXX check for errors ? - /* Read in the printer status */ - ret = read_data(ctx->dev, ctx->endp_up, - rdbuf, READBACK_LEN, &num); - if (ret < 0) - return ret; + /* Wait for completion */ + if (sts.b1_id == ctx->jobid && sts.b1_complete == sts.b1_total) + break; + if (sts.b2_id == ctx->jobid && sts.b2_complete == sts.b2_total) + break; - if (num < (int)sizeof(rdbuf)) { - ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(rdbuf)); - return 4; - } + if (fast_return) { + INFO("Fast return mode enabled.\n"); + break; + } + } while(1); - DEBUG("status: "); - for (i = 0 ; i < num ; i++) { - DEBUG2("%02x ", rdbuf[i]); - } + INFO("Print complete\n"); - return 0; + return CUPS_BACKEND_OK; +} + +static void kodak605_dump_status(struct kodak605_status *sts) +{ + INFO("Bank 1: %s Job %03u @ %03u/%03u\n", + bank_statuses(sts->b1_sts), sts->b1_id, + le16_to_cpu(sts->b1_complete), le16_to_cpu(sts->b1_complete)); + INFO("Bank 2: %s Job %03u @ %03u/%03u\n", + bank_statuses(sts->b2_sts), sts->b2_id, + le16_to_cpu(sts->b2_complete), le16_to_cpu(sts->b2_complete)); + + INFO("Lifetime prints : %d\n", be32_to_cpu(sts->ctr_life)); + INFO("Cutter actuations : %d\n", be32_to_cpu(sts->ctr_cut)); + INFO("Head prints : %d\n", be32_to_cpu(sts->ctr_head)); + INFO("Media prints : %d\n", be32_to_cpu(sts->ctr_media)); + INFO("Donor : %d%%\n", sts->donor); } static void kodak605_dump_mediainfo(struct kodak605_media_list *media) { int i; + if (media->type == KODAK_MEDIA_NONE) { + DEBUG("No Media Loaded\n"); + return; + } + + if (media->type == KODAK_MEDIA_6R) { + DEBUG("Media type: 6R (Kodak 197-4096 or equivalent)\n"); + } else { + DEBUG("Media type %02x (unknown, please report!)\n", media->type); + } + DEBUG("Legal print sizes:\n"); for (i = 0 ; i < media->count ; i++) { - DEBUG("\t%d: %dx%d\n", i, + DEBUG("\t%d: %dx%d\n", i, le16_to_cpu(media->entries[i].cols), le16_to_cpu(media->entries[i].rows)); } DEBUG("\n"); } -static int kodak605_get_media(struct kodak605_ctx *ctx) -{ - uint8_t cmdbuf[4]; - uint8_t rdbuf[113]; - - int ret, num = 0; - - /* Send Media Query */ - cmdbuf[0] = 0x02; - cmdbuf[1] = 0x00; - cmdbuf[2] = 0x00; - cmdbuf[3] = 0x00; - if ((ret = send_data(ctx->dev, ctx->endp_down, - cmdbuf, sizeof(cmdbuf)))) - return ret; - - /* Read in the printer status */ - ret = read_data(ctx->dev, ctx->endp_up, - rdbuf, READBACK_LEN, &num); - if (ret < 0) - return ret; - - if (num < (int)sizeof(rdbuf)) { - ERROR("Short Read! (%d/%d)\n", num, (int)sizeof(rdbuf)); - return 4; - } - - kodak605_dump_mediainfo((struct kodak605_media_list *)rdbuf); - - return 0; -} - #define UPDATE_SIZE 1536 static int kodak605_set_tonecurve(struct kodak605_ctx *ctx, char *fname) { @@ -507,29 +564,29 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv) struct kodak605_ctx *ctx = vctx; int i, j = 0; + if (!ctx) + return -1; + /* Reset arg parsing */ optind = 1; opterr = 0; - while ((i = getopt(argc, argv, "C:ms")) >= 0) { + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:ms")) >= 0) { switch(i) { + GETOPT_PROCESS_GLOBAL case 'C': - if (ctx) { - j = kodak605_set_tonecurve(ctx, optarg); - break; - } - return 1; + j = kodak605_set_tonecurve(ctx, optarg); + break; case 'm': - if (ctx) { - j = kodak605_get_media(ctx); - break; - } - return 1; - case 's': - if (ctx) { - j = kodak605_get_status(ctx); - break; - } - return 1; + kodak605_dump_mediainfo(ctx->media); + break; + case 's': { + struct kodak605_status sts; + + j = kodak605_get_status(ctx, &sts); + if (!j) + kodak605_dump_status(&sts); + break; + } default: break; /* Ignore completely */ } @@ -543,7 +600,7 @@ static int kodak605_cmdline_arg(void *vctx, int argc, char **argv) /* Exported */ struct dyesub_backend kodak605_backend = { .name = "Kodak 605", - .version = "0.21", + .version = "0.24", .uri_prefix = "kodak605", .cmdline_usage = kodak605_cmdline, .cmdline_arg = kodak605_cmdline_arg, @@ -563,76 +620,23 @@ struct dyesub_backend kodak605_backend = { Spool file consists of 14-byte header followed by plane-interleaved BGR data. Native printer resolution is 1844 pixels per row, and 1240 or 2434 rows. + All fields are LITTLE ENDIAN unless otherwise specified + Header: 01 40 0a 00 Fixed header - XX Unknown, always 01 in file, but 02 seen in sniffs sometimes - CC Number of copies (1-255) - 00 Always 0x00 - WW WW Number of columns, little endian. (Fixed at 1844) - HH HH Number of rows, little endian. (1240 or 2434) + XX Job ID + CC CC Number of copies (1-???) + WW WW Number of columns (Fixed at 1844) + HH HH Number of rows (1240 or 2434) DD 0x01 (4x6) 0x03 (8x6) LL Laminate, 0x01 (off) or 0x02 (on) - 00 + 00 Print Mode (???) ************************************************************************ - Kodak 605 Printer Comms: - - [[file header]] 01 40 0a 00 01 CC 00 WW WW HH HH MT LL 00 - --> 01 00 00 00 -<- [76 bytes -- status ] - - 01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00 - 00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 00 - 00 00 00 00 00 00 01 01 00 00 00 01 00 20 00 00 - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 01 00 00 00 00 00 - --> 01 00 00 00 -<- [76 bytes -- status ] + Note: Kodak 605 is actually a Shinko CHC-S1545-5A - 01 00 00 00 00 00 02 00 42 00 30 00 00 00 30 00 - 00 00 13 00 00 00 75 00 00 00 30 00 00 00 5d 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 00 00 00 01 00 00 00 00 00 - - --> 02 00 00 00 -<- [113 bytes -- supported media/sizes? Always seems to be identical ] - - [ 13-byte header, plus 10 slots for 10-byte media definitions, see above ] - - 01 00 00 00 00 00 02 00 67 00 02 0b 04 01 34 07 - d8 04 01 00 00 00 00 02 dc 05 34 08 01 00 00 00 - 00 03 34 07 82 09 01 00 00 00 00 04 34 07 ba 09 - 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 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 - --> 01 40 0a 00 01 01 00 34 07 d8 04 01 02 00 [[ unmodified header ]] -<- 01 00 00 00 00 00 XX 00 00 00 [[ Seen 0x01 and 0x02 ] --> image data! --> image data! - --> 01 00 00 00 -<- [76 bytes -- status ?? ] - - 01 00 00 00 00 00 01 00 42 00 31 00 00 00 31 00 - 00 00 14 00 00 00 77 00 00 00 31 00 00 00 5d 00 - 00 00 00 00 00 00 01 00 00 01 00 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 01 00 00 00 00 00 - - Write tone curve data: - --> 04 c0 0a 00 03 01 00 00 00 00 LL LL 00 00 [[ LL LL == 0x0600 in LE ]] -<- 01 00 00 00 00 00 XX 00 00 00 [[ Seen 0x01 and 0x02 ] - --> [[ 1536 bytes of LE tone curve data ]] + ************************************************************************ */ |