From 392aa8cc2ecaba02069581ba0069660ea3f0e2ee Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Fri, 26 Jan 2024 10:04:26 -0600 Subject: [PATCH 1/3] xerox_mfp: Fix whitespace and code formatting --- backend/xerox_mfp-tcp.c | 70 ++++++++------- backend/xerox_mfp-usb.c | 6 +- backend/xerox_mfp.c | 64 ++++++------- backend/xerox_mfp.h | 194 ++++++++++++++++++++-------------------- 4 files changed, 171 insertions(+), 163 deletions(-) diff --git a/backend/xerox_mfp-tcp.c b/backend/xerox_mfp-tcp.c index 845ab7e5e..1d49bd6bf 100644 --- a/backend/xerox_mfp-tcp.c +++ b/backend/xerox_mfp-tcp.c @@ -1,17 +1,16 @@ /* - * SANE backend for - * Samsung SCX-4500W + * SANE backend for Samsung SCX-4500W * - * Network Scanners Support - * Copyright 2010 Alexander Kuznetsov + * Network Scanners Support + * Copyright 2010 Alexander Kuznetsov * * 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); } diff --git a/backend/xerox_mfp-usb.c b/backend/xerox_mfp-usb.c index 519aba611..aacfb89a2 100644 --- a/backend/xerox_mfp-usb.c +++ b/backend/xerox_mfp-usb.c @@ -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; diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 48e1eca71..0dc537eb9 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -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) { @@ -1563,17 +1563,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; diff --git a/backend/xerox_mfp.h b/backend/xerox_mfp.h index ebd1b56e4..44db90703 100644 --- a/backend/xerox_mfp.h +++ b/backend/xerox_mfp.h @@ -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 */ From fc171e9191e8442100dc16fab05c651a7f3f0431 Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Sun, 28 Jan 2024 16:37:39 -0600 Subject: [PATCH 2/3] xerox_mfp: Add comments to explain the circular buffer implementation --- backend/xerox_mfp.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 0dc537eb9..03bde195c 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -1414,6 +1414,38 @@ 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 */ From a07d4982701760e482a16fef1d3219d94e4225b3 Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Mon, 5 Feb 2024 21:44:10 -0600 Subject: [PATCH 3/3] 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`. --- backend/xerox_mfp.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 03bde195c..f0defc191 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -1451,10 +1451,32 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) 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); @@ -1463,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", @@ -1472,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 */