• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2 
3    Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru>
4    Copyright (C) 2005-2007 Henning Geinitz <sane@geinitz.org>
5 
6    This file is part of the SANE package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 
21    As a special exception, the authors of SANE give permission for
22    additional uses of the libraries contained in this release of SANE.
23 
24    The exception is that, if you link a SANE library with other files
25    to produce an executable, this does not by itself cause the
26    resulting executable to be covered by the GNU General Public
27    License.  Your use of that executable is in no way restricted on
28    account of linking the SANE library code into it.
29 
30    This exception does not, however, invalidate any other reasons why
31    the executable file might be covered by the GNU General Public
32    License.
33 
34    If you submit changes to SANE to the maintainers to be included in
35    a subsequent release, you agree by submitting the changes that
36    those changes may be distributed with this exception intact.
37 
38    If you write modifications of your own for SANE, it is your choice
39    whether to permit this exception to apply to your modifications.
40    If you do not wish that, delete this exception notice.
41 */
42 
43 /** @file
44  * @brief GT68xx commands common for most GT68xx-based scanners.
45  */
46 
47 #include "gt68xx_generic.h"
48 
49 
50 SANE_Status
gt68xx_generic_move_relative(GT68xx_Device * dev,SANE_Int distance)51 gt68xx_generic_move_relative (GT68xx_Device * dev, SANE_Int distance)
52 {
53   GT68xx_Packet req;
54 
55   memset (req, 0, sizeof (req));
56   if (distance >= 0)
57     req[0] = 0x14;
58   else
59     {
60       req[0] = 0x15;
61       distance = -distance;
62     }
63   req[1] = 0x01;
64   req[2] = LOBYTE (distance);
65   req[3] = HIBYTE (distance);
66 
67   return gt68xx_device_req (dev, req, req);
68 }
69 
70 SANE_Status
gt68xx_generic_start_scan(GT68xx_Device * dev)71 gt68xx_generic_start_scan (GT68xx_Device * dev)
72 {
73   GT68xx_Packet req;
74   SANE_Status status;
75 
76   memset (req, 0, sizeof (req));
77   req[0] = 0x43;
78   req[1] = 0x01;
79   RIE (gt68xx_device_req (dev, req, req));
80   RIE (gt68xx_device_check_result (req, 0x43));
81 
82   return SANE_STATUS_GOOD;
83 }
84 
85 SANE_Status
gt68xx_generic_read_scanned_data(GT68xx_Device * dev,SANE_Bool * ready)86 gt68xx_generic_read_scanned_data (GT68xx_Device * dev, SANE_Bool * ready)
87 {
88   SANE_Status status;
89   GT68xx_Packet req;
90 
91   memset (req, 0, sizeof (req));
92   req[0] = 0x35;
93   req[1] = 0x01;
94 
95   RIE (gt68xx_device_req (dev, req, req));
96 
97   *ready = SANE_FALSE;
98   if (req[0] == 0)
99     *ready = SANE_TRUE;
100 
101   return SANE_STATUS_GOOD;
102 }
103 
104 static SANE_Byte
gt68xx_generic_fix_gain(SANE_Int gain)105 gt68xx_generic_fix_gain (SANE_Int gain)
106 {
107   if (gain < 0)
108     gain = 0;
109   else if (gain > 31)
110     gain += 12;
111   else if (gain > 51)
112     gain = 63;
113 
114   return gain;
115 }
116 
117 static SANE_Byte
gt68xx_generic_fix_offset(SANE_Int offset)118 gt68xx_generic_fix_offset (SANE_Int offset)
119 {
120   if (offset < 0)
121     offset = 0;
122   else if (offset > 63)
123     offset = 63;
124   return offset;
125 }
126 
127 SANE_Status
gt68xx_generic_set_afe(GT68xx_Device * dev,GT68xx_AFE_Parameters * params)128 gt68xx_generic_set_afe (GT68xx_Device * dev, GT68xx_AFE_Parameters * params)
129 {
130   GT68xx_Packet req;
131 
132   memset (req, 0, sizeof (req));
133   req[0] = 0x22;
134   req[1] = 0x01;
135   req[2] = gt68xx_generic_fix_offset (params->r_offset);
136   req[3] = gt68xx_generic_fix_gain (params->r_pga);
137   req[4] = gt68xx_generic_fix_offset (params->g_offset);
138   req[5] = gt68xx_generic_fix_gain (params->g_pga);
139   req[6] = gt68xx_generic_fix_offset (params->b_offset);
140   req[7] = gt68xx_generic_fix_gain (params->b_pga);
141 
142   DBG (6,
143        "gt68xx_generic_set_afe: real AFE: 0x%02x 0x%02x  0x%02x 0x%02x  0x%02x 0x%02x\n",
144        req[2], req[3], req[4], req[5], req[6], req[7]);
145   return gt68xx_device_req (dev, req, req);
146 }
147 
148 SANE_Status
gt68xx_generic_set_exposure_time(GT68xx_Device * dev,GT68xx_Exposure_Parameters * params)149 gt68xx_generic_set_exposure_time (GT68xx_Device * dev,
150 				  GT68xx_Exposure_Parameters * params)
151 {
152   GT68xx_Packet req;
153   SANE_Status status;
154 
155   memset (req, 0, sizeof (req));
156   req[0] = 0x76;
157   req[1] = 0x01;
158   req[2] = req[6] = req[10] = 0x04;
159   req[4] = LOBYTE (params->r_time);
160   req[5] = HIBYTE (params->r_time);
161   req[8] = LOBYTE (params->g_time);
162   req[9] = HIBYTE (params->g_time);
163   req[12] = LOBYTE (params->b_time);
164   req[13] = HIBYTE (params->b_time);
165 
166   DBG (6, "gt68xx_generic_set_exposure_time: 0x%03x 0x%03x 0x%03x\n",
167        params->r_time, params->g_time, params->b_time);
168 
169   RIE (gt68xx_device_req (dev, req, req));
170   RIE (gt68xx_device_check_result (req, 0x76));
171   return SANE_STATUS_GOOD;
172 }
173 
174 SANE_Status
gt68xx_generic_get_id(GT68xx_Device * dev)175 gt68xx_generic_get_id (GT68xx_Device * dev)
176 {
177   GT68xx_Packet req;
178   SANE_Status status;
179 
180   memset (req, 0, sizeof (req));
181   req[0] = 0x2e;
182   req[1] = 0x01;
183   RIE (gt68xx_device_req (dev, req, req));
184   RIE (gt68xx_device_check_result (req, 0x2e));
185 
186   DBG (2,
187        "get_id: vendor id=0x%04X, product id=0x%04X, DID=0x%08X, FID=0x%04X\n",
188        req[2] + (req[3] << 8), req[4] + (req[5] << 8),
189        req[6] + (req[7] << 8) + (req[8] << 16) + (req[9] << 24),
190        req[10] + (req[11] << 8));
191   return SANE_STATUS_GOOD;
192 }
193 
194 SANE_Status
gt68xx_generic_paperfeed(GT68xx_Device * dev)195 gt68xx_generic_paperfeed (GT68xx_Device * dev)
196 {
197   GT68xx_Packet req;
198   SANE_Status status;
199 
200   memset (req, 0, sizeof (req));
201   req[0] = 0x83;
202   req[1] = 0x01;
203 
204   RIE (gt68xx_device_req (dev, req, req));
205   return SANE_STATUS_GOOD;
206 }
207 
208 #define MAX_PIXEL_MODE 15600
209 
210 SANE_Status
gt68xx_generic_setup_scan(GT68xx_Device * dev,GT68xx_Scan_Request * request,GT68xx_Scan_Action action,GT68xx_Scan_Parameters * params)211 gt68xx_generic_setup_scan (GT68xx_Device * dev,
212 			   GT68xx_Scan_Request * request,
213 			   GT68xx_Scan_Action action,
214 			   GT68xx_Scan_Parameters * params)
215 {
216   SANE_Status status;
217   GT68xx_Model *model;
218   SANE_Int xdpi, ydpi;
219   SANE_Bool color;
220   SANE_Int depth;
221   SANE_Int pixel_x0, pixel_y0, pixel_xs, pixel_ys;
222   SANE_Int pixel_align;
223 
224   SANE_Int abs_x0, abs_y0, abs_xs, abs_ys, base_xdpi, base_ydpi;
225   SANE_Int scan_xs, scan_ys, scan_bpl;
226   SANE_Int bits_per_line;
227   SANE_Byte color_mode_code;
228   SANE_Bool line_mode;
229   SANE_Int overscan_lines;
230   SANE_Fixed x0, y0, xs, ys;
231   SANE_Bool backtrack = SANE_FALSE;
232 
233   DBG (6, "gt6816_setup_scan: enter (action=%s)\n",
234        action == SA_CALIBRATE ? "calibrate" :
235        action == SA_CALIBRATE_ONE_LINE ? "calibrate one line" :
236        action == SA_SCAN ? "scan" : "calculate only");
237 
238   model = dev->model;
239 
240   xdpi = request->xdpi;
241   ydpi = request->ydpi;
242   color = request->color;
243   depth = request->depth;
244 
245   base_xdpi = model->base_xdpi;
246   base_ydpi = model->base_ydpi;
247 
248   if (xdpi > model->base_xdpi)
249     base_xdpi = model->optical_xdpi;
250 
251   /* Special fixes */
252   if ((dev->model->flags & GT68XX_FLAG_USE_OPTICAL_X) && xdpi <= 50)
253     base_xdpi = model->optical_xdpi;
254 
255   if ((dev->model->flags & GT68XX_FLAG_SCAN_FROM_HOME) &&
256       !request->use_ta && action == SA_SCAN)
257     request->mbs = SANE_TRUE;
258 
259   if (!model->constant_ydpi)
260     {
261       if (ydpi > model->base_ydpi)
262 	base_ydpi = model->optical_ydpi;
263     }
264 
265   DBG (6, "gt68xx_generic_setup_scan: base_xdpi=%d, base_ydpi=%d\n",
266        base_xdpi, base_ydpi);
267 
268   switch (action)
269     {
270     case SA_CALIBRATE_ONE_LINE:
271       {
272 	x0 = request->x0;
273 	if (request->use_ta)
274 	  y0 = model->y_offset_calib_ta;
275 	else
276 	  y0 = model->y_offset_calib;
277 	ys = SANE_FIX (1.0 * MM_PER_INCH / ydpi);	/* one line */
278 	xs = request->xs;
279 	depth = 8;
280 	break;
281       }
282     case SA_CALIBRATE:
283       {
284 	if (request->use_ta)
285 	  {
286 	    if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
287 	      x0 = request->x0 - model->x_offset_ta;
288 	    else
289 	      x0 = request->x0 + model->x_offset_ta;
290 	    if (request->mbs)
291 	      y0 = model->y_offset_calib_ta;
292 	    else
293 	      y0 = 0;
294 	  }
295 	else
296 	  {
297 	    if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
298 	      x0 = request->x0 - model->x_offset;
299 	    else
300 	      x0 = request->x0 + model->x_offset;
301 	    if (request->mbs)
302 	      y0 = model->y_offset_calib;
303 	    else
304 	      y0 = 0;
305 	  }
306 	ys = SANE_FIX (CALIBRATION_HEIGHT);
307 	xs = request->xs;
308 	break;
309       }
310     case SA_SCAN:
311       {
312 	SANE_Fixed x_offset, y_offset;
313 
314 	if (strcmp (dev->model->command_set->name, "mustek-gt6816") != 0)
315 	  request->mbs = SANE_TRUE;	/* always go home for gt6801 scanners */
316 	if (request->use_ta)
317 	  {
318 	    x_offset = model->x_offset_ta;
319 	    if (request->mbs)
320 	      y_offset = model->y_offset_ta;
321 	    else
322 	      {
323 		y_offset = model->y_offset_ta - model->y_offset_calib_ta
324 		  - SANE_FIX (CALIBRATION_HEIGHT);
325 		if ((request->y0 + y_offset) < 0)
326 		  {
327 		    y_offset = model->y_offset_ta;
328 		    request->mbs = SANE_TRUE;
329 		  }
330 	      }
331 
332 	  }
333 	else
334 	  {
335 	    x_offset = model->x_offset;
336 	    if (request->mbs)
337 	      y_offset = model->y_offset;
338 	    else
339 	      {
340 		y_offset = model->y_offset - model->y_offset_calib
341 		  - SANE_FIX (CALIBRATION_HEIGHT);
342 		if ((request->y0 + y_offset) < 0)
343 		  {
344 		    y_offset = model->y_offset;
345 		    request->mbs = SANE_TRUE;
346 		  }
347 	      }
348 
349 	  }
350 	if (dev->model->flags & GT68XX_FLAG_MIRROR_X)
351 	  x0 = request->x0 - x_offset;
352 	else
353 	  x0 = request->x0 + x_offset;
354 	y0 = request->y0 + y_offset;
355 	if (y0 < 0)
356 	  y0 = 0;
357 	ys = request->ys;
358 	xs = request->xs;
359 	backtrack = request->backtrack;
360 	break;
361       }
362 
363     default:
364       DBG (1, "gt68xx_generic_setup_scan: invalid action=%d\n", (int) action);
365       return SANE_STATUS_INVAL;
366     }
367 
368   pixel_x0 = SANE_UNFIX (x0) * xdpi / MM_PER_INCH + 0.5;
369   pixel_y0 = SANE_UNFIX (y0) * ydpi / MM_PER_INCH + 0.5;
370   pixel_ys = SANE_UNFIX (ys) * ydpi / MM_PER_INCH + 0.5;
371   pixel_xs = SANE_UNFIX (xs) * xdpi / MM_PER_INCH + 0.5;
372 
373 
374   DBG (6, "gt68xx_generic_setup_scan: xdpi=%d, ydpi=%d\n", xdpi, ydpi);
375   DBG (6, "gt68xx_generic_setup_scan: color=%s, depth=%d\n",
376        color ? "TRUE" : "FALSE", depth);
377   DBG (6, "gt68xx_generic_setup_scan: pixel_x0=%d, pixel_y0=%d\n",
378        pixel_x0, pixel_y0);
379   DBG (6, "gt68xx_generic_setup_scan: pixel_xs=%d, pixel_ys=%d\n",
380        pixel_xs, pixel_ys);
381 
382 
383   color_mode_code = 0x80;
384   if (color)
385     color_mode_code |= (1 << 2);
386   else
387     color_mode_code |= dev->gray_mode_color;
388 
389   if (depth > 12)
390     color_mode_code |= (1 << 5);
391   else if (depth > 8)
392     {
393       color_mode_code &= 0x7f;
394       color_mode_code |= (1 << 4);
395     }
396 
397   DBG (6, "gt68xx_generic_setup_scan: color_mode_code = 0x%02X\n",
398        color_mode_code);
399 
400   overscan_lines = 0;
401   params->ld_shift_r = params->ld_shift_g = params->ld_shift_b = 0;
402   params->ld_shift_double = 0;
403 
404   /* Line distance correction is required for color scans. */
405   if (action == SA_SCAN && color)
406     {
407       SANE_Int optical_ydpi = model->optical_ydpi;
408       SANE_Int ld_shift_r = model->ld_shift_r;
409       SANE_Int ld_shift_g = model->ld_shift_g;
410       SANE_Int ld_shift_b = model->ld_shift_b;
411       SANE_Int max_ld = MAX (MAX (ld_shift_r, ld_shift_g), ld_shift_b);
412 
413       overscan_lines = max_ld * ydpi / optical_ydpi;
414       params->ld_shift_r = ld_shift_r * ydpi / optical_ydpi;
415       params->ld_shift_g = ld_shift_g * ydpi / optical_ydpi;
416       params->ld_shift_b = ld_shift_b * ydpi / optical_ydpi;
417       params->ld_shift_double = 0;
418       DBG (6, "gt68xx_generic_setup_scan: overscan=%d, ld=%d/%d/%d\n",
419 	   overscan_lines, params->ld_shift_r, params->ld_shift_g,
420 	   params->ld_shift_b);
421     }
422 
423   /* Used for CCD scanners with 6 instead of 3 CCD lines */
424   if (action == SA_SCAN && xdpi >= model->optical_xdpi
425       && model->ld_shift_double > 0)
426     {
427       params->ld_shift_double =
428 	model->ld_shift_double * ydpi / model->optical_ydpi;
429       if (color)
430 	overscan_lines += (params->ld_shift_double * 3);
431       else
432 	overscan_lines += params->ld_shift_double;
433 
434       DBG (6, "gt68xx_generic_setup_scan: overscan=%d, ld double=%d\n",
435 	   overscan_lines, params->ld_shift_double);
436     }
437 
438   abs_x0 = pixel_x0 * base_xdpi / xdpi;
439   abs_y0 = pixel_y0 * base_ydpi / ydpi;
440   DBG (6, "gt68xx_generic_setup_scan: abs_x0=%d, abs_y0=%d\n", abs_x0,
441        abs_y0);
442 
443   params->double_column = abs_x0 & 1;
444 
445   /* Calculate minimum number of pixels which span an integral multiple of 64
446    * bytes. */
447   pixel_align = 32;		/* best case for depth = 16 */
448   while ((depth * pixel_align) % (64 * 8) != 0)
449     pixel_align *= 2;
450   DBG (6, "gt68xx_generic_setup_scan: pixel_align=%d\n", pixel_align);
451 
452   if (pixel_xs % pixel_align == 0)
453     scan_xs = pixel_xs;
454   else
455     scan_xs = (pixel_xs / pixel_align + 1) * pixel_align;
456   scan_ys = pixel_ys + overscan_lines;
457 
458   if ((xdpi != base_xdpi)
459       && (strcmp (dev->model->command_set->name, "mustek-gt6816") != 0))
460     abs_xs = (scan_xs - 1) * base_xdpi / xdpi;	/* gt6801 */
461   else
462     abs_xs = scan_xs * base_xdpi / xdpi;	/* gt6816 */
463 
464   if (action == SA_CALIBRATE_ONE_LINE)
465     abs_ys = 2;
466   else
467     abs_ys = scan_ys * base_ydpi / ydpi;
468   DBG (6, "gt68xx_generic_setup_scan: abs_xs=%d, abs_ys=%d\n", abs_xs,
469        abs_ys);
470 
471   if (model->flags & GT68XX_FLAG_NO_LINEMODE)
472     {
473       line_mode = SANE_FALSE;
474       DBG (6,
475 	   "gt68xx_generic_setup_scan: using pixel mode (GT68XX_FLAG_NO_LINEMODE)\n");
476     }
477   else if (model->is_cis && !(model->flags & GT68XX_FLAG_CIS_LAMP))
478     {
479       line_mode = SANE_TRUE;
480       DBG (6, "gt68xx_generic_setup_scan: using line mode (CIS)\n");
481     }
482   else if (model->flags & GT68XX_FLAG_ALWAYS_LINEMODE)
483     {
484       line_mode = SANE_TRUE;
485       DBG (6,
486 	   "gt68xx_generic_setup_scan: using line mode (GT68XX_FLAG_ALWAYS_LINEMODE)\n");
487     }
488   else
489     {
490       SANE_Int max_bpl = xdpi * 3 * depth *
491 	(SANE_UNFIX (model->x_size) -
492 	 SANE_UNFIX (model->x_offset)) / MM_PER_INCH / 8;
493 
494       line_mode = SANE_FALSE;
495       if (!color)
496 	{
497 	  DBG (6,
498 	       "gt68xx_generic_setup_scan: using line mode for monochrome scan\n");
499 	  line_mode = SANE_TRUE;
500 	}
501       else if (max_bpl > MAX_PIXEL_MODE)
502 	{
503 	  DBG (6,
504 	       "gt68xx_generic_setup_scan: max_bpl = %d > %d: forcing line mode\n",
505 	       max_bpl, MAX_PIXEL_MODE);
506 	  line_mode = SANE_TRUE;
507 	}
508       else
509 	DBG (6,
510 	     "gt68xx_generic_setup_scan: max_bpl = %d <= %d: using pixel mode\n",
511 	     max_bpl, MAX_PIXEL_MODE);
512     }
513 
514   bits_per_line = depth * scan_xs;
515 
516   if (color && !line_mode)
517     bits_per_line *= 3;
518 
519   if (bits_per_line % 8)	/* impossible */
520     {
521       DBG (0, "gt68xx_generic_setup_scan: BUG: unaligned bits_per_line=%d\n",
522 	   bits_per_line);
523       return SANE_STATUS_INVAL;
524     }
525   scan_bpl = bits_per_line / 8;
526 
527   if (scan_bpl % 64)		/* impossible */
528     {
529       DBG (0, "gt68xx_generic_setup_scan: BUG: unaligned scan_bpl=%d\n",
530 	   scan_bpl);
531       return SANE_STATUS_INVAL;
532     }
533 
534   if (color)
535     if (line_mode || dev->model->flags & GT68XX_FLAG_SE_2400)
536       scan_ys *= 3;
537 
538   DBG (6, "gt68xx_generic_setup_scan: scan_xs=%d, scan_ys=%d\n", scan_xs,
539        scan_ys);
540 
541   DBG (6, "gt68xx_generic_setup_scan: scan_bpl=%d\n", scan_bpl);
542 
543   if (!request->calculate)
544     {
545       GT68xx_Packet req;
546       SANE_Byte motor_mode_1, motor_mode_2;
547 
548       if (scan_bpl > (16 * 1024))
549 	{
550 	  DBG (0, "gt68xx_generic_setup_scan: scan_bpl=%d, too large\n",
551 	       scan_bpl);
552 	  return SANE_STATUS_NO_MEM;
553 	}
554 
555       if ((dev->model->flags & GT68XX_FLAG_NO_LINEMODE) && line_mode && color)
556 	{
557 	  DBG (0,
558 	       "gt68xx_generic_setup_scan: the scanner's memory is too small for "
559 	       "that combination of resolution, dpi and width\n");
560 	  return SANE_STATUS_NO_MEM;
561 	}
562       DBG (6, "gt68xx_generic_setup_scan: backtrack=%d\n", backtrack);
563 
564       motor_mode_1 = (request->mbs ? 0 : 1) << 1;
565       motor_mode_1 |= (request->mds ? 0 : 1) << 2;
566       motor_mode_1 |= (request->mas ? 0 : 1) << 0;
567       motor_mode_1 |= (backtrack ? 1 : 0) << 3;
568 
569       motor_mode_2 = (request->lamp ? 0 : 1) << 0;
570       motor_mode_2 |= (line_mode ? 0 : 1) << 2;
571 
572       if ((action != SA_SCAN)
573 	  && (strcmp (dev->model->command_set->name, "mustek-gt6816") == 0))
574 	motor_mode_2 |= 1 << 3;
575 
576       DBG (6,
577 	   "gt68xx_generic_setup_scan: motor_mode_1 = 0x%02X, motor_mode_2 = 0x%02X\n",
578 	   motor_mode_1, motor_mode_2);
579 
580       /* Fill in the setup command */
581       memset (req, 0, sizeof (req));
582       req[0x00] = 0x20;
583       req[0x01] = 0x01;
584       req[0x02] = LOBYTE (abs_y0);
585       req[0x03] = HIBYTE (abs_y0);
586       req[0x04] = LOBYTE (abs_ys);
587       req[0x05] = HIBYTE (abs_ys);
588       req[0x06] = LOBYTE (abs_x0);
589       req[0x07] = HIBYTE (abs_x0);
590       req[0x08] = LOBYTE (abs_xs);
591       req[0x09] = HIBYTE (abs_xs);
592       req[0x0a] = color_mode_code;
593       if (model->is_cis && !(model->flags & GT68XX_FLAG_CIS_LAMP))
594 	req[0x0b] = 0x60;
595       else
596 	req[0x0b] = 0x20;
597       req[0x0c] = LOBYTE (xdpi);
598       req[0x0d] = HIBYTE (xdpi);
599       req[0x0e] = 0x12;		/* ??? 0x12 */
600       req[0x0f] = 0x00;		/* ??? 0x00 */
601       req[0x10] = LOBYTE (scan_bpl);
602       req[0x11] = HIBYTE (scan_bpl);
603       req[0x12] = LOBYTE (scan_ys);
604       req[0x13] = HIBYTE (scan_ys);
605       req[0x14] = motor_mode_1;
606       req[0x15] = motor_mode_2;
607       req[0x16] = LOBYTE (ydpi);
608       req[0x17] = HIBYTE (ydpi);
609       if (backtrack)
610 	req[0x18] = request->backtrack_lines;
611       else
612 	req[0x18] = 0x00;
613 
614       status = gt68xx_device_req (dev, req, req);
615       if (status != SANE_STATUS_GOOD)
616 	{
617 	  DBG (3, "gt68xx_generic_setup_scan: setup request failed: %s\n",
618 	       sane_strstatus (status));
619 	  return status;
620 	}
621       RIE (gt68xx_device_check_result (req, 0x20));
622     }
623 
624   /* Fill in calculated values */
625   params->xdpi = xdpi;
626   params->ydpi = ydpi;
627   params->depth = depth;
628   params->color = color;
629   params->pixel_xs = pixel_xs;
630   params->pixel_ys = pixel_ys;
631   params->scan_xs = scan_xs;
632   params->scan_ys = scan_ys;
633   params->scan_bpl = scan_bpl;
634   params->line_mode = line_mode;
635   params->overscan_lines = overscan_lines;
636   params->pixel_x0 = pixel_x0;
637 
638   DBG (6, "gt68xx_generic_setup_scan: leave: ok\n");
639   return SANE_STATUS_GOOD;
640 }
641 
642 SANE_Status
gt68xx_generic_move_paper(GT68xx_Device * dev,GT68xx_Scan_Request * request)643 gt68xx_generic_move_paper (GT68xx_Device * dev,
644 			   GT68xx_Scan_Request * request)
645 {
646   GT68xx_Packet req;
647   SANE_Status status;
648   SANE_Int ydpi;
649   SANE_Int pixel_y0;
650   SANE_Int abs_y0, base_ydpi;
651   GT68xx_Model *model = dev->model;
652 
653   ydpi = request->ydpi;
654   base_ydpi = model->base_ydpi;
655 
656   if (ydpi > model->base_ydpi)
657     ydpi = base_ydpi;
658 
659   pixel_y0 =
660     SANE_UNFIX ((request->y0 + model->y_offset)) * ydpi / MM_PER_INCH + 0.5;
661   abs_y0 = pixel_y0 * base_ydpi / ydpi;
662 
663   DBG (6, "gt68xx_generic_move_paper: base_ydpi=%d\n", base_ydpi);
664   DBG (6, "gt68xx_generic_move_paper: ydpi=%d\n", ydpi);
665   DBG (6, "gt68xx_generic_move_paper: abs_y0=%d\n", abs_y0);
666 
667   /* paper move request */
668   memset (req, 0, sizeof (req));
669   req[0] = 0x82;
670   req[1] = 0x01;
671   req[2] = LOBYTE (abs_y0);
672   req[3] = HIBYTE (abs_y0);
673   RIE (gt68xx_device_req (dev, req, req));
674 
675   DBG (6, "gt68xx_generic_move_paper: leave: ok\n");
676   return SANE_STATUS_GOOD;
677 }
678