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 50SANE_Status 51gt68xx_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 70SANE_Status 71gt68xx_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 85SANE_Status 86gt68xx_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 104static SANE_Byte 105gt68xx_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 117static SANE_Byte 118gt68xx_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 127SANE_Status 128gt68xx_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 148SANE_Status 149gt68xx_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 174SANE_Status 175gt68xx_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 194SANE_Status 195gt68xx_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 210SANE_Status 211gt68xx_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 642SANE_Status 643gt68xx_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