diff options
Diffstat (limited to 'src/cups/backend_canonselphyneo.c')
-rw-r--r-- | src/cups/backend_canonselphyneo.c | 261 |
1 files changed, 208 insertions, 53 deletions
diff --git a/src/cups/backend_canonselphyneo.c b/src/cups/backend_canonselphyneo.c index 85f51b2..93f539d 100644 --- a/src/cups/backend_canonselphyneo.c +++ b/src/cups/backend_canonselphyneo.c @@ -1,7 +1,7 @@ /* * Canon SELPHY CPneo series CUPS backend -- libusb-1.0 version * - * (c) 2016 Solomon Peachy <pizza@shaftnet.org> + * (c) 2016-2018 Solomon Peachy <pizza@shaftnet.org> * * The latest version of this program can be found at: * @@ -18,11 +18,12 @@ * 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. + * along with this program. If not, see <https://www.gnu.org/licenses/>. * * [http://www.gnu.org/licenses/gpl-2.0.html] * + * SPDX-License-Identifier: GPL-2.0+ + * */ #include <stdio.h> @@ -45,6 +46,7 @@ #define USB_PID_CANON_CP910 0x327a #define USB_PID_CANON_CP1000 0x32ae #define USB_PID_CANON_CP1200 0x32b1 +#define USB_PID_CANON_CP1300 0x32db /* Header data structure */ struct selphyneo_hdr { @@ -59,13 +61,20 @@ struct selphyneo_readback { } __attribute((packed)); /* Private data structure */ +struct selphyneo_printjob { + uint8_t *databuf; + uint32_t datalen; + + int copies; +}; + struct selphyneo_ctx { struct libusb_device_handle *dev; uint8_t endp_up; uint8_t endp_down; + int type; - uint8_t *databuf; - uint32_t datalen; + struct marker marker; }; static char *selphyneo_statuses(uint8_t sts) @@ -97,6 +106,8 @@ static char *selphyneo_errors(uint8_t err) return "Paper Feed"; case 0x03: return "No Paper"; + case 0x05: + return "Incorrect Paper loaded"; case 0x06: return "Ink Cassette Empty"; case 0x07: @@ -105,6 +116,8 @@ static char *selphyneo_errors(uint8_t err) return "No Paper and Ink"; case 0x0A: return "Incorrect media for job"; + case 0x0B: + return "Paper jam"; default: return "Unknown Error"; } @@ -140,6 +153,34 @@ static int selphyneo_send_reset(struct selphyneo_ctx *ctx) return CUPS_BACKEND_OK; } +static int selphyneo_get_status(struct selphyneo_ctx *ctx) +{ + struct selphyneo_readback rdback; + int ret, num; + + /* Read in the printer status to clear last state */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + + /* And again, for the markers */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + + INFO("Printer state: %s\n", selphyneo_statuses(rdback.data[0])); + INFO("Media type: %s\n", selphynew_pgcodes(rdback.data[6])); + if (rdback.data[2]) { + INFO("Printer error: %s\n", selphyneo_errors(rdback.data[2])); + } + + return CUPS_BACKEND_OK; +} + static void *selphyneo_init(void) { struct selphyneo_ctx *ctx = malloc(sizeof(struct selphyneo_ctx)); @@ -154,21 +195,60 @@ static void *selphyneo_init(void) extern struct dyesub_backend selphyneo_backend; -static void selphyneo_attach(void *vctx, struct libusb_device_handle *dev, - uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +static int selphyneo_attach(void *vctx, struct libusb_device_handle *dev, int type, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) { struct selphyneo_ctx *ctx = vctx; - struct libusb_device *device; - struct libusb_device_descriptor desc; + struct selphyneo_readback rdback; + int ret, num; UNUSED(jobid); ctx->dev = dev; ctx->endp_up = endp_up; ctx->endp_down = endp_down; + ctx->type = type; + + if (test_mode < TEST_MODE_NOATTACH) { + /* Read in the printer status to clear last state */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + + /* And again, for the markers */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + } else { + rdback.data[2] = 0; + rdback.data[6] = 0x01; + if (getenv("MEDIA_CODE")) + rdback.data[6] = atoi(getenv("MEDIA_CODE")); + } + + ctx->marker.color = "#00FFFF#FF00FF#FFFF00"; + ctx->marker.name = selphynew_pgcodes(rdback.data[6]); + ctx->marker.levelmax = -1; + if (rdback.data[2]) { + ctx->marker.levelnow = 0; + } else { + ctx->marker.levelnow = -3; + } + + return CUPS_BACKEND_OK; +} + +static void selphyneo_cleanup_job(const void *vjob) { + const struct selphyneo_printjob *job = vjob; - device = libusb_get_device(dev); - libusb_get_device_descriptor(device, &desc); + if (job->databuf) + free(job->databuf); + + free((void*)job); } static void selphyneo_teardown(void *vctx) { @@ -177,29 +257,39 @@ static void selphyneo_teardown(void *vctx) { if (!ctx) return; - if (ctx->databuf) - free(ctx->databuf); - free(ctx); } -static int selphyneo_read_parse(void *vctx, int data_fd) +static int selphyneo_read_parse(void *vctx, const void **vjob, int data_fd, int copies) { struct selphyneo_ctx *ctx = vctx; struct selphyneo_hdr hdr; int i, remain; + struct selphyneo_printjob *job = NULL; + if (!ctx) return CUPS_BACKEND_FAILED; + job = malloc(sizeof(*job)); + if (!job) { + ERROR("Memory allocation failure!\n"); + return CUPS_BACKEND_RETRY_CURRENT; + } + memset(job, 0, sizeof(*job)); + job->copies = copies; + /* Read the header.. */ i = read(data_fd, &hdr, sizeof(hdr)); if (i != sizeof(hdr)) { - if (i == 0) + if (i == 0) { + selphyneo_cleanup_job(job); return CUPS_BACKEND_CANCEL; + } ERROR("Read failed (%d/%d)\n", i, (int)sizeof(hdr)); perror("ERROR: Read failed"); + selphyneo_cleanup_job(job); return CUPS_BACKEND_FAILED; } @@ -213,53 +303,63 @@ static int selphyneo_read_parse(void *vctx, int data_fd) default: ERROR("Unknown print size! (%02x, %ux%u)\n", hdr.data[10], le32_to_cpu(hdr.cols), le32_to_cpu(hdr.rows)); + selphyneo_cleanup_job(job); return CUPS_BACKEND_CANCEL; } + // XXX Sanity check job against loaded media? + /* Allocate a buffer */ - ctx->datalen = 0; - ctx->databuf = malloc(remain + sizeof(hdr)); - if (!ctx->databuf) { + job->datalen = 0; + job->databuf = malloc(remain + sizeof(hdr)); + if (!job->databuf) { ERROR("Memory allocation failure!\n"); - return CUPS_BACKEND_FAILED; + selphyneo_cleanup_job(job); + return CUPS_BACKEND_RETRY_CURRENT; } /* Store the read-in header */ - memcpy(ctx->databuf, &hdr, sizeof(hdr)); - ctx->datalen += sizeof(hdr); + memcpy(job->databuf, &hdr, sizeof(hdr)); + job->datalen += sizeof(hdr); /* Read in data */ while (remain > 0) { - i = read(data_fd, ctx->databuf + ctx->datalen, remain); - if (i < 0) + i = read(data_fd, job->databuf + job->datalen, remain); + if (i < 0) { + selphyneo_cleanup_job(job); return CUPS_BACKEND_CANCEL; + } remain -= i; - ctx->datalen += i; + job->datalen += i; } + *vjob = job; + return CUPS_BACKEND_OK; } -static int selphyneo_main_loop(void *vctx, int copies) { +static int selphyneo_main_loop(void *vctx, const void *vjob) { struct selphyneo_ctx *ctx = vctx; struct selphyneo_readback rdback; int ret, num; + int copies; - /* Read in the printer status to clear last state */ - ret = read_data(ctx->dev, ctx->endp_up, - (uint8_t*) &rdback, sizeof(rdback), &num); + const struct selphyneo_printjob *job = vjob; - /* And again, for the markers */ + if (!ctx) + return CUPS_BACKEND_FAILED; + if (!job) + return CUPS_BACKEND_FAILED; + + copies = job->copies; + + /* Read in the printer status to clear last state */ ret = read_data(ctx->dev, ctx->endp_up, (uint8_t*) &rdback, sizeof(rdback), &num); - ATTR("marker-colors=#00FFFF#FF00FF#FFFF00\n"); - ATTR("marker-high-levels=100\n"); - ATTR("marker-low-levels=10\n"); - ATTR("marker-names='%s'\n", selphynew_pgcodes(rdback.data[6])); - - ATTR("marker-types=ribbonWax\n"); + if (ret < 0) + return CUPS_BACKEND_FAILED; top: INFO("Waiting for printer idle\n"); @@ -281,18 +381,20 @@ top: break; case 0x0A: ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]); - ATTR("marker-levels=%d\n", 0); + ctx->marker.levelnow = 0; + dump_markers(&ctx->marker, 1, 0); return CUPS_BACKEND_CANCEL; default: ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]); - ATTR("marker-levels=%d\n", 0); + ctx->marker.levelnow = 0; + dump_markers(&ctx->marker, 1, 0); return CUPS_BACKEND_STOP; } sleep(1); } while(1); - ATTR("marker-levels=%d\n", -3); /* ie Unknown but OK */ + dump_markers(&ctx->marker, 1, 0); INFO("Sending spool data\n"); /* Send the data over in 256K chunks */ @@ -301,10 +403,10 @@ top: int sent = 0; while (chunk > 0) { if ((ret = send_data(ctx->dev, ctx->endp_down, - ctx->databuf + sent, chunk))) + job->databuf + sent, chunk))) return CUPS_BACKEND_FAILED; sent += chunk; - chunk = ctx->datalen - sent; + chunk = job->datalen - sent; if (chunk > 256*1024) chunk = 256*1024; } @@ -314,6 +416,9 @@ top: ret = read_data(ctx->dev, ctx->endp_up, (uint8_t*) &rdback, sizeof(rdback), &num); + if (ret < 0) + return CUPS_BACKEND_FAILED; + INFO("Waiting for printer acknowledgement\n"); do { ret = read_data(ctx->dev, ctx->endp_up, @@ -332,15 +437,17 @@ top: break; case 0x0A: ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]); - ATTR("marker-levels=%d\n", 0); + ctx->marker.levelnow = 0; + dump_markers(&ctx->marker, 1, 0); return CUPS_BACKEND_CANCEL; default: ERROR("Printer error: %s (%02x)\n", selphyneo_errors(rdback.data[2]), rdback.data[2]); - ATTR("marker-levels=%d\n", 0); + ctx->marker.levelnow = 0; + dump_markers(&ctx->marker, 1, 0); return CUPS_BACKEND_STOP; } - if (rdback.data[0] > 0x02 && fast_return) { + if (rdback.data[0] > 0x02 && fast_return && copies <= 1) { INFO("Fast return mode enabled.\n"); break; } @@ -369,12 +476,15 @@ static int selphyneo_cmdline_arg(void *vctx, int argc, char **argv) if (!ctx) return -1; - while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "R")) >= 0) { + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "Rs")) >= 0) { switch(i) { GETOPT_PROCESS_GLOBAL case 'R': selphyneo_send_reset(ctx); break; + case 's': + selphyneo_get_status(ctx); + break; } if (j) return j; @@ -386,25 +496,68 @@ static int selphyneo_cmdline_arg(void *vctx, int argc, char **argv) static void selphyneo_cmdline(void) { DEBUG("\t\t[ -R ] # Reset printer\n"); + DEBUG("\t\t[ -s ] # Query printer status\n"); } +static int selphyneo_query_markers(void *vctx, struct marker **markers, int *count) +{ + struct selphyneo_ctx *ctx = vctx; + struct selphyneo_readback rdback; + int ret, num; + + /* Read in the printer status to clear last state */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + + /* And again, for the markers */ + ret = read_data(ctx->dev, ctx->endp_up, + (uint8_t*) &rdback, sizeof(rdback), &num); + + if (ret < 0) + return CUPS_BACKEND_FAILED; + + if (rdback.data[2]) + ctx->marker.levelnow = 0; + else + ctx->marker.levelnow = -3; + + *markers = &ctx->marker; + *count = 1; + + return CUPS_BACKEND_OK; +} + +static const char *canonselphyneo_prefixes[] = { + "canonselphyneo", // Family name + "canon-cp820", "canon-cp910", "canon-cp1000", "canon-cp1200", "canon-cp1300", + // backwards compatibility + "selphycp820", "selphycp910", "selphycp1000", "selphycp1200", "selphycp1300", + NULL +}; + struct dyesub_backend canonselphyneo_backend = { - .name = "Canon SELPHY CPneo", - .version = "0.08", - .uri_prefix = "canonselphyneo", + .name = "Canon SELPHY CP (new)", + .version = "0.20", + .uri_prefixes = canonselphyneo_prefixes, .cmdline_usage = selphyneo_cmdline, .cmdline_arg = selphyneo_cmdline_arg, .init = selphyneo_init, .attach = selphyneo_attach, + .cleanup_job = selphyneo_cleanup_job, .teardown = selphyneo_teardown, .read_parse = selphyneo_read_parse, .main_loop = selphyneo_main_loop, + .query_markers = selphyneo_query_markers, .devices = { - { USB_VID_CANON, USB_PID_CANON_CP820, P_CP910, ""}, - { USB_VID_CANON, USB_PID_CANON_CP910, P_CP910, ""}, - { USB_VID_CANON, USB_PID_CANON_CP1000, P_CP910, ""}, - { USB_VID_CANON, USB_PID_CANON_CP1200, P_CP910, ""}, - { 0, 0, 0, ""} + { USB_VID_CANON, USB_PID_CANON_CP820, P_CP910, NULL, "canon-cp820"}, + { USB_VID_CANON, USB_PID_CANON_CP910, P_CP910, NULL, "canon-cp910"}, + { USB_VID_CANON, USB_PID_CANON_CP1000, P_CP910, NULL, "canon-cp1000"}, + { USB_VID_CANON, USB_PID_CANON_CP1200, P_CP910, NULL, "canon-cp1200"}, + { USB_VID_CANON, USB_PID_CANON_CP1300, P_CP910, NULL, "canon-cp1300"}, + { 0, 0, 0, NULL, NULL} } }; /* @@ -468,9 +621,11 @@ struct dyesub_backend canonselphyneo_backend = { 00 None 02 No Paper (?) 03 No Paper + 05 Wrong Paper 07 No Ink 09 No Paper and Ink 0A Media/Job mismatch + 0B Paper Jam ZZ == Media? |