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