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