2017-08-05 16:29:19 -04:00
|
|
|
/*
|
|
|
|
* Magicard card printer family CUPS backend -- libusb-1.0 version
|
|
|
|
*
|
2020-06-30 23:42:54 -04:00
|
|
|
* (c) 2017-2020 Solomon Peachy <pizza@shaftnet.org>
|
2017-08-05 16:29:19 -04:00
|
|
|
*
|
|
|
|
* 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 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
|
2020-01-17 16:50:56 -05:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2017-08-05 16:29:19 -04:00
|
|
|
*
|
2017-11-17 13:34:26 -05:00
|
|
|
* SPDX-License-Identifier: GPL-3.0+
|
|
|
|
*
|
2017-08-05 16:29:19 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define BACKEND magicard_backend
|
|
|
|
|
|
|
|
#include "backend_common.h"
|
|
|
|
|
2019-09-28 11:05:42 -04:00
|
|
|
#include <time.h>
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
/* Exported */
|
|
|
|
#define USB_VID_MAGICARD 0x0C1F
|
|
|
|
#define USB_PID_MAGICARD_TANGO2E 0x1800
|
2018-03-10 07:51:35 -05:00
|
|
|
#define USB_PID_MAGICARD_ENDURO 0x4800 // ??
|
|
|
|
#define USB_PID_MAGICARD_ENDUROPLUS 0x880A // ??
|
2017-08-05 16:29:19 -04:00
|
|
|
|
2018-01-03 21:00:57 -05:00
|
|
|
/* Gamma tables computed with this perl program:
|
|
|
|
|
|
|
|
my $input_bpp = 8;
|
|
|
|
my $output_bpp = 6;
|
|
|
|
my $gamma = 1/1.8; # or 1/2.2 or whatever.
|
|
|
|
|
|
|
|
my $i;
|
|
|
|
|
|
|
|
for (my $i = 0 ; $i < (2 ** $input_bpp) ; $i++) {
|
|
|
|
my $linear = $i / (2 ** $input_bpp);
|
|
|
|
my $gc = ($linear ** $gamma) * (2 ** $output_bpp);
|
|
|
|
$gc = int($gc);
|
|
|
|
print "$gc, ";
|
|
|
|
}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint8_t gammas[2][256] = {
|
|
|
|
/* Gamma = 2.2 */
|
|
|
|
{
|
|
|
|
0, 5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17,
|
|
|
|
17, 18, 18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 23, 23, 23,
|
|
|
|
24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28,
|
|
|
|
29, 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32,
|
|
|
|
33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 35, 36, 36,
|
|
|
|
36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39,
|
|
|
|
39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, 42,
|
|
|
|
42, 42, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45,
|
|
|
|
45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47,
|
|
|
|
47, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 50,
|
|
|
|
50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 52, 52,
|
|
|
|
52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54,
|
|
|
|
54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56,
|
|
|
|
56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58,
|
|
|
|
58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60,
|
|
|
|
60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 62,
|
|
|
|
62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63,
|
|
|
|
},
|
|
|
|
/* Gamma = 1.8 */
|
|
|
|
{
|
|
|
|
0, 2, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12,
|
|
|
|
13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19,
|
|
|
|
19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24,
|
|
|
|
24, 24, 24, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 28, 28,
|
|
|
|
28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32,
|
|
|
|
32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35,
|
|
|
|
35, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38,
|
|
|
|
39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41,
|
|
|
|
42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44,
|
|
|
|
44, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 47, 47, 47,
|
|
|
|
47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49,
|
|
|
|
50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 52, 52, 52,
|
|
|
|
52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54,
|
|
|
|
55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 57, 57,
|
|
|
|
57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59,
|
|
|
|
59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61,
|
|
|
|
61, 61, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
struct magicard_printjob {
|
|
|
|
uint8_t *databuf;
|
|
|
|
int datalen;
|
|
|
|
|
|
|
|
int hdr_len;
|
|
|
|
int copies;
|
|
|
|
};
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
/* Private data structure */
|
|
|
|
struct magicard_ctx {
|
|
|
|
struct libusb_device_handle *dev;
|
|
|
|
uint8_t endp_up;
|
|
|
|
uint8_t endp_down;
|
2018-05-09 23:09:01 -04:00
|
|
|
int type;
|
2017-08-05 16:29:19 -04:00
|
|
|
|
2018-04-29 14:07:08 -04:00
|
|
|
struct marker marker;
|
2017-08-05 16:29:19 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct magicard_cmd_header {
|
|
|
|
uint8_t guard[9]; /* 0x05 */
|
|
|
|
uint8_t guard2[1]; /* 0x01 */
|
|
|
|
uint8_t cmd[4]; /* 'REQ,' */
|
|
|
|
uint8_t subcmd[4]; /* '???,' */
|
|
|
|
uint8_t arg[4]; /* '???,' */
|
|
|
|
uint8_t footer[2]; /* 0x1c 0x03 */
|
|
|
|
};
|
|
|
|
|
2017-11-11 11:22:45 -05:00
|
|
|
struct magicard_cmd_simple_header {
|
|
|
|
uint8_t guard[9]; /* 0x05 */
|
|
|
|
uint8_t guard2[1]; /* 0x01 */
|
|
|
|
uint8_t cmd[]; /* '???' */
|
|
|
|
// uint8_t footer[2]; /* 0x1c 0x03 */
|
|
|
|
};
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
struct magicard_resp_header {
|
|
|
|
uint8_t guard[1]; /* 0x01 */
|
|
|
|
uint8_t subcmd_arg[7]; /* '???,???' */
|
|
|
|
uint8_t data[0]; /* freeform resp */
|
|
|
|
// uint8_t term[2]; /* 0x2c 0x03 terminates! */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct magicard_requests {
|
2020-03-24 18:22:39 -04:00
|
|
|
const char *key;
|
|
|
|
const char *desc;
|
2017-08-05 16:29:19 -04:00
|
|
|
uint8_t type;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
TYPE_UNKNOWN = 0,
|
|
|
|
TYPE_STRING,
|
2017-11-15 14:35:38 -05:00
|
|
|
TYPE_STRINGINT,
|
|
|
|
TYPE_STRINGINT_HEX,
|
2017-08-05 16:29:19 -04:00
|
|
|
TYPE_IPADDR,
|
|
|
|
TYPE_YESNO,
|
|
|
|
TYPE_MODEL,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Data definitions */
|
|
|
|
static struct magicard_requests magicard_sta_requests[] = {
|
2017-12-31 18:05:10 -05:00
|
|
|
{ "MSR", "Printer Serial Number", TYPE_STRING },
|
|
|
|
{ "PSR", "Print Head Serial Number", TYPE_STRING },
|
|
|
|
{ "BSR", "PCB Serial Number", TYPE_STRING },
|
2017-08-05 16:29:19 -04:00
|
|
|
{ "VRS", "Firmware Version", TYPE_STRING },
|
2018-03-10 07:51:35 -05:00
|
|
|
{ "FDC", "Head Density", TYPE_STRINGINT }, /* 25 per step */
|
|
|
|
{ "FSP", "Image Start", TYPE_STRINGINT }, /* 8 steps per pixel */
|
|
|
|
{ "FEP", "Image End", TYPE_STRINGINT }, /* 8 steps per pixel */
|
2017-12-31 18:05:10 -05:00
|
|
|
{ "FSS", "Ramp Adjust", TYPE_STRINGINT },
|
2018-03-10 07:51:35 -05:00
|
|
|
{ "FPP", "Head Position", TYPE_STRINGINT }, /* L-R alignment */
|
2017-08-05 16:29:19 -04:00
|
|
|
{ "MDL", "Model", TYPE_MODEL }, /* 0 == Standard. Others? */
|
2017-11-15 14:35:38 -05:00
|
|
|
{ "PID", "USB PID", TYPE_STRINGINT_HEX }, /* ASCII integer, but needs to be shown as hex */
|
2017-12-31 18:05:10 -05:00
|
|
|
{ "VID", "USB VID", TYPE_STRINGINT_HEX }, /* ASCII integer, but needs to be shown as hex */
|
|
|
|
{ "USN", "USB Serial Number", TYPE_STRING },
|
|
|
|
{ "UPN", "USB Manufacturer", TYPE_STRING },
|
2017-08-05 16:29:19 -04:00
|
|
|
{ "MAC", "Ethernet MAC Address", TYPE_STRING },
|
|
|
|
{ "DYN", "Dynamic Address", TYPE_YESNO }, /* 1 == yes, 0 == no */
|
|
|
|
{ "IPA", "IP Address", TYPE_IPADDR }, /* ASCII signed integer */
|
|
|
|
{ "SNM", "IP Netmask", TYPE_IPADDR }, /* ASCII signed integer */
|
|
|
|
{ "GWY", "IP Gateway", TYPE_IPADDR }, /* ASCII signed integer */
|
|
|
|
|
2017-12-31 18:05:10 -05:00
|
|
|
{ "TCQ", "Total Cards Printed", TYPE_STRINGINT },
|
|
|
|
{ "TCP", "Prints on Head", TYPE_STRINGINT },
|
|
|
|
{ "TCN", "Cleaning Cycles", TYPE_STRINGINT },
|
|
|
|
{ "CCQ", "Cards Since Last Cleaning", TYPE_STRINGINT },
|
|
|
|
{ "TPQ", "Total Panels Printed", TYPE_STRINGINT },
|
|
|
|
{ "CCP", "Cards between Cleaning Prompts", TYPE_STRINGINT },
|
|
|
|
{ "CPQ", "Panels Since Last Cleaning", TYPE_STRINGINT },
|
|
|
|
{ "DFR", "Panels Remaining", TYPE_STRINGINT }, // cook somehow?
|
|
|
|
{ "CLP", "Cleaning Prompt", TYPE_STRING },
|
|
|
|
|
|
|
|
// CRQ: OFF ?? Cleaning overdue?
|
|
|
|
// CHK: checksum of fw? (8 chars, hex?)
|
|
|
|
// TES: ??? signed int? IP addr?
|
|
|
|
// RAMP: ??? hangs.
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
{ NULL, NULL, 0 }
|
|
|
|
};
|
|
|
|
|
2017-12-31 18:05:10 -05:00
|
|
|
// Sensors: CAM1 CAM2 TACHO FLIP DYE BARCODE LID FRONT REAR BUTTON TEMP ON OFF
|
|
|
|
// Languages: ENG ITA POR FRA DEU ESP SCH
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
/* Helper functions */
|
|
|
|
static int magicard_build_cmd(uint8_t *buf,
|
2020-03-24 18:22:39 -04:00
|
|
|
const char *cmd, const char *subcmd, const char *arg)
|
2017-08-05 16:29:19 -04:00
|
|
|
{
|
|
|
|
struct magicard_cmd_header *hdr = (struct magicard_cmd_header *) buf;
|
|
|
|
|
|
|
|
memset(hdr->guard, 0x05, sizeof(hdr->guard));
|
|
|
|
hdr->guard2[0] = 0x01;
|
|
|
|
memcpy(hdr->cmd, cmd, 3);
|
|
|
|
hdr->cmd[3] = ',';
|
|
|
|
memcpy(hdr->subcmd, subcmd, 3);
|
|
|
|
hdr->subcmd[3] = ',';
|
|
|
|
memcpy(hdr->arg, arg, 3);
|
|
|
|
hdr->arg[3] = ',';
|
|
|
|
hdr->footer[0] = 0x1c;
|
|
|
|
hdr->footer[1] = 0x03;
|
|
|
|
|
|
|
|
return sizeof(*hdr);
|
|
|
|
}
|
|
|
|
|
2017-11-11 11:22:45 -05:00
|
|
|
static int magicard_build_cmd_simple(uint8_t *buf,
|
2020-03-24 18:22:39 -04:00
|
|
|
const char *cmd)
|
2017-11-11 11:22:45 -05:00
|
|
|
{
|
|
|
|
struct magicard_cmd_simple_header *hdr = (struct magicard_cmd_simple_header *) buf;
|
|
|
|
int len = strlen(cmd);
|
|
|
|
|
|
|
|
memset(hdr->guard, 0x05, sizeof(hdr->guard));
|
|
|
|
hdr->guard2[0] = 0x01;
|
|
|
|
strncpy((char*)hdr->cmd, cmd, len);
|
|
|
|
hdr->cmd[len] = 0x1c;
|
|
|
|
hdr->cmd[len+1] = 0x03;
|
|
|
|
|
|
|
|
return (sizeof(*hdr) + len + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
static uint8_t * magicard_parse_resp(uint8_t *buf, uint16_t len, uint16_t *resplen)
|
|
|
|
{
|
|
|
|
struct magicard_resp_header *hdr = (struct magicard_resp_header *) buf;
|
|
|
|
|
|
|
|
*resplen = len - sizeof(hdr->guard) - sizeof(hdr->subcmd_arg) - 2;
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
return hdr->data;
|
|
|
|
}
|
|
|
|
|
2017-11-23 14:26:52 -05:00
|
|
|
static int magicard_query_sensors(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
uint8_t buf[256];
|
|
|
|
char buf2[24];
|
|
|
|
|
|
|
|
for (i = 1 ; ; i++) {
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
snprintf(buf2, sizeof(buf2), "SNR%d", i);
|
|
|
|
ret = magicard_build_cmd_simple(buf, buf2);
|
|
|
|
|
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
ret = read_data(ctx->dev, ctx->endp_up,
|
|
|
|
buf, sizeof(buf), &num);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!memcmp(buf, "END", 3))
|
|
|
|
break;
|
|
|
|
|
|
|
|
buf[num] = 0;
|
|
|
|
INFO("%s\n", buf);
|
|
|
|
}
|
2019-12-12 07:15:25 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
2017-11-23 14:26:52 -05:00
|
|
|
}
|
|
|
|
|
2018-03-10 07:51:35 -05:00
|
|
|
static int magicard_selftest_card(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
uint8_t buf[256];
|
|
|
|
|
2018-08-22 10:00:22 -04:00
|
|
|
ret = magicard_build_cmd_simple(buf, "TST,");
|
2018-03-10 07:51:35 -05:00
|
|
|
|
|
|
|
ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int magicard_reset(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
uint8_t buf[256];
|
|
|
|
|
2018-08-22 10:00:22 -04:00
|
|
|
ret = magicard_build_cmd_simple(buf, "RST,");
|
2018-03-10 07:51:35 -05:00
|
|
|
|
|
|
|
ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int magicard_eject(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
uint8_t buf[256];
|
|
|
|
|
2018-08-22 10:00:22 -04:00
|
|
|
ret = magicard_build_cmd_simple(buf, "EJT,");
|
2018-03-10 07:51:35 -05:00
|
|
|
|
|
|
|
ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-11-11 11:22:45 -05:00
|
|
|
static int magicard_query_printer(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
uint8_t buf[256];
|
|
|
|
char buf2[24];
|
|
|
|
|
|
|
|
for (i = 1 ; ; i++) {
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
snprintf(buf2, sizeof(buf2), "QPR%d", i);
|
|
|
|
ret = magicard_build_cmd_simple(buf, buf2);
|
|
|
|
|
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
ret = read_data(ctx->dev, ctx->endp_up,
|
|
|
|
buf, sizeof(buf), &num);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!memcmp(buf, "END", 3))
|
|
|
|
break;
|
|
|
|
|
|
|
|
buf[num] = 0;
|
|
|
|
INFO("%s\n", buf);
|
|
|
|
}
|
2019-12-12 07:15:25 -05:00
|
|
|
return CUPS_BACKEND_OK;
|
2017-11-11 11:22:45 -05:00
|
|
|
}
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
static int magicard_query_status(struct magicard_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int i;
|
|
|
|
uint8_t buf[256];
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
for (i = 0 ; ; i++) {
|
|
|
|
uint16_t resplen = 0;
|
|
|
|
uint8_t *resp;
|
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
if (magicard_sta_requests[i].key == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ret = magicard_build_cmd(buf, "REQ", "STA",
|
|
|
|
magicard_sta_requests[i].key);
|
|
|
|
|
|
|
|
if ((ret = send_data(ctx->dev, ctx->endp_down,
|
|
|
|
buf, ret)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
ret = read_data(ctx->dev, ctx->endp_up,
|
|
|
|
buf, sizeof(buf), &num);
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
resp = magicard_parse_resp(buf, num, &resplen);
|
|
|
|
resp[resplen] = 0;
|
2017-11-25 10:45:51 -05:00
|
|
|
switch(magicard_sta_requests[i].type) {
|
2017-08-05 16:29:19 -04:00
|
|
|
case TYPE_IPADDR: {
|
|
|
|
int32_t ipaddr;
|
|
|
|
uint8_t *addr = (uint8_t *) &ipaddr;
|
|
|
|
ipaddr = atoi((char*)resp);
|
|
|
|
INFO("%s:\t%d.%d.%d.%d\n",
|
|
|
|
magicard_sta_requests[i].desc,
|
|
|
|
addr[3], addr[2], addr[1], addr[0]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_YESNO: {
|
|
|
|
int val = atoi((char*)resp);
|
|
|
|
INFO("%s:\t%s\n",
|
|
|
|
magicard_sta_requests[i].desc,
|
|
|
|
val? "Yes" : "No");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_MODEL: {
|
|
|
|
int val = atoi((char*)resp);
|
|
|
|
INFO("%s:\t%s\n",
|
|
|
|
magicard_sta_requests[i].desc,
|
|
|
|
val == 0? "Standard" : "Unknown");
|
|
|
|
break;
|
|
|
|
}
|
2017-11-15 14:35:38 -05:00
|
|
|
case TYPE_STRINGINT_HEX: {
|
|
|
|
int val = atoi((char*)resp);
|
|
|
|
INFO("%s:\t%X\n",
|
|
|
|
magicard_sta_requests[i].desc,
|
|
|
|
val);
|
|
|
|
break;
|
|
|
|
}
|
2017-08-05 16:29:19 -04:00
|
|
|
case TYPE_STRINGINT:
|
|
|
|
// treat differently?
|
|
|
|
case TYPE_STRING:
|
|
|
|
case TYPE_UNKNOWN:
|
|
|
|
default:
|
|
|
|
INFO("%s:\t%s\n",
|
|
|
|
magicard_sta_requests[i].desc,
|
|
|
|
resp);
|
|
|
|
}
|
|
|
|
}
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Main driver */
|
|
|
|
static void* magicard_init(void)
|
|
|
|
{
|
|
|
|
struct magicard_ctx *ctx = malloc(sizeof(struct magicard_ctx));
|
|
|
|
if (!ctx) {
|
2019-10-03 20:26:00 -04:00
|
|
|
ERROR("Memory Allocation Failure!\n");
|
2017-08-05 16:29:19 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(ctx, 0, sizeof(struct magicard_ctx));
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2018-05-09 23:09:01 -04:00
|
|
|
static int magicard_attach(void *vctx, struct libusb_device_handle *dev, int type,
|
2019-11-02 09:12:30 -04:00
|
|
|
uint8_t endp_up, uint8_t endp_down, int iface, uint8_t jobid)
|
2017-08-05 16:29:19 -04:00
|
|
|
{
|
|
|
|
struct magicard_ctx *ctx = vctx;
|
|
|
|
|
|
|
|
UNUSED(jobid);
|
2019-11-02 09:12:30 -04:00
|
|
|
UNUSED(iface);
|
2017-08-05 16:29:19 -04:00
|
|
|
|
|
|
|
ctx->dev = dev;
|
|
|
|
ctx->endp_up = endp_up;
|
|
|
|
ctx->endp_down = endp_down;
|
2018-05-09 23:09:01 -04:00
|
|
|
ctx->type = type;
|
2017-08-05 16:29:19 -04:00
|
|
|
|
2018-04-29 14:07:08 -04:00
|
|
|
ctx->marker.color = "#00FFFF#FF00FF#FFFF00"; // XXX YMCK too!
|
|
|
|
ctx->marker.name = "Unknown"; // LC1/LC3/LC6/LC8
|
2019-09-28 10:54:10 -04:00
|
|
|
ctx->marker.numtype = -1;
|
2019-12-11 23:18:39 -05:00
|
|
|
ctx->marker.levelmax = CUPS_MARKER_UNAVAILABLE;
|
|
|
|
ctx->marker.levelnow = CUPS_MARKER_UNKNOWN;
|
2018-04-29 14:07:08 -04:00
|
|
|
|
2018-04-27 15:07:43 -04:00
|
|
|
return CUPS_BACKEND_OK;
|
2017-08-05 16:29:19 -04:00
|
|
|
}
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
static void magicard_cleanup_job(const void *vjob)
|
|
|
|
{
|
|
|
|
const struct magicard_printjob *job = vjob;
|
|
|
|
|
|
|
|
if (job->databuf)
|
|
|
|
free(job->databuf);
|
|
|
|
|
|
|
|
free((void*)job);
|
|
|
|
}
|
|
|
|
|
2018-01-01 19:54:15 -05:00
|
|
|
static void downscale_and_extract(int gamma, uint32_t pixels,
|
2017-11-15 07:47:44 -05:00
|
|
|
uint8_t *y_i, uint8_t *m_i, uint8_t *c_i,
|
|
|
|
uint8_t *y_o, uint8_t *m_o, uint8_t *c_o, uint8_t *k_o)
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < pixels; i++)
|
|
|
|
{
|
|
|
|
uint8_t y, m, c;
|
|
|
|
uint8_t k = 0;
|
2017-11-23 05:56:16 -05:00
|
|
|
uint32_t j;
|
|
|
|
uint32_t row;
|
|
|
|
uint32_t col;
|
|
|
|
uint32_t b_offset;
|
2017-11-23 07:13:03 -05:00
|
|
|
uint8_t b_shift;
|
2017-11-15 07:47:44 -05:00
|
|
|
|
|
|
|
/* Downscale color planes from 8bpp -> 6bpp; */
|
2018-01-03 21:00:57 -05:00
|
|
|
if (gamma) {
|
|
|
|
if (gamma > 2)
|
|
|
|
gamma = 2;
|
|
|
|
gamma--;
|
|
|
|
y = gammas[gamma][*y_i++];
|
|
|
|
m = gammas[gamma][*m_i++];
|
|
|
|
c = gammas[gamma][*c_i++];
|
|
|
|
} else {
|
|
|
|
y = *y_i++ >> 2;
|
|
|
|
m = *m_i++ >> 2;
|
|
|
|
c = *c_i++ >> 2;
|
|
|
|
}
|
2017-11-15 07:47:44 -05:00
|
|
|
|
|
|
|
/* Extract "true black" from ymc data, if enabled */
|
|
|
|
if (k_o && y == 0x3f && m == 0x3f && c == 0x3f) {
|
|
|
|
k = 1;
|
|
|
|
y = m = c = 0;
|
|
|
|
}
|
|
|
|
|
2017-11-23 05:56:16 -05:00
|
|
|
/* Compute row number and offsets */
|
|
|
|
row = i / 672;
|
|
|
|
col = i - (row * 672);
|
2017-11-23 07:13:03 -05:00
|
|
|
b_offset = col / 8;
|
|
|
|
b_shift = 7 - (col - (b_offset * 8));
|
2017-11-23 05:56:16 -05:00
|
|
|
|
|
|
|
/* Now, for each row, break it down into sub-chunks */
|
|
|
|
for (j = 0 ; j < 6 ; j++) {
|
2017-11-23 07:13:03 -05:00
|
|
|
if (b_shift == 7) {
|
2017-11-23 05:56:16 -05:00
|
|
|
y_o[row * 504 + j * 84 + b_offset] = 0;
|
|
|
|
m_o[row * 504 + j * 84 + b_offset] = 0;
|
|
|
|
c_o[row * 504 + j * 84 + b_offset] = 0;
|
|
|
|
}
|
|
|
|
if (y & (1 << j))
|
2017-11-23 07:13:03 -05:00
|
|
|
y_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
|
2017-11-23 05:56:16 -05:00
|
|
|
if (m & (1 << j))
|
2017-11-23 07:13:03 -05:00
|
|
|
m_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
|
2017-11-23 05:56:16 -05:00
|
|
|
if (c & (1 << j))
|
2017-11-23 07:13:03 -05:00
|
|
|
c_o[row * 504 + j * 84 + b_offset] |= (1 << b_shift);
|
2017-11-15 07:47:44 -05:00
|
|
|
}
|
2017-11-23 05:56:16 -05:00
|
|
|
|
2017-11-15 07:47:44 -05:00
|
|
|
/* And resin black, if enabled */
|
|
|
|
if (k_o) {
|
2017-11-23 07:13:03 -05:00
|
|
|
if (b_shift == 7) {
|
|
|
|
k_o[row * 84 + b_offset] = 0;
|
2017-11-15 07:47:44 -05:00
|
|
|
}
|
2017-11-23 05:56:16 -05:00
|
|
|
if (k)
|
2017-11-23 07:13:03 -05:00
|
|
|
k_o[row * 84 + b_offset] |= (1 << b_shift);
|
2017-11-15 07:47:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-25 20:28:49 -04:00
|
|
|
#define MAX_HEADERS_LEN 2048
|
|
|
|
#define MAX_PRINTJOB_LEN (1016*672*4) + MAX_HEADERS_LEN /* 1016*672 * 4color */
|
2017-11-15 14:35:38 -05:00
|
|
|
#define INITIAL_BUF_LEN 1024
|
2018-06-15 14:55:03 -04:00
|
|
|
static int magicard_read_parse(void *vctx, const void **vjob, int data_fd, int copies) {
|
2017-08-05 16:29:19 -04:00
|
|
|
struct magicard_ctx *ctx = vctx;
|
2017-11-15 14:35:38 -05:00
|
|
|
uint8_t initial_buf[INITIAL_BUF_LEN + 1];
|
|
|
|
uint32_t buf_offset = 0;
|
|
|
|
int i;
|
2017-08-05 16:29:19 -04:00
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
uint8_t *in_y, *in_m, *in_c;
|
|
|
|
uint8_t *out_y, *out_m, *out_c, *out_k;
|
|
|
|
uint32_t len_y = 0, len_m = 0, len_c = 0, len_k = 0;
|
2018-01-01 19:54:15 -05:00
|
|
|
int gamma = 0;
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
uint8_t x_gp_8bpp;
|
|
|
|
uint8_t x_gp_rk;
|
|
|
|
uint8_t k_only;
|
|
|
|
|
|
|
|
struct magicard_printjob *job = NULL;
|
|
|
|
|
2017-08-05 16:29:19 -04:00
|
|
|
if (!ctx)
|
|
|
|
return CUPS_BACKEND_FAILED;
|
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
job = malloc(sizeof(*job));
|
|
|
|
if (!job) {
|
|
|
|
ERROR("Memory allocation failure!\n");
|
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
|
|
|
}
|
|
|
|
memset(job, 0, sizeof(*job));
|
|
|
|
job->copies = copies;
|
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
/* Read in the first chunk */
|
|
|
|
i = read(data_fd, initial_buf, INITIAL_BUF_LEN);
|
2018-06-17 19:17:28 -04:00
|
|
|
if (i < 0) {
|
|
|
|
magicard_cleanup_job(job);
|
2017-11-15 14:35:38 -05:00
|
|
|
return i;
|
2018-06-17 19:17:28 -04:00
|
|
|
} else if (i == 0) {
|
|
|
|
magicard_cleanup_job(job);
|
2017-11-20 11:55:14 -05:00
|
|
|
return CUPS_BACKEND_CANCEL; /* Ie no data, we're done */
|
2018-06-17 19:17:28 -04:00
|
|
|
} else if (i < INITIAL_BUF_LEN) {
|
|
|
|
magicard_cleanup_job(job);
|
2017-11-15 14:35:38 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Basic Sanity Check */
|
|
|
|
if (initial_buf[0] != 0x05 ||
|
|
|
|
initial_buf[64] != 0x01 ||
|
2017-11-15 14:35:38 -05:00
|
|
|
initial_buf[65] != 0x2c) {
|
2018-06-15 14:55:03 -04:00
|
|
|
ERROR("Unrecognized header data format @%d!\n", job->datalen);
|
2018-06-17 19:17:28 -04:00
|
|
|
magicard_cleanup_job(job);
|
2017-11-15 14:35:38 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
initial_buf[INITIAL_BUF_LEN] = 0;
|
|
|
|
|
|
|
|
/* We can start allocating! */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (job->databuf) {
|
|
|
|
free(job->databuf);
|
|
|
|
job->databuf = NULL;
|
2017-11-19 20:33:12 -05:00
|
|
|
}
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen = 0;
|
|
|
|
job->databuf = malloc(MAX_PRINTJOB_LEN);
|
|
|
|
if (!job->databuf) {
|
2017-11-19 20:33:12 -05:00
|
|
|
ERROR("Memory allocation failure!\n");
|
2018-06-17 19:17:28 -04:00
|
|
|
magicard_cleanup_job(job);
|
2018-02-16 10:49:21 -05:00
|
|
|
return CUPS_BACKEND_RETRY_CURRENT;
|
2017-11-19 20:33:12 -05:00
|
|
|
}
|
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
/* Copy over initial header */
|
2018-06-15 14:55:03 -04:00
|
|
|
memcpy(job->databuf + job->datalen, initial_buf + buf_offset, 65);
|
|
|
|
job->datalen += 65;
|
2017-11-15 14:35:38 -05:00
|
|
|
buf_offset += 65;
|
|
|
|
|
|
|
|
/* Start parsing headers */
|
2018-06-15 14:55:03 -04:00
|
|
|
x_gp_8bpp = x_gp_rk = k_only = job->hdr_len = 0;
|
2017-11-19 20:33:12 -05:00
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
char *ptr;
|
|
|
|
ptr = strtok((char*)initial_buf + ++buf_offset, ",\x1c");
|
2018-09-25 20:28:49 -04:00
|
|
|
while (ptr
|
|
|
|
&& ((ptr - (char*)initial_buf) < INITIAL_BUF_LEN)
|
|
|
|
&& ((ptr - (char*)initial_buf) + strnlen(ptr, INITIAL_BUF_LEN) < INITIAL_BUF_LEN)
|
|
|
|
&& *ptr != 0x1c) {
|
2017-11-15 14:35:38 -05:00
|
|
|
if (!strcmp("X-GP-8", ptr)) {
|
2018-06-15 14:55:03 -04:00
|
|
|
x_gp_8bpp = 1;
|
2017-11-17 07:21:10 -05:00
|
|
|
} else if (!strncmp("TDT", ptr, 3)) {
|
|
|
|
/* Strip out the timestamp, replace it with one from the backend */
|
2017-11-18 14:29:19 -05:00
|
|
|
} else if (!strncmp("IMF", ptr,3)) {
|
|
|
|
/* Strip out the image format, replace it with backend */
|
2017-11-19 20:33:12 -05:00
|
|
|
// } else if (!strncmp("ESS", ptr, 3)) {
|
|
|
|
// /* Strip out copies */
|
2017-11-15 14:35:38 -05:00
|
|
|
} else if (!strcmp("X-GP-RK", ptr)) {
|
2018-06-15 14:55:03 -04:00
|
|
|
x_gp_rk = 1;
|
2018-01-01 19:54:15 -05:00
|
|
|
} else if (!strncmp("ICC", ptr,3)) {
|
|
|
|
/* Gamma curve is not handled by printer,
|
|
|
|
strip it out and use it! */
|
|
|
|
gamma = atoi(ptr + 3);
|
2017-11-15 14:35:38 -05:00
|
|
|
} else if (!strncmp("SZ", ptr, 2)) {
|
|
|
|
if (ptr[2] == 'B') {
|
2017-11-19 15:37:44 -05:00
|
|
|
len_y = atoi(ptr + 3);
|
2017-11-15 14:35:38 -05:00
|
|
|
} else if (ptr[2] == 'G') {
|
2017-11-19 15:37:44 -05:00
|
|
|
len_m = atoi(ptr + 3);
|
2017-11-15 14:35:38 -05:00
|
|
|
} else if (ptr[2] == 'R') {
|
2017-11-19 15:37:44 -05:00
|
|
|
len_c = atoi(ptr + 3);
|
2017-11-15 14:35:38 -05:00
|
|
|
} else if (ptr[2] == 'K') {
|
2017-11-19 15:37:44 -05:00
|
|
|
len_k = atoi(ptr + 3);
|
2017-11-15 14:35:38 -05:00
|
|
|
}
|
|
|
|
} else {
|
2018-09-25 20:28:49 -04:00
|
|
|
/* Safety valve */
|
|
|
|
if (strlen(ptr) + job->datalen > MAX_HEADERS_LEN) {
|
|
|
|
ERROR("headers too long, bogus job!\n");
|
2019-05-26 13:05:41 -04:00
|
|
|
magicard_cleanup_job(job);
|
2018-09-25 20:28:49 -04:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
/* Everything else goes in */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",%s", ptr);
|
2017-11-15 14:35:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep going */
|
|
|
|
buf_offset += strlen(ptr) + 1;
|
|
|
|
/* Peek ahead to see if this is it */
|
2017-11-19 15:37:44 -05:00
|
|
|
if (initial_buf[buf_offset + 1] == 0x1c)
|
2017-11-15 14:35:38 -05:00
|
|
|
break;
|
|
|
|
/* Otherwise continue to the next token */
|
2017-11-19 15:37:44 -05:00
|
|
|
ptr = strtok(NULL, ",\x1c");
|
2017-11-15 14:35:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity checks */
|
2017-11-17 07:21:10 -05:00
|
|
|
if (!len_y || !len_m || !len_c) {
|
|
|
|
ERROR("Plane lengths missing? %u/%u/%u!\n", len_y, len_m, len_c);
|
2018-06-17 19:17:28 -04:00
|
|
|
magicard_cleanup_job(job);
|
2017-11-17 07:21:10 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
2017-11-15 14:35:38 -05:00
|
|
|
if (len_y != len_m || len_y != len_c) {
|
|
|
|
ERROR("Inconsistent data plane lengths! %u/%u/%u!\n", len_y, len_m, len_c);
|
2018-06-17 19:17:28 -04:00
|
|
|
magicard_cleanup_job(job);
|
2017-11-15 14:35:38 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
2018-06-15 14:55:03 -04:00
|
|
|
if (x_gp_rk && len_k) {
|
2017-11-15 14:35:38 -05:00
|
|
|
ERROR("Data stream already has a K layer!\n");
|
2018-06-17 19:17:28 -04:00
|
|
|
magicard_cleanup_job(job);
|
2017-11-15 14:35:38 -05:00
|
|
|
return CUPS_BACKEND_CANCEL;
|
|
|
|
}
|
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Generate a timestamp */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",TDT%08X", (uint32_t) time(NULL));
|
2017-11-18 14:29:19 -05:00
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Generate image format tag */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (k_only == 1) {
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFK");
|
|
|
|
} else if (x_gp_rk || len_k) {
|
2017-11-19 20:33:12 -05:00
|
|
|
/* We're adding K, so make this BGRK */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFBGRK");
|
2017-11-19 20:33:12 -05:00
|
|
|
} else {
|
|
|
|
/* Just BGR */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",IMFBGR");
|
2017-11-19 20:33:12 -05:00
|
|
|
}
|
2017-11-18 14:29:19 -05:00
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Insert SZB/G/R/K length descriptors */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (x_gp_8bpp) {
|
|
|
|
if (k_only == 1) {
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_c / 8);
|
2017-11-18 14:29:19 -05:00
|
|
|
} else {
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZB%u", len_y * 6 / 8);
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZG%u", len_m * 6 / 8);
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZR%u", len_c * 6 / 8);
|
2017-11-18 14:29:19 -05:00
|
|
|
/* Add in a SZK length indication if requested */
|
2018-06-15 14:55:03 -04:00
|
|
|
if (x_gp_rk == 1) {
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_c / 8);
|
2017-11-18 14:29:19 -05:00
|
|
|
}
|
2017-11-15 14:35:38 -05:00
|
|
|
}
|
2017-11-19 20:33:12 -05:00
|
|
|
} else {
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZB%u", len_y);
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZG%u", len_m);
|
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZR%u", len_c);
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Add in a SZK length indication if requested */
|
|
|
|
if (len_k) {
|
2018-06-15 14:55:03 -04:00
|
|
|
job->datalen += sprintf((char*)job->databuf + job->datalen, ",SZK%u", len_k);
|
2017-11-19 20:33:12 -05:00
|
|
|
}
|
2017-11-15 14:35:38 -05:00
|
|
|
}
|
2017-11-25 10:45:51 -05:00
|
|
|
|
2017-11-15 14:35:38 -05:00
|
|
|
/* Terminate command stream */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->databuf[job->datalen++] = 0x1c;
|
2017-11-15 14:35:38 -05:00
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Let's figure out how long the image data stream is supposed to be. */
|
2017-11-18 14:29:19 -05:00
|
|
|
uint32_t remain;
|
2018-06-15 14:55:03 -04:00
|
|
|
if (k_only) {
|
2017-11-19 15:37:44 -05:00
|
|
|
remain = len_k + 3;
|
2017-11-18 14:29:19 -05:00
|
|
|
} else {
|
2017-11-19 15:37:44 -05:00
|
|
|
remain = len_y + len_m + len_c + 3 * 3;
|
2017-11-18 14:29:19 -05:00
|
|
|
if (len_k)
|
|
|
|
remain += len_k + 3;
|
|
|
|
}
|
2017-11-19 20:33:12 -05:00
|
|
|
/* Offset the stuff we already read in. */
|
|
|
|
remain -= INITIAL_BUF_LEN - buf_offset;
|
|
|
|
remain++; /* Add in a byte for the end of job marker. This is our final value. */
|
2017-11-18 14:29:19 -05:00
|
|
|
|
2017-11-19 20:33:12 -05:00
|
|
|
/* This is how much of the initial buffer is the header length. */
|
2018-06-15 14:55:03 -04:00
|
|
|
job->hdr_len = job->datalen;
|
2017-11-19 15:37:44 -05:00
|
|
|
|
2018-06-15 14:55:03 -04:00
|
|
|
if (x_gp_8bpp) {
|
2017-11-19 20:33:12 -05:00
|
|
|
uint32_t srcbuf_offset = INITIAL_BUF_LEN - buf_offset;
|
|
|
|
uint8_t *srcbuf = malloc(MAX_PRINTJOB_LEN);
|
|
|
|
if (!srcbuf) {
|
2018-06-17 19:17:28 -04:00
|
|