diff options
Diffstat (limited to 'src/cups/backend_sonyupdr150.c')
-rw-r--r-- | src/cups/backend_sonyupdr150.c | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/src/cups/backend_sonyupdr150.c b/src/cups/backend_sonyupdr150.c new file mode 100644 index 0000000..be8423f --- /dev/null +++ b/src/cups/backend_sonyupdr150.c @@ -0,0 +1,407 @@ +/* + * Sony UP-DR150 Photo Printer CUPS backend -- libusb-1.0 version + * + * (c) 2013-2016 Solomon Peachy <pizza@shaftnet.org> + * + * The latest version of this program can be found at: + * + * http://git.shaftnet.org/cgit/selphy_print.git + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * 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. + * + * [http://www.gnu.org/licenses/gpl-2.0.html] + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> + +#define BACKEND updr150_backend + +#include "backend_common.h" + +/* Exported */ +#define USB_VID_SONY 0x054C +#define USB_PID_SONY_UPDR150 0x01E8 +#define USB_PID_SONY_UPDR200 0x035F +#define USB_PID_SONY_UPCR10 0x0226 + +/* Private data stucture */ +struct updr150_ctx { + struct libusb_device_handle *dev; + uint8_t endp_up; + uint8_t endp_down; + int type; + + uint8_t *databuf; + int datalen; + + uint32_t copies_offset; +}; + +static void* updr150_init(void) +{ + struct updr150_ctx *ctx = malloc(sizeof(struct updr150_ctx)); + if (!ctx) { + ERROR("Memory Allocation Failure!"); + return NULL; + } + memset(ctx, 0, sizeof(struct updr150_ctx)); + return ctx; +} + +static void updr150_attach(void *vctx, struct libusb_device_handle *dev, + uint8_t endp_up, uint8_t endp_down, uint8_t jobid) +{ + struct updr150_ctx *ctx = vctx; + struct libusb_device *device; + struct libusb_device_descriptor desc; + + UNUSED(jobid); + + 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(&updr150_backend, + desc.idVendor, desc.idProduct); + + ctx->copies_offset = 0; +} + +static void updr150_teardown(void *vctx) { + struct updr150_ctx *ctx = vctx; + + if (!ctx) + return; + + if (ctx->databuf) + free(ctx->databuf); + free(ctx); +} + +#define MAX_PRINTJOB_LEN 16736455 +static int updr150_read_parse(void *vctx, int data_fd) { + struct updr150_ctx *ctx = vctx; + int len, run = 1; + + if (!ctx) + return CUPS_BACKEND_FAILED; + + if (ctx->databuf) { + free(ctx->databuf); + ctx->databuf = NULL; + } + + ctx->datalen = 0; + ctx->databuf = malloc(MAX_PRINTJOB_LEN); + if (!ctx->databuf) { + ERROR("Memory allocation failure!\n"); + return CUPS_BACKEND_FAILED; + } + + while(run) { + int i; + int keep = 0; + i = read(data_fd, ctx->databuf + ctx->datalen, 4); + if (i < 0) + return CUPS_BACKEND_CANCEL; + if (i == 0) + break; + + memcpy(&len, ctx->databuf + ctx->datalen, sizeof(len)); + len = le32_to_cpu(len); + + /* Filter out chunks we don't send to the printer */ + switch (len) { + case 0xffffff60: + case 0xffffff6a: + case 0xffffffeb: + case 0xffffffec: + case 0xffffffed: + case 0xfffffff4: + case 0xfffffff8: + case 0xfffffff9: + case 0xfffffffa: + case 0xfffffffb: + case 0xfffffffc: + case 0xffffffff: + if(dyesub_debug) + DEBUG("Block ID '%08x' (len %d)\n", len, 0); + len = 0; + break; + case 0xfffffff3: + if(dyesub_debug) + DEBUG("Block ID '%08x' (len %d)\n", len, 0); + len = 0; + if (ctx->type == P_SONY_UPDR150) + run = 0; + break; + case 0xfffffff7: + if(dyesub_debug) + DEBUG("Block ID '%08x' (len %d)\n", len, 0); + len = 0; + if (ctx->type == P_SONY_UPCR10) + run = 0; + break; + case 0xffffffef: + case 0xfffffff5: + if(dyesub_debug) + DEBUG("Block ID '%08x' (len %d)\n", len, 4); + len = 4; + break; + default: + if (len & 0xff000000) { + ERROR("Unknown block ID '%08x', aborting!\n", len); + return CUPS_BACKEND_CANCEL; + } else { + /* Only keep these chunks */ + if(dyesub_debug) + DEBUG("Data block (len %d)\n", len); + keep = 1; + } + break; + } + if (keep) + ctx->datalen += sizeof(uint32_t); + + /* Read in the data chunk */ + while(len > 0) { + i = read(data_fd, ctx->databuf + ctx->datalen, len); + if (i < 0) + return CUPS_BACKEND_CANCEL; + if (i == 0) + break; + + if (ctx->databuf[ctx->datalen] == 0x1b && + ctx->databuf[ctx->datalen + 1] == 0xee) { + if (ctx->type == P_SONY_UPCR10) + ctx->copies_offset = ctx->datalen + 8; + else + ctx->copies_offset = ctx->datalen + 12; + } + + if (keep) + ctx->datalen += i; + len -= i; + } + } + if (!ctx->datalen) + return CUPS_BACKEND_CANCEL; + + return CUPS_BACKEND_OK; +} + +static int updr150_main_loop(void *vctx, int copies) { + struct updr150_ctx *ctx = vctx; + int i = 0, ret; + + if (!ctx) + return CUPS_BACKEND_FAILED; + + /* Some models specify copies in the print job */ + if (ctx->copies_offset) { + ctx->databuf[ctx->copies_offset] = copies; + copies = 1; + } + +top: + while (i < ctx->datalen) { + uint32_t len; + memcpy(&len, ctx->databuf + i, sizeof(len)); + len = le32_to_cpu(len); + + i += sizeof(uint32_t); + + if ((ret = send_data(ctx->dev, ctx->endp_down, + ctx->databuf + i, len))) + return CUPS_BACKEND_FAILED; + + i += len; + } + + /* Clean up */ + if (terminate) + copies = 1; + + INFO("Print complete (%d copies remaining)\n", copies - 1); + + if (copies && --copies) { + goto top; + } + + return CUPS_BACKEND_OK; +} + +static int updr150_cmdline_arg(void *vctx, int argc, char **argv) +{ + struct updr150_ctx *ctx = vctx; + int i, j = 0; + + if (!ctx) + return -1; + + while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL)) >= 0) { + switch(i) { + GETOPT_PROCESS_GLOBAL + } + + if (j) return j; + } + + return 0; +} + +struct dyesub_backend updr150_backend = { + .name = "Sony UP-DR150/UP-DR200/UP-CR10", + .version = "0.18", + .uri_prefix = "sonyupdr150", + .cmdline_arg = updr150_cmdline_arg, + .init = updr150_init, + .attach = updr150_attach, + .teardown = updr150_teardown, + .read_parse = updr150_read_parse, + .main_loop = updr150_main_loop, + .devices = { + { USB_VID_SONY, USB_PID_SONY_UPDR150, P_SONY_UPDR150, ""}, + { USB_VID_SONY, USB_PID_SONY_UPDR200, P_SONY_UPDR150, ""}, + { USB_VID_SONY, USB_PID_SONY_UPCR10, P_SONY_UPCR10, ""}, + { 0, 0, 0, ""} + } +}; + +/* Sony UP-DR150/UP-DR200 Spool file format + + The spool file is a series of 4-byte commands, followed by optional + arguments. The purpose of the commands is unknown, but they presumably + instruct the driver to perform certain things. + + If you treat these 4 bytes as a 32-bit little-endian number, if the + most significant four bits are bits are non-zero, the value is is to + be interpreted as a driver command. If the most significant bits are + zero, the value signifies that the following N bytes of data should be + sent to the printer as-is. + + Known driver "commands": + + 6a ff ff ff + fc ff ff ff + fb ff ff ff + f4 ff ff ff + ed ff ff ff + f9 ff ff ff + f8 ff ff ff + ec ff ff ff + eb ff ff ff + fa ff ff ff + f3 ff ff ff + ef ff ff ff XX 00 00 00 # XX == print size (0x01/0x02/0x03/0x04) + f5 ff ff ff YY 00 00 00 # YY == ??? (seen 0x01) + + All printer commands start with 0x1b, and are at least 7 bytes long. + + ************************************************************************ + + The data stream sent to the printer consists of all the commands in the + spool file, plus a couple other ones that generate responses. It is + unknown if those additional commands are necessary. This is a typical + sequence: + +[[ Sniff start of a UP-DR150 ]] + +<- 1b e0 00 00 00 0f 00 +-> 0e 00 00 00 00 00 00 00 00 04 a8 08 0a a4 00 + +<- 1b 16 00 00 00 00 00 +-> "reset" ?? + +[[ begin job ]] + +<- 1b ef 00 00 00 06 00 +-> 05 00 00 00 00 22 + +<- 1b e5 00 00 00 08 00 ** In spool file +<- 00 00 00 00 00 00 01 00 + +<- 1b c1 00 02 06 00 00 +-> 02 02 00 03 00 00 + +<- 1b ee 00 00 00 02 00 ** In spool file +<- 00 01 + +<- 1b 15 00 00 00 0d 00 ** In spool file +<- 00 00 00 00 07 00 00 00 00 08 00 0a a4 + +<- 1b 03 00 00 00 13 00 +-> 70 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00 + 00 00 00 + +<- 1b e1 00 00 00 0b 00 ** In spool file +<- 00 80 00 00 00 00 00 08 00 0a a4 + +<- 1b 03 00 00 00 13 00 +-> 70 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 00 + 00 00 00 + +<- 1b ea 00 00 00 00 00 ff 60 00 00 ** In spool file +<- [[ 0x0060ff00 bytes of data ]] + +<- 1b e0 00 00 00 0f 00 +-> 0e 00 00 00 00 00 00 00 04 a8 08 00 0a a4 00 + +<- 1b 0a 00 00 00 00 00 ** In spool file +<- 1b 17 00 00 00 00 00 ** In spool file + +[[fin]] + + ************** + + Sony UP-CL10 / DNP SL-10 spool format: + +60 ff ff ff +f8 ff ff ff +fd ff ff ff 14 00 00 00 1b 15 00 00 00 0d 00 00 00 00 00 07 00 00 00 00 WW WW HH HH +fb ff ff ff +f4 ff ff ff 0b 00 00 00 1b ea 00 00 00 00 SH SH SH SH 00 SL SL SL SL + + [[ Data, rows * cols * 3 bytes ]] + +f3 ff ff ff 0f 00 00 00 1b e5 00 00 00 08 00 00 00 00 00 00 00 00 00 + 12 00 00 00 1b e1 00 00 00 0b 00 00 80 00 00 00 00 00 WW WW HH HH +fa ff ff ff 09 00 00 00 1b ee 00 00 00 02 00 00 NN + 07 00 00 00 1b 0a 00 00 00 00 00 +f9 ff ff ff +fc ff ff ff 07 00 00 00 1b 17 00 00 00 00 00 +f7 ff ff ff + + WW WW == Columns, Big Endian + HH HH == Rows, Big Endian + SL SL SL SL == Plane size, Little Endian (Rows * Cols * 3) + SH SH SH SH == Plane size, Big Endian (Rows * Cols * 3) + NN == Copies + + + +*/ |