Draft: coolscan3: add LS-5000 RGBI and multisample policy
!936 (merged) has merged. This draft is rebased on
masterand contains only the LS-5000 RGBI, frame/count, and multisample policy changes.!939 fixes padded-pass extraction for RGB multisampling in a separate MR. It targets
masterdirectly and does not depend on this draft. This branch should be rebased after !939 lands.
What this MR changes
This draft enables the hardware-tested LS-5000 paths and guards the layouts the backend cannot decode yet.
- Infrared is active only on the tested LS-5000 model. Other coolscan3 models keep the option inactive until someone verifies them.
- Conventional RGBI scanning with
samples-per-scan=1returns pixel-interleaved red, green, blue, and infrared samples. - Enabling infrared updates
bytes_per_lineand tells the frontend to reload parameters. - Preview remains RGB-only. Toggling Preview also tells the frontend to reload parameters.
- The LS-5000 defaults to 16-bit. Firmware 1.03 rejects the tested 8-bit SET WINDOW path.
- RGB multisampling is enabled.
- Selecting infrared with
samples-per-scan > 1returns an error before device I/O. The firmware supports this combination, but it uses a packed layout that this backend does not decode. This is a decoder guard, not a hardware safety restriction. - The frame-count descriptor is bounded by the adapter-reported transport capacity. Moving to a later frame clamps an existing count to the remaining positions and asks the frontend to reload options. Setting the count first reaches the same final state.
- Multisample SCAN handles the two vendor reissue responses observed on firmware 1.03. It makes at most four reissues and returns an I/O error if the scanner continues requesting another.
- A failed
sane_start()clears the scanning state, so a setup error does not leave the handle falsely armed.
Scanner-independent helpers and tests cover the scan-mode policy, frame/count rules, failed-start cleanup, and bounded reissue state machine.
Packed RGB plus infrared mode
A full wire replay confirmed that the LS-5000 can scan RGB with hardware multisampling and infrared in one traversal.
The 4000 dpi run returned 2,980 records of 207,872 bytes, or 619,458,560 bytes total. The decoded records contain four independent RGB sample groups and one spatially aligned IR plane.
Only one IR plane is exposed in the transferred stream. That does not tell us whether the scanner captured infrared once or combined several infrared readings in firmware. The IR aggregation semantics therefore remain unresolved, and the plane should not be described as either 1x or 4x.
This MR does not implement that packed decoder. It rejects the combined setting before issuing a scan command. Conventional RGBI with samples-per-scan=1 remains supported, as does RGB-only multisampling.
Frame representation question
The current code follows the in-tree pieusb precedent. It reports SANE_FRAME_RGB, gives the actual four-sample byte count in bytes_per_line, and returns pixel-interleaved R, G, B, IR data when infrared is enabled.
That is not a normal RGB frame. During testing, scanimage wrote a P6 RGB header followed by the complete four-channel raster. Consumers must understand the convention before saving or processing the infrared channel.
The alternative is the coolscan2 approach: return RGB first, buffer the infrared plane, and expose it as a grayscale frame on the next sane_start(). Guidance on which representation the project prefers would be useful. This API question is why the MR remains a draft.
Adapter capacity and roll length
The tested converted SA-21 reports 40 addressable transport positions. That is the adapter's capacity, not a count of photographs on the loaded film. The backend does not perform a Nikon Scan-style prescan to count exposed frames.
Frame selection was exercised at positions 03, 07, 14, and 16 on this modified adapter. This does not establish support for a stock SA-21 or other feeders.
Hardware evidence
Tests used a Nikon Super Coolscan LS-5000 ED with firmware 1.03 and an SA-21 fitted with the solderless SA-30 conversion.
| Configuration | Geometry | Raw raster | scanimage PNM file |
|---|---|---|---|
| 16-bit RGB, 1000 dpi | 986 x 1489 x 3 | 8,808,924 bytes | 8,808,962 bytes |
| 16-bit RGBI, 1000 dpi | 986 x 1489 x 4 | 11,745,232 bytes | 11,745,270 bytes |
| 16-bit RGB, 4000 dpi | 3946 x 5959 x 3 | 141,085,284 bytes | 141,085,323 bytes |
| 16-bit RGBI, 4000 dpi | 3946 x 5959 x 4 | 188,113,712 bytes | 188,113,751 bytes |
The PNM totals include a 38-byte header at 1000 dpi and a 39-byte header at 4000 dpi. Each file contains the expected raster. The fourth RGBI lane contains a real infrared defect signal from dust, scratches, and fibers.
RGB-only 2x and 16x multisample scans completed at 1000 dpi. Full-width 4000 dpi RGB 4x also passed after applying the padded-pass extraction fix from !939. Its ghost-comb metric fell to 0.0000, and the 4x output matched a sharp 1x reference at lag zero with correlations from 0.999 to 1.000.
A combined build containing this MR and !939 passed the real-scanner protocol: low-resolution RGB, conventional RGBI, full-resolution RGBI, alignment checks, and local rejection of the unsupported packed setting.
Scope and limits
- Hardware testing covers one LS-5000 ED running firmware 1.03.
- The feeder was a modified SA-21 operating as an SA-30.
- A stock SA-21, MA-21, LS-50, and other coolscan3 models were not tested.
- Preview is RGB-only.
- Firmware 1.03 rejects the tested 8-bit SET WINDOW path.
- The packed RGB multisample plus infrared decoder is not included.
- Firmware IR aggregation remains unresolved.
- Host
loadremains unresolved for this firmware and adapter mode. - The RGBI frame representation still needs a project-level API decision.
- This branch should be rebased after the padded-stride fix in !939 reaches
master.
Verification
Local branch: coolscan3-ls5000-rgbi-safe
Corrected head: ed55c588c3525c0c73b5c235cd0f5e6261164f26
Base: upstream master at 9eef4994dfe4fac361808731878e5f094ac2cd41
- Project Linux style check passed.
- The Linux build passed with warnings treated as errors.
- Full
make checkpassed, includingcoolscan3_policy_test. - The policy test also passed directly under strict C99 with pedantic warnings treated as errors.
- The combined !937 plus !939 branch passed
coolscan3_policy_test,coolscan3_stride_test, and independent ASan/UBSan runs. - The full real-hardware protocol passed on the combined branch.
- No experimental frame-pitch or alternate READ-size change is included.
- GitLab CI passed for
ed55c588c3525c0c73b5c235cd0f5e6261164f26(pipeline 2677332510).
Related issue: #8