From a3dea1d4002604d015d9fb33c77e91a9cad80831 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 6 Nov 2020 17:35:27 -0500 Subject: [PATCH] updneo: Major fixes for Sony UP-D898MD * Add USB PID * Validate job parameters against printer's max reported dimensions * Serial numbers reported correctly * Handle two more status marker types * Better media status reporting * Printer-generated copies * Issue USB Reset between prints --- README | 4 +- backend_sonyupdneo.c | 132 ++++++++++++++++++++++++++++++++----------- blacklist | 3 + 3 files changed, 104 insertions(+), 35 deletions(-) diff --git a/README b/README index 12ae765..9198950 100644 --- a/README +++ b/README @@ -68,6 +68,7 @@ Sony UP-DR200 Sony UP-D895 Sony UP-D897 + Sony UP-D898 series Stryker SDP1000 Work-in-progress Printers: @@ -96,7 +97,6 @@ Shinko CHC-S6145-5A (aka Sinfonia CS2-c) Shinko CHC-S6245 (aka Sinfonia CE1) Sony UP-CR20L (aka DNP DS-SL20) - Sony UP-D898 series Sony UP-DR80 *************************************************************************** @@ -893,6 +893,7 @@ Sony UP-DR80MD Stryker SDP1000 + Sony UP-D898 / UP-X898 Work-in-progress printers @@ -900,7 +901,6 @@ Work-in-progress printers (Lack USB PIDs) - Sony UP-D898 / UP-X898 Sony UP-CR20L DNP DS-SL20 diff --git a/backend_sonyupdneo.c b/backend_sonyupdneo.c index 2340b71..f0278a8 100644 --- a/backend_sonyupdneo.c +++ b/backend_sonyupdneo.c @@ -30,6 +30,9 @@ /* Private data structures */ struct updneo_printjob { + size_t jobsize; + int copies; + uint8_t *databuf; int datalen; uint8_t *hdrbuf; @@ -37,10 +40,6 @@ struct updneo_printjob { uint8_t *ftrbuf; int ftrlen; -// int copies_offset; // XXX eventually implement - - int copies; - uint16_t rows; uint16_t cols; }; @@ -59,13 +58,15 @@ struct updneo_sts { uint16_t scmde; uint8_t scmce; char scjbi[17]; /* 16 char string, unknown */ - char scsyi[31]; /* 30 char string, unknown */ + char scsyi[31]; /* 30 char string, max resolution? */ uint32_t scsvi[2]; /* 2* 6char numbers */ uint32_t scmni[2]; /* 2* 6char numbers */ char sccai[15]; /* 14 char string, unknown */ uint16_t scgai; uint8_t scgsi; uint32_t scmdi; + uint32_t scqti; + uint32_t spuqi; }; struct updneo_ctx { @@ -92,6 +93,8 @@ static const char* updneo_decode_errors(uint16_t mde, uint8_t mce, uint8_t sye) return "No paper loaded"; if (mde == 0x0002) return "No ribbon loaded"; + if (mde == 0x0300) + return "No media loaded"; if (mde == 0x2000) return "Job does not match installed media"; @@ -109,6 +112,19 @@ static void* updneo_init(void) return ctx; } +static const char *updneo_medias(uint32_t mdi) +{ + mdi >>= 16; + mdi &= 0xff; + + switch(mdi) { + case 0x11: return "UPC-R81MD (Letter)"; + // UPC-R80MD (A4) + case 0x20: return "UPP-110 Roll"; + default: return "Unknown"; + } +} + static int updneo_attach(void *vctx, struct dyesub_connection *conn, uint8_t jobid) { struct updneo_ctx *ctx = vctx; @@ -122,14 +138,22 @@ static int updneo_attach(void *vctx, struct dyesub_connection *conn, uint8_t job if ((ret = updneo_get_status(ctx))) { return ret; } + + /* Needed by the UP-D898! But should be safe for + all models */ + libusb_reset_device(ctx->conn->dev); } + if (test_mode >= TEST_MODE_NOATTACH && getenv("MEDIA_CODE")) + ctx->marker.numtype = atoi(getenv("MEDIA_CODE")); + else + ctx->marker.numtype = (ctx->sts.scmdi >> 16) & 0xff; + + ctx->marker.name = updneo_medias(ctx->sts.scmdi); + if (ctx->conn->type == P_SONY_UPD898) { ctx->marker.color = "#000000"; /* Ie black! */ ctx->native_bpp = 1; - - ctx->marker.name = "Unknown"; - ctx->marker.numtype = -1; ctx->marker.levelmax = CUPS_MARKER_UNAVAILABLE; ctx->marker.levelnow = CUPS_MARKER_UNKNOWN; } else { @@ -138,15 +162,6 @@ static int updneo_attach(void *vctx, struct dyesub_connection *conn, uint8_t job ctx->marker.levelmax = 50; ctx->marker.numtype = (ctx->sts.scmdi >> 16) & 0xff; ctx->marker.levelnow = ctx->sts.scmds[4]; - - if (test_mode >= TEST_MODE_NOATTACH && getenv("MEDIA_CODE")) - ctx->marker.numtype = atoi(getenv("MEDIA_CODE")); - - if (ctx->marker.numtype == 0x11) { /* UP-DR80MD */ - ctx->marker.name = "UPC-R81MD (Letter)"; // vs UPC-R80MD (A4) - } else { - ctx->marker.name = "Unknown"; - } } return CUPS_BACKEND_OK; @@ -307,11 +322,37 @@ static int updneo_read_parse(void *vctx, const void **vjob, int data_fd, int cop } /* Sanity check job parameters */ - // XXX rows * cols lines up with imgsize, and others? - // Check vs loaded media type (ctx->marker.numtype, plus scsyi) - // set job copies to max(job, parameter) - // job->copies = copies; + /* Validate against max print size in SCSYI */ + { + char w[5], h[5]; + uint16_t mw, mh; + uint16_t jw, jh; + memcpy(h, ctx->sts.scsyi, 4); + h[4] = 0; + memcpy(w, ctx->sts.scsyi + 4, 4); + w[4] = 0; + mw = strtol(w, NULL, 16); + mh = strtol(h, NULL, 16); + + memcpy(&jw, job->databuf + 40, 2); + memcpy(&jh, job->databuf + 40 + 2, 2); + + jw = be16_to_cpu(jw); + jh = be16_to_cpu(jh); + + if (jw > mw || jh > mh) { + ERROR("Job (%dx%d) exceeds max dimensions(%d/%d)\n", + jw,jh,mw,mh); + updneo_cleanup_job(job); + return CUPS_BACKEND_CANCEL; + } + } + + // XXX Check vs loaded media type (ctx->marker.numtype?) + + // XXX set job copies to max(job, parameter) + job->databuf[28] = job->copies; job->copies = 1; /* Printer makes copies */ UNUSED(copies); @@ -346,6 +387,14 @@ static int updneo_get_status(struct updneo_ctx *ctx) ctx->sts.scsyv = strtol(dict[i].val, NULL, 16); } else if (!strcmp("SCSNO", dict[i].key)) { strncpy(ctx->sts.scsno, dict[i].val, sizeof(ctx->sts.scsno) - 1); + + /* Trim trailing '-'s off of serial number (UP-D898)*/ + for (int i = 0; i < (int) sizeof(ctx->sts.scsno); i++) { + if (ctx->sts.scsno[i] == '-') { + ctx->sts.scsno[i] = 0; + break; + } + } } else if (!strcmp("SCSYS", dict[i].key)) { strncpy(ctx->sts.scsys, dict[i].val, sizeof(ctx->sts.scsys) - 1); } else if (!strcmp("SCMDS", dict[i].key)) { @@ -398,15 +447,18 @@ static int updneo_get_status(struct updneo_ctx *ctx) ctx->sts.scgsi = strtol(dict[i].val, NULL, 16); } else if (!strcmp("SCMDI", dict[i].key)) { ctx->sts.scmdi = strtol(dict[i].val, NULL, 16); + } else if (!strcmp("SCQTI", dict[i].key)) { + ctx->sts.scqti = strtol(dict[i].val, NULL, 16); + } else if (!strcmp("SPUQI", dict[i].key)) { + ctx->sts.spuqi = strtol(dict[i].val, NULL, 16); } else if (!strcmp("MFG", dict[i].key) || !strcmp("MDL", dict[i].key) || !strcmp("DES", dict[i].key) || !strcmp("CMD", dict[i].key) || - !strcmp("CLS", dict[i].key)) - { + !strcmp("CLS", dict[i].key)) { /* Ignore standard IEEE1284 attributes! */ } else { - if (!strncmp("SC", dict[i].key, 2)) + if (!strncmp("SC", dict[i].key, 2) && !strncmp("SP", dict[i].key, 2)) DEBUG("Extra/Unknown IEEE1284 field '%s' = '%s'\n", dict[i].key, dict[i].val); } @@ -423,7 +475,7 @@ static int updneo_get_status(struct updneo_ctx *ctx) return CUPS_BACKEND_OK; } -static void updneo_dump_status(struct updneo_sts *sts) +static void updneo_dump_status(struct updneo_ctx *ctx, struct updneo_sts *sts) { /* Dump status */ INFO("Serial Number: %s\n", sts->scsno); @@ -432,8 +484,11 @@ static void updneo_dump_status(struct updneo_sts *sts) (sts->scsyv >> 16) & 0xff, (sts->scsyv >> 8) & 0xff, (sts->scsyv >> 0) & 0xff); - INFO("Media type: %s\n", sts->scmdi == 0x110154 ? "UPC-R81MD (Letter)" : "Unknown"); - INFO("Remaining prints: %u/50\n", sts->scmds[4]); + INFO("Media type: %s\n", updneo_medias(sts->scmdi)); + + if (ctx->conn->type == P_SONY_UPDR80) + INFO("Remaining prints: %u/50\n", sts->scmds[4]); + INFO("Print count: %u\n", sts->scsvi[0]); /* If the printer reports an error, pass it on */ @@ -528,6 +583,10 @@ retry: goto top; } + /* Needed by the UP-D898! But should be safe for + all models */ + libusb_reset_device(ctx->conn->dev); + return CUPS_BACKEND_OK; } @@ -550,7 +609,7 @@ static int updneo_cmdline_arg(void *vctx, int argc, char **argv) case 's': j = updneo_get_status(ctx); if (!j) - updneo_dump_status(&ctx->sts); + updneo_dump_status(ctx, &ctx->sts); break; } @@ -567,7 +626,6 @@ static int updneo_query_serno(struct dyesub_connection *conn, char *buf, int buf struct updneo_ctx ctx = { .conn = conn, }; - if ((ret = updneo_get_status(&ctx))) { return ret; } @@ -575,7 +633,6 @@ static int updneo_query_serno(struct dyesub_connection *conn, char *buf, int buf while (*ptr == 0x30) ptr++; strncpy(buf, ptr, buf_len); buf[buf_len-1] = 0; - return CUPS_BACKEND_OK; } @@ -606,8 +663,8 @@ static const char *sonyupdneo_prefixes[] = { }; /* Exported */ -#define USB_VID_SONY 0x054C -#define USB_PID_SONY_UPD898MD 0xabcd // 0x589a? +#define USB_VID_SONY 0x054C +#define USB_PID_SONY_UPD898MD 0x0877 // 0x589a? #define USB_PID_SONY_UPCR20L 0xbcde #define USB_PID_SONY_UPDR80MD 0x03c3 #define USB_PID_STRYKER_SDP1000 0x03c4 @@ -616,7 +673,8 @@ static const char *sonyupdneo_prefixes[] = { const struct dyesub_backend sonyupdneo_backend = { .name = "Sony UP-D Neo", - .version = "0.11", + .version = "0.12", + .flags = BACKEND_FLAG_BADISERIAL, /* UP-D898MD at least */ .uri_prefixes = sonyupdneo_prefixes, .cmdline_arg = updneo_cmdline_arg, .cmdline_usage = updneo_cmdline, @@ -833,6 +891,12 @@ const struct dyesub_backend sonyupdneo_backend = { [ Notable difference is SCSYI ] + UP-DR898MD + + MFG:Sony;MDL:UP-D898MD_X898MD;DES:Sony UP-D898MD_X898MD;CMD:SPJL-DS,SPDL-DS2;CLS:PRINTER;SCDIV:0100;SCSYV:01010000;SCSYS:0000001000010000000000;SCMDS:00000500000100000000;SCSYE:00;SCMDE:0000;SCMCE:00;SCSYI:100005001000050000000000014500;SCSVI:000204000204;SCMDI:200406;SCSNO:7100886---------;SCJBS:0000;SCCAI:00000000000000;SCGSI:01;SCQTI:0001;SPUQI:0000 + + [ This adds SCQTI; SCSNO is formatted differently, no SCPRS/SCJBI ] + Breakdown: (+) means referenced by their Windows driver @@ -857,6 +921,8 @@ Breakdown: SCGAI SCGSI +SCMDI # MeDiaInfo: 110154 OK w/UPD-R81MD(Letter), 1100FF with no paper, 000154 with no ribbon + SCQTI # QT Info (898MD) + SPUQI # UQ Info (898MD) Guess: diff --git a/blacklist b/blacklist index 3d9cea5..91c6f13 100644 --- a/blacklist +++ b/blacklist @@ -171,6 +171,9 @@ # Sony UP-D897 0x054c 0x01e7 blacklist +# Sony UP-D898MD +0x054c 0x0877 blacklist + # Sony UP-DR80 0x054c 0x03c5 blacklist