Gutenprint + CUPS backends for Dye Sublimation printers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
selphy_print/backend_sinfonia.c

1472 lines
35 KiB

/*
* Shinko/Sinfonia Common Code
*
* (c) 2019-2021 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
* https://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
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0+
*
*/
#include "backend_common.h"
#include "backend_sinfonia.h"
int sinfonia_read_parse(int data_fd, uint32_t model,
struct sinfonia_printjob *job)
{
uint32_t hdr[29];
int ret, i;
uint8_t tmpbuf[4];
job->common.jobsize = sizeof(*job);
/* Read in header */
ret = read(data_fd, hdr, SINFONIA_HDR_LEN);
if (ret < 0 || ret != SINFONIA_HDR_LEN) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d)\n",
ret, SINFONIA_HDR_LEN);
perror("ERROR: Read failed");
return ret;
}
/* Byteswap everything */
for (i = 0 ; i < (SINFONIA_HDR_LEN / 4) ; i++) {
hdr[i] = le32_to_cpu(hdr[i]);
}
/* Sanity-check headers */
if (hdr[0] != SINFONIA_HDR1_LEN ||
hdr[4] != SINFONIA_HDR2_LEN ||
hdr[22] != SINFONIA_DPI) {
ERROR("Unrecognized header data format!\n");
return CUPS_BACKEND_CANCEL;
}
if (hdr[1] != model) {
ERROR("job/printer mismatch (%u/%u)!\n", hdr[1], model);
return CUPS_BACKEND_CANCEL;
}
if (!hdr[13] || !hdr[14]) {
ERROR("Bad job cols/rows!\n");
return CUPS_BACKEND_CANCEL;
}
/* Work out data length */
job->datalen = hdr[13] * hdr[14] * 3;
job->databuf = malloc(job->datalen);
if (!job->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_RETRY_CURRENT;
}
/* Read in payload data */
{
uint32_t remain = job->datalen;
uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%u/%d)\n",
ret, remain, job->datalen);
perror("ERROR: Read failed");
free(job->databuf);
job->databuf = NULL;
return ret;
}
ptr += ret;
remain -= ret;
} while (remain);
}
/* Make sure footer is sane too */
ret = read(data_fd, tmpbuf, 4);
if (ret != 4) {
ERROR("Read failed (%d/%d)\n", ret, 4);
perror("ERROR: Read failed");
free(job->databuf);
job->databuf = NULL;
return ret;
}
if (tmpbuf[0] != 0x04 ||
tmpbuf[1] != 0x03 ||
tmpbuf[2] != 0x02 ||
tmpbuf[3] != 0x01) {
ERROR("Unrecognized footer data format!\n");
free (job->databuf);
job->databuf = NULL;
return CUPS_BACKEND_CANCEL;
}
/* Fill out job params */
job->jp.media = hdr[6];
if (hdr[1] != 6245)
job->jp.method = hdr[8];
if (hdr[1] == 2245 || hdr[1] == 6245)
job->jp.quality = hdr[9];
if (hdr[1] == 1245 || hdr[1] == 2145)
job->jp.oc_mode = hdr[9];
else
job->jp.oc_mode = hdr[10];
if (hdr[1] == 1245) {
job->jp.mattedepth = hdr[11];
job->jp.dust = hdr[12];
}
job->jp.columns = hdr[13];
job->jp.rows = hdr[14];
job->common.copies = hdr[15];
if (hdr[1] == 2245 || hdr[1] == 6145)
job->jp.ext_flags = hdr[28];
return CUPS_BACKEND_OK;
}
int sinfonia_raw10_read_parse(int data_fd, struct sinfonia_printjob *job)
{
struct sinfonia_printcmd10_hdr hdr;
int ret;
job->common.jobsize = sizeof(*job);
/* Read in header */
ret = read(data_fd, &hdr, sizeof(hdr));
if (ret < 0 || ret != sizeof(hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
/* Validate header */
if (le16_to_cpu(hdr.hdr.cmd) != SINFONIA_CMD_PRINTJOB ||
le16_to_cpu(hdr.hdr.len) != 10) {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
job->common.copies = le16_to_cpu(hdr.copies);
job->jp.rows = le16_to_cpu(hdr.rows);
job->jp.columns = le16_to_cpu(hdr.columns);
job->jp.media = hdr.media;
job->jp.oc_mode = hdr.oc_mode;
job->jp.method = hdr.method;
/* Allocate buffer */
job->datalen = job->jp.rows * job->jp.columns * 3;
/* Hack in backprinting */
if (job->common.copies & 0x8000) {
job->common.copies &= ~0x8000;
job->datalen += (44 * 2);
job->jp.ext_flags = EXT_FLAG_BACKPRINT;
}
job->databuf = malloc(job->datalen);
if (!job->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_RETRY_CURRENT;
}
{
int remain = job->datalen;
uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, job->datalen);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
} while (remain);
}
return CUPS_BACKEND_OK;
}
int sinfonia_panorama_splitjob(struct sinfonia_printjob *injob,
uint16_t max_rows,
struct sinfonia_printjob **newjobs)
{
uint8_t *panels[3] = { NULL, NULL, NULL };
uint16_t panel_rows[3] = { 0, 0, 0 };
uint8_t numpanels;
uint16_t overlap_rows;
uint16_t inrows;
uint16_t cols;
int i;
inrows = injob->jp.rows;
cols = injob->jp.columns;
switch (cols) {
case 1548: /* EK6900/6950 */
if (max_rows != 2136) {
ERROR("Bad pano input\n");
return CUPS_BACKEND_CANCEL;
}
if (inrows > 3036) // 5x10
numpanels = 3;
else
numpanels = 2;
overlap_rows = 600 + 36;
if (numpanels == 3) {
if (inrows > 4536) // 5x15
overlap_rows = 100 + 36;
else
overlap_rows = 600 + 36;
}
break;
case 1844: /* EK6900/6950 */
if (max_rows != 2436) {
ERROR("Bad pano input\n");
return CUPS_BACKEND_CANCEL;
}
overlap_rows = 600 + 36;
if (inrows > 4236) // ie 6x14
numpanels = 3;
else
numpanels = 2;
break;
case 2464: /* EK8810 */
if (max_rows != 3624 && max_rows != 3024) {
ERROR("Bad pano input\n");
return CUPS_BACKEND_CANCEL;
}
overlap_rows = 600 + 24;
if (max_rows == 3024) { /* 8x10 media */
if (inrows > 5424) // 8x18
numpanels = 3;
else
numpanels = 2;
} else { /* 8x12 media */
if (inrows > 6624) // 8x22
numpanels = 3;
else
numpanels = 2;
}
if (numpanels == 3) {
if (max_rows == 3024) {
if (inrows == 6024) // 8x20
overlap_rows = 24;
} else {
if (inrows == 10824) // 8x36
overlap_rows = 24;
}
} else {
if (max_rows == 3024) {
if (inrows == 9024) // 8x30
overlap_rows = 24;
} else {
if (inrows == 7224) // 8x24
overlap_rows = 24;
}
}
break;
default:
ERROR("Unknown pano input cols: %d\n", cols);
return CUPS_BACKEND_CANCEL;
}
/* Work out which number of rows per panel */
if (!panel_rows[0]) {
panel_rows[0] = max_rows;
panel_rows[1] = inrows - panel_rows[0] + overlap_rows;
if (numpanels > 2)
panel_rows[2] = inrows - panel_rows[0] - panel_rows[1] + overlap_rows + overlap_rows;
}
/* Allocate and set up new jobs and buffers */
for (i = 0 ; i < numpanels ; i++) {
newjobs[i] = malloc(sizeof(struct sinfonia_printjob));
if (!newjobs[i]) {
ERROR("Memory allocation failure");
return CUPS_BACKEND_RETRY_CURRENT;
}
panels[i] = malloc(cols * panel_rows[i] * 3);
if (!panels[i]) {
ERROR("Memory allocation failure");
return CUPS_BACKEND_RETRY_CURRENT;
}
/* Fill in header differences */
memcpy(newjobs[i], injob, sizeof(struct sinfonia_printjob));
newjobs[i]->databuf = panels[i];
newjobs[i]->jp.rows = panel_rows[i];
// XXX what else?
}
dyesub_pano_split_rgb8(injob->databuf, cols, inrows,
numpanels, overlap_rows, max_rows,
panels, panel_rows);
// XXX postprocess buffers!
// pano_process_rgb8(numpanels, cols, overlap_rows, panels, panel_rows);
return CUPS_BACKEND_OK;
}
int sinfonia_raw18_read_parse(int data_fd, struct sinfonia_printjob *job)
{
struct sinfonia_printcmd18_hdr hdr;
int ret;
job->common.jobsize = sizeof(*job);
/* Read in header */
ret = read(data_fd, &hdr, sizeof(hdr));
if (ret < 0 || ret != sizeof(hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
/* Validate header */
if (le16_to_cpu(hdr.hdr.cmd) != SINFONIA_CMD_PRINTJOB ||
le16_to_cpu(hdr.hdr.len) != 18) {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
job->common.copies = le16_to_cpu(hdr.copies);
job->jp.rows = le16_to_cpu(hdr.rows);
job->jp.columns = le16_to_cpu(hdr.columns);
job->jp.media = hdr.media;
job->jp.oc_mode = hdr.oc_mode;
job->jp.method = hdr.method;
/* Allocate buffer */
job->datalen = job->jp.rows * job->jp.columns * 3;
job->databuf = malloc(job->datalen);
if (!job->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_RETRY_CURRENT;
}
{
int remain = job->datalen;
uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, job->datalen);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
} while (remain);
}
return CUPS_BACKEND_OK;
}
int sinfonia_raw28_read_parse(int data_fd, struct sinfonia_printjob *job)
{
struct sinfonia_printcmd28_hdr hdr;
int ret;
job->common.jobsize = sizeof(*job);
/* Read in header */
ret = read(data_fd, &hdr, sizeof(hdr));
if (ret < 0 || ret != sizeof(hdr)) {
if (ret == 0)
return CUPS_BACKEND_CANCEL;
ERROR("Read failed (%d/%d/%d)\n",
ret, 0, (int)sizeof(hdr));
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
/* Validate header */
if (le16_to_cpu(hdr.hdr.cmd) != SINFONIA_CMD_PRINTJOB ||
le16_to_cpu(hdr.hdr.len) != 28) {
ERROR("Unrecognized data format!\n");
return CUPS_BACKEND_CANCEL;
}
job->common.copies = le16_to_cpu(hdr.copies);
job->jp.rows = le16_to_cpu(hdr.rows);
job->jp.columns = le16_to_cpu(hdr.columns);
job->jp.media = hdr.media;
job->jp.oc_mode = hdr.options & SINFONIA_PRINT28_OC_MASK;
job->jp.quality = hdr.options & SINFONIA_PRINT28_OPTIONS_HQ;
job->jp.method = hdr.method;
/* Allocate buffer */
job->datalen = job->jp.rows * job->jp.columns * 3;
job->databuf = malloc(job->datalen);
if (!job->databuf) {
ERROR("Memory allocation failure!\n");
return CUPS_BACKEND_RETRY_CURRENT;
}
{
int remain = job->datalen;
uint8_t *ptr = job->databuf;
do {
ret = read(data_fd, ptr, remain);
if (ret < 0) {
ERROR("Read failed (%d/%d/%d)\n",
ret, remain, job->datalen);
perror("ERROR: Read failed");
return CUPS_BACKEND_CANCEL;
}
ptr += ret;
remain -= ret;
} while (remain);
}
return CUPS_BACKEND_OK;
}
void sinfonia_cleanup_job(const void *vjob)
{
const struct sinfonia_printjob *job = vjob;
if (job->databuf)
free(job->databuf);
free((void*)job);
}
int sinfonia_docmd(struct sinfonia_usbdev *usbh,
uint8_t *cmd, int cmdlen,
uint8_t *resp, int resplen,
int *num)
{
int ret;
struct sinfonia_cmd_hdr *cmdhdr = (struct sinfonia_cmd_hdr *) cmd;
struct sinfonia_status_hdr *resphdr = (struct sinfonia_status_hdr *)resp;
if ((ret = send_data(usbh->conn,
cmd, cmdlen))) {
goto fail;
}
ret = read_data(usbh->conn,
(uint8_t *)resp, resplen, num);
if (ret < 0)
goto fail;
if (resphdr->result != RESULT_SUCCESS) {
INFO("Printer Status: %02x (%s)\n", resphdr->status,
sinfonia_status_str(resphdr->status));
INFO(" Result: 0x%02x Error: 0x%02x (0x%02x/0x%02x = %s)\n",
resphdr->result, resphdr->error, resphdr->printer_major,
resphdr->printer_minor, usbh->error_codes(resphdr->printer_major, resphdr->printer_minor));
ret = CUPS_BACKEND_FAILED;
goto fail;
}
return CUPS_BACKEND_OK;
fail:
ERROR("Failed to execute %s command\n", sinfonia_cmd_names(cmdhdr->cmd));
return ret;
}
int sinfonia_flashled(struct sinfonia_usbdev *usbh)
{
struct sinfonia_cmd_hdr cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
cmd.cmd = cpu_to_le16(SINFONIA_CMD_FLASHLED);
cmd.len = cpu_to_le16(0);
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
return CUPS_BACKEND_OK;
}
int sinfonia_canceljob(struct sinfonia_usbdev *usbh, int id)
{
struct sinfonia_cancel_cmd cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
cmd.id = id;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_CANCELJOB);
cmd.hdr.len = cpu_to_le16(1);
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
return CUPS_BACKEND_OK;
}
int sinfonia_getparam(struct sinfonia_usbdev *usbh, int target, uint32_t *param)
{
struct sinfonia_getparam_cmd cmd;
struct sinfonia_getparam_resp resp;
int ret, num = 0;
/* Set up command */
cmd.target = target;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_GETPARAM);
cmd.hdr.len = cpu_to_le16(sizeof(struct sinfonia_getparam_cmd)-sizeof(cmd.hdr));
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
// ERROR("Unable to query param id %02x: %s\n",
// target, sinfonia_paramname(usbh, target));
return ret;
}
*param = le32_to_cpu(resp.param);
return CUPS_BACKEND_OK;
}
const char *sinfonia_paramname(struct sinfonia_usbdev *usbh,
int id)
{
int i;
for (i = 0 ; i < usbh->params_count ; i++) {
if (usbh->params[i].id == id)
return usbh->params[i].descr;
}
return "Unknown/Not Found!";
}
int sinfonia_dumpallparams(struct sinfonia_usbdev *usbh, int known)
{
int i, ret;
uint32_t param = 0;
if (known) {
for (i = 0 ; i < usbh->params_count ; i++) {
ret = sinfonia_getparam(usbh, usbh->params[i].id, &param);
if (ret)
continue;
DEBUG("%02x (%s): %08x\n", usbh->params[i].id,
usbh->params[i].descr, param);
}
} else {
for (i = 0 ; i < 256 ; i++) {
ret = sinfonia_getparam(usbh, i, &param);
if (ret)
continue;
DEBUG("%02x (%s): %08x\n", i, sinfonia_paramname(usbh, i), param);
}
}
return CUPS_BACKEND_OK;
}
int sinfonia_setparam(struct sinfonia_usbdev *usbh, int target, uint32_t param)
{
struct sinfonia_setparam_cmd cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
/* Set up command */
cmd.target = target;
cmd.param = cpu_to_le32(param);
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_SETPARAM);
cmd.hdr.len = cpu_to_le16(sizeof(struct sinfonia_setparam_cmd)-sizeof(cmd.hdr));
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
// ERROR("Unable to query param id %02x: %s\n",
// target, sinfonia_paramname(usbh, target));
}
return CUPS_BACKEND_OK;
}
int sinfonia_getfwinfo(struct sinfonia_usbdev *usbh)
{
struct sinfonia_fwinfo_cmd cmd;
struct sinfonia_fwinfo_resp resp;
int num = 0;
int i;
int last = FWINFO_TARGET_PRINT_TABLES2;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_FWINFO);
cmd.hdr.len = cpu_to_le16(1);
resp.hdr.payload_len = 0;
INFO("FW Information:\n");
if (usbh->conn->type == P_SHINKO_S6145) last = FWINFO_TARGET_PRINT_TABLES;
if (usbh->conn->type == P_SHINKO_S2245) last = FWINFO_TARGET_DSP;
for (i = FWINFO_TARGET_MAIN_BOOT ; i <= last ; i++) {
int ret;
cmd.target = i;
resp.major = 0;
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
continue;
}
if (resp.major == 0)
continue;
if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct sinfonia_fwinfo_resp) - sizeof(struct sinfonia_status_hdr)))
continue;
INFO(" %s\t ver %02x.%02x\n", sinfonia_fwinfo_targets(i),
resp.major, resp.minor);
#if 0
INFO(" name: '%s'\n", resp.name);
INFO(" type: '%s'\n", resp.type);
INFO(" date: '%s'\n", resp.date);
INFO(" version: %02x.%02x (CRC %04x)\n", resp.major, resp.minor,
le16_to_cpu(resp.checksum));
#endif
}
return CUPS_BACKEND_OK;
}
int sinfonia_geterrorlog(struct sinfonia_usbdev *usbh)
{
struct sinfonia_cmd_hdr cmd;
struct sinfonia_errorlog_resp resp;
int ret, num = 0;
int i;
cmd.cmd = cpu_to_le16(SINFONIA_CMD_ERRORLOG);
cmd.len = cpu_to_le16(0);
resp.hdr.payload_len = 0;
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct sinfonia_errorlog_resp) - sizeof(struct sinfonia_status_hdr)))
return -2;
INFO("Stored Error Events: %u entries:\n", resp.count);
for (i = 0 ; i < resp.count ; i++) {
INFO(" %02d: @ %08u prints : 0x%02x/0x%02x (%s)\n", i,
le32_to_cpu(resp.items[i].print_counter),
resp.items[i].major, resp.items[i].minor,
usbh->error_codes(resp.items[i].major, resp.items[i].minor));
}
return CUPS_BACKEND_OK;
}
int sinfonia_resetcurve(struct sinfonia_usbdev *usbh, int target, int id)
{
struct sinfonia_reset_cmd cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
cmd.target = target;
cmd.curveid = id;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_RESET);
cmd.hdr.len = cpu_to_le16(2);
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
return CUPS_BACKEND_OK;
}
int sinfonia_gettonecurve(struct sinfonia_usbdev *usbh, int type, char *fname)
{
struct sinfonia_readtone_cmd cmd;
struct sinfonia_readtone_resp resp;
int ret, num = 0;
uint8_t *data;
uint16_t curves[TONE_CURVE_SIZE] = { 0 };
int i,j;
cmd.target = type;
cmd.curveid = TONE_CURVE_ID;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_READTONE);
cmd.hdr.len = cpu_to_le16(2);
resp.hdr.payload_len = 0;
INFO("Dump %s Tone Curve to '%s'\n", sinfonia_tonecurve_statuses(type), fname);
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
if (le16_to_cpu(resp.hdr.payload_len) != (sizeof(struct sinfonia_readtone_resp) - sizeof(struct sinfonia_status_hdr)))
return -2;
resp.total_size = le16_to_cpu(resp.total_size);
data = malloc(resp.total_size * 2);
if (!data) {
ERROR("Memory Allocation Failure!\n");
return -1;
}
i = 0;
while (i < resp.total_size) {
ret = read_data(usbh->conn,
data + i,
resp.total_size * 2 - i,
&num);
if (ret < 0)
goto done;
i += num;
}
i = j = 0;
while (i < resp.total_size) {
memcpy(curves + j, data + i+2, data[i+1]);
j += data[i+1] / 2;
i += data[i+1] + 2;
}
/* Open file and write it out */
{
int tc_fd = open(fname, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
if (tc_fd < 0) {
ret = -1;
goto done;
}
for (i = 0 ; i < TONE_CURVE_SIZE; i++) {
/* Byteswap appropriately */
curves[i] = cpu_to_be16(le16_to_cpu(curves[i]));
}
ret = write(tc_fd, curves, TONE_CURVE_SIZE * sizeof(uint16_t));
close(tc_fd);
}
done:
free(data);
return ret;
}
int sinfonia_button_set(struct sinfonia_usbdev *dev, int enable)
{
struct sinfonia_button_cmd cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_BUTTON);
cmd.hdr.len = cpu_to_le16(1);
cmd.enabled = enable;
if ((ret = sinfonia_docmd(dev,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&cmd, sizeof(resp),
&num))) {
return ret;
}
return CUPS_BACKEND_OK;
}
int sinfonia_settonecurve(struct sinfonia_usbdev *usbh, int target, char *fname)
{
struct sinfonia_update_cmd cmd;
struct sinfonia_status_hdr resp;
int ret, num = 0;
INFO("Set %s from '%s'\n", sinfonia_update_targets(target), fname);
uint16_t *data = malloc(TONE_CURVE_SIZE * sizeof(uint16_t));
if (!data) {
ERROR("Memory Allocation Failure!\n");
return -1;
}
/* Read in file */
if ((ret = dyesub_read_file(fname, data, TONE_CURVE_SIZE * sizeof(uint16_t), NULL))) {
ERROR("Failed to read Tone Curve file\n");
goto done;
}
/* Byteswap data to local CPU.. */
for (ret = 0; ret < TONE_CURVE_SIZE ; ret++) {
data[ret] = be16_to_cpu(data[ret]);
}
/* Set up command */
cmd.target = target;
cmd.curve_id = TONE_CURVE_ID;
cmd.reserved[0] = cmd.reserved[1] = cmd.reserved[2] = 0;
cmd.reset = 0;
cmd.size = cpu_to_le32(TONE_CURVE_SIZE * sizeof(uint16_t));
cmd.hdr.cmd = cpu_to_le16(SINFONIA_CMD_UPDATE);
cmd.hdr.len = cpu_to_le16(sizeof(struct sinfonia_update_cmd)-sizeof(cmd.hdr));
/* Byteswap data to format printer is expecting.. */
for (ret = 0; ret < TONE_CURVE_SIZE ; ret++) {
data[ret] = cpu_to_le16(data[ret]);
}
if ((ret = sinfonia_docmd(usbh,
(uint8_t*)&cmd, sizeof(cmd),
(uint8_t*)&resp, sizeof(resp),
&num))) {
return ret;
}
/* Sent transfer */
if ((ret = send_data(usbh->conn,
(uint8_t *) data, TONE_CURVE_SIZE * sizeof(uint16_t)))) {
goto done;
}
done: