Porównaj commity

...

8 Commity

Autor SHA1 Wiadomość Data
Nomadbyte 3e0e4cd915 Merge branch 'xerox_mfp-729-read' into 'master'
xerox_mfp: Avoid a buffering stall, when reading image data

Closes #729

See merge request sane-project/backends!827
2024-04-20 11:33:33 +00:00
Ralph Little 0f472aa205 Merge branch 'editorconfig_inline_comment' into 'master'
.editorconfig: inline comments are forbidden

See merge request sane-project/backends!832
2024-04-19 19:53:22 +00:00
ThierryFR 728ca40272 Merge branch 'escl-force-idle-status' into 'master'
Escl force idle status

See merge request sane-project/backends!835
2024-04-16 20:45:49 +00:00
ThierryFR 113be50f6b Escl force idle status 2024-04-16 20:45:49 +00:00
Guillaume Girol a6d63a72ec .editorconfig: inline comments are forbidden
source: https://spec.editorconfig.org/#no-inline-comments

this makes neovim unhappy, at least.
2024-02-26 12:00:00 +00:00
Artur Shepilko a07d498270 xerox_mfp: Avoid a buffering stall, when reading image data
This addresses a buffering stall which could occur, when the length
of free space after the buffered data at the end of the allocated
buffer is less than `USB_BLOCK_SIZE`, i.e.
`(DATAROOM(dev) > 0 && DATAROOM(dev) < USB_BLOCK_SIZE)`.

In such case an expectation for the read request length to be a multiple
of `USB_BLOCK_SIZE`, that is (`DATAROOM(dev) & USB_BLOCK_MASK`), would
result in zero remaining buffer room. Combined with no data consumed out
of the buffer, yet more data to receive for the current block, it would
lead to an infinite loop. This was observed with Samsung SCX-4729FW in
network (TCP) mode via Wi-Fi, with JPEG compression disabled.

The `USB_BLOCK_SIZE` is imposed by USB specs; USB 2.0 requires max
512 byte packet size for bulk transfers with high-speed endpoints.
This is applicable to USB transport. TCP transport does not have such
restriction.

NOTE: `DATAROOM(dev)` returns the length of free space from the end of
the buffered data up till the allocated end of the buffer. That means,
it may not always report the total free space left -- only the length
of the contiguous space. When the free space "wraps around", the
reported free space is short of `dev->dataoff`.
2024-02-13 19:55:32 -06:00
Artur Shepilko fc171e9191 xerox_mfp: Add comments to explain the circular buffer implementation 2024-02-08 12:00:01 -06:00
Artur Shepilko 392aa8cc2e xerox_mfp: Fix whitespace and code formatting 2024-02-08 12:00:01 -06:00
9 zmienionych plików z 407 dodań i 176 usunięć

Wyświetl plik

@ -6,7 +6,8 @@
# Your editor may need a plugin for this configuration to take effect.
# See http://editorconfig.org/#download for details.
root = true ; look no further
; look no further
root = true
[*]
charset = utf-8

Wyświetl plik

@ -1345,7 +1345,7 @@ sane_cancel(SANE_Handle h)
}
handler->scanner->work = SANE_FALSE;
handler->cancel = SANE_TRUE;
escl_scanner(handler->device, handler->scanner->scanJob, handler->result);
escl_scanner(handler->device, handler->scanner->scanJob, handler->result, SANE_TRUE);
free(handler->result);
handler->result = NULL;
free(handler->scanner->scanJob);
@ -1566,6 +1566,7 @@ sane_start(SANE_Handle h)
handler->decompress_scan_data = SANE_FALSE;
handler->end_read = SANE_FALSE;
if (handler->scanner->work == SANE_FALSE) {
escl_reset_all_jobs(handler->device);
SANE_Status st = escl_status(handler->device,
handler->scanner->source,
NULL,

Wyświetl plik

@ -248,7 +248,11 @@ SANE_Status escl_scan(capabilities_t *scanner,
void escl_scanner(const ESCL_Device *device,
char *scanJob,
char *result);
char *result,
SANE_Bool status);
SANE_Status escl_reset_all_jobs(ESCL_Device *device);
typedef void CURL;

Wyświetl plik

@ -44,7 +44,32 @@ write_callback(void __sane_unused__*str,
* This function is called in the 'sane_cancel' function.
*/
void
escl_scanner(const ESCL_Device *device, char *scanJob, char *result)
escl_delete(const ESCL_Device *device, char *uri)
{
CURL *curl_handle = NULL;
long answer = 0;
if (uri == NULL)
return;
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
escl_curl_url(curl_handle, device, uri);
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "DELETE");
if (curl_easy_perform(curl_handle) == CURLE_OK) {
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &answer);
return;
}
curl_easy_cleanup(curl_handle);
}
}
/**
* \fn void escl_scanner(const ESCL_Device *device, char *result)
* \brief Function that resets the scanner after each scan, using curl.
* This function is called in the 'sane_cancel' function.
*/
void
escl_scanner(const ESCL_Device *device, char *scanJob, char *result, SANE_Bool status)
{
CURL *curl_handle = NULL;
const char *scan_jobs = "/eSCL/";
@ -70,10 +95,15 @@ CURL_CALL:
if (i >= 15) return;
}
curl_easy_cleanup(curl_handle);
if (SANE_STATUS_GOOD != escl_status(device,
PLATEN,
NULL,
NULL))
goto CURL_CALL;
char* end = strrchr(scan_cmd, '/');
*end = 0;
escl_delete(device, scan_cmd);
if (status) {
if (SANE_STATUS_GOOD != escl_status(device,
PLATEN,
NULL,
NULL))
goto CURL_CALL;
}
}
}

