From 0a9bf84d3c9e82e8bb12270a1a5a01a9f541fcc9 Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Thu, 25 Jan 2024 16:45:51 -0600 Subject: [PATCH 1/3] xerox_mfp: Add support for Samsung SCX-4729FW (network mode) --- backend/xerox_mfp.c | 1 + backend/xerox_mfp.conf.in | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 082175431..1151a4055 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -212,6 +212,7 @@ static int isSupportedDevice(struct device __sane_unused__ *dev) /* blacklist malfunctioning device(s) */ if (!strncmp (dev->sane.model, "SCX-4500W", 9) || !strncmp (dev->sane.model, "C460", 4) + || !!strstr(dev->sane.model, "SCX-472") || !!strstr (dev->sane.model, "WorkCentre 3225") || !!strstr (dev->sane.model, "CLX-3170") || !!strstr (dev->sane.model, "4x24") diff --git a/backend/xerox_mfp.conf.in b/backend/xerox_mfp.conf.in index d9deecc7e..4d1d934d0 100644 --- a/backend/xerox_mfp.conf.in +++ b/backend/xerox_mfp.conf.in @@ -169,6 +169,10 @@ usb 0x04e8 0x3450 #Samsung SCX-472x Series, Samsung SCX-4729FD usb 0x04e8 0x3453 +#Samsung SCX-4729FW, network mode +# tcp HOST_NAME_OR_IP PORT +#tcp scx4729fw 9400 + #Samsung CLX-6260 Series usb 0x04e8 0x3455 From 8fe58ab678ab772b74a5b5f9eaf07d9380642674 Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Thu, 25 Jan 2024 16:51:31 -0600 Subject: [PATCH 2/3] xerox_mfp: Use doc source macros for clarity --- backend/xerox_mfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 1151a4055..55f8acbda 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -503,7 +503,7 @@ static SANE_String_Const doc_sources[] = { }; static int doc_source_to_code[] = { - 0x40, 0x20, 0x80 + DOC_FLATBED, DOC_ADF, DOC_AUTO }; static SANE_String_Const scan_modes[] = { From 86bb976ad6fdc577c679617522788665adba8600 Mon Sep 17 00:00:00 2001 From: Artur Shepilko Date: Thu, 25 Jan 2024 16:54:12 -0600 Subject: [PATCH 3/3] xerox_mfp: When scanning from ADF, do not stop the device at page completion - Stopping and releasing the device causes the ADF to purge any remaining pages, thus only the first page gets properly scanned (observed with Samsung SCX-4729FW). - Instead, when sourcing from the ADF, at each page's completion it should continue and issue "OBJECT POSITION" command to proceed to the next page. - Once all pages have been processed, the subsequent "OBJECT POSITION" command returns the proper "CHECK CONDITION" status (ADF is empty) and triggers the device stop and release. - Additionally, the status of the ADF (loaded/empty) needs to be requeried at the `sane_start()` for proper handling of the "Auto" mode. Otherwise, the scanning session retains the ADF state from the start of the session, even though ADF will become empty. Thus the "Auto" mode will not properly switch to Flatbed as intended in the client application (observed in Simple-Scan). > NOTE: the initial "READ" command in `sane_start()` is extraneous and > appears to always return STATUS_BUSY (indeed, the scanner is usually > busy loading the page). The actual READ is correctly done in > `dev_acquire()`. It may appear benign in a single page scan mode, however, > it becomes malfunctioning in the mutipage ADF mode. The initial READ, > when successful, will cause the skipping of the read block from processing, > as the actual processing is tied to content read from `dev_acquire()`. > > Therefore, the initial READ command in the `sane_start()` is removed. --- backend/xerox_mfp.c | 63 +++++++++++++++++++++++++++++++++------------ backend/xerox_mfp.h | 1 + 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 55f8acbda..48e1eca71 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -703,6 +703,14 @@ static void set_parameters(struct device *dev) } } +/* determine if document is to be sourced from ADF */ +static int sourcing_from_adf(struct device *dev) +{ + return (dev->doc_source == DOC_ADF || + (dev->doc_source == DOC_AUTO && dev->doc_loaded)); +} + + /* resolve all options related to scan window */ /* called after option changed and in set_window */ static int fix_window(struct device *dev) @@ -732,11 +740,10 @@ static int fix_window(struct device *dev) dev->doc_source = doc_source_to_code[string_match_index(doc_sources, dev->val[OPT_SOURCE].s)]; /* max window len is dependent of document source */ - if (dev->doc_source == DOC_FLATBED || - (dev->doc_source == DOC_AUTO && !dev->doc_loaded)) - dev->max_len = dev->max_len_fb; - else + if (sourcing_from_adf(dev)) dev->max_len = dev->max_len_adf; + else + dev->max_len = dev->max_len_fb; /* parameters */ dev->win_y_range.max = SANE_FIX((double)dev->max_len / PNT_PER_MM); @@ -880,8 +887,9 @@ dev_inquiry(struct device *dev) dev->res[0x3f]; dev->line_order = dev->res[0x31]; dev->compressionTypes = dev->res[0x32]; - dev->doc_loaded = (dev->res[0x35] == 0x02) && - (dev->res[0x26] & 0x03); + dev->has_adf = ((dev->res[0x26] & 0x03) != 0); + dev->doc_loaded = (dev->res[0x35] == 0x02) + && dev->has_adf; init_options(dev); reset_options(dev); @@ -892,6 +900,25 @@ dev_inquiry(struct device *dev) return SANE_STATUS_GOOD; } + +static SANE_Status +dev_inquiry_adf_status(struct device *dev) +{ + if (!dev_cmd(dev, CMD_INQUIRY)) + return SANE_STATUS_IO_ERROR; + + dev->has_adf = ((dev->res[0x26] & 0x03) != 0); + dev->doc_loaded = (dev->res[0x35] == 0x02) + && dev->has_adf; + + DBG(3, "%s: ADF present: %s, loaded: %s\n", __func__, + (dev->has_adf ? "true" : "false"), + (dev->doc_loaded ? "true" : "false")); + + return SANE_STATUS_GOOD; +} + + const SANE_Option_Descriptor * sane_get_option_descriptor(SANE_Handle h, SANE_Int opt) { @@ -1362,7 +1389,10 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) remove(encTmpFileName); } /* that's all */ - dev_stop(dev); + /* finished receving the document; */ + /* stop and release the unit, unless sourcing from ADF */ + if (!sourcing_from_adf(dev)) + dev_stop(dev); return SANE_STATUS_EOF; } @@ -1466,7 +1496,6 @@ SANE_Status sane_start(SANE_Handle h) { struct device *dev = h; - DBG(3, "%s: %p\n", __func__, h); dev->cancel = 0; @@ -1477,22 +1506,24 @@ sane_start(SANE_Handle h) dev->blocks = 0; if (!dev->reserved) { + if (dev->has_adf + && (dev->doc_source == DOC_AUTO || dev->doc_source == DOC_ADF)) { + if (dev_inquiry_adf_status(dev) != SANE_STATUS_GOOD) + return dev_stop(dev); + } + if (!dev_cmd_wait(dev, CMD_RESERVE_UNIT)) return dev->state; dev->reserved++; + + if (!dev_set_window(dev) || + (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) + return dev_stop(dev); } - if (!dev_set_window(dev) || - (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) - return dev_stop(dev); - if (!dev_cmd_wait(dev, CMD_OBJECT_POSITION)) return dev_stop(dev); - if (!dev_cmd(dev, CMD_READ) || - (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) - return dev_stop(dev); - dev->scanning = 1; dev->final_block = 0; dev->blocklen = 0; diff --git a/backend/xerox_mfp.h b/backend/xerox_mfp.h index 6aa83a459..ebd1b56e4 100644 --- a/backend/xerox_mfp.h +++ b/backend/xerox_mfp.h @@ -64,6 +64,7 @@ struct device { 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 */