summaryrefslogtreecommitdiff
path: root/src/cups/backend_canonselphyneo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cups/backend_canonselphyneo.c')
-rw-r--r--src/cups/backend_canonselphyneo.c261
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?