2013-01-19 17:10:21 -05:00
|
|
|
/*
|
2013-07-27 07:32:21 -04:00
|
|
|
* Kodak Professional 1400/805 CUPS backend -- libusb-1.0 version
|
2013-01-19 17:10:21 -05:00
|
|
|
*
|
2015-01-05 21:39:22 -05:00
|
|
|
* (c) 2013-2015 Solomon Peachy <pizza@shaftnet.org>
|
2013-01-19 17:10:21 -05:00
|
|
|
*
|
|
|
|
* The latest version of this program can be found at:
|
2014-01-13 05:41:48 -05:00
|
|
|
*
|
2013-08-20 20:10:21 -04:00
|
|
|
* http://git.shaftnet.org/cgit/selphy_print.git
|
2014-01-13 05:41:48 -05:00
|
|
|
*
|
2013-01-19 17:10:21 -05:00
|
|
|
* 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 3 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-3.0.html]
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2013-05-02 20:15:55 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
2015-08-13 21:09:56 -04:00
|
|
|
#define BACKEND kodak1400_backend
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
#include "backend_common.h"
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-01-19 19:11:20 -05:00
|
|
|
/* Program states */
|
|
|
|
enum {
|
|
|
|
S_IDLE = 0,
|
|
|
|
S_PRINTER_READY_Y,
|
2013-01-19 21:36:23 -05:00
|
|
|
S_PRINTER_SENT_Y,
|
2013-01-19 19:11:20 -05:00
|
|
|
S_PRINTER_READY_M,
|
2013-01-19 21:36:23 -05:00
|
|
|
S_PRINTER_SENT_M,
|
2013-01-19 19:11:20 -05:00
|
|
|
S_PRINTER_READY_C,
|
2013-01-19 21:36:23 -05:00
|
|
|
S_PRINTER_SENT_C,
|
|
|
|
S_PRINTER_READY_L,
|
|
|
|
S_PRINTER_SENT_L,
|
2013-01-19 19:11:20 -05:00
|
|
|
S_PRINTER_DONE,
|
|
|
|
S_FINISHED,
|
|
|
|
};
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
#define CMDBUF_LEN 96
|
|
|
|
#define READBACK_LEN 8
|
|
|
|
|
|
|
|
/* File header */
|
2013-01-19 17:10:21 -05:00
|
|
|
struct kodak1400_hdr {
|
2013-01-19 19:11:20 -05:00
|
|
|
uint8_t hdr[4];
|
|
|
|
uint16_t columns;
|
|
|
|
uint16_t null1;
|
|
|
|
uint16_t rows;
|
|
|
|
uint16_t null2;
|
|
|
|
uint32_t planesize;
|
|
|
|
uint32_t null3;
|
|
|
|
uint8_t matte;
|
|
|
|
uint8_t laminate;
|
|
|
|
uint8_t unk1; /* Always 0x01 */
|
|
|
|
uint8_t lam_strength;
|
|
|
|
uint8_t null4[12];
|
2013-06-28 07:18:16 -04:00
|
|
|
} __attribute__((packed));
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-06-27 23:02:34 -04:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
/* Private data stucture */
|
|
|
|
struct kodak1400_ctx {
|
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
uint8_t endp_up;
|
|
|
|
uint8_t endp_down;
|
2015-08-12 22:56:29 -04:00
|
|
|
int type;
|
2013-01-19 21:36:23 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
struct kodak1400_hdr hdr;
|
|
|
|
uint8_t *plane_r;
|
|
|
|
uint8_t *plane_g;
|
|
|
|
uint8_t *plane_b;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int send_plane(struct kodak1400_ctx *ctx,
|
2013-01-19 22:24:58 -05:00
|
|
|
uint8_t planeno, uint8_t *planedata,
|
2013-07-18 21:05:33 -04:00
|
|
|
uint8_t *cmdbuf)
|
2013-01-19 22:24:58 -05:00
|
|
|
{
|
|
|
|
uint16_t temp16;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (planeno != 1) {
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x74;
|
|
|
|
cmdbuf[2] = 0x00;
|
|
|
|
cmdbuf[3] = 0x50;
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:24:58 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x5a;
|
|
|
|
cmdbuf[2] = 0x54;
|
|
|
|
cmdbuf[3] = planeno;
|
2013-01-19 22:26:52 -05:00
|
|
|
|
|
|
|
if (planedata) {
|
2013-07-18 21:05:33 -04:00
|
|
|
temp16 = htons(ctx->hdr.columns);
|
2013-01-19 22:26:52 -05:00
|
|
|
memcpy(cmdbuf+7, &temp16, 2);
|
2013-07-18 21:05:33 -04:00
|
|
|
temp16 = htons(ctx->hdr.rows);
|
2013-01-19 22:26:52 -05:00
|
|
|
memcpy(cmdbuf+9, &temp16, 2);
|
2013-01-19 22:46:04 -05:00
|
|
|
}
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:46:04 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (planedata) {
|
2014-02-11 20:11:33 -05:00
|
|
|
int i;
|
2013-07-18 21:05:33 -04:00
|
|
|
for (i = 0 ; i < ctx->hdr.rows ; i++) {
|
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
planedata + i * ctx->hdr.columns,
|
|
|
|
ctx->hdr.columns)))
|
2013-01-19 22:26:52 -05:00
|
|
|
return ret;
|
|
|
|
}
|
2013-01-19 22:24:58 -05:00
|
|
|
}
|
2013-01-19 22:26:52 -05:00
|
|
|
|
2013-01-19 22:24:58 -05:00
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x74;
|
|
|
|
cmdbuf[2] = 0x01;
|
|
|
|
cmdbuf[3] = 0x50;
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:24:58 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-08 20:45:46 -04:00
|
|
|
#define UPDATE_SIZE 1552
|
2013-07-18 21:05:33 -04:00
|
|
|
static int kodak1400_set_tonecurve(struct kodak1400_ctx *ctx, char *fname)
|
2013-07-08 20:45:46 -04:00
|
|
|
{
|
2013-07-18 21:05:33 -04:00
|
|
|
libusb_device_handle *dev = ctx->dev;
|
|
|
|
uint8_t endp_down = ctx->endp_down;
|
|
|
|
uint8_t endp_up = ctx->endp_up;
|
|
|
|
|
2013-07-08 20:45:46 -04:00
|
|
|
uint8_t cmdbuf[8];
|
|
|
|
uint8_t respbuf[64];
|
2014-02-11 20:11:33 -05:00
|
|
|
int ret = 0, num = 0;
|
2013-07-08 20:45:46 -04:00
|
|
|
|
|
|
|
INFO("Set Tone Curve from '%s'\n", fname);
|
|
|
|
|
|
|
|
uint16_t *data = malloc(UPDATE_SIZE);
|
|
|
|
|
2015-06-23 20:32:41 -04:00
|
|
|
if (!data) {
|
|
|
|
ERROR("Memory Allocation Failure!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-08 20:45:46 -04:00
|
|
|
/* Read in file */
|
|
|
|
int tc_fd = open(fname, O_RDONLY);
|
2014-02-11 20:11:33 -05:00
|
|
|
if (tc_fd < 0) {
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if (read(tc_fd, data, UPDATE_SIZE) != UPDATE_SIZE) {
|
|
|
|
ret = -2;
|
|
|
|
goto done;
|
|
|
|
}
|
2013-07-08 20:45:46 -04:00
|
|
|
close(tc_fd);
|
|
|
|
|
|
|
|
/* Byteswap data to printer's format */
|
2013-07-08 21:53:52 -04:00
|
|
|
for (ret = 0; ret < (UPDATE_SIZE-16)/2 ; ret++) {
|
2013-07-08 20:45:46 -04:00
|
|
|
data[ret] = cpu_to_le16(be16_to_cpu(data[ret]));
|
|
|
|
}
|
|
|
|
/* Null-terminate */
|
2014-02-11 20:11:33 -05:00
|
|
|
memset(data + (UPDATE_SIZE-16)/2, 0, 16);
|
2013-07-08 20:45:46 -04:00
|
|
|
|
|
|
|
/* Clear tables */
|
|
|
|
memset(cmdbuf, 0, sizeof(cmdbuf));
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0xa2;
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
2014-02-11 20:11:33 -05:00
|
|
|
cmdbuf, 2))) {
|
|
|
|
ret = -3;
|
|
|
|
goto done;
|
|
|
|
}
|
2013-07-08 20:45:46 -04:00
|
|
|
|
2013-12-21 22:55:33 -05:00
|
|
|
ret = read_data(dev, endp_up,
|
|
|
|
respbuf, sizeof(respbuf), &num);
|
2013-07-08 20:45:46 -04:00
|
|
|
|
2013-12-21 22:55:33 -05:00
|
|
|
if (ret < 0)
|
2014-02-11 20:11:33 -05:00
|
|
|
goto done;
|
2013-12-21 22:55:33 -05:00
|
|
|
if (num != 8) {
|
|
|
|
ERROR("Short Read! (%d/%d)\n", num, 8);
|
2014-02-11 20:11:33 -05:00
|
|
|
ret = -4;
|
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
}
|
|
|
|
if (respbuf[1] != 0x01) {
|
|
|
|
ERROR("Received unexpected response\n");
|
2014-02-11 20:11:33 -05:00
|
|
|
ret = -5;
|
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the update command */
|
|
|
|
memset(cmdbuf, 0, sizeof(cmdbuf));
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0xa0;
|
|
|
|
cmdbuf[2] = 0x02;
|
|
|
|
cmdbuf[3] = 0x03;
|
|
|
|
cmdbuf[4] = 0x06;
|
|
|
|
cmdbuf[5] = 0x10; /* 06 10 == UPDATE_SIZE */
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
|
|
|
cmdbuf, 6)))
|
2014-02-11 20:11:33 -05:00
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
|
|
|
|
/* Send the payload over */
|
|
|
|
if ((ret = send_data(dev, endp_down,
|
2014-02-11 20:11:33 -05:00
|
|
|
(uint8_t *) data, UPDATE_SIZE)))
|
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
|
|
|
|
/* get the response */
|
2013-12-21 22:55:33 -05:00
|
|
|
ret = read_data(dev, endp_up,
|
|
|
|
respbuf, sizeof(respbuf), &num);
|
2013-07-08 20:45:46 -04:00
|
|
|
|
2013-12-21 22:55:33 -05:00
|
|
|
if (ret < 0)
|
2014-02-11 20:11:33 -05:00
|
|
|
goto done;
|
2013-12-21 22:55:33 -05:00
|
|
|
if (num != 8) {
|
|
|
|
ERROR("Short Read! (%d/%d)\n", num, 8);
|
2014-02-11 20:11:33 -05:00
|
|
|
ret = -6;
|
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
}
|
|
|
|
if (respbuf[1] != 0x00) {
|
2013-12-21 22:55:33 -05:00
|
|
|
ERROR("Received unexpected response!\n");
|
2014-02-11 20:11:33 -05:00
|
|
|
ret = -7;
|
|
|
|
goto done;
|
2013-07-08 20:45:46 -04:00
|
|
|
}
|
|
|
|
|
2014-02-11 20:11:33 -05:00
|
|
|
done:
|
2013-07-08 20:45:46 -04:00
|
|
|
free(data);
|
|
|
|
|
2014-02-11 20:11:33 -05:00
|
|
|
return ret;
|
2013-07-08 20:45:46 -04:00
|
|
|
}
|
|
|
|
|
2014-02-10 20:10:36 -05:00
|
|
|
static void kodak1400_cmdline(void)
|
2013-01-19 17:10:21 -05:00
|
|
|
{
|
2014-02-10 20:10:36 -05:00
|
|
|
DEBUG("\t\t[ -C filename ] # Set tone curve\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
}
|
2013-01-19 21:36:23 -05:00
|
|
|
|
2014-02-10 20:10:36 -05:00
|
|
|
int kodak1400_cmdline_arg(void *vctx, int argc, char **argv)
|
2013-07-18 21:05:33 -04:00
|
|
|
{
|
|
|
|
struct kodak1400_ctx *ctx = vctx;
|
2014-02-11 22:45:14 -05:00
|
|
|
int i, j = 0;
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2014-02-10 20:10:36 -05:00
|
|
|
/* Reset arg parsing */
|
|
|
|
optind = 1;
|
|
|
|
opterr = 0;
|
2015-08-13 21:09:56 -04:00
|
|
|
while ((i = getopt(argc, argv, GETOPT_LIST_GLOBAL "C:")) >= 0) {
|
2014-02-10 20:10:36 -05:00
|
|
|
switch(i) {
|
2015-08-13 21:09:56 -04:00
|
|
|
GETOPT_PROCESS_GLOBAL
|
2014-02-10 20:10:36 -05:00
|
|
|
case 'C':
|
2014-02-11 22:45:14 -05:00
|
|
|
if (ctx) {
|
|
|
|
j = kodak1400_set_tonecurve(ctx, optarg);
|
|
|
|
break;
|
|
|
|
}
|
2015-06-30 21:33:02 -04:00
|
|
|
return 2;
|
2014-02-10 20:10:36 -05:00
|
|
|
default:
|
|
|
|
break; /* Ignore completely */
|
|
|
|
}
|
2014-02-11 22:45:14 -05:00
|
|
|
|
|
|
|
if (j) return j;
|
2014-02-10 20:10:36 -05:00
|
|
|
}
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2014-02-10 20:10:36 -05:00
|
|
|
return 0;
|
2013-07-18 21:05:33 -04:00
|
|
|
}
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-07-19 09:23:53 -04:00
|
|
|
static void *kodak1400_init(void)
|
2013-07-18 21:05:33 -04:00
|
|
|
{
|
|
|
|
struct kodak1400_ctx *ctx = malloc(sizeof(struct kodak1400_ctx));
|
2015-06-23 20:32:41 -04:00
|
|
|
if (!ctx) {
|
|
|
|
ERROR("Memory Allocation Failure!\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
return NULL;
|
2015-06-23 20:32:41 -04:00
|
|
|
}
|
2013-07-18 21:05:33 -04:00
|
|
|
memset(ctx, 0, sizeof(struct kodak1400_ctx));
|
|
|
|
|
2013-07-19 09:23:53 -04:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kodak1400_attach(void *vctx, struct libusb_device_handle *dev,
|
|
|
|
uint8_t endp_up, uint8_t endp_down, uint8_t jobid)
|
|
|
|
{
|
|
|
|
struct kodak1400_ctx *ctx = vctx;
|
2015-08-12 22:56:29 -04:00
|
|
|
struct libusb_device *device;
|
|
|
|
struct libusb_device_descriptor desc;
|
2013-07-19 09:23:53 -04:00
|
|
|
|
2013-11-23 19:51:55 -05:00
|
|
|
UNUSED(jobid);
|
|
|
|
|
2013-07-19 09:23:53 -04:00
|
|
|
ctx->dev = dev;
|
2013-07-18 21:05:33 -04:00
|
|
|
ctx->endp_up = endp_up;
|
|
|
|
ctx->endp_down = endp_down;
|
2013-06-30 07:28:51 -04:00
|
|
|
|
2015-08-12 22:56:29 -04:00
|
|
|
device = libusb_get_device(dev);
|
|
|
|
libusb_get_device_descriptor(device, &desc);
|
|
|
|
|
|
|
|
ctx->type = lookup_printer_type(&kodak1400_backend,
|
|
|
|
desc.idVendor, desc.idProduct);
|
|
|
|
}
|
2013-07-19 09:23:53 -04:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
static void kodak1400_teardown(void *vctx) {
|
|
|
|
struct kodak1400_ctx *ctx = vctx;
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if (!ctx)
|
|
|
|
return;
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if (ctx->plane_r)
|
|
|
|
free(ctx->plane_r);
|
|
|
|
if (ctx->plane_g)
|
|
|
|
free(ctx->plane_g);
|
|
|
|
if (ctx->plane_b)
|
|
|
|
free(ctx->plane_b);
|
|
|
|
free(ctx);
|
|
|
|
}
|
2013-07-17 19:47:47 -04:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
static int kodak1400_read_parse(void *vctx, int data_fd) {
|
|
|
|
struct kodak1400_ctx *ctx = vctx;
|
|
|
|
int i, ret;
|
2013-07-17 19:47:47 -04:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if (!ctx)
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2014-01-21 20:34:00 -05:00
|
|
|
if (ctx->plane_r) {
|
2014-01-17 22:54:25 -05:00
|
|
|
free(ctx->plane_r);
|
2014-01-21 20:34:00 -05:00
|
|
|
ctx->plane_r = NULL;
|
|
|
|
}
|
|
|
|
if (ctx->plane_g) {
|
2014-01-17 22:54:25 -05:00
|
|
|
free(ctx->plane_g);
|
2014-01-21 20:34:00 -05:00
|
|
|
ctx->plane_g = NULL;
|
|
|
|
}
|
|
|
|
if (ctx->plane_b) {
|
2014-01-17 22:54:25 -05:00
|
|
|
free(ctx->plane_b);
|
2014-01-21 20:34:00 -05:00
|
|
|
ctx->plane_b = NULL;
|
|
|
|
}
|
2013-05-02 20:15:55 -04:00
|
|
|
|
2013-01-19 17:10:21 -05:00
|
|
|
/* Read in then validate header */
|
2014-01-13 18:30:30 -05:00
|
|
|
ret = read(data_fd, &ctx->hdr, sizeof(ctx->hdr));
|
|
|
|
if (ret < 0 || ret != sizeof(ctx->hdr)) {
|
2014-01-20 19:41:52 -05:00
|
|
|
if (ret == 0)
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2014-01-13 18:30:30 -05:00
|
|
|
ERROR("Read failed (%d/%d/%d)\n",
|
|
|
|
ret, 0, (int)sizeof(ctx->hdr));
|
|
|
|
perror("ERROR: Read failed");
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2014-01-13 18:30:30 -05:00
|
|
|
}
|
2013-07-18 21:05:33 -04:00
|
|
|
if (ctx->hdr.hdr[0] != 'P' ||
|
|
|
|
ctx->hdr.hdr[1] != 'G' ||
|
|
|
|
ctx->hdr.hdr[2] != 'H' ||
|
|
|
|
ctx->hdr.hdr[3] != 'D') {
|
2013-01-19 17:10:21 -05:00
|
|
|
ERROR("Unrecognized data format!\n");
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2013-01-19 17:10:21 -05:00
|
|
|
}
|
2013-07-18 21:05:33 -04:00
|
|
|
ctx->hdr.planesize = le32_to_cpu(ctx->hdr.planesize);
|
|
|
|
ctx->hdr.rows = le16_to_cpu(ctx->hdr.rows);
|
|
|
|
ctx->hdr.columns = le16_to_cpu(ctx->hdr.columns);
|
|
|
|
|
2013-01-19 17:10:21 -05:00
|
|
|
/* Set up plane data */
|
2013-07-18 21:05:33 -04:00
|
|
|
ctx->plane_r = malloc(ctx->hdr.planesize);
|
|
|
|
ctx->plane_g = malloc(ctx->hdr.planesize);
|
|
|
|
ctx->plane_b = malloc(ctx->hdr.planesize);
|
|
|
|
if (!ctx->plane_r || !ctx->plane_g || !ctx->plane_b) {
|
2013-01-19 17:10:21 -05:00
|
|
|
ERROR("Memory allocation failure!\n");
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 17:10:21 -05:00
|
|
|
}
|
2013-07-18 21:05:33 -04:00
|
|
|
for (i = 0 ; i < ctx->hdr.rows ; i++) {
|
2013-01-19 17:10:21 -05:00
|
|
|
int j;
|
|
|
|
uint8_t *ptr;
|
|
|
|
for (j = 0 ; j < 3 ; j++) {
|
2014-02-11 20:11:33 -05:00
|
|
|
int remain;
|
2013-01-19 17:10:21 -05:00
|
|
|
if (j == 0)
|
2013-07-18 21:05:33 -04:00
|
|
|
ptr = ctx->plane_r + i * ctx->hdr.columns;
|
2013-02-02 12:47:53 -05:00
|
|
|
else if (j == 1)
|
2013-07-18 21:05:33 -04:00
|
|
|
ptr = ctx->plane_g + i * ctx->hdr.columns;
|
2013-02-02 12:47:53 -05:00
|
|
|
else if (j == 2)
|
2013-07-18 21:05:33 -04:00
|
|
|
ptr = ctx->plane_b + i * ctx->hdr.columns;
|
2013-01-19 23:10:09 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
remain = ctx->hdr.columns;
|
2013-02-02 12:47:53 -05:00
|
|
|
do {
|
|
|
|
ret = read(data_fd, ptr, remain);
|
|
|
|
if (ret < 0) {
|
|
|
|
ERROR("Read failed (%d/%d/%d) (%d/%d @ %d)\n",
|
2013-07-18 21:05:33 -04:00
|
|
|
ret, remain, ctx->hdr.columns,
|
|
|
|
i, ctx->hdr.rows, j);
|
2013-02-02 12:47:53 -05:00
|
|
|
perror("ERROR: Read failed");
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
2013-02-02 12:47:53 -05:00
|
|
|
}
|
|
|
|
ptr += ret;
|
|
|
|
remain -= ret;
|
|
|
|
} while (remain);
|
2013-01-19 17:10:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_OK;
|
2013-07-18 21:05:33 -04:00
|
|
|
}
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
static uint8_t idle_data[READBACK_LEN] = { 0xe4, 0x72, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00 };
|
2013-01-19 17:10:21 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
static int kodak1400_main_loop(void *vctx, int copies) {
|
|
|
|
struct kodak1400_ctx *ctx = vctx;
|
2013-07-08 20:45:46 -04:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
uint8_t rdbuf[READBACK_LEN], rdbuf2[READBACK_LEN];
|
|
|
|
uint8_t cmdbuf[CMDBUF_LEN];
|
|
|
|
int last_state = -1, state = S_IDLE;
|
|
|
|
int num, ret;
|
|
|
|
uint16_t temp16;
|
2013-01-19 19:11:20 -05:00
|
|
|
|
|
|
|
top:
|
2013-07-16 23:19:04 -04:00
|
|
|
if (state != last_state) {
|
2013-12-21 22:15:18 -05:00
|
|
|
if (dyesub_debug)
|
|
|
|
DEBUG("last_state %d new %d\n", last_state, state);
|
2013-07-16 23:19:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Send Status Query */
|
2013-01-19 19:11:20 -05:00
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x72;
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 19:11:20 -05:00
|
|
|
|
|
|
|
/* Read in the printer status */
|
2013-12-21 22:55:33 -05:00
|
|
|
ret = read_data(ctx->dev, ctx->endp_up,
|
|
|
|
rdbuf, READBACK_LEN, &num);
|
|
|
|
|
|
|
|
if (ret < 0)
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 19:11:20 -05:00
|
|
|
if (memcmp(rdbuf, rdbuf2, READBACK_LEN)) {
|
|
|
|
memcpy(rdbuf2, rdbuf, READBACK_LEN);
|
2013-07-16 23:19:04 -04:00
|
|
|
} else if (state == last_state) {
|
2013-01-19 19:11:20 -05:00
|
|
|
sleep(1);
|
|
|
|
}
|
2013-07-16 23:19:04 -04:00
|
|
|
last_state = state;
|
|
|
|
|
2013-09-01 16:58:11 -04:00
|
|
|
/* Error handling */
|
|
|
|
if (rdbuf[4] || rdbuf[5]) {
|
|
|
|
ERROR("Error code reported by printer (%02x/%02x), terminating print\n",
|
|
|
|
rdbuf[4], rdbuf[5]);
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_STOP; // HOLD/CANCEL/FAILED? XXXX parse error!
|
2013-09-01 16:58:11 -04:00
|
|
|
}
|
|
|
|
|
2013-01-19 19:11:20 -05:00
|
|
|
fflush(stderr);
|
|
|
|
|
|
|
|
switch (state) {
|
2013-01-19 21:36:23 -05:00
|
|
|
case S_IDLE:
|
2013-05-02 20:15:55 -04:00
|
|
|
INFO("Printing started\n");
|
|
|
|
|
2013-01-19 21:36:23 -05:00
|
|
|
/* Send reset/attention */
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-05-02 20:15:55 -04:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
|
|
|
|
/* Send page setup */
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x5a;
|
|
|
|
cmdbuf[2] = 0x53;
|
2013-07-18 21:05:33 -04:00
|
|
|
temp16 = be16_to_cpu(ctx->hdr.columns);
|
2013-01-19 21:36:23 -05:00
|
|
|
memcpy(cmdbuf+3, &temp16, 2);
|
2013-07-18 21:05:33 -04:00
|
|
|
temp16 = be16_to_cpu(ctx->hdr.rows);
|
2013-01-19 21:36:23 -05:00
|
|
|
memcpy(cmdbuf+5, &temp16, 2);
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
|
2013-01-19 21:54:18 -05:00
|
|
|
/* Send lamination toggle? */
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x59;
|
2013-07-18 21:05:33 -04:00
|
|
|
cmdbuf[2] = ctx->hdr.matte; // ???
|
2013-01-19 21:54:18 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:54:18 -05:00
|
|
|
|
2013-01-27 11:35:32 -05:00
|
|
|
/* Send matte toggle */
|
2013-01-19 21:54:18 -05:00
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x60;
|
2013-07-18 21:05:33 -04:00
|
|
|
cmdbuf[2] = ctx->hdr.laminate;
|
2013-01-19 21:54:18 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if (send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 19:11:20 -05:00
|
|
|
|
2013-01-19 21:36:23 -05:00
|
|
|
/* Send lamination strength */
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x62;
|
2013-07-18 21:05:33 -04:00
|
|
|
cmdbuf[2] = ctx->hdr.lam_strength;
|
2013-01-19 19:11:20 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
|
2013-01-27 11:35:32 -05:00
|
|
|
/* Send unknown */
|
2013-01-19 21:54:18 -05:00
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x61;
|
2013-07-18 21:05:33 -04:00
|
|
|
cmdbuf[2] = ctx->hdr.unk1; // ???
|
2013-01-19 21:54:18 -05:00
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:52:02 -05:00
|
|
|
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_PRINTER_READY_Y;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_READY_Y:
|
2013-07-01 07:23:13 -04:00
|
|
|
INFO("Sending YELLOW plane\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_plane(ctx, 1, ctx->plane_b, cmdbuf)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_PRINTER_SENT_Y;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_SENT_Y:
|
|
|
|
if (!memcmp(rdbuf, idle_data, READBACK_LEN))
|
|
|
|
state = S_PRINTER_READY_M;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_READY_M:
|
2013-07-01 07:23:13 -04:00
|
|
|
INFO("Sending MAGENTA plane\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_plane(ctx, 2, ctx->plane_g, cmdbuf)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_PRINTER_SENT_M;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_SENT_M:
|
|
|
|
if (!memcmp(rdbuf, idle_data, READBACK_LEN))
|
|
|
|
state = S_PRINTER_READY_C;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_READY_C:
|
2013-07-01 07:23:13 -04:00
|
|
|
INFO("Sending CYAN plane\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_plane(ctx, 3, ctx->plane_r, cmdbuf)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_PRINTER_SENT_C;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_SENT_C:
|
2013-02-03 10:34:42 -05:00
|
|
|
if (!memcmp(rdbuf, idle_data, READBACK_LEN)) {
|
2013-07-18 21:05:33 -04:00
|
|
|
if (ctx->hdr.laminate)
|
2013-02-03 10:34:42 -05:00
|
|
|
state = S_PRINTER_READY_L;
|
|
|
|
else
|
|
|
|
state = S_PRINTER_DONE;
|
|
|
|
}
|
2013-01-19 21:36:23 -05:00
|
|
|
break;
|
|
|
|
case S_PRINTER_READY_L:
|
2013-07-01 07:23:13 -04:00
|
|
|
INFO("Laminating page\n");
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_plane(ctx, 4, NULL, cmdbuf)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_PRINTER_SENT_L;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_SENT_L:
|
|
|
|
if (!memcmp(rdbuf, idle_data, READBACK_LEN))
|
|
|
|
state = S_PRINTER_DONE;
|
|
|
|
break;
|
|
|
|
case S_PRINTER_DONE:
|
2013-07-01 07:23:13 -04:00
|
|
|
INFO("Cleaning up\n");
|
2013-01-19 21:44:58 -05:00
|
|
|
/* Cleanup */
|
|
|
|
memset(cmdbuf, 0, CMDBUF_LEN);
|
|
|
|
cmdbuf[0] = 0x1b;
|
|
|
|
cmdbuf[1] = 0x74;
|
|
|
|
cmdbuf[2] = 0x00;
|
|
|
|
cmdbuf[3] = 0x50;
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
2013-01-19 22:17:33 -05:00
|
|
|
cmdbuf, CMDBUF_LEN)))
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_FAILED;
|
2013-01-19 21:44:58 -05:00
|
|
|
|
2013-01-19 21:36:23 -05:00
|
|
|
state = S_FINISHED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2013-01-19 19:11:20 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
if (state != S_FINISHED)
|
|
|
|
goto top;
|
2013-02-02 12:47:53 -05:00
|
|
|
|
2013-05-03 07:42:23 -04:00
|
|
|
/* Clean up */
|
|
|
|
if (terminate)
|
|
|
|
copies = 1;
|
|
|
|
|
2014-01-22 09:10:34 -05:00
|
|
|
INFO("Print complete (%d copies remaining)\n", copies - 1);
|
2013-05-02 20:15:55 -04:00
|
|
|
|
|
|
|
if (copies && --copies) {
|
|
|
|
state = S_IDLE;
|
|
|
|
goto top;
|
|
|
|
}
|
|
|
|
|
2014-04-20 11:57:26 -04:00
|
|
|
return CUPS_BACKEND_OK;
|
2013-01-19 17:10:21 -05:00
|
|
|
}
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
/* Exported */
|
2013-07-18 23:39:36 -04:00
|
|
|
#define USB_VID_KODAK 0x040A
|
|
|
|
#define USB_PID_KODAK_1400 0x4022
|
|
|
|
#define USB_PID_KODAK_805 0x4034
|
|
|
|
|
2013-07-18 21:05:33 -04:00
|
|
|
struct dyesub_backend kodak1400_backend = {
|
|
|
|
.name = "Kodak 1400/805",
|
2015-06-23 20:32:41 -04:00
|
|
|
.version = "0.33",
|
2013-07-18 21:05:33 -04:00
|
|
|
.uri_prefix = "kodak1400",
|
|
|
|
.cmdline_usage = kodak1400_cmdline,
|
|
|
|
.cmdline_arg = kodak1400_cmdline_arg,
|
|
|
|
.init = kodak1400_init,
|
2013-07-19 09:23:53 -04:00
|
|
|
.attach = kodak1400_attach,
|
2013-07-18 21:05:33 -04:00
|
|
|
.teardown = kodak1400_teardown,
|
|
|
|
.read_parse = kodak1400_read_parse,
|
|
|
|
.main_loop = kodak1400_main_loop,
|
2013-07-18 23:39:36 -04:00
|
|
|
.devices = {
|
|
|
|
{ USB_VID_KODAK, USB_PID_KODAK_1400, P_KODAK_1400_805, "Kodak"},
|
|
|
|
{ USB_VID_KODAK, USB_PID_KODAK_805, P_KODAK_1400_805, "Kodak"},
|
|
|
|
{ 0, 0, 0, ""}
|
|
|
|
}
|
2013-07-18 21:05:33 -04:00
|
|
|
};
|
|
|
|
|
2013-02-02 07:34:53 -05:00
|
|
|
/* Kodak 1400/805 data format
|
2013-01-19 17:10:21 -05:00
|
|
|
|
|
|
|
Spool file consists of 36-byte header followed by row-interleaved BGR data.
|
|
|
|
Native printer resolution is 2560 pixels per row, and 3010 or 3612 rows.
|
|
|
|
|
|
|
|
Header:
|
|
|
|
|
|
|
|
50 47 48 44 "PGHD"
|
2013-06-29 10:37:38 -04:00
|
|
|
XX XX Number of columns, Little endian. Fixed at 2560.
|
2013-01-19 17:10:21 -05:00
|
|
|
00 00 NULL
|
2013-01-19 19:11:20 -05:00
|
|
|
XX XX Number of rows, Little Endian
|
2013-01-19 17:10:21 -05:00
|
|
|
00 00 NULL
|
|
|
|
XX XX XX XX Number of bytes per plane, Little Endian
|
|
|
|
00 00 00 00 NULL
|
2013-02-02 07:34:53 -05:00
|
|
|
XX 00 Glossy, 01 Matte (Note: Kodak805 only supports Glossy)
|
2013-01-19 19:11:20 -05:00
|
|
|
XX 01 to laminate, 00 to not.
|
|
|
|
01 Unkown, always set to 01
|
2013-01-19 17:10:21 -05:00
|
|
|
XX Lamination Strength:
|
|
|
|
|
|
|
|
3c Glossy
|
|
|
|
28 Matte +5
|
|
|
|
2e Matte +4
|
|
|
|
34 Matte +3
|
|
|
|
3a Matte +2
|
|
|
|
40 Matte +1
|
|
|
|
46 Matte
|
|
|
|
52 Matte -1
|
|
|
|
5e Matte -2
|
|
|
|
6a Matte -3
|
|
|
|
76 Matte -4
|
|
|
|
82 Matte -5
|
|
|
|
|
|
|
|
00 00 00 00 00 00 00 00 00 00 00 00 NULL
|
|