1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy.
2141cc406Sopenharmony_ci
3141cc406Sopenharmony_ci   Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru>
4141cc406Sopenharmony_ci   Copyright (C) 2005-2007 Henning Geinitz <sane@geinitz.org>
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci   This file is part of the SANE package.
7141cc406Sopenharmony_ci
8141cc406Sopenharmony_ci   This program is free software; you can redistribute it and/or
9141cc406Sopenharmony_ci   modify it under the terms of the GNU General Public License as
10141cc406Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
11141cc406Sopenharmony_ci   License, or (at your option) any later version.
12141cc406Sopenharmony_ci
13141cc406Sopenharmony_ci   This program is distributed in the hope that it will be useful, but
14141cc406Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
15141cc406Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16141cc406Sopenharmony_ci   General Public License for more details.
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci   You should have received a copy of the GNU General Public License
19141cc406Sopenharmony_ci   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20141cc406Sopenharmony_ci
21141cc406Sopenharmony_ci   As a special exception, the authors of SANE give permission for
22141cc406Sopenharmony_ci   additional uses of the libraries contained in this release of SANE.
23141cc406Sopenharmony_ci
24141cc406Sopenharmony_ci   The exception is that, if you link a SANE library with other files
25141cc406Sopenharmony_ci   to produce an executable, this does not by itself cause the
26141cc406Sopenharmony_ci   resulting executable to be covered by the GNU General Public
27141cc406Sopenharmony_ci   License.  Your use of that executable is in no way restricted on
28141cc406Sopenharmony_ci   account of linking the SANE library code into it.
29141cc406Sopenharmony_ci
30141cc406Sopenharmony_ci   This exception does not, however, invalidate any other reasons why
31141cc406Sopenharmony_ci   the executable file might be covered by the GNU General Public
32141cc406Sopenharmony_ci   License.
33141cc406Sopenharmony_ci
34141cc406Sopenharmony_ci   If you submit changes to SANE to the maintainers to be included in
35141cc406Sopenharmony_ci   a subsequent release, you agree by submitting the changes that
36141cc406Sopenharmony_ci   those changes may be distributed with this exception intact.
37141cc406Sopenharmony_ci
38141cc406Sopenharmony_ci   If you write modifications of your own for SANE, it is your choice
39141cc406Sopenharmony_ci   whether to permit this exception to apply to your modifications.
40141cc406Sopenharmony_ci   If you do not wish that, delete this exception notice.
41141cc406Sopenharmony_ci*/
42141cc406Sopenharmony_ci
43141cc406Sopenharmony_ci/** @file
44141cc406Sopenharmony_ci * @brief GT68xx commands common for most GT68xx-based scanners.
45141cc406Sopenharmony_ci */
46141cc406Sopenharmony_ci
47141cc406Sopenharmony_ci#include "gt68xx_generic.h"
48141cc406Sopenharmony_ci
49141cc406Sopenharmony_ci
50141cc406Sopenharmony_ciSANE_Status
51141cc406Sopenharmony_cigt68xx_generic_move_relative (GT68xx_Device * dev, SANE_Int distance)
52141cc406Sopenharmony_ci{
53141cc406Sopenharmony_ci  GT68xx_Packet req;
54141cc406Sopenharmony_ci
55141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
56141cc406Sopenharmony_ci  if (distance >= 0)
57141cc406Sopenharmony_ci    req[0] = 0x14;
58141cc406Sopenharmony_ci  else
59141cc406Sopenharmony_ci    {
60141cc406Sopenharmony_ci      req[0] = 0x15;
61141cc406Sopenharmony_ci      distance = -distance;
62141cc406Sopenharmony_ci    }
63141cc406Sopenharmony_ci  req[1] = 0x01;
64141cc406Sopenharmony_ci  req[2] = LOBYTE (distance);
65141cc406Sopenharmony_ci  req[3] = HIBYTE (distance);
66141cc406Sopenharmony_ci
67141cc406Sopenharmony_ci  return gt68xx_device_req (dev, req, req);
68141cc406Sopenharmony_ci}
69141cc406Sopenharmony_ci
70141cc406Sopenharmony_ciSANE_Status
71141cc406Sopenharmony_cigt68xx_generic_start_scan (GT68xx_Device * dev)
72141cc406Sopenharmony_ci{
73141cc406Sopenharmony_ci  GT68xx_Packet req;
74141cc406Sopenharmony_ci  SANE_Status status;
75141cc406Sopenharmony_ci
76141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
77141cc406Sopenharmony_ci  req[0] = 0x43;
78141cc406Sopenharmony_ci  req[1] = 0x01;
79141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
80141cc406Sopenharmony_ci  RIE (gt68xx_device_check_result (req, 0x43));
81141cc406Sopenharmony_ci
82141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
83141cc406Sopenharmony_ci}
84141cc406Sopenharmony_ci
85141cc406Sopenharmony_ciSANE_Status
86141cc406Sopenharmony_cigt68xx_generic_read_scanned_data (GT68xx_Device * dev, SANE_Bool * ready)
87141cc406Sopenharmony_ci{
88141cc406Sopenharmony_ci  SANE_Status status;
89141cc406Sopenharmony_ci  GT68xx_Packet req;
90141cc406Sopenharmony_ci
91141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
92141cc406Sopenharmony_ci  req[0] = 0x35;
93141cc406Sopenharmony_ci  req[1] = 0x01;
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
96141cc406Sopenharmony_ci
97141cc406Sopenharmony_ci  *ready = SANE_FALSE;
98141cc406Sopenharmony_ci  if (req[0] == 0)
99141cc406Sopenharmony_ci    *ready = SANE_TRUE;
100141cc406Sopenharmony_ci
101141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
102141cc406Sopenharmony_ci}
103141cc406Sopenharmony_ci
104141cc406Sopenharmony_cistatic SANE_Byte
105141cc406Sopenharmony_cigt68xx_generic_fix_gain (SANE_Int gain)
106141cc406Sopenharmony_ci{
107141cc406Sopenharmony_ci  if (gain < 0)
108141cc406Sopenharmony_ci    gain = 0;
109141cc406Sopenharmony_ci  else if (gain > 31)
110141cc406Sopenharmony_ci    gain += 12;
111141cc406Sopenharmony_ci  else if (gain > 51)
112141cc406Sopenharmony_ci    gain = 63;
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci  return gain;
115141cc406Sopenharmony_ci}
116141cc406Sopenharmony_ci
117141cc406Sopenharmony_cistatic SANE_Byte
118141cc406Sopenharmony_cigt68xx_generic_fix_offset (SANE_Int offset)
119141cc406Sopenharmony_ci{
120141cc406Sopenharmony_ci  if (offset < 0)
121141cc406Sopenharmony_ci    offset = 0;
122141cc406Sopenharmony_ci  else if (offset > 63)
123141cc406Sopenharmony_ci    offset = 63;
124141cc406Sopenharmony_ci  return offset;
125141cc406Sopenharmony_ci}
126141cc406Sopenharmony_ci
127141cc406Sopenharmony_ciSANE_Status
128141cc406Sopenharmony_cigt68xx_generic_set_afe (GT68xx_Device * dev, GT68xx_AFE_Parameters * params)
129141cc406Sopenharmony_ci{
130141cc406Sopenharmony_ci  GT68xx_Packet req;
131141cc406Sopenharmony_ci
132141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
133141cc406Sopenharmony_ci  req[0] = 0x22;
134141cc406Sopenharmony_ci  req[1] = 0x01;
135141cc406Sopenharmony_ci  req[2] = gt68xx_generic_fix_offset (params->r_offset);
136141cc406Sopenharmony_ci  req[3] = gt68xx_generic_fix_gain (params->r_pga);
137141cc406Sopenharmony_ci  req[4] = gt68xx_generic_fix_offset (params->g_offset);
138141cc406Sopenharmony_ci  req[5] = gt68xx_generic_fix_gain (params->g_pga);
139141cc406Sopenharmony_ci  req[6] = gt68xx_generic_fix_offset (params->b_offset);
140141cc406Sopenharmony_ci  req[7] = gt68xx_generic_fix_gain (params->b_pga);
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci  DBG (6,
143141cc406Sopenharmony_ci       "gt68xx_generic_set_afe: real AFE: 0x%02x 0x%02x  0x%02x 0x%02x  0x%02x 0x%02x\n",
144141cc406Sopenharmony_ci       req[2], req[3], req[4], req[5], req[6], req[7]);
145141cc406Sopenharmony_ci  return gt68xx_device_req (dev, req, req);
146141cc406Sopenharmony_ci}
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ciSANE_Status
149141cc406Sopenharmony_cigt68xx_generic_set_exposure_time (GT68xx_Device * dev,
150141cc406Sopenharmony_ci				  GT68xx_Exposure_Parameters * params)
151141cc406Sopenharmony_ci{
152141cc406Sopenharmony_ci  GT68xx_Packet req;
153141cc406Sopenharmony_ci  SANE_Status status;
154141cc406Sopenharmony_ci
155141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
156141cc406Sopenharmony_ci  req[0] = 0x76;
157141cc406Sopenharmony_ci  req[1] = 0x01;
158141cc406Sopenharmony_ci  req[2] = req[6] = req[10] = 0x04;
159141cc406Sopenharmony_ci  req[4] = LOBYTE (params->r_time);
160141cc406Sopenharmony_ci  req[5] = HIBYTE (params->r_time);
161141cc406Sopenharmony_ci  req[8] = LOBYTE (params->g_time);
162141cc406Sopenharmony_ci  req[9] = HIBYTE (params->g_time);
163141cc406Sopenharmony_ci  req[12] = LOBYTE (params->b_time);
164141cc406Sopenharmony_ci  req[13] = HIBYTE (params->b_time);
165141cc406Sopenharmony_ci
166141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_set_exposure_time: 0x%03x 0x%03x 0x%03x\n",
167141cc406Sopenharmony_ci       params->r_time, params->g_time, params->b_time);
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
170141cc406Sopenharmony_ci  RIE (gt68xx_device_check_result (req, 0x76));
171141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
172141cc406Sopenharmony_ci}
173141cc406Sopenharmony_ci
174141cc406Sopenharmony_ciSANE_Status
175141cc406Sopenharmony_cigt68xx_generic_get_id (GT68xx_Device * dev)
176141cc406Sopenharmony_ci{
177141cc406Sopenharmony_ci  GT68xx_Packet req;
178141cc406Sopenharmony_ci  SANE_Status status;
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
181141cc406Sopenharmony_ci  req[0] = 0x2e;
182141cc406Sopenharmony_ci  req[1] = 0x01;
183141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
184141cc406Sopenharmony_ci  RIE (gt68xx_device_check_result (req, 0x2e));
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci  DBG (2,
187141cc406Sopenharmony_ci       "get_id: vendor id=0x%04X, product id=0x%04X, DID=0x%08X, FID=0x%04X\n",
188141cc406Sopenharmony_ci       req[2] + (req[3] << 8), req[4] + (req[5] << 8),
189141cc406Sopenharmony_ci       req[6] + (req[7] << 8) + (req[8] << 16) + (req[9] << 24),
190141cc406Sopenharmony_ci       req[10] + (req[11] << 8));
191141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
192141cc406Sopenharmony_ci}
193141cc406Sopenharmony_ci
194141cc406Sopenharmony_ciSANE_Status
195141cc406Sopenharmony_cigt68xx_generic_paperfeed (GT68xx_Device * dev)
196141cc406Sopenharmony_ci{
197141cc406Sopenharmony_ci  GT68xx_Packet req;
198141cc406Sopenharmony_ci  SANE_Status status;
199141cc406Sopenharmony_ci
200141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
201141cc406Sopenharmony_ci  req[0] = 0x83;
202141cc406Sopenharmony_ci  req[1] = 0x01;
203141cc406Sopenharmony_ci
204141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
205141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
206141cc406Sopenharmony_ci}
207141cc406Sopenharmony_ci
208141cc406Sopenharmony_ci#define MAX_PIXEL_MODE 15600
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ciSANE_Status
211141cc406Sopenharmony_cigt68xx_generic_setup_scan (GT68xx_Device * dev,
212141cc406Sopenharmony_ci			   GT68xx_Scan_Request * request,
213141cc406Sopenharmony_ci			   GT68xx_Scan_Action action,
214141cc406Sopenharmony_ci			   GT68xx_Scan_Parameters * params)
215141cc406Sopenharmony_ci{
216141cc406Sopenharmony_ci  SANE_Status status;
217141cc406Sopenharmony_ci  GT68xx_Model *model;
218141cc406Sopenharmony_ci  SANE_Int xdpi, ydpi;
219141cc406Sopenharmony_ci  SANE_Bool color;
220141cc406Sopenharmony_ci  SANE_Int depth;
221141cc406Sopenharmony_ci  SANE_Int pixel_x0, pixel_y0, pixel_xs, pixel_ys;
222141cc406Sopenharmony_ci  SANE_Int pixel_align;
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci  SANE_Int abs_x0, abs_y0, abs_xs, abs_ys, base_xdpi, base_ydpi;
225141cc406Sopenharmony_ci  SANE_Int scan_xs, scan_ys, scan_bpl;
226141cc406Sopenharmony_ci  SANE_Int bits_per_line;
227141cc406Sopenharmony_ci  SANE_Byte color_mode_code;
228141cc406Sopenharmony_ci  SANE_Bool line_mode;
229141cc406Sopenharmony_ci  SANE_Int overscan_lines;
230141cc406Sopenharmony_ci  SANE_Fixed x0, y0, xs, ys;
231141cc406Sopenharmony_ci  SANE_Bool backtrack = SANE_FALSE;
232141cc406Sopenharmony_ci
233141cc406Sopenharmony_ci  DBG (6, "gt6816_setup_scan: enter (action=%s)\n",
234141cc406Sopenharmony_ci       action == SA_CALIBRATE ? "calibrate" :
235141cc406Sopenharmony_ci       action == SA_CALIBRATE_ONE_LINE ? "calibrate one line" :
236141cc406Sopenharmony_ci       action == SA_SCAN ? "scan" : "calculate only");
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci  model = dev->model;
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci  xdpi = request->xdpi;
241141cc406Sopenharmony_ci  ydpi = request->ydpi;
242141cc406Sopenharmony_ci  color = request->color;
243141cc406Sopenharmony_ci  depth = request->depth;
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci  base_xdpi = model->base_xdpi;
246141cc406Sopenharmony_ci  base_ydpi = model->base_ydpi;
247141cc406Sopenharmony_ci
248141cc406Sopenharmony_ci  if (xdpi > model->base_xdpi)
249141cc406Sopenharmony_ci    base_xdpi = model->optical_xdpi;
250141cc406Sopenharmony_ci
251141cc406Sopenharmony_ci  /* Special fixes */
252141cc406Sopenharmony_ci  if ((dev->model->flags & GT68XX_FLAG_USE_OPTICAL_X) && xdpi <= 50)
253141cc406Sopenharmony_ci    base_xdpi = model->optical_xdpi;
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci  if ((dev->model->flags & GT68XX_FLAG_SCAN_FROM_HOME) &&
256141cc406Sopenharmony_ci      !request->use_ta && action == SA_SCAN)
257141cc406Sopenharmony_ci    request->mbs = SANE_TRUE;
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci  if (!model->constant_ydpi)
260141cc406Sopenharmony_ci    {
261141cc406Sopenharmony_ci      if (ydpi > model->base_ydpi)
262141cc406Sopenharmony_ci	base_ydpi = model->optical_ydpi;
263141cc406Sopenharmony_ci    }
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: base_xdpi=%d, base_ydpi=%d\n",
266141cc406Sopenharmony_ci       base_xdpi, base_ydpi);
267141cc406Sopenharmony_ci
268141cc406Sopenharmony_ci  switch (action)
269141cc406Sopenharmony_ci    {
270141cc406Sopenharmony_ci    case SA_CALIBRATE_ONE_LINE:
271141cc406Sopenharmony_ci      {
272141cc406Sopenharmony_ci	x0 = request->x0;
273141cc406Sopenharmony_ci	if (request->use_ta)
274141cc406Sopenharmony_ci	  y0 = model->y_offset_calib_ta;
275141cc406Sopenharmony_ci	else
276141cc406Sopenharmony_ci	  y0 = model->y_offset_calib;
277141cc406Sopenharmony_ci	ys = SANE_FIX (1.0 * MM_PER_INCH / ydpi);	/* one line */
278141cc406Sopenharmony_ci	xs = request->xs;
279141cc406Sopenharmony_ci	depth = 8;
280141cc406Sopenharmony_ci	break;
281141cc406Sopenharmony_ci      }
282141cc406Sopenharmony_ci    case SA_CALIBRATE:
283141cc406Sopenharmony_ci      {
284141cc406Sopenharmony_ci	if (request->use_ta)
285141cc406Sopenharmony_ci	  {
286141cc406Sopenharmony_ci	    if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
287141cc406Sopenharmony_ci	      x0 = request->x0 - model->x_offset_ta;
288141cc406Sopenharmony_ci	    else
289141cc406Sopenharmony_ci	      x0 = request->x0 + model->x_offset_ta;
290141cc406Sopenharmony_ci	    if (request->mbs)
291141cc406Sopenharmony_ci	      y0 = model->y_offset_calib_ta;
292141cc406Sopenharmony_ci	    else
293141cc406Sopenharmony_ci	      y0 = 0;
294141cc406Sopenharmony_ci	  }
295141cc406Sopenharmony_ci	else
296141cc406Sopenharmony_ci	  {
297141cc406Sopenharmony_ci	    if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
298141cc406Sopenharmony_ci	      x0 = request->x0 - model->x_offset;
299141cc406Sopenharmony_ci	    else
300141cc406Sopenharmony_ci	      x0 = request->x0 + model->x_offset;
301141cc406Sopenharmony_ci	    if (request->mbs)
302141cc406Sopenharmony_ci	      y0 = model->y_offset_calib;
303141cc406Sopenharmony_ci	    else
304141cc406Sopenharmony_ci	      y0 = 0;
305141cc406Sopenharmony_ci	  }
306141cc406Sopenharmony_ci	ys = SANE_FIX (CALIBRATION_HEIGHT);
307141cc406Sopenharmony_ci	xs = request->xs;
308141cc406Sopenharmony_ci	break;
309141cc406Sopenharmony_ci      }
310141cc406Sopenharmony_ci    case SA_SCAN:
311141cc406Sopenharmony_ci      {
312141cc406Sopenharmony_ci	SANE_Fixed x_offset, y_offset;
313141cc406Sopenharmony_ci
314141cc406Sopenharmony_ci	if (strcmp (dev->model->command_set->name, "mustek-gt6816") != 0)
315141cc406Sopenharmony_ci	  request->mbs = SANE_TRUE;	/* always go home for gt6801 scanners */
316141cc406Sopenharmony_ci	if (request->use_ta)
317141cc406Sopenharmony_ci	  {
318141cc406Sopenharmony_ci	    x_offset = model->x_offset_ta;
319141cc406Sopenharmony_ci	    if (request->mbs)
320141cc406Sopenharmony_ci	      y_offset = model->y_offset_ta;
321141cc406Sopenharmony_ci	    else
322141cc406Sopenharmony_ci	      {
323141cc406Sopenharmony_ci		y_offset = model->y_offset_ta - model->y_offset_calib_ta
324141cc406Sopenharmony_ci		  - SANE_FIX (CALIBRATION_HEIGHT);
325141cc406Sopenharmony_ci		if ((request->y0 + y_offset) < 0)
326141cc406Sopenharmony_ci		  {
327141cc406Sopenharmony_ci		    y_offset = model->y_offset_ta;
328141cc406Sopenharmony_ci		    request->mbs = SANE_TRUE;
329141cc406Sopenharmony_ci		  }
330141cc406Sopenharmony_ci	      }
331141cc406Sopenharmony_ci
332141cc406Sopenharmony_ci	  }
333141cc406Sopenharmony_ci	else
334141cc406Sopenharmony_ci	  {
335141cc406Sopenharmony_ci	    x_offset = model->x_offset;
336141cc406Sopenharmony_ci	    if (request->mbs)
337141cc406Sopenharmony_ci	      y_offset = model->y_offset;
338141cc406Sopenharmony_ci	    else
339141cc406Sopenharmony_ci	      {
340141cc406Sopenharmony_ci		y_offset = model->y_offset - model->y_offset_calib
341141cc406Sopenharmony_ci		  - SANE_FIX (CALIBRATION_HEIGHT);
342141cc406Sopenharmony_ci		if ((request->y0 + y_offset) < 0)
343141cc406Sopenharmony_ci		  {
344141cc406Sopenharmony_ci		    y_offset = model->y_offset;
345141cc406Sopenharmony_ci		    request->mbs = SANE_TRUE;
346141cc406Sopenharmony_ci		  }
347141cc406Sopenharmony_ci	      }
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci	  }
350141cc406Sopenharmony_ci	if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
351141cc406Sopenharmony_ci	  x0 = request->x0 - x_offset;
352141cc406Sopenharmony_ci	else
353141cc406Sopenharmony_ci	  x0 = request->x0 + x_offset;
354141cc406Sopenharmony_ci	y0 = request->y0 + y_offset;
355141cc406Sopenharmony_ci	if (y0 < 0)
356141cc406Sopenharmony_ci	  y0 = 0;
357141cc406Sopenharmony_ci	ys = request->ys;
358141cc406Sopenharmony_ci	xs = request->xs;
359141cc406Sopenharmony_ci	backtrack = request->backtrack;
360141cc406Sopenharmony_ci	break;
361141cc406Sopenharmony_ci      }
362141cc406Sopenharmony_ci
363141cc406Sopenharmony_ci    default:
364141cc406Sopenharmony_ci      DBG (1, "gt68xx_generic_setup_scan: invalid action=%d\n", (int) action);
365141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
366141cc406Sopenharmony_ci    }
367141cc406Sopenharmony_ci
368141cc406Sopenharmony_ci  pixel_x0 = SANE_UNFIX (x0) * xdpi / MM_PER_INCH + 0.5;
369141cc406Sopenharmony_ci  pixel_y0 = SANE_UNFIX (y0) * ydpi / MM_PER_INCH + 0.5;
370141cc406Sopenharmony_ci  pixel_ys = SANE_UNFIX (ys) * ydpi / MM_PER_INCH + 0.5;
371141cc406Sopenharmony_ci  pixel_xs = SANE_UNFIX (xs) * xdpi / MM_PER_INCH + 0.5;
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci
374141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: xdpi=%d, ydpi=%d\n", xdpi, ydpi);
375141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: color=%s, depth=%d\n",
376141cc406Sopenharmony_ci       color ? "TRUE" : "FALSE", depth);
377141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: pixel_x0=%d, pixel_y0=%d\n",
378141cc406Sopenharmony_ci       pixel_x0, pixel_y0);
379141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: pixel_xs=%d, pixel_ys=%d\n",
380141cc406Sopenharmony_ci       pixel_xs, pixel_ys);
381141cc406Sopenharmony_ci
382141cc406Sopenharmony_ci
383141cc406Sopenharmony_ci  color_mode_code = 0x80;
384141cc406Sopenharmony_ci  if (color)
385141cc406Sopenharmony_ci    color_mode_code |= (1 << 2);
386141cc406Sopenharmony_ci  else
387141cc406Sopenharmony_ci    color_mode_code |= dev->gray_mode_color;
388141cc406Sopenharmony_ci
389141cc406Sopenharmony_ci  if (depth > 12)
390141cc406Sopenharmony_ci    color_mode_code |= (1 << 5);
391141cc406Sopenharmony_ci  else if (depth > 8)
392141cc406Sopenharmony_ci    {
393141cc406Sopenharmony_ci      color_mode_code &= 0x7f;
394141cc406Sopenharmony_ci      color_mode_code |= (1 << 4);
395141cc406Sopenharmony_ci    }
396141cc406Sopenharmony_ci
397141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: color_mode_code = 0x%02X\n",
398141cc406Sopenharmony_ci       color_mode_code);
399141cc406Sopenharmony_ci
400141cc406Sopenharmony_ci  overscan_lines = 0;
401141cc406Sopenharmony_ci  params->ld_shift_r = params->ld_shift_g = params->ld_shift_b = 0;
402141cc406Sopenharmony_ci  params->ld_shift_double = 0;
403141cc406Sopenharmony_ci
404141cc406Sopenharmony_ci  /* Line distance correction is required for color scans. */
405141cc406Sopenharmony_ci  if (action == SA_SCAN && color)
406141cc406Sopenharmony_ci    {
407141cc406Sopenharmony_ci      SANE_Int optical_ydpi = model->optical_ydpi;
408141cc406Sopenharmony_ci      SANE_Int ld_shift_r = model->ld_shift_r;
409141cc406Sopenharmony_ci      SANE_Int ld_shift_g = model->ld_shift_g;
410141cc406Sopenharmony_ci      SANE_Int ld_shift_b = model->ld_shift_b;
411141cc406Sopenharmony_ci      SANE_Int max_ld = MAX (MAX (ld_shift_r, ld_shift_g), ld_shift_b);
412141cc406Sopenharmony_ci
413141cc406Sopenharmony_ci      overscan_lines = max_ld * ydpi / optical_ydpi;
414141cc406Sopenharmony_ci      params->ld_shift_r = ld_shift_r * ydpi / optical_ydpi;
415141cc406Sopenharmony_ci      params->ld_shift_g = ld_shift_g * ydpi / optical_ydpi;
416141cc406Sopenharmony_ci      params->ld_shift_b = ld_shift_b * ydpi / optical_ydpi;
417141cc406Sopenharmony_ci      params->ld_shift_double = 0;
418141cc406Sopenharmony_ci      DBG (6, "gt68xx_generic_setup_scan: overscan=%d, ld=%d/%d/%d\n",
419141cc406Sopenharmony_ci	   overscan_lines, params->ld_shift_r, params->ld_shift_g,
420141cc406Sopenharmony_ci	   params->ld_shift_b);
421141cc406Sopenharmony_ci    }
422141cc406Sopenharmony_ci
423141cc406Sopenharmony_ci  /* Used for CCD scanners with 6 instead of 3 CCD lines */
424141cc406Sopenharmony_ci  if (action == SA_SCAN && xdpi >= model->optical_xdpi
425141cc406Sopenharmony_ci      && model->ld_shift_double > 0)
426141cc406Sopenharmony_ci    {
427141cc406Sopenharmony_ci      params->ld_shift_double =
428141cc406Sopenharmony_ci	model->ld_shift_double * ydpi / model->optical_ydpi;
429141cc406Sopenharmony_ci      if (color)
430141cc406Sopenharmony_ci	overscan_lines += (params->ld_shift_double * 3);
431141cc406Sopenharmony_ci      else
432141cc406Sopenharmony_ci	overscan_lines += params->ld_shift_double;
433141cc406Sopenharmony_ci
434141cc406Sopenharmony_ci      DBG (6, "gt68xx_generic_setup_scan: overscan=%d, ld double=%d\n",
435141cc406Sopenharmony_ci	   overscan_lines, params->ld_shift_double);
436141cc406Sopenharmony_ci    }
437141cc406Sopenharmony_ci
438141cc406Sopenharmony_ci  abs_x0 = pixel_x0 * base_xdpi / xdpi;
439141cc406Sopenharmony_ci  abs_y0 = pixel_y0 * base_ydpi / ydpi;
440141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: abs_x0=%d, abs_y0=%d\n", abs_x0,
441141cc406Sopenharmony_ci       abs_y0);
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci  params->double_column = abs_x0 & 1;
444141cc406Sopenharmony_ci
445141cc406Sopenharmony_ci  /* Calculate minimum number of pixels which span an integral multiple of 64
446141cc406Sopenharmony_ci   * bytes. */
447141cc406Sopenharmony_ci  pixel_align = 32;		/* best case for depth = 16 */
448141cc406Sopenharmony_ci  while ((depth * pixel_align) % (64 * 8) != 0)
449141cc406Sopenharmony_ci    pixel_align *= 2;
450141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: pixel_align=%d\n", pixel_align);
451141cc406Sopenharmony_ci
452141cc406Sopenharmony_ci  if (pixel_xs % pixel_align == 0)
453141cc406Sopenharmony_ci    scan_xs = pixel_xs;
454141cc406Sopenharmony_ci  else
455141cc406Sopenharmony_ci    scan_xs = (pixel_xs / pixel_align + 1) * pixel_align;
456141cc406Sopenharmony_ci  scan_ys = pixel_ys + overscan_lines;
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_ci  if ((xdpi != base_xdpi)
459141cc406Sopenharmony_ci      && (strcmp (dev->model->command_set->name, "mustek-gt6816") != 0))
460141cc406Sopenharmony_ci    abs_xs = (scan_xs - 1) * base_xdpi / xdpi;	/* gt6801 */
461141cc406Sopenharmony_ci  else
462141cc406Sopenharmony_ci    abs_xs = scan_xs * base_xdpi / xdpi;	/* gt6816 */
463141cc406Sopenharmony_ci
464141cc406Sopenharmony_ci  if (action == SA_CALIBRATE_ONE_LINE)
465141cc406Sopenharmony_ci    abs_ys = 2;
466141cc406Sopenharmony_ci  else
467141cc406Sopenharmony_ci    abs_ys = scan_ys * base_ydpi / ydpi;
468141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: abs_xs=%d, abs_ys=%d\n", abs_xs,
469141cc406Sopenharmony_ci       abs_ys);
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci  if (model->flags & GT68XX_FLAG_NO_LINEMODE)
472141cc406Sopenharmony_ci    {
473141cc406Sopenharmony_ci      line_mode = SANE_FALSE;
474141cc406Sopenharmony_ci      DBG (6,
475141cc406Sopenharmony_ci	   "gt68xx_generic_setup_scan: using pixel mode (GT68XX_FLAG_NO_LINEMODE)\n");
476141cc406Sopenharmony_ci    }
477141cc406Sopenharmony_ci  else if (model->is_cis && !(model->flags & GT68XX_FLAG_CIS_LAMP))
478141cc406Sopenharmony_ci    {
479141cc406Sopenharmony_ci      line_mode = SANE_TRUE;
480141cc406Sopenharmony_ci      DBG (6, "gt68xx_generic_setup_scan: using line mode (CIS)\n");
481141cc406Sopenharmony_ci    }
482141cc406Sopenharmony_ci  else if (model->flags & GT68XX_FLAG_ALWAYS_LINEMODE)
483141cc406Sopenharmony_ci    {
484141cc406Sopenharmony_ci      line_mode = SANE_TRUE;
485141cc406Sopenharmony_ci      DBG (6,
486141cc406Sopenharmony_ci	   "gt68xx_generic_setup_scan: using line mode (GT68XX_FLAG_ALWAYS_LINEMODE)\n");
487141cc406Sopenharmony_ci    }
488141cc406Sopenharmony_ci  else
489141cc406Sopenharmony_ci    {
490141cc406Sopenharmony_ci      SANE_Int max_bpl = xdpi * 3 * depth *
491141cc406Sopenharmony_ci	(SANE_UNFIX (model->x_size) -
492141cc406Sopenharmony_ci	 SANE_UNFIX (model->x_offset)) / MM_PER_INCH / 8;
493141cc406Sopenharmony_ci
494141cc406Sopenharmony_ci      line_mode = SANE_FALSE;
495141cc406Sopenharmony_ci      if (!color)
496141cc406Sopenharmony_ci	{
497141cc406Sopenharmony_ci	  DBG (6,
498141cc406Sopenharmony_ci	       "gt68xx_generic_setup_scan: using line mode for monochrome scan\n");
499141cc406Sopenharmony_ci	  line_mode = SANE_TRUE;
500141cc406Sopenharmony_ci	}
501141cc406Sopenharmony_ci      else if (max_bpl > MAX_PIXEL_MODE)
502141cc406Sopenharmony_ci	{
503141cc406Sopenharmony_ci	  DBG (6,
504141cc406Sopenharmony_ci	       "gt68xx_generic_setup_scan: max_bpl = %d > %d: forcing line mode\n",
505141cc406Sopenharmony_ci	       max_bpl, MAX_PIXEL_MODE);
506141cc406Sopenharmony_ci	  line_mode = SANE_TRUE;
507141cc406Sopenharmony_ci	}
508141cc406Sopenharmony_ci      else
509141cc406Sopenharmony_ci	DBG (6,
510141cc406Sopenharmony_ci	     "gt68xx_generic_setup_scan: max_bpl = %d <= %d: using pixel mode\n",
511141cc406Sopenharmony_ci	     max_bpl, MAX_PIXEL_MODE);
512141cc406Sopenharmony_ci    }
513141cc406Sopenharmony_ci
514141cc406Sopenharmony_ci  bits_per_line = depth * scan_xs;
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci  if (color && !line_mode)
517141cc406Sopenharmony_ci    bits_per_line *= 3;
518141cc406Sopenharmony_ci
519141cc406Sopenharmony_ci  if (bits_per_line % 8)	/* impossible */
520141cc406Sopenharmony_ci    {
521141cc406Sopenharmony_ci      DBG (0, "gt68xx_generic_setup_scan: BUG: unaligned bits_per_line=%d\n",
522141cc406Sopenharmony_ci	   bits_per_line);
523141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
524141cc406Sopenharmony_ci    }
525141cc406Sopenharmony_ci  scan_bpl = bits_per_line / 8;
526141cc406Sopenharmony_ci
527141cc406Sopenharmony_ci  if (scan_bpl % 64)		/* impossible */
528141cc406Sopenharmony_ci    {
529141cc406Sopenharmony_ci      DBG (0, "gt68xx_generic_setup_scan: BUG: unaligned scan_bpl=%d\n",
530141cc406Sopenharmony_ci	   scan_bpl);
531141cc406Sopenharmony_ci      return SANE_STATUS_INVAL;
532141cc406Sopenharmony_ci    }
533141cc406Sopenharmony_ci
534141cc406Sopenharmony_ci  if (color)
535141cc406Sopenharmony_ci    if (line_mode || dev->model->flags & GT68XX_FLAG_SE_2400)
536141cc406Sopenharmony_ci      scan_ys *= 3;
537141cc406Sopenharmony_ci
538141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: scan_xs=%d, scan_ys=%d\n", scan_xs,
539141cc406Sopenharmony_ci       scan_ys);
540141cc406Sopenharmony_ci
541141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: scan_bpl=%d\n", scan_bpl);
542141cc406Sopenharmony_ci
543141cc406Sopenharmony_ci  if (!request->calculate)
544141cc406Sopenharmony_ci    {
545141cc406Sopenharmony_ci      GT68xx_Packet req;
546141cc406Sopenharmony_ci      SANE_Byte motor_mode_1, motor_mode_2;
547141cc406Sopenharmony_ci
548141cc406Sopenharmony_ci      if (scan_bpl > (16 * 1024))
549141cc406Sopenharmony_ci	{
550141cc406Sopenharmony_ci	  DBG (0, "gt68xx_generic_setup_scan: scan_bpl=%d, too large\n",
551141cc406Sopenharmony_ci	       scan_bpl);
552141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
553141cc406Sopenharmony_ci	}
554141cc406Sopenharmony_ci
555141cc406Sopenharmony_ci      if ((dev->model->flags & GT68XX_FLAG_NO_LINEMODE) && line_mode && color)
556141cc406Sopenharmony_ci	{
557141cc406Sopenharmony_ci	  DBG (0,
558141cc406Sopenharmony_ci	       "gt68xx_generic_setup_scan: the scanner's memory is too small for "
559141cc406Sopenharmony_ci	       "that combination of resolution, dpi and width\n");
560141cc406Sopenharmony_ci	  return SANE_STATUS_NO_MEM;
561141cc406Sopenharmony_ci	}
562141cc406Sopenharmony_ci      DBG (6, "gt68xx_generic_setup_scan: backtrack=%d\n", backtrack);
563141cc406Sopenharmony_ci
564141cc406Sopenharmony_ci      motor_mode_1 = (request->mbs ? 0 : 1) << 1;
565141cc406Sopenharmony_ci      motor_mode_1 |= (request->mds ? 0 : 1) << 2;
566141cc406Sopenharmony_ci      motor_mode_1 |= (request->mas ? 0 : 1) << 0;
567141cc406Sopenharmony_ci      motor_mode_1 |= (backtrack ? 1 : 0) << 3;
568141cc406Sopenharmony_ci
569141cc406Sopenharmony_ci      motor_mode_2 = (request->lamp ? 0 : 1) << 0;
570141cc406Sopenharmony_ci      motor_mode_2 |= (line_mode ? 0 : 1) << 2;
571141cc406Sopenharmony_ci
572141cc406Sopenharmony_ci      if ((action != SA_SCAN)
573141cc406Sopenharmony_ci	  && (strcmp (dev->model->command_set->name, "mustek-gt6816") == 0))
574141cc406Sopenharmony_ci	motor_mode_2 |= 1 << 3;
575141cc406Sopenharmony_ci
576141cc406Sopenharmony_ci      DBG (6,
577141cc406Sopenharmony_ci	   "gt68xx_generic_setup_scan: motor_mode_1 = 0x%02X, motor_mode_2 = 0x%02X\n",
578141cc406Sopenharmony_ci	   motor_mode_1, motor_mode_2);
579141cc406Sopenharmony_ci
580141cc406Sopenharmony_ci      /* Fill in the setup command */
581141cc406Sopenharmony_ci      memset (req, 0, sizeof (req));
582141cc406Sopenharmony_ci      req[0x00] = 0x20;
583141cc406Sopenharmony_ci      req[0x01] = 0x01;
584141cc406Sopenharmony_ci      req[0x02] = LOBYTE (abs_y0);
585141cc406Sopenharmony_ci      req[0x03] = HIBYTE (abs_y0);
586141cc406Sopenharmony_ci      req[0x04] = LOBYTE (abs_ys);
587141cc406Sopenharmony_ci      req[0x05] = HIBYTE (abs_ys);
588141cc406Sopenharmony_ci      req[0x06] = LOBYTE (abs_x0);
589141cc406Sopenharmony_ci      req[0x07] = HIBYTE (abs_x0);
590141cc406Sopenharmony_ci      req[0x08] = LOBYTE (abs_xs);
591141cc406Sopenharmony_ci      req[0x09] = HIBYTE (abs_xs);
592141cc406Sopenharmony_ci      req[0x0a] = color_mode_code;
593141cc406Sopenharmony_ci      if (model->is_cis && !(model->flags & GT68XX_FLAG_CIS_LAMP))
594141cc406Sopenharmony_ci	req[0x0b] = 0x60;
595141cc406Sopenharmony_ci      else
596141cc406Sopenharmony_ci	req[0x0b] = 0x20;
597141cc406Sopenharmony_ci      req[0x0c] = LOBYTE (xdpi);
598141cc406Sopenharmony_ci      req[0x0d] = HIBYTE (xdpi);
599141cc406Sopenharmony_ci      req[0x0e] = 0x12;		/* ??? 0x12 */
600141cc406Sopenharmony_ci      req[0x0f] = 0x00;		/* ??? 0x00 */
601141cc406Sopenharmony_ci      req[0x10] = LOBYTE (scan_bpl);
602141cc406Sopenharmony_ci      req[0x11] = HIBYTE (scan_bpl);
603141cc406Sopenharmony_ci      req[0x12] = LOBYTE (scan_ys);
604141cc406Sopenharmony_ci      req[0x13] = HIBYTE (scan_ys);
605141cc406Sopenharmony_ci      req[0x14] = motor_mode_1;
606141cc406Sopenharmony_ci      req[0x15] = motor_mode_2;
607141cc406Sopenharmony_ci      req[0x16] = LOBYTE (ydpi);
608141cc406Sopenharmony_ci      req[0x17] = HIBYTE (ydpi);
609141cc406Sopenharmony_ci      if (backtrack)
610141cc406Sopenharmony_ci	req[0x18] = request->backtrack_lines;
611141cc406Sopenharmony_ci      else
612141cc406Sopenharmony_ci	req[0x18] = 0x00;
613141cc406Sopenharmony_ci
614141cc406Sopenharmony_ci      status = gt68xx_device_req (dev, req, req);
615141cc406Sopenharmony_ci      if (status != SANE_STATUS_GOOD)
616141cc406Sopenharmony_ci	{
617141cc406Sopenharmony_ci	  DBG (3, "gt68xx_generic_setup_scan: setup request failed: %s\n",
618141cc406Sopenharmony_ci	       sane_strstatus (status));
619141cc406Sopenharmony_ci	  return status;
620141cc406Sopenharmony_ci	}
621141cc406Sopenharmony_ci      RIE (gt68xx_device_check_result (req, 0x20));
622141cc406Sopenharmony_ci    }
623141cc406Sopenharmony_ci
624141cc406Sopenharmony_ci  /* Fill in calculated values */
625141cc406Sopenharmony_ci  params->xdpi = xdpi;
626141cc406Sopenharmony_ci  params->ydpi = ydpi;
627141cc406Sopenharmony_ci  params->depth = depth;
628141cc406Sopenharmony_ci  params->color = color;
629141cc406Sopenharmony_ci  params->pixel_xs = pixel_xs;
630141cc406Sopenharmony_ci  params->pixel_ys = pixel_ys;
631141cc406Sopenharmony_ci  params->scan_xs = scan_xs;
632141cc406Sopenharmony_ci  params->scan_ys = scan_ys;
633141cc406Sopenharmony_ci  params->scan_bpl = scan_bpl;
634141cc406Sopenharmony_ci  params->line_mode = line_mode;
635141cc406Sopenharmony_ci  params->overscan_lines = overscan_lines;
636141cc406Sopenharmony_ci  params->pixel_x0 = pixel_x0;
637141cc406Sopenharmony_ci
638141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_setup_scan: leave: ok\n");
639141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
640141cc406Sopenharmony_ci}
641141cc406Sopenharmony_ci
642141cc406Sopenharmony_ciSANE_Status
643141cc406Sopenharmony_cigt68xx_generic_move_paper (GT68xx_Device * dev,
644141cc406Sopenharmony_ci			   GT68xx_Scan_Request * request)
645141cc406Sopenharmony_ci{
646141cc406Sopenharmony_ci  GT68xx_Packet req;
647141cc406Sopenharmony_ci  SANE_Status status;
648141cc406Sopenharmony_ci  SANE_Int ydpi;
649141cc406Sopenharmony_ci  SANE_Int pixel_y0;
650141cc406Sopenharmony_ci  SANE_Int abs_y0, base_ydpi;
651141cc406Sopenharmony_ci  GT68xx_Model *model = dev->model;
652141cc406Sopenharmony_ci
653141cc406Sopenharmony_ci  ydpi = request->ydpi;
654141cc406Sopenharmony_ci  base_ydpi = model->base_ydpi;
655141cc406Sopenharmony_ci
656141cc406Sopenharmony_ci  if (ydpi > model->base_ydpi)
657141cc406Sopenharmony_ci    ydpi = base_ydpi;
658141cc406Sopenharmony_ci
659141cc406Sopenharmony_ci  pixel_y0 =
660141cc406Sopenharmony_ci    SANE_UNFIX ((request->y0 + model->y_offset)) * ydpi / MM_PER_INCH + 0.5;
661141cc406Sopenharmony_ci  abs_y0 = pixel_y0 * base_ydpi / ydpi;
662141cc406Sopenharmony_ci
663141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_move_paper: base_ydpi=%d\n", base_ydpi);
664141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_move_paper: ydpi=%d\n", ydpi);
665141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_move_paper: abs_y0=%d\n", abs_y0);
666141cc406Sopenharmony_ci
667141cc406Sopenharmony_ci  /* paper move request */
668141cc406Sopenharmony_ci  memset (req, 0, sizeof (req));
669141cc406Sopenharmony_ci  req[0] = 0x82;
670141cc406Sopenharmony_ci  req[1] = 0x01;
671141cc406Sopenharmony_ci  req[2] = LOBYTE (abs_y0);
672141cc406Sopenharmony_ci  req[3] = HIBYTE (abs_y0);
673141cc406Sopenharmony_ci  RIE (gt68xx_device_req (dev, req, req));
674141cc406Sopenharmony_ci
675141cc406Sopenharmony_ci  DBG (6, "gt68xx_generic_move_paper: leave: ok\n");
676141cc406Sopenharmony_ci  return SANE_STATUS_GOOD;
677141cc406Sopenharmony_ci}
678