Wyświetl plik

@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libxml/parser.h>
@ -270,3 +271,135 @@ clean_data:
}
return (status);
}
static void
print_xml_job_finish(xmlNode *node,
SANE_Status *job)
{
while (node) {
if (node->type == XML_ELEMENT_NODE) {
if (find_nodes_s(node)) {
if (strcmp((const char *)node->name, "JobState") == 0) {
const char *state = (const char *)xmlNodeGetContent(node);
if (!strcmp(state, "Canceled")) {
*job = SANE_STATUS_GOOD;
DBG(10, "jobId Completed SANE_STATUS_GOOD\n");
}
else if (!strcmp(state, "Aborted")) {
*job = SANE_STATUS_GOOD;
DBG(10, "jobId Completed SANE_STATUS_GOOD\n");
}
else if (!strcmp(state, "Completed")) {
*job = SANE_STATUS_GOOD;
DBG(10, "jobId Completed SANE_STATUS_GOOD\n");
}
}
}
}
print_xml_job_finish(node->children, job);
node = node->next;
}
}
static void
print_xml_reset_all_jobs (xmlNode *node,
ESCL_Device *device)
{
DBG(10, "print_xml_reset_all_jobs\n");
SANE_Status status = SANE_STATUS_DEVICE_BUSY;
while (node) {
if (node->type == XML_ELEMENT_NODE) {
if (find_nodes_s(node)) {
if (strcmp((const char *)node->name, "JobUri") == 0) {
DBG(10, "print_xml_reset_all_jobs: %s\n", node->name);
if (device != NULL) {
print_xml_job_finish (node, &status);
if (status == SANE_STATUS_DEVICE_BUSY) {
char *jobUri = (char *)xmlNodeGetContent(node);
char *job = strrchr((const char *)jobUri, '/');
char *scanj = NULL;
if (job != NULL) {
if (strstr(jobUri,"ScanJobs"))
scanj = strdup("ScanJobs");
else
scanj = strdup("ScanJob");
DBG(10, "print_xml_reset_all_jobs: %s/%s\n", scanj, job);
escl_scanner(device, scanj, job, SANE_FALSE);
free(scanj);
}
DBG(10, "print_xml_reset_all_jobs: sleep to finish the job\n");
}
}
}
}
}
print_xml_reset_all_jobs (node->children,
device);
node = node->next;
}
}
/**
* \fn SANE_Status escl_reset_all_jobs (ESCL_Device *device, , char *scanJob)
* \brief Function that forces the end of jobs, using curl.
* This function is called in the 'sane_start' function.
*
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_reset_all_jobs(ESCL_Device *device)
{
CURL *curl_handle = NULL;
xmlDoc *data = NULL;
xmlNode *node = NULL;
struct idle *var = NULL;
const char *scanner_status = "/eSCL/ScannerStatus";
SANE_Status status = SANE_STATUS_DEVICE_BUSY;
DBG(10, "escl_reset_all_jobs\n");
if (device == NULL)
return (SANE_STATUS_NO_MEM);
DBG(10, "1 - escl_reset_all_jobs\n");
var = (struct idle*)calloc(1, sizeof(struct idle));
if (var == NULL)
return (SANE_STATUS_NO_MEM);
DBG(10, "2 - escl_reset_all_jobs\n");
var->memory = malloc(1);
var->size = 0;
curl_handle = curl_easy_init();
escl_curl_url(curl_handle, device, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L);
CURLcode res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res));
status = SANE_STATUS_INVAL;
goto clean_data1;
}
DBG(10, "3 - escl_reset_all_jobs\n");
DBG( 10, "eSCL : Status : %s.\n", var->memory);
data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0);
if (data == NULL) {
status = SANE_STATUS_NO_MEM;
goto clean_data1;
}
node = xmlDocGetRootElement(data);
if (node == NULL) {
status = SANE_STATUS_NO_MEM;
goto clean1;
}
print_xml_reset_all_jobs (node, device);
status = SANE_STATUS_GOOD;
clean1:
xmlFreeDoc(data);
clean_data1:
xmlCleanupParser();
xmlMemoryDump();
curl_easy_cleanup(curl_handle);
free(var->memory);
free(var);
return status;
}

Wyświetl plik

@ -1,17 +1,16 @@
/*
* SANE backend for
* Samsung SCX-4500W
* SANE backend for Samsung SCX-4500W
*
* Network Scanners Support
* Copyright 2010 Alexander Kuznetsov <acca(at)cpan.org>
* Network Scanners Support
* Copyright 2010 Alexander Kuznetsov <acca(at)cpan.org>
*
* This program is licensed under GPL + SANE exception.
* More info at http://www.sane-project.org/license.html
*
*/
#undef BACKEND_NAME
#define BACKEND_NAME xerox_mfp
#undef BACKEND_NAME
#define BACKEND_NAME xerox_mfp
#define DEBUG_DECLARE_ONLY
#define DEBUG_NOT_STATIC
@ -44,16 +43,17 @@
#include "xerox_mfp.h"
#define RECV_TIMEOUT 1 /* seconds */
#define RECV_TIMEOUT 1 /* seconds */
extern int sanei_debug_xerox_mfp;
int tcp_dev_request(struct device *dev,
SANE_Byte *cmd, size_t cmdlen,
SANE_Byte *resp, size_t *resplen)
int
tcp_dev_request(struct device *dev,
SANE_Byte *cmd, size_t cmdlen,
SANE_Byte *resp, size_t *resplen)
{
size_t bytes_recv = 0;
ssize_t rc = 1;
size_t len;
size_t bytes_recv = 0;
ssize_t rc = 1;
size_t len;
/* Send request, if any */
@ -73,14 +73,16 @@ int tcp_dev_request(struct device *dev,
while (bytes_recv < *resplen && rc > 0) {
rc = recv(dev->dn, resp+bytes_recv, *resplen-bytes_recv, 0);
if (rc > 0) bytes_recv += rc;
if (rc > 0) {
bytes_recv += rc;
}
else {
DBG(1, "%s: error %s, bytes requested: %i, bytes read: %i\n",
__func__, strerror(errno), (int)*resplen, (int)bytes_recv);
*resplen = bytes_recv;
/*
TODO:
do something smarter than that!
do something smarter than that!
*/
return SANE_STATUS_GOOD;
return SANE_STATUS_IO_ERROR;
@ -93,24 +95,28 @@ int tcp_dev_request(struct device *dev,
return SANE_STATUS_GOOD;
}
SANE_Status tcp_dev_open(struct device *dev)
SANE_Status
tcp_dev_open(struct device *dev)
{
SANE_Status status;
char *strhost;
char *strport;
int port;
struct servent *sp;
struct timeval tv;
SANE_String_Const devname;
SANE_Status status;
char *strhost;
char *strport;
int port;
struct servent *sp;
struct timeval tv;
SANE_String_Const devname;
devname = dev->sane.name;
DBG(3, "%s: open %s\n", __func__, devname);
if (strncmp(devname, "tcp", 3) != 0) return SANE_STATUS_INVAL;
if (strncmp(devname, "tcp", 3) != 0)
return SANE_STATUS_INVAL;
devname += 3;
devname = sanei_config_skip_whitespace(devname);
if (!*devname) return SANE_STATUS_INVAL;
if (!*devname)
return SANE_STATUS_INVAL;
devname = sanei_config_get_string(devname, &strhost);
devname = sanei_config_skip_whitespace(devname);
@ -147,7 +153,8 @@ SANE_Status tcp_dev_open(struct device *dev)
void
tcp_dev_close(struct device *dev)
{
if (!dev) return;
if (!dev)
return;
DBG(3, "%s: closing dev %p\n", __func__, (void *)dev);
@ -155,7 +162,8 @@ tcp_dev_close(struct device *dev)
if (dev->scanning) {
dev->cancel = 1;
/* flush READ_IMAGE data */
if (dev->reading) sane_read(dev, NULL, 1, NULL);
if (dev->reading)
sane_read(dev, NULL, 1, NULL);
/* send cancel if not sent before */
if (dev->state != SANE_STATUS_CANCELLED)
ret_cancel(dev, 0);
@ -170,11 +178,11 @@ SANE_Status
tcp_configure_device(const char *devname, SANE_Status(*list_one)(SANE_String_Const devname))
{
/*
TODO: LAN scanners multicast discovery.
devname would contain "tcp auto"
TODO: LAN scanners multicast discovery.
devname would contain "tcp auto"
We find new devnames and feed them to
`list_one_device' one by one
We find new devnames and feed them to
`list_one_device' one by one
*/
return list_one(devname);
}

Wyświetl plik

@ -6,8 +6,8 @@
* More info at http://www.sane-project.org/license.html
*/
#undef BACKEND_NAME
#define BACKEND_NAME xerox_mfp
#undef BACKEND_NAME
#define BACKEND_NAME xerox_mfp
#define DEBUG_DECLARE_ONLY
#define DEBUG_NOT_STATIC
#include "sane/config.h"
@ -110,7 +110,7 @@ usb_dev_close(struct device *dev)
}
if (xerox_need_clear_halt()) {
sanei_usb_clear_halt(dev->dn); /* unstall for next users */
sanei_usb_clear_halt(dev->dn); /* unstall for next users */
}
sanei_usb_close(dev->dn);
dev->dn = -1;

Wyświetl plik

@ -41,8 +41,8 @@
#define BACKEND_BUILD 13
#define XEROX_CONFIG_FILE "xerox_mfp.conf"
static const SANE_Device **devlist = NULL; /* sane_get_devices array */
static struct device *devices_head = NULL; /* sane_get_devices list */
static const SANE_Device **devlist = NULL; /* sane_get_devices array */
static struct device *devices_head = NULL; /* sane_get_devices list */
enum { TRANSPORT_USB, TRANSPORT_TCP, TRANSPORTS_MAX };
transport available_transports[TRANSPORTS_MAX] = {
@ -80,14 +80,14 @@ static int resolv_state(int state)
static char *str_cmd(int cmd)
{
switch (cmd) {
case CMD_ABORT: return "ABORT";
case CMD_INQUIRY: return "INQUIRY";
case CMD_RESERVE_UNIT: return "RESERVE_UNIT";
case CMD_RELEASE_UNIT: return "RELEASE_UNIT";
case CMD_SET_WINDOW: return "SET_WINDOW";
case CMD_READ: return "READ";
case CMD_READ_IMAGE: return "READ_IMAGE";
case CMD_OBJECT_POSITION: return "OBJECT_POSITION";
case CMD_ABORT: return "ABORT";
case CMD_INQUIRY: return "INQUIRY";
case CMD_RESERVE_UNIT: return "RESERVE_UNIT";
case CMD_RELEASE_UNIT: return "RELEASE_UNIT";
case CMD_SET_WINDOW: return "SET_WINDOW";
case CMD_READ: return "READ";
case CMD_READ_IMAGE: return "READ_IMAGE";
case CMD_OBJECT_POSITION: return "OBJECT_POSITION";
}
return "unknown";
}
@ -163,17 +163,17 @@ static int copy_decompress_data(struct device *dev, unsigned char *pDest, int ma
int data_size = 0;
if (destLen)
*destLen = 0;
*destLen = 0;
if (!dev->decDataSize)
return 0;
data_size = dev->decDataSize - dev->currentDecDataIndex;
if (data_size > maxlen)
data_size = maxlen;
if (data_size && pDest) {
memcpy(pDest, dev->decData + dev->currentDecDataIndex, data_size);
if (destLen)
*destLen = data_size;
dev->currentDecDataIndex += data_size;
memcpy(pDest, dev->decData + dev->currentDecDataIndex, data_size);
if (destLen)
*destLen = data_size;
dev->currentDecDataIndex += data_size;
}
if (dev->decDataSize == dev->currentDecDataIndex) {
dev->currentDecDataIndex = 0;
@ -261,8 +261,8 @@ static int dev_command(struct device *dev, SANE_Byte *cmd, size_t reqlen)
SANE_Byte *res = dev->res;
assert(reqlen <= sizeof(dev->res)); /* requested len */
dev->reslen = sizeof(dev->res); /* doing full buffer to flush stalled commands */
assert(reqlen <= sizeof(dev->res)); /* requested len */
dev->reslen = sizeof(dev->res); /* doing full buffer to flush stalled commands */
if (cmd[2] == CMD_SET_WINDOW) {
/* Set Window have wrong packet length, huh. */
@ -296,7 +296,7 @@ static int dev_command(struct device *dev, SANE_Byte *cmd, size_t reqlen)
dev->state = SANE_STATUS_IO_ERROR;
return 0;
} else {
size_t pktlen; /* len specified in packet */
size_t pktlen; /* len specified in packet */
if (DBG_LEVEL > 3)
dbg_dump(dev);
@ -801,8 +801,8 @@ static int dev_set_window(struct device *dev)
cmd[0x0a] = dev->win_len >> 16;
cmd[0x0b] = dev->win_len >> 8;
cmd[0x0c] = dev->win_len;
cmd[0x0d] = dev->resolution; /* x */
cmd[0x0e] = dev->resolution; /* y */
cmd[0x0d] = dev->resolution; /* x */
cmd[0x0e] = dev->resolution; /* y */
cmd[0x0f] = (SANE_Byte)floor(dev->win_off_x);
cmd[0x10] = (SANE_Byte)((dev->win_off_x - floor(dev->win_off_x)) * 100);
cmd[0x11] = (SANE_Byte)floor(dev->win_off_y);
@ -853,7 +853,7 @@ dev_inquiry(struct device *dev)
/* skip spaces */;
dev->sane.model = optr = (SANE_Char *) malloc(33);
xptr = optr; /* is last non space character + 1 */
xptr = optr; /* is last non space character + 1 */
for (; ptr < &dev->res[0x24] && *ptr;) {
if (*ptr != ' ')
xptr = optr + 1;
@ -1356,8 +1356,8 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
int bufLen = (diff < maxlen) ? diff : maxlen;
if (diff &&
copy_decompress_data(dev, buf, bufLen, lenp)) {
if (lenp)
dev->total_out_size += *lenp;
if (lenp)
dev->total_out_size += *lenp;
return SANE_STATUS_GOOD;
}
} else if (dev->composition != MODE_RGB24) {
@ -1414,15 +1414,69 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
dev->blocks++;
}
/* Receive the on-device raw image data into a cyclic aka circular buffer.
*
* The circular buffer implementation is as follows:
* - buffer::{data[DATASIZE], dataoff, datalen};
* - data storage is preallocated to a fixed capacity: DATASIZE;
* - dataoff is used to track the data start (for read);
* - datalen is the stored data's length;
* - DATATAIL() macro is to track the data end position (for write);
* - Both start and end positions may be wrapped around at the DATASIZE,
* (& DATAMASK);
* - DATAROOM() macro is used to determine the currently available
* length of the __contiguous__ storage after the data end (from DATATAIL)
* - write is allowed only into the remaining capacity, overwriting of the
* the buffered but not consumed data is not allowed;
* - once data has been consumed, the dataoff and datalen must be adjusted
* accordingly; dataoff may wrap around (& DATAMASK);
* - when DATAROOM() returns 0, the data must be consumed before any more
* data could be buffered.
*
* NOTE: the DATAROOM() does not wrap around and yields the length
* from DATATAIL() up to the DATASIZE position. So the returned length may
* be shorter than the actual remaining capacity, that is there may be
* more unoccupied space from the beginning of the buffer till dataoff.
*
* This is because the buffer's storage pointer at the write position is passed
* directly to the IO receive call, so it's expected to be contiguous and can't
* wrap around. Thus in such cases this may result in extra IO receive call in
* order to first fill the residual length till DATASIZE, and then continue
* filling from the start of the buffer.
*
* It's all manual and requires some discipline but it does the job.
*/
do {
size_t datalen;
int clrlen; /* cleared lines len */
int olen; /* output len */
/* read as much data into the buffer */
datalen = MIN(dev->blocklen, DATAROOM(dev) & USB_BLOCK_MASK);
/* set up to read as much data as room left in the buffer */
datalen = DATAROOM(dev);
while (datalen && dev->blocklen) {
SANE_Byte *rbuf = dev->data + DATATAIL(dev);
/* USB 2.0 spec requires 512 byte packet max size for bulk transfers
* with high-speed endpoints. Smaller max sizes are allowed
* for slower endpoints (64, 32, 16, 8 for full-speed).
* Some Samsung MFP scanners require requests for at least the
* defined max size, when there are sufficient data available;
* otherwise successfully return 0 bytes.
* For example,
* - requesting 256 bytes with more than 256 bytes data available
* will return 0 bytes;
* - requesting at least 512 will properly fulfill the request;
* - requesting 8 bytes with 16 bytes remaining will return 0 bytes;
* yet requesting 16 bytes (or more) will correctly return the
* remaining 16 bytes.
*/
int usb_datalen = datalen & USB_BLOCK_MASK;
if (usb_datalen)
datalen = usb_datalen;
else if (strcmp(dev->io->ttype, "usb") == 0)
break;
datalen = MIN((size_t)dev->blocklen, datalen);
DBG(9, "<> request len: %zu, [%d, %d; %d]\n",
datalen, dev->dataoff, DATATAIL(dev), dev->datalen);
@ -1431,7 +1485,7 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
SANE_STATUS_GOOD)
return status;
dev->datalen += datalen;
dev->datalen += datalen; /* of actually received data */
dev->blocklen -= datalen;
DBG(9, "<> got %zu, [%d, %d; %d]\n",
@ -1440,7 +1494,7 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp)
if (dev->blocklen < 0)
return ret_cancel(dev, SANE_STATUS_IO_ERROR);
datalen = MIN(dev->blocklen, DATAROOM(dev) & USB_BLOCK_MASK);
datalen = DATAROOM(dev);
}
if (buf && lenp) { /* read mode */
@ -1563,17 +1617,17 @@ sane_start(SANE_Handle h)
if (isJPEGEnabled(dev) &&
dev->composition == MODE_RGB24) {
int fd;
int fd;
remove(encTmpFileName);
/* Precreate temporary file in exclusive mode. */
fd = open(encTmpFileName, O_CREAT|O_EXCL, 0600);
if (fd == -1) {
DBG(3, "%s: %p, can't create temporary file %s: %s\n", __func__,
(void *)dev, encTmpFileName, strerror(errno));
return ret_cancel(dev, SANE_STATUS_ACCESS_DENIED);
}
close(fd);
/* Precreate temporary file in exclusive mode. */
fd = open(encTmpFileName, O_CREAT|O_EXCL, 0600);
if (fd == -1) {
DBG(3, "%s: %p, can't create temporary file %s: %s\n", __func__,
(void *)dev, encTmpFileName, strerror(errno));
return ret_cancel(dev, SANE_STATUS_ACCESS_DENIED);
}
close(fd);
}
dev->currentDecDataIndex = 0;

Wyświetl plik

@ -25,22 +25,22 @@
#define UNCONST(ptr) ((void *)(long)(ptr))
#define PNT_PER_MM (1200. / MM_PER_INCH)
#define PNT_PER_MM (1200. / MM_PER_INCH)
#define PADDING_SIZE 16
#define PADDING_SIZE 16
#define SWAP_Word(x, y) { SANE_Word z = x; x = y; y = z; }
enum options {
OPT_NUMOPTIONS,
OPT_GROUP_STD,
OPT_RESOLUTION, /* dpi*/
OPT_MODE, /* color */
OPT_THRESHOLD, /* brightness */
OPT_SOURCE, /* affects max window size */
OPT_RESOLUTION, /* dpi*/
OPT_MODE, /* color */
OPT_THRESHOLD, /* brightness */
OPT_SOURCE, /* affects max window size */
OPT_JPEG,
OPT_GROUP_GEO,
OPT_SCAN_TL_X, /* for (OPT_SCAN_TL_X to OPT_SCAN_BR_Y) */
OPT_SCAN_TL_X, /* for (OPT_SCAN_TL_X to OPT_SCAN_BR_Y) */
OPT_SCAN_TL_Y,
OPT_SCAN_BR_X,
OPT_SCAN_BR_Y,
@ -52,83 +52,83 @@ typedef struct transport transport;
struct device {
struct device *next;
SANE_Device sane;
int dn; /* usb file descriptor */
SANE_Byte res[1024]; /* buffer for responses */
size_t reslen; /* response len */
int dn; /* usb file descriptor */
SANE_Byte res[1024]; /* buffer for responses */
size_t reslen; /* response len */
SANE_Option_Descriptor opt[NUM_OPTIONS];
Option_Value val[NUM_OPTIONS];
SANE_Parameters para;
SANE_Bool non_blocking;
int scanning; /* scanning is started */
int cancel; /* cancel flag */
int state; /* current state */
int reserved; /* CMD_RESERVE_UNIT */
int reading; /* READ_IMAGE is sent */
int has_adf; /* ADF is present */
int scanning; /* scanning is started */
int cancel; /* cancel flag */
int state; /* current state */
int reserved; /* CMD_RESERVE_UNIT */
int reading; /* READ_IMAGE is sent */
int has_adf; /* ADF is present */
SANE_Byte *data; /* postprocessing cyclic buffer 64k */
int datalen; /* how data in buffer */
int dataoff; /* offset of data */
int dataindex; /* sequental number */
#define DATAMASK 0xffff /* mask of data buffer */
#define DATASIZE (DATAMASK + 1) /* size of data buffer */
SANE_Byte *data; /* postprocessing cyclic buffer 64k */
int datalen; /* how data in buffer */
int dataoff; /* offset of data */
int dataindex; /* sequental number */
#define DATAMASK 0xffff /* mask of data buffer */
#define DATASIZE (DATAMASK + 1) /* size of data buffer */
/* 64K will be enough to hold whole line of 2400 dpi of 23cm */
#define DATATAIL(dev) ((dev->dataoff + dev->datalen) & DATAMASK)
#define DATAROOM(dev) dataroom(dev)
#define POST_DATASIZE 0xFFFFFF /* 16777215 bytes */
SANE_Byte *decData; /* static buffer of POST_DATASIZE bytes */
#define POST_DATASIZE 0xFFFFFF /* 16777215 bytes */
SANE_Byte *decData; /* static buffer of POST_DATASIZE bytes */
int decDataSize;
int currentDecDataIndex;
/* data from CMD_INQUIRY: */
int resolutions; /* supported resolution bitmask */
int compositions; /* supported image compositions bitmask */
int max_len; /* effective max len for current doc source */
int resolutions; /* supported resolution bitmask */
int compositions; /* supported image compositions bitmask */
int max_len; /* effective max len for current doc source */
int max_win_width;
int max_win_len;
int max_len_adf;
int max_len_fb;
int line_order; /* if need post processing */
SANE_Word dpi_list[30]; /* allowed resolutions */
int line_order; /* if need post processing */
SANE_Word dpi_list[30]; /* allowed resolutions */
int doc_loaded;
SANE_Range win_x_range;
SANE_Range win_y_range;
/* CMD_SET_WINDOW parameters we set: */
int win_width; /* in 1200dpi points */
int win_width; /* in 1200dpi points */
int win_len;
double win_off_x; /* in inches (byte.byte) */
double win_off_x; /* in inches (byte.byte) */
double win_off_y;
int resolution; /* dpi indexed values */
int composition; /* MODE_ */
int doc_source; /* document source */
int threshold; /* brightness */
int resolution; /* dpi indexed values */
int composition; /* MODE_ */
int doc_source; /* document source */
int threshold; /* brightness */
int compressionTypes;
SANE_Bool compressionEnabled;
/* CMD_READ data. It is per block only, image could be in many blocks */
int blocklen; /* image data block len (padding incl.) */
int vertical; /* lines in block (padded) */
int horizontal; /* b/w: bytes, gray/color: pixels (padded) */
int blocklen; /* image data block len (padding incl.) */
int vertical; /* lines in block (padded) */
int horizontal; /* b/w: bytes, gray/color: pixels (padded) */
int final_block;
int pixels_per_line;
int bytes_per_line;
int ulines; /* up to this block including */
int y_off; /* up to this block excluding*/
int ulines; /* up to this block including */
int y_off; /* up to this block excluding*/
int blocks;
/* stat */
int total_img_size; /* predicted image size */
int total_out_size; /* total we sent to user */
int total_data_size; /* total of what scanner sent us */
int total_img_size; /* predicted image size */
int total_out_size; /* total we sent to user */
int total_data_size; /* total of what scanner sent us */
/* transport to use */
transport *io;
};
/* Transport abstract layer */
/* Transport abstract layer */
struct transport {
char *ttype;
@ -140,17 +140,17 @@ struct transport {
SANE_Status(*configure_device)(const char *devname, SANE_Status(*cb)(SANE_String_Const devname));
};
/* USB transport */
int usb_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen);
SANE_Status usb_dev_open(struct device *dev);
void usb_dev_close(struct device *dev);
SANE_Status usb_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname));
/* USB transport */
int usb_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen);
SANE_Status usb_dev_open(struct device *dev);
void usb_dev_close(struct device *dev);
SANE_Status usb_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname));
/* TCP unicast */
int tcp_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen);
SANE_Status tcp_dev_open(struct device *dev);
void tcp_dev_close(struct device *dev);
SANE_Status tcp_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname));
/* TCP unicast */
int tcp_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen);
SANE_Status tcp_dev_open(struct device *dev);
void tcp_dev_close(struct device *dev);
SANE_Status tcp_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname));
/* device wants transfer buffer to be multiple of 512 */
#define USB_BLOCK_SIZE 512
@ -167,62 +167,62 @@ static inline int dataroom(struct device *dev)
return DATASIZE - tail;
}
/* Functions from original xerox_mfp.c, used in -usb.c and -tcp.c */
/* Functions from original xerox_mfp.c, used in -usb.c and -tcp.c */
SANE_Status ret_cancel(struct device *dev, SANE_Status ret);
/* a la SCSI commands. */ /* request len, response len, exception */
#define CMD_ABORT 0x06 /* 4, 32 */
#define CMD_INQUIRY 0x12 /* 4, 70 */
#define CMD_RESERVE_UNIT 0x16 /* 4, 32 */
#define CMD_RELEASE_UNIT 0x17 /* 4, 32 */
#define CMD_SET_WINDOW 0x24 /* 25, 32, specified req len is 22 */
#define CMD_READ 0x28 /* 4, 32 */
#define CMD_READ_IMAGE 0x29 /* 4, var + padding[16] */
#define CMD_OBJECT_POSITION 0x31 /* 4, 32 */
#define CMD_ABORT 0x06 /* 4, 32 */
#define CMD_INQUIRY 0x12 /* 4, 70 */
#define CMD_RESERVE_UNIT 0x16 /* 4, 32 */
#define CMD_RELEASE_UNIT 0x17 /* 4, 32 */
#define CMD_SET_WINDOW 0x24 /* 25, 32, specified req len is 22 */
#define CMD_READ 0x28 /* 4, 32 */
#define CMD_READ_IMAGE 0x29 /* 4, var + padding[16] */
#define CMD_OBJECT_POSITION 0x31 /* 4, 32 */
/* Packet Headers */
#define REQ_CODE_A 0x1b
#define REQ_CODE_B 0xa8
#define RES_CODE 0xa8
#define REQ_CODE_A 0x1b
#define REQ_CODE_B 0xa8
#define RES_CODE 0xa8
/* Status Codes, going into dev->state */
#define STATUS_GOOD 0x00
#define STATUS_CHECK 0x02 /* MSG_SCANNER_STATE */
#define STATUS_CANCEL 0x04
#define STATUS_BUSY 0x08
#define STATUS_GOOD 0x00
#define STATUS_CHECK 0x02 /* MSG_SCANNER_STATE */
#define STATUS_CANCEL 0x04
#define STATUS_BUSY 0x08
/* Message Code */
#define MSG_NO_MESSAGE 0x00
#define MSG_PRODUCT_INFO 0x10 /* CMD_INQUIRY */
#define MSG_SCANNER_STATE 0x20 /* CMD_RESERVE_UNIT, and
CMD_READ, CMD_SET_WINDOW, CMD_OBJECT_POSITION */
#define MSG_SCANNING_PARAM 0x30 /* CMD_SET_WINDOW */
#define MSG_PREVIEW_PARAM 0x31 /* CMD_SET_WINDOW */
#define MSG_LINK_BLOCK 0x80 /* CMD_READ */
#define MSG_END_BLOCK 0x81 /* CMD_READ */
#define MSG_NO_MESSAGE 0x00
#define MSG_PRODUCT_INFO 0x10 /* CMD_INQUIRY */
#define MSG_SCANNER_STATE 0x20 /* CMD_RESERVE_UNIT, and
CMD_READ, CMD_SET_WINDOW, CMD_OBJECT_POSITION */
#define MSG_SCANNING_PARAM 0x30 /* CMD_SET_WINDOW */
#define MSG_PREVIEW_PARAM 0x31 /* CMD_SET_WINDOW */
#define MSG_LINK_BLOCK 0x80 /* CMD_READ */
#define MSG_END_BLOCK 0x81 /* CMD_READ */
/* Scanner State Bits (if MSG_SCANNER_STATE if STATUS_CHECK) */
#define STATE_NO_ERROR 0x001
#define STATE_COMMAND_ERROR 0x002
#define STATE_UNSUPPORTED 0x004
#define STATE_RESET 0x008
#define STATE_NO_DOCUMENT 0x010
#define STATE_DOCUMENT_JAM 0x020
#define STATE_COVER_OPEN 0x040
#define STATE_WARMING 0x080
#define STATE_LOCKING 0x100
#define STATE_INVALID_AREA 0x200
#define STATE_RESOURCE_BUSY 0x400
#define STATE_NO_ERROR 0x001
#define STATE_COMMAND_ERROR 0x002
#define STATE_UNSUPPORTED 0x004
#define STATE_RESET 0x008
#define STATE_NO_DOCUMENT 0x010
#define STATE_DOCUMENT_JAM 0x020
#define STATE_COVER_OPEN 0x040
#define STATE_WARMING 0x080
#define STATE_LOCKING 0x100
#define STATE_INVALID_AREA 0x200
#define STATE_RESOURCE_BUSY 0x400
/* Image Composition */
#define MODE_LINEART 0x00
#define MODE_HALFTONE 0x01
#define MODE_GRAY8 0x03
#define MODE_RGB24 0x05
#define MODE_LINEART 0x00
#define MODE_HALFTONE 0x01
#define MODE_GRAY8 0x03
#define MODE_RGB24 0x05
/* Document Source */
#define DOC_ADF 0x20
#define DOC_FLATBED 0x40
#define DOC_AUTO 0x80
#define DOC_ADF 0x20
#define DOC_FLATBED 0x40
#define DOC_AUTO 0x80
#endif /* xerox_mfp_h */
#endif /* xerox_mfp_h */