1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2007-2012 stef.dev@free.fr
4141cc406Sopenharmony_ci
5141cc406Sopenharmony_ci   This file is part of the SANE package.
6141cc406Sopenharmony_ci
7141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
8141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
9141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
10141cc406Sopenharmony_ci   License, or (at your option) any later version.
11141cc406Sopenharmony_ci
12141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
13141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15141cc406Sopenharmony_ci   General Public License for more details.
16141cc406Sopenharmony_ci
17141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
18141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
19141cc406Sopenharmony_ci
20141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
21141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
22141cc406Sopenharmony_ci
23141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
24141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
25141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
26141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
27141cc406Sopenharmony_ci   account of linking the SANE library code into it.
28141cc406Sopenharmony_ci
29141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
30141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
31141cc406Sopenharmony_ci   License.
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
34141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
35141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
36141cc406Sopenharmony_ci
37141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
38141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
39141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
40141cc406Sopenharmony_ci*/
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci/* this file contains functions common to rts88xx ASICs */
43141cc406Sopenharmony_ci
44141cc406Sopenharmony_ci#undef BACKEND_NAME
45141cc406Sopenharmony_ci#define BACKEND_NAME rts88xx_lib
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#include "../include/sane/config.h"
48141cc406Sopenharmony_ci#include "../include/sane/sane.h"
49141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h"
50141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
51141cc406Sopenharmony_ci#include "rts88xx_lib.h"
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci#include <stdio.h>
54141cc406Sopenharmony_ci#include <sys/time.h>
55141cc406Sopenharmony_ci#include <sys/types.h>
56141cc406Sopenharmony_ci
57141cc406Sopenharmony_ci#include "../include/_stdint.h"
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci#define RTS88XX_LIB_BUILD 30
60141cc406Sopenharmony_ci
61141cc406Sopenharmony_ci/* init rts88xx library */
62141cc406Sopenharmony_civoid
63141cc406Sopenharmony_cisanei_rts88xx_lib_init (void)
64141cc406Sopenharmony_ci{
65141cc406Sopenharmony_ci  DBG_INIT ();
66141cc406Sopenharmony_ci  DBG (DBG_info, "RTS88XX library, version %d.%d-%d\n", SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR,
67141cc406Sopenharmony_ci       RTS88XX_LIB_BUILD);
68141cc406Sopenharmony_ci}
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ci/*
71141cc406Sopenharmony_ci * registers helpers to avoid direct access
72141cc406Sopenharmony_ci */
73141cc406Sopenharmony_ciSANE_Bool
74141cc406Sopenharmony_cisanei_rts88xx_is_color (SANE_Byte * regs)
75141cc406Sopenharmony_ci{
76141cc406Sopenharmony_ci  if ((regs[0x2f] & 0x11) == 0x11)
77141cc406Sopenharmony_ci    return SANE_TRUE;
78141cc406Sopenharmony_ci  return SANE_FALSE;
79141cc406Sopenharmony_ci}
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_civoid
82141cc406Sopenharmony_cisanei_rts88xx_set_gray_scan (SANE_Byte * regs)
83141cc406Sopenharmony_ci{
84141cc406Sopenharmony_ci  regs[0x2f] = (regs[0x2f] & 0x0f) | 0x20;
85141cc406Sopenharmony_ci}
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_civoid
88141cc406Sopenharmony_cisanei_rts88xx_set_color_scan (SANE_Byte * regs)
89141cc406Sopenharmony_ci{
90141cc406Sopenharmony_ci  regs[0x2f] = (regs[0x2f] & 0x0f) | 0x10;
91141cc406Sopenharmony_ci}
92141cc406Sopenharmony_ci
93141cc406Sopenharmony_civoid
94141cc406Sopenharmony_cisanei_rts88xx_set_offset (SANE_Byte * regs, SANE_Byte red, SANE_Byte green,
95141cc406Sopenharmony_ci                          SANE_Byte blue)
96141cc406Sopenharmony_ci{
97141cc406Sopenharmony_ci  /* offset for odd pixels */
98141cc406Sopenharmony_ci  regs[0x02] = red;
99141cc406Sopenharmony_ci  regs[0x03] = green;
100141cc406Sopenharmony_ci  regs[0x04] = blue;
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci  /* offset for even pixels */
103141cc406Sopenharmony_ci  regs[0x05] = red;
104141cc406Sopenharmony_ci  regs[0x06] = green;
105141cc406Sopenharmony_ci  regs[0x07] = blue;
106141cc406Sopenharmony_ci}
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_civoid
109141cc406Sopenharmony_cisanei_rts88xx_set_gain (SANE_Byte * regs, SANE_Byte red, SANE_Byte green,
110141cc406Sopenharmony_ci                        SANE_Byte blue)
111141cc406Sopenharmony_ci{
112141cc406Sopenharmony_ci  regs[0x08] = red;
113141cc406Sopenharmony_ci  regs[0x09] = green;
114141cc406Sopenharmony_ci  regs[0x0a] = blue;
115141cc406Sopenharmony_ci}
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_civoid
118141cc406Sopenharmony_cisanei_rts88xx_set_scan_frequency (SANE_Byte * regs, int frequency)
119141cc406Sopenharmony_ci{
120141cc406Sopenharmony_ci  regs[0x64] = (regs[0x64] & 0xf0) | (frequency & 0x0f);
121141cc406Sopenharmony_ci}
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci/*
124141cc406Sopenharmony_ci * read one register at given index
125141cc406Sopenharmony_ci */
126141cc406Sopenharmony_ciSANE_Status
127141cc406Sopenharmony_cisanei_rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg)
128141cc406Sopenharmony_ci{
129141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
130141cc406Sopenharmony_ci  unsigned char cmd[] = { 0x80, 0x00, 0x00, 0x01 };
131141cc406Sopenharmony_ci  size_t size;
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci  cmd[1] = index;
134141cc406Sopenharmony_ci
135141cc406Sopenharmony_ci  size = 4;
136141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, cmd, &size);
137141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
138141cc406Sopenharmony_ci    {
139141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_read_reg: bulk write failed\n");
140141cc406Sopenharmony_ci      return status;
141141cc406Sopenharmony_ci    }
142141cc406Sopenharmony_ci  size = 1;
143141cc406Sopenharmony_ci  status = sanei_usb_read_bulk (devnum, reg, &size);
144141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
145141cc406Sopenharmony_ci    {
146141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_read_reg: bulk read failed\n");
147141cc406Sopenharmony_ci      return status;
148141cc406Sopenharmony_ci    }
149141cc406Sopenharmony_ci  DBG (DBG_io2, "sanei_rts88xx_read_reg: reg[0x%02x]=0x%02x\n", index, *reg);
150141cc406Sopenharmony_ci  return status;
151141cc406Sopenharmony_ci}
152141cc406Sopenharmony_ci
153141cc406Sopenharmony_ci/*
154141cc406Sopenharmony_ci * write one register at given index
155141cc406Sopenharmony_ci */
156141cc406Sopenharmony_ciSANE_Status
157141cc406Sopenharmony_cisanei_rts88xx_write_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg)
158141cc406Sopenharmony_ci{
159141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
160141cc406Sopenharmony_ci  unsigned char cmd[] = { 0x88, 0x00, 0x00, 0x01, 0xff };
161141cc406Sopenharmony_ci  size_t size;
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci  cmd[1] = index;
164141cc406Sopenharmony_ci  cmd[4] = *reg;
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci  size = 5;
167141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, cmd, &size);
168141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
169141cc406Sopenharmony_ci    {
170141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_write_reg: bulk write failed\n");
171141cc406Sopenharmony_ci      return status;
172141cc406Sopenharmony_ci    }
173141cc406Sopenharmony_ci  DBG (DBG_io2, "sanei_rts88xx_write_reg: reg[0x%02x]=0x%02x\n", index, *reg);
174141cc406Sopenharmony_ci  return status;
175141cc406Sopenharmony_ci}
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci/*
178141cc406Sopenharmony_ci * write length consecutive registers, starting at index
179141cc406Sopenharmony_ci * register 0xb3 is never wrote in bulk register write, so we split
180141cc406Sopenharmony_ci * write if it belongs to the register set sent
181141cc406Sopenharmony_ci */
182141cc406Sopenharmony_ciSANE_Status
183141cc406Sopenharmony_cisanei_rts88xx_write_regs (SANE_Int devnum, SANE_Int start,
184141cc406Sopenharmony_ci                          SANE_Byte * source, SANE_Int length)
185141cc406Sopenharmony_ci{
186141cc406Sopenharmony_ci  size_t size = 0;
187141cc406Sopenharmony_ci  size_t i;
188141cc406Sopenharmony_ci  SANE_Byte buffer[260];
189141cc406Sopenharmony_ci  char message[256 * 5];
190141cc406Sopenharmony_ci
191141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io)
192141cc406Sopenharmony_ci    {
193141cc406Sopenharmony_ci      for (i = 0; i < (size_t) length; i++)
194141cc406Sopenharmony_ci        {
195141cc406Sopenharmony_ci          sprintf (message + 5 * i, "0x%02x ", source[i]);
196141cc406Sopenharmony_ci        }
197141cc406Sopenharmony_ci      DBG (DBG_io, "sanei_rts88xx_write_regs : write_regs(0x%02x,%d)=%s\n",
198141cc406Sopenharmony_ci           start, length, message);
199141cc406Sopenharmony_ci    }
200141cc406Sopenharmony_ci
201141cc406Sopenharmony_ci  /* when writing several registers at a time, we avoid writing the 0xb3 register
202141cc406Sopenharmony_ci   * which is used to control the status of the scanner */
203141cc406Sopenharmony_ci  if ((start + length > 0xb3) && (length > 1))
204141cc406Sopenharmony_ci    {
205141cc406Sopenharmony_ci      size = 0xb3 - start;
206141cc406Sopenharmony_ci      buffer[0] = 0x88;
207141cc406Sopenharmony_ci      buffer[1] = start;
208141cc406Sopenharmony_ci      buffer[2] = 0x00;
209141cc406Sopenharmony_ci      buffer[3] = size;
210141cc406Sopenharmony_ci      for (i = 0; i < size; i++)
211141cc406Sopenharmony_ci        buffer[i + 4] = source[i];
212141cc406Sopenharmony_ci      /* the USB block is size + 4 bytes of header long */
213141cc406Sopenharmony_ci      size += 4;
214141cc406Sopenharmony_ci      if (sanei_usb_write_bulk (devnum, buffer, &size) != SANE_STATUS_GOOD)
215141cc406Sopenharmony_ci        {
216141cc406Sopenharmony_ci          DBG (DBG_error,
217141cc406Sopenharmony_ci               "sanei_rts88xx_write_regs : write registers part 1 failed ...\n");
218141cc406Sopenharmony_ci          return SANE_STATUS_IO_ERROR;
219141cc406Sopenharmony_ci        }
220141cc406Sopenharmony_ci
221141cc406Sopenharmony_ci      /* skip 0xb3 register */
222141cc406Sopenharmony_ci      size -= 3;
223141cc406Sopenharmony_ci      start = 0xb4;
224141cc406Sopenharmony_ci      source = source + size;
225141cc406Sopenharmony_ci    }
226141cc406Sopenharmony_ci  size = length - size;
227141cc406Sopenharmony_ci  buffer[0] = 0x88;
228141cc406Sopenharmony_ci  buffer[1] = start;
229141cc406Sopenharmony_ci  buffer[2] = 0x00;
230141cc406Sopenharmony_ci  buffer[3] = size;
231141cc406Sopenharmony_ci  for (i = 0; i < size; i++)
232141cc406Sopenharmony_ci    buffer[i + 4] = source[i];
233141cc406Sopenharmony_ci  /* the USB block is size + 4 bytes of header long */
234141cc406Sopenharmony_ci  size += 4;
235141cc406Sopenharmony_ci  if (sanei_usb_write_bulk (devnum, buffer, &size) != SANE_STATUS_GOOD)
236141cc406Sopenharmony_ci    {
237141cc406Sopenharmony_ci      DBG (DBG_error,
238141cc406Sopenharmony_ci           "sanei_rts88xx_write_regs : write registers part 2 failed ...\n");
239141cc406Sopenharmony_ci      return SANE_STATUS_IO_ERROR;
240141cc406Sopenharmony_ci    }
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
243141cc406Sopenharmony_ci
244141cc406Sopenharmony_ci}
245141cc406Sopenharmony_ci
246141cc406Sopenharmony_ci/* read several registers starting at the given index */
247141cc406Sopenharmony_ciSANE_Status
248141cc406Sopenharmony_cisanei_rts88xx_read_regs (SANE_Int devnum, SANE_Int start,
249141cc406Sopenharmony_ci                         SANE_Byte * dest, SANE_Int length)
250141cc406Sopenharmony_ci{
251141cc406Sopenharmony_ci  SANE_Status status;
252141cc406Sopenharmony_ci  static SANE_Byte command_block[] = { 0x80, 0, 0x00, 0xFF };
253141cc406Sopenharmony_ci  size_t size, i;
254141cc406Sopenharmony_ci  char message[256 * 5];
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci  if (start + length > 255)
257141cc406Sopenharmony_ci    {
258141cc406Sopenharmony_ci      DBG (DBG_error,
259141cc406Sopenharmony_ci           "sanei_rts88xx_read_regs: start and length must be within [0..255]\n");
260141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
261141cc406Sopenharmony_ci    }
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci  /* write header */
264141cc406Sopenharmony_ci  size = 4;
265141cc406Sopenharmony_ci  command_block[1] = start;
266141cc406Sopenharmony_ci  command_block[3] = length;
267141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, command_block, &size);
268141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
269141cc406Sopenharmony_ci    {
270141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_read_regs: failed to write header\n");
271141cc406Sopenharmony_ci      return status;
272141cc406Sopenharmony_ci    }
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci  /* read data */
275141cc406Sopenharmony_ci  size = length;
276141cc406Sopenharmony_ci  status = sanei_usb_read_bulk (devnum, dest, &size);
277141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
278141cc406Sopenharmony_ci    {
279141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_read_regs: failed to read data\n");
280141cc406Sopenharmony_ci      return status;
281141cc406Sopenharmony_ci    }
282141cc406Sopenharmony_ci  if (size != (size_t) length)
283141cc406Sopenharmony_ci    {
284141cc406Sopenharmony_ci      DBG (DBG_warn, "sanei_rts88xx_read_regs: read got only %lu bytes\n",
285141cc406Sopenharmony_ci           (u_long) size);
286141cc406Sopenharmony_ci    }
287141cc406Sopenharmony_ci  if (DBG_LEVEL >= DBG_io)
288141cc406Sopenharmony_ci    {
289141cc406Sopenharmony_ci      for (i = 0; i < size; i++)
290141cc406Sopenharmony_ci        sprintf (message + 5 * i, "0x%02x ", dest[i]);
291141cc406Sopenharmony_ci      DBG (DBG_io, "sanei_rts88xx_read_regs: read_regs(0x%02x,%d)=%s\n",
292141cc406Sopenharmony_ci           start, length, message);
293141cc406Sopenharmony_ci    }
294141cc406Sopenharmony_ci  return status;
295141cc406Sopenharmony_ci}
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci/*
298141cc406Sopenharmony_ci * get status by reading registers 0x10 and 0x11
299141cc406Sopenharmony_ci */
300141cc406Sopenharmony_ciSANE_Status
301141cc406Sopenharmony_cisanei_rts88xx_get_status (SANE_Int devnum, SANE_Byte * regs)
302141cc406Sopenharmony_ci{
303141cc406Sopenharmony_ci  SANE_Status status;
304141cc406Sopenharmony_ci  status = sanei_rts88xx_read_regs (devnum, 0x10, regs + 0x10, 2);
305141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_get_status: get_status()=0x%02x 0x%02x\n",
306141cc406Sopenharmony_ci       regs[0x10], regs[0x11]);
307141cc406Sopenharmony_ci  return status;
308141cc406Sopenharmony_ci}
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_ci/*
311141cc406Sopenharmony_ci * set status by writing registers 0x10 and 0x11
312141cc406Sopenharmony_ci */
313141cc406Sopenharmony_ciSANE_Status
314141cc406Sopenharmony_cisanei_rts88xx_set_status (SANE_Int devnum, SANE_Byte * regs,
315141cc406Sopenharmony_ci                          SANE_Byte reg10, SANE_Byte reg11)
316141cc406Sopenharmony_ci{
317141cc406Sopenharmony_ci  SANE_Status status;
318141cc406Sopenharmony_ci
319141cc406Sopenharmony_ci  regs[0x10] = reg10;
320141cc406Sopenharmony_ci  regs[0x11] = reg11;
321141cc406Sopenharmony_ci  status = sanei_rts88xx_write_regs (devnum, 0x10, regs + 0x10, 2);
322141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_set_status: 0x%02x 0x%02x\n", regs[0x10],
323141cc406Sopenharmony_ci       regs[0x11]);
324141cc406Sopenharmony_ci  return status;
325141cc406Sopenharmony_ci}
326141cc406Sopenharmony_ci
327141cc406Sopenharmony_ci/*
328141cc406Sopenharmony_ci * get lamp status by reading registers 0x84 to 0x8f, only 0x8F is currently useful
329141cc406Sopenharmony_ci * 0x84 and following could "on" timers
330141cc406Sopenharmony_ci */
331141cc406Sopenharmony_ciSANE_Status
332141cc406Sopenharmony_cisanei_rts88xx_get_lamp_status (SANE_Int devnum, SANE_Byte * regs)
333141cc406Sopenharmony_ci{
334141cc406Sopenharmony_ci  SANE_Status status;
335141cc406Sopenharmony_ci  status = sanei_rts88xx_read_regs (devnum, 0x84, regs + 0x84, 11);
336141cc406Sopenharmony_ci  return status;
337141cc406Sopenharmony_ci}
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci/* resets lamp */
340141cc406Sopenharmony_ciSANE_Status
341141cc406Sopenharmony_cisanei_rts88xx_reset_lamp (SANE_Int devnum, SANE_Byte * regs)
342141cc406Sopenharmony_ci{
343141cc406Sopenharmony_ci  SANE_Status status;
344141cc406Sopenharmony_ci  SANE_Byte reg;
345141cc406Sopenharmony_ci
346141cc406Sopenharmony_ci  /* read the 0xda register, then clear lower nibble and write it back */
347141cc406Sopenharmony_ci  status = sanei_rts88xx_read_reg (devnum, 0xda, &reg);
348141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
349141cc406Sopenharmony_ci    {
350141cc406Sopenharmony_ci      DBG (DBG_error,
351141cc406Sopenharmony_ci           "sanei_rts88xx_reset_lamp: failed to read 0xda register\n");
352141cc406Sopenharmony_ci      return status;
353141cc406Sopenharmony_ci    }
354141cc406Sopenharmony_ci  reg = 0xa0;
355141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (devnum, 0xda, &reg);
356141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
357141cc406Sopenharmony_ci    {
358141cc406Sopenharmony_ci      DBG (DBG_error,
359141cc406Sopenharmony_ci           "sanei_rts88xx_reset_lamp: failed to write 0xda register\n");
360141cc406Sopenharmony_ci      return status;
361141cc406Sopenharmony_ci    }
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci  /* on cleared, get status */
364141cc406Sopenharmony_ci  status = sanei_rts88xx_get_status (devnum, regs);
365141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
366141cc406Sopenharmony_ci    {
367141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_reset_lamp: failed to get status\n");
368141cc406Sopenharmony_ci      return status;
369141cc406Sopenharmony_ci    }
370141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_reset_lamp: status=0x%02x 0x%02x\n", regs[0x10],
371141cc406Sopenharmony_ci       regs[0x11]);
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci  /* set low nibble to 7 and write it */
374141cc406Sopenharmony_ci  reg = reg | 0x07;
375141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (devnum, 0xda, &reg);
376141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
377141cc406Sopenharmony_ci    {
378141cc406Sopenharmony_ci      DBG (DBG_error,
379141cc406Sopenharmony_ci           "sanei_rts88xx_reset_lamp: failed to write 0xda register\n");
380141cc406Sopenharmony_ci      return status;
381141cc406Sopenharmony_ci    }
382141cc406Sopenharmony_ci  status = sanei_rts88xx_read_reg (devnum, 0xda, &reg);
383141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
384141cc406Sopenharmony_ci    {
385141cc406Sopenharmony_ci      DBG (DBG_error,
386141cc406Sopenharmony_ci           "sanei_rts88xx_reset_lamp: failed to read 0xda register\n");
387141cc406Sopenharmony_ci      return status;
388141cc406Sopenharmony_ci    }
389141cc406Sopenharmony_ci  if (reg != 0xa7)
390141cc406Sopenharmony_ci    {
391141cc406Sopenharmony_ci      DBG (DBG_warn,
392141cc406Sopenharmony_ci           "sanei_rts88xx_reset_lamp: expected reg[0xda]=0xa7, got 0x%02x\n",
393141cc406Sopenharmony_ci           reg);
394141cc406Sopenharmony_ci    }
395141cc406Sopenharmony_ci
396141cc406Sopenharmony_ci  /* store read value in shadow register */
397141cc406Sopenharmony_ci  regs[0xda] = reg;
398141cc406Sopenharmony_ci
399141cc406Sopenharmony_ci  return status;
400141cc406Sopenharmony_ci}
401141cc406Sopenharmony_ci
402141cc406Sopenharmony_ci/*
403141cc406Sopenharmony_ci * get lcd status by reading registers 0x20, 0x21 and 0x22
404141cc406Sopenharmony_ci */
405141cc406Sopenharmony_ciSANE_Status
406141cc406Sopenharmony_cisanei_rts88xx_get_lcd (SANE_Int devnum, SANE_Byte * regs)
407141cc406Sopenharmony_ci{
408141cc406Sopenharmony_ci  SANE_Status status;
409141cc406Sopenharmony_ci  status = sanei_rts88xx_read_regs (devnum, 0x20, regs + 0x20, 3);
410141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_get_lcd: 0x%02x 0x%02x 0x%02x\n", regs[0x20],
411141cc406Sopenharmony_ci       regs[0x21], regs[0x22]);
412141cc406Sopenharmony_ci  return status;
413141cc406Sopenharmony_ci}
414141cc406Sopenharmony_ci
415141cc406Sopenharmony_ci/*
416141cc406Sopenharmony_ci * write to special control register CONTROL_REG=0xb3
417141cc406Sopenharmony_ci */
418141cc406Sopenharmony_ciSANE_Status
419141cc406Sopenharmony_cisanei_rts88xx_write_control (SANE_Int devnum, SANE_Byte value)
420141cc406Sopenharmony_ci{
421141cc406Sopenharmony_ci  SANE_Status status;
422141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (devnum, CONTROL_REG, &value);
423141cc406Sopenharmony_ci  return status;
424141cc406Sopenharmony_ci}
425141cc406Sopenharmony_ci
426141cc406Sopenharmony_ci/*
427141cc406Sopenharmony_ci * send the cancel control sequence
428141cc406Sopenharmony_ci */
429141cc406Sopenharmony_ciSANE_Status
430141cc406Sopenharmony_cisanei_rts88xx_cancel (SANE_Int devnum)
431141cc406Sopenharmony_ci{
432141cc406Sopenharmony_ci  SANE_Status status;
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci  status = sanei_rts88xx_write_control (devnum, 0x02);
435141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
436141cc406Sopenharmony_ci    return status;
437141cc406Sopenharmony_ci  status = sanei_rts88xx_write_control (devnum, 0x02);
438141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
439141cc406Sopenharmony_ci    return status;
440141cc406Sopenharmony_ci  status = sanei_rts88xx_write_control (devnum, 0x00);
441141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
442141cc406Sopenharmony_ci    return status;
443141cc406Sopenharmony_ci  status = sanei_rts88xx_write_control (devnum, 0x00);
444141cc406Sopenharmony_ci  return status;
445141cc406Sopenharmony_ci}
446141cc406Sopenharmony_ci
447141cc406Sopenharmony_ci/*
448141cc406Sopenharmony_ci * write the given number of bytes pointed by value into memory
449141cc406Sopenharmony_ci * length is payload length
450141cc406Sopenharmony_ci * extra is number of bytes to add to the usb write length
451141cc406Sopenharmony_ci */
452141cc406Sopenharmony_ciSANE_Status
453141cc406Sopenharmony_cisanei_rts88xx_write_mem (SANE_Int devnum, SANE_Int length, SANE_Int extra,
454141cc406Sopenharmony_ci                         SANE_Byte * value)
455141cc406Sopenharmony_ci{
456141cc406Sopenharmony_ci  SANE_Status status;
457141cc406Sopenharmony_ci  SANE_Byte *buffer;
458141cc406Sopenharmony_ci  size_t i, size;
459141cc406Sopenharmony_ci  char message[(0xFFC0 + 10) * 3] = "";
460141cc406Sopenharmony_ci
461141cc406Sopenharmony_ci  buffer = (SANE_Byte *) malloc (length + 10);
462141cc406Sopenharmony_ci  if (buffer == NULL)
463141cc406Sopenharmony_ci    return SANE_STATUS_NO_MEM;
464141cc406Sopenharmony_ci  memset (buffer, 0, length + 10);
465141cc406Sopenharmony_ci
466141cc406Sopenharmony_ci  buffer[0] = 0x89;
467141cc406Sopenharmony_ci  buffer[1] = 0x00;
468141cc406Sopenharmony_ci  buffer[2] = HIBYTE (length);
469141cc406Sopenharmony_ci  buffer[3] = LOBYTE (length);
470141cc406Sopenharmony_ci  for (i = 0; i < (size_t) length; i++)
471141cc406Sopenharmony_ci    {
472141cc406Sopenharmony_ci      buffer[i + 4] = value[i];
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci      if (DBG_LEVEL > DBG_io2)
475141cc406Sopenharmony_ci        {
476141cc406Sopenharmony_ci          sprintf (message + 3 * i, "%02x ", buffer[i + 4]);
477141cc406Sopenharmony_ci        }
478141cc406Sopenharmony_ci    }
479141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_write_mem: %02x %02x %02x %02x -> %s\n",
480141cc406Sopenharmony_ci       buffer[0], buffer[1], buffer[2], buffer[3], message);
481141cc406Sopenharmony_ci
482141cc406Sopenharmony_ci  size = length + 4 + extra;
483141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, buffer, &size);
484141cc406Sopenharmony_ci  free (buffer);
485141cc406Sopenharmony_ci  if ((status == SANE_STATUS_GOOD) && (size != (size_t) length + 4 + extra))
486141cc406Sopenharmony_ci    {
487141cc406Sopenharmony_ci      DBG (DBG_error,
488141cc406Sopenharmony_ci           "sanei_rts88xx_write_mem: only wrote %lu bytes out of %d\n",
489141cc406Sopenharmony_ci           (u_long) size, length + 4);
490141cc406Sopenharmony_ci      status = SANE_STATUS_IO_ERROR;
491141cc406Sopenharmony_ci    }
492141cc406Sopenharmony_ci  return status;
493141cc406Sopenharmony_ci}
494141cc406Sopenharmony_ci
495141cc406Sopenharmony_ci/*
496141cc406Sopenharmony_ci * set memory with the given data
497141cc406Sopenharmony_ci */
498141cc406Sopenharmony_ciSANE_Status
499141cc406Sopenharmony_cisanei_rts88xx_set_mem (SANE_Int devnum, SANE_Byte ctrl1,
500141cc406Sopenharmony_ci                       SANE_Byte ctrl2, SANE_Int length, SANE_Byte * value)
501141cc406Sopenharmony_ci{
502141cc406Sopenharmony_ci  SANE_Status status;
503141cc406Sopenharmony_ci  SANE_Byte regs[2];
504141cc406Sopenharmony_ci  regs[0] = ctrl1;
505141cc406Sopenharmony_ci  regs[1] = ctrl2;
506141cc406Sopenharmony_ci
507141cc406Sopenharmony_ci  status = sanei_rts88xx_write_regs (devnum, 0x91, regs, 2);
508141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
509141cc406Sopenharmony_ci    {
510141cc406Sopenharmony_ci      DBG (DBG_error,
511141cc406Sopenharmony_ci           "sanei_rts88xx_set_mem: failed to write 0x91/0x92 registers\n");
512141cc406Sopenharmony_ci      return status;
513141cc406Sopenharmony_ci    }
514141cc406Sopenharmony_ci  status = sanei_rts88xx_write_mem (devnum, length, 0, value);
515141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
516141cc406Sopenharmony_ci    {
517141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_set_mem: failed to write memory\n");
518141cc406Sopenharmony_ci    }
519141cc406Sopenharmony_ci  return status;
520141cc406Sopenharmony_ci}
521141cc406Sopenharmony_ci
522141cc406Sopenharmony_ci/*
523141cc406Sopenharmony_ci * read length bytes of memory into area pointed by value
524141cc406Sopenharmony_ci */
525141cc406Sopenharmony_ciSANE_Status
526141cc406Sopenharmony_cisanei_rts88xx_read_mem (SANE_Int devnum, SANE_Int length, SANE_Byte * value)
527141cc406Sopenharmony_ci{
528141cc406Sopenharmony_ci  SANE_Status status;
529141cc406Sopenharmony_ci  size_t size, read, want;
530141cc406Sopenharmony_ci  SANE_Byte header[4];
531141cc406Sopenharmony_ci
532141cc406Sopenharmony_ci  /* build and write length header */
533141cc406Sopenharmony_ci  header[0] = 0x81;
534141cc406Sopenharmony_ci  header[1] = 0x00;
535141cc406Sopenharmony_ci  header[2] = HIBYTE (length);
536141cc406Sopenharmony_ci  header[3] = LOBYTE (length);
537141cc406Sopenharmony_ci  size = 4;
538141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, header, &size);
539141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
540141cc406Sopenharmony_ci    {
541141cc406Sopenharmony_ci      DBG (DBG_error,
542141cc406Sopenharmony_ci           "sanei_rts88xx_read_mem: failed to write length header\n");
543141cc406Sopenharmony_ci      return status;
544141cc406Sopenharmony_ci    }
545141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_read_mem: %02x %02x %02x %02x -> ...\n",
546141cc406Sopenharmony_ci       header[0], header[1], header[2], header[3]);
547141cc406Sopenharmony_ci  read = 0;
548141cc406Sopenharmony_ci  while (length > 0)
549141cc406Sopenharmony_ci    {
550141cc406Sopenharmony_ci      if (length > 2048)
551141cc406Sopenharmony_ci        want = 2048;
552141cc406Sopenharmony_ci      else
553141cc406Sopenharmony_ci        want = length;
554141cc406Sopenharmony_ci      size = want;
555141cc406Sopenharmony_ci      status = sanei_usb_read_bulk (devnum, value + read, &size);
556141cc406Sopenharmony_ci      if (size != want)
557141cc406Sopenharmony_ci        {
558141cc406Sopenharmony_ci          DBG (DBG_error,
559141cc406Sopenharmony_ci               "sanei_rts88xx_read_mem: only read %lu bytes out of %lu\n",
560141cc406Sopenharmony_ci               (u_long) size, (u_long) want);
561141cc406Sopenharmony_ci          status = SANE_STATUS_IO_ERROR;
562141cc406Sopenharmony_ci        }
563141cc406Sopenharmony_ci      length -= size;
564141cc406Sopenharmony_ci      read += size;
565141cc406Sopenharmony_ci    }
566141cc406Sopenharmony_ci  return status;
567141cc406Sopenharmony_ci}
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci/*
570141cc406Sopenharmony_ci * set memory with the given data
571141cc406Sopenharmony_ci */
572141cc406Sopenharmony_ciSANE_Status
573141cc406Sopenharmony_cisanei_rts88xx_get_mem (SANE_Int devnum, SANE_Byte ctrl1,
574141cc406Sopenharmony_ci                       SANE_Byte ctrl2, SANE_Int length, SANE_Byte * value)
575141cc406Sopenharmony_ci{
576141cc406Sopenharmony_ci  SANE_Status status;
577141cc406Sopenharmony_ci  SANE_Byte regs[2];
578141cc406Sopenharmony_ci  regs[0] = ctrl1;
579141cc406Sopenharmony_ci  regs[1] = ctrl2;
580141cc406Sopenharmony_ci
581141cc406Sopenharmony_ci  status = sanei_rts88xx_write_regs (devnum, 0x91, regs, 2);
582141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
583141cc406Sopenharmony_ci    {
584141cc406Sopenharmony_ci      DBG (DBG_error,
585141cc406Sopenharmony_ci           "sanei_rts88xx_get_mem: failed to write 0x91/0x92 registers\n");
586141cc406Sopenharmony_ci      return status;
587141cc406Sopenharmony_ci    }
588141cc406Sopenharmony_ci  status = sanei_rts88xx_read_mem (devnum, length, value);
589141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
590141cc406Sopenharmony_ci    {
591141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_get_mem: failed to read memory\n");
592141cc406Sopenharmony_ci    }
593141cc406Sopenharmony_ci  return status;
594141cc406Sopenharmony_ci}
595141cc406Sopenharmony_ci
596141cc406Sopenharmony_ci/*
597141cc406Sopenharmony_ci * write to the nvram controller
598141cc406Sopenharmony_ci */
599141cc406Sopenharmony_ciSANE_Status
600141cc406Sopenharmony_cisanei_rts88xx_nvram_ctrl (SANE_Int devnum, SANE_Int length, SANE_Byte * value)
601141cc406Sopenharmony_ci{
602141cc406Sopenharmony_ci  SANE_Status status;
603141cc406Sopenharmony_ci  SANE_Int i;
604141cc406Sopenharmony_ci  char message[60 * 5];
605141cc406Sopenharmony_ci#ifdef HAZARDOUS_EXPERIMENT
606141cc406Sopenharmony_ci  SANE_Int size = 0;
607141cc406Sopenharmony_ci  SANE_Byte buffer[60];
608141cc406Sopenharmony_ci#endif
609141cc406Sopenharmony_ci
610141cc406Sopenharmony_ci  if (DBG_LEVEL > DBG_io)
611141cc406Sopenharmony_ci    {
612141cc406Sopenharmony_ci      for (i = 0; i < length; i++)
613141cc406Sopenharmony_ci        {
614141cc406Sopenharmony_ci          sprintf (message + 5 * i, "0x%02x ", value[i]);
615141cc406Sopenharmony_ci        }
616141cc406Sopenharmony_ci      DBG (DBG_io, "sanei_rts88xx_nvram_ctrl : devnum=%d, nvram_ctrl(0x00,%d)=%s\n",
617141cc406Sopenharmony_ci	   devnum, length, message);
618141cc406Sopenharmony_ci    }
619141cc406Sopenharmony_ci
620141cc406Sopenharmony_ci#ifdef HAZARDOUS_EXPERIMENT
621141cc406Sopenharmony_ci  buffer[0] = 0x8a;
622141cc406Sopenharmony_ci  buffer[1] = 0x00;
623141cc406Sopenharmony_ci  buffer[2] = 0x00;
624141cc406Sopenharmony_ci  buffer[3] = length;
625141cc406Sopenharmony_ci  for (i = 0; i < size; i++)
626141cc406Sopenharmony_ci    buffer[i + 4] = value[i];
627141cc406Sopenharmony_ci  /* the USB block is size + 4 bytes of header long */
628141cc406Sopenharmony_ci  size = length + 4;
629141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, buffer, &size);
630141cc406Sopenharmony_ci#else
631141cc406Sopenharmony_ci  status = SANE_STATUS_GOOD;
632141cc406Sopenharmony_ci#endif
633141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
634141cc406Sopenharmony_ci    {
635141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_nvram_ctrl : write failed ...\n");
636141cc406Sopenharmony_ci    }
637141cc406Sopenharmony_ci  return status;
638141cc406Sopenharmony_ci}
639141cc406Sopenharmony_ci
640141cc406Sopenharmony_ci/*
641141cc406Sopenharmony_ci * setup nvram
642141cc406Sopenharmony_ci */
643141cc406Sopenharmony_ciSANE_Status
644141cc406Sopenharmony_cisanei_rts88xx_setup_nvram (SANE_Int devnum, SANE_Int length,
645141cc406Sopenharmony_ci                           SANE_Byte * value)
646141cc406Sopenharmony_ci{
647141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
648141cc406Sopenharmony_ci  SANE_Byte local[2], reg;
649141cc406Sopenharmony_ci  int i;
650141cc406Sopenharmony_ci
651141cc406Sopenharmony_ci  status = sanei_rts88xx_nvram_ctrl (devnum, length, value);
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci#ifndef HAZARDOUS_EXPERIMENT
654141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
655141cc406Sopenharmony_ci#endif
656141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
657141cc406Sopenharmony_ci    {
658141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_setup_nvram : failed step #1 ...\n");
659141cc406Sopenharmony_ci      return status;
660141cc406Sopenharmony_ci    }
661141cc406Sopenharmony_ci  local[0] = 0x18;
662141cc406Sopenharmony_ci  local[1] = 0x08;
663141cc406Sopenharmony_ci  for (i = 0; i < 8; i++)
664141cc406Sopenharmony_ci    {
665141cc406Sopenharmony_ci      status = sanei_rts88xx_nvram_ctrl (devnum, 2, local);
666141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
667141cc406Sopenharmony_ci        {
668141cc406Sopenharmony_ci          DBG (DBG_error, "sanei_rts88xx_setup_nvram : failed loop #%d ...\n",
669141cc406Sopenharmony_ci               i);
670141cc406Sopenharmony_ci          return status;
671141cc406Sopenharmony_ci        }
672141cc406Sopenharmony_ci      status = sanei_rts88xx_read_reg (devnum, 0x10, &reg);
673141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
674141cc406Sopenharmony_ci        {
675141cc406Sopenharmony_ci          DBG (DBG_error,
676141cc406Sopenharmony_ci               "sanei_rts88xx_setup_nvram : register reading failed loop #%d ...\n",
677141cc406Sopenharmony_ci               i);
678141cc406Sopenharmony_ci          return status;
679141cc406Sopenharmony_ci        }
680141cc406Sopenharmony_ci      DBG (DBG_io, "sanei_rts88xx_setup_nvram: reg[0x10]=0x%02x\n", reg);
681141cc406Sopenharmony_ci    }
682141cc406Sopenharmony_ci  reg = 0;
683141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (devnum, CONTROLER_REG, &reg);
684141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
685141cc406Sopenharmony_ci    {
686141cc406Sopenharmony_ci      DBG (DBG_error,
687141cc406Sopenharmony_ci           "sanei_rts88xx_setup_nvram : controller register write failed\n");
688141cc406Sopenharmony_ci      return status;
689141cc406Sopenharmony_ci    }
690141cc406Sopenharmony_ci  reg = 1;
691141cc406Sopenharmony_ci  status = sanei_rts88xx_write_reg (devnum, CONTROLER_REG, &reg);
692141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
693141cc406Sopenharmony_ci    {
694141cc406Sopenharmony_ci      DBG (DBG_error,
695141cc406Sopenharmony_ci           "sanei_rts88xx_setup_nvram : controller register write failed\n");
696141cc406Sopenharmony_ci      return status;
697141cc406Sopenharmony_ci    }
698141cc406Sopenharmony_ci  return status;
699141cc406Sopenharmony_ci}
700141cc406Sopenharmony_ci
701141cc406Sopenharmony_ci/*
702141cc406Sopenharmony_ci * Sets scan area, no checks are being done, so watch your steps
703141cc406Sopenharmony_ci */
704141cc406Sopenharmony_civoid
705141cc406Sopenharmony_cisanei_rts88xx_set_scan_area (SANE_Byte * regs, SANE_Int ystart,
706141cc406Sopenharmony_ci                             SANE_Int yend, SANE_Int xstart, SANE_Int xend)
707141cc406Sopenharmony_ci{
708141cc406Sopenharmony_ci  /* vertical lines to move before scan */
709141cc406Sopenharmony_ci  regs[START_LINE] = LOBYTE (ystart);
710141cc406Sopenharmony_ci  regs[START_LINE + 1] = HIBYTE (ystart);
711141cc406Sopenharmony_ci
712141cc406Sopenharmony_ci  /* total number of line to move */
713141cc406Sopenharmony_ci  regs[END_LINE] = LOBYTE (yend);
714141cc406Sopenharmony_ci  regs[END_LINE + 1] = HIBYTE (yend);
715141cc406Sopenharmony_ci
716141cc406Sopenharmony_ci  /* set horizontal start position */
717141cc406Sopenharmony_ci  regs[START_PIXEL] = LOBYTE (xstart);
718141cc406Sopenharmony_ci  regs[START_PIXEL + 1] = HIBYTE (xstart);
719141cc406Sopenharmony_ci
720141cc406Sopenharmony_ci  /* set horizontal end position */
721141cc406Sopenharmony_ci  regs[END_PIXEL] = LOBYTE (xend);
722141cc406Sopenharmony_ci  regs[END_PIXEL + 1] = HIBYTE (xend);
723141cc406Sopenharmony_ci}
724141cc406Sopenharmony_ci
725141cc406Sopenharmony_ci/**
726141cc406Sopenharmony_ci * read available data count from scanner
727141cc406Sopenharmony_ci * from tests it appears that advertised data
728141cc406Sopenharmony_ci * may not be really available, and that a pause must be made
729141cc406Sopenharmony_ci * before reading data so that it is really there.
730141cc406Sopenharmony_ci * Such as reading data twice.
731141cc406Sopenharmony_ci */
732141cc406Sopenharmony_ciSANE_Status
733141cc406Sopenharmony_cisanei_rts88xx_data_count (SANE_Int devnum, SANE_Word * count)
734141cc406Sopenharmony_ci{
735141cc406Sopenharmony_ci  SANE_Status status;
736141cc406Sopenharmony_ci  size_t size;
737141cc406Sopenharmony_ci  static SANE_Byte header[4] = { 0x90, 0x00, 0x00, 3 };
738141cc406Sopenharmony_ci  SANE_Byte result[3];
739141cc406Sopenharmony_ci
740141cc406Sopenharmony_ci  /* set count in case of failure */
741141cc406Sopenharmony_ci  *count = 0;
742141cc406Sopenharmony_ci
743141cc406Sopenharmony_ci  size = 4;
744141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, header, &size);
745141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
746141cc406Sopenharmony_ci    {
747141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_data_count : failed to write header\n");
748141cc406Sopenharmony_ci      return status;
749141cc406Sopenharmony_ci    }
750141cc406Sopenharmony_ci  size = 3;
751141cc406Sopenharmony_ci  status = sanei_usb_read_bulk (devnum, result, &size);
752141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
753141cc406Sopenharmony_ci    {
754141cc406Sopenharmony_ci      DBG (DBG_error,
755141cc406Sopenharmony_ci           "sanei_rts88xx_data_count : failed to read data count\n");
756141cc406Sopenharmony_ci      return status;
757141cc406Sopenharmony_ci    }
758141cc406Sopenharmony_ci  *count = result[0] + (result[1] << 8) + (result[2] << 16);
759141cc406Sopenharmony_ci  DBG (DBG_io2, "sanei_rts88xx_data_count: %d bytes available (0x%06x)\n",
760141cc406Sopenharmony_ci       *count, *count);
761141cc406Sopenharmony_ci  return status;
762141cc406Sopenharmony_ci}
763141cc406Sopenharmony_ci
764141cc406Sopenharmony_ci/**
765141cc406Sopenharmony_ci * Waits for data being available while optionally polling motor. There is a timeout
766141cc406Sopenharmony_ci * to prevent scanner waiting forever non coming data.
767141cc406Sopenharmony_ci */
768141cc406Sopenharmony_ciSANE_Status
769141cc406Sopenharmony_cisanei_rts88xx_wait_data (SANE_Int devnum, SANE_Bool busy, SANE_Word * count)
770141cc406Sopenharmony_ci{
771141cc406Sopenharmony_ci  SANE_Status status;
772141cc406Sopenharmony_ci  SANE_Byte control;
773141cc406Sopenharmony_ci
774141cc406Sopenharmony_ci  /* poll the available byte count until not 0 */
775141cc406Sopenharmony_ci  while (SANE_TRUE)
776141cc406Sopenharmony_ci    {
777141cc406Sopenharmony_ci      status = sanei_rts88xx_data_count (devnum, count);
778141cc406Sopenharmony_ci      if (*count != 0)
779141cc406Sopenharmony_ci        {
780141cc406Sopenharmony_ci          DBG (DBG_io, "sanei_rts88xx_wait_data: %d bytes available\n",
781141cc406Sopenharmony_ci               *count);
782141cc406Sopenharmony_ci          return status;
783141cc406Sopenharmony_ci        }
784141cc406Sopenharmony_ci
785141cc406Sopenharmony_ci      /* check that the scanner is busy scanning */
786141cc406Sopenharmony_ci      if (busy)
787141cc406Sopenharmony_ci        {
788141cc406Sopenharmony_ci          sanei_rts88xx_read_reg (devnum, CONTROL_REG, &control);
789141cc406Sopenharmony_ci          if ((control & 0x08) == 0 && (*count == 0))
790141cc406Sopenharmony_ci            {
791141cc406Sopenharmony_ci              DBG (DBG_error,
792141cc406Sopenharmony_ci                   "sanei_rts88xx_wait_data: scanner stopped being busy before data are available\n");
793141cc406Sopenharmony_ci              return SANE_STATUS_IO_ERROR;
794141cc406Sopenharmony_ci            }
795141cc406Sopenharmony_ci        }
796141cc406Sopenharmony_ci    }
797141cc406Sopenharmony_ci
798141cc406Sopenharmony_ci  /* we hit timeout */
799141cc406Sopenharmony_ci  return SANE_STATUS_IO_ERROR;
800141cc406Sopenharmony_ci}
801141cc406Sopenharmony_ci
802141cc406Sopenharmony_ci/*
803141cc406Sopenharmony_ci * read scanned data from scanner up to the size given. The actual length read is returned.
804141cc406Sopenharmony_ci */
805141cc406Sopenharmony_ciSANE_Status
806141cc406Sopenharmony_cisanei_rts88xx_read_data (SANE_Int devnum, SANE_Word * length,
807141cc406Sopenharmony_ci                         unsigned char *dest)
808141cc406Sopenharmony_ci{
809141cc406Sopenharmony_ci  SANE_Status status = SANE_STATUS_GOOD;
810141cc406Sopenharmony_ci  SANE_Byte header[4];
811141cc406Sopenharmony_ci  size_t size, len, remain, read;
812141cc406Sopenharmony_ci
813141cc406Sopenharmony_ci  /* do not read too much data */
814141cc406Sopenharmony_ci  if (*length > RTS88XX_MAX_XFER_SIZE)
815141cc406Sopenharmony_ci    len = RTS88XX_MAX_XFER_SIZE;
816141cc406Sopenharmony_ci  else
817141cc406Sopenharmony_ci    len = *length;
818141cc406Sopenharmony_ci
819141cc406Sopenharmony_ci  /* write command header first */
820141cc406Sopenharmony_ci  header[0] = 0x91;
821141cc406Sopenharmony_ci  header[1] = 0x00;
822141cc406Sopenharmony_ci  header[2] = HIBYTE (len);
823141cc406Sopenharmony_ci  header[3] = LOBYTE (len);
824141cc406Sopenharmony_ci  size = 4;
825141cc406Sopenharmony_ci
826141cc406Sopenharmony_ci  status = sanei_usb_write_bulk (devnum, header, &size);
827141cc406Sopenharmony_ci  if (status != SANE_STATUS_GOOD)
828141cc406Sopenharmony_ci    {
829141cc406Sopenharmony_ci      DBG (DBG_error, "sanei_rts88xx_read_data: failed to write header\n");
830141cc406Sopenharmony_ci    }
831141cc406Sopenharmony_ci  read = 0;
832141cc406Sopenharmony_ci
833141cc406Sopenharmony_ci  /* first read blocks aligned on 64 bytes boundary */
834141cc406Sopenharmony_ci  while (len - read > 64)
835141cc406Sopenharmony_ci    {
836141cc406Sopenharmony_ci      size = (len - read) & 0xFFC0;
837141cc406Sopenharmony_ci      status = sanei_usb_read_bulk (devnum, dest + read, &size);
838141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
839141cc406Sopenharmony_ci        {
840141cc406Sopenharmony_ci          DBG (DBG_error, "sanei_rts88xx_read_data: failed to read data\n");
841141cc406Sopenharmony_ci          return status;
842141cc406Sopenharmony_ci        }
843141cc406Sopenharmony_ci      DBG (DBG_io2, "sanei_rts88xx_read_data: read %lu bytes\n",
844141cc406Sopenharmony_ci           (u_long) size);
845141cc406Sopenharmony_ci      read += size;
846141cc406Sopenharmony_ci    }
847141cc406Sopenharmony_ci
848141cc406Sopenharmony_ci  /* then read remainder */
849141cc406Sopenharmony_ci  remain = len - read;
850141cc406Sopenharmony_ci  if (remain > 0)
851141cc406Sopenharmony_ci    {
852141cc406Sopenharmony_ci      status = sanei_usb_read_bulk (devnum, dest + read, &remain);
853141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
854141cc406Sopenharmony_ci        {
855141cc406Sopenharmony_ci          DBG (DBG_error, "sanei_rts88xx_read_data: failed to read data\n");
856141cc406Sopenharmony_ci          return status;
857141cc406Sopenharmony_ci        }
858141cc406Sopenharmony_ci      DBG (DBG_io2, "sanei_rts88xx_read_data: read %lu bytes\n",
859141cc406Sopenharmony_ci           (u_long) remain);
860141cc406Sopenharmony_ci      read += remain;
861141cc406Sopenharmony_ci    }
862141cc406Sopenharmony_ci
863141cc406Sopenharmony_ci  /* update actual read length */
864141cc406Sopenharmony_ci  DBG (DBG_io, "sanei_rts88xx_read_data: read %lu bytes, %d required\n",
865141cc406Sopenharmony_ci       (u_long) read, *length);
866141cc406Sopenharmony_ci  *length = read;
867141cc406Sopenharmony_ci  return status;
868141cc406Sopenharmony_ci}
869