1141cc406Sopenharmony_ci/*............................................................................. 2141cc406Sopenharmony_ci * Project : SANE library for Plustek flatbed scanners. 3141cc406Sopenharmony_ci *............................................................................. 4141cc406Sopenharmony_ci */ 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci/** @file plustek-usbscan.c 7141cc406Sopenharmony_ci * @brief Scanning... 8141cc406Sopenharmony_ci * 9141cc406Sopenharmony_ci * Based on sources acquired from Plustek Inc.<br> 10141cc406Sopenharmony_ci * Copyright (C) 2001-2013 Gerhard Jaeger <gerhard@gjaeger.de> 11141cc406Sopenharmony_ci * 12141cc406Sopenharmony_ci * History: 13141cc406Sopenharmony_ci * - 0.40 - starting version of the USB support 14141cc406Sopenharmony_ci * - 0.41 - minor fixes 15141cc406Sopenharmony_ci * - 0.42 - added some stuff for CIS devices 16141cc406Sopenharmony_ci * - 0.43 - no changes 17141cc406Sopenharmony_ci * - 0.44 - added CIS specific settings and calculations 18141cc406Sopenharmony_ci * - removed usb_IsEscPressed 19141cc406Sopenharmony_ci * - 0.45 - fixed the special setting stuff for CanoScan 20141cc406Sopenharmony_ci * - fixed pixel calculation for binary modes 21141cc406Sopenharmony_ci * - fixed cancel hang problem 22141cc406Sopenharmony_ci * - fixed CIS PhyBytes adjustment 23141cc406Sopenharmony_ci * - removed CanoScan specific setting stuff 24141cc406Sopenharmony_ci * - 0.46 - fixed problem in usb_SetScanParameters() 25141cc406Sopenharmony_ci * - 0.47 - no changes 26141cc406Sopenharmony_ci * - 0.48 - minor fixes 27141cc406Sopenharmony_ci * - 0.49 - a_bRegs is now part of the device structure 28141cc406Sopenharmony_ci * - using now PhyDpi.y as selector for the motor MCLK range 29141cc406Sopenharmony_ci * - changed usb_MapDownload prototype 30141cc406Sopenharmony_ci * - 0.50 - cleanup 31141cc406Sopenharmony_ci * - 0.51 - added usb_get_res() and usb_GetPhyPixels() 32141cc406Sopenharmony_ci * - 0.52 - removed stuff, that will most probably never be used 33141cc406Sopenharmony_ci * . 34141cc406Sopenharmony_ci * <hr> 35141cc406Sopenharmony_ci * This file is part of the SANE package. 36141cc406Sopenharmony_ci * 37141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or 38141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as 39141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the 40141cc406Sopenharmony_ci * License, or (at your option) any later version. 41141cc406Sopenharmony_ci * 42141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 43141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 44141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 45141cc406Sopenharmony_ci * General Public License for more details. 46141cc406Sopenharmony_ci * 47141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License 48141cc406Sopenharmony_ci * along with this program. If not, see <https://www.gnu.org/licenses/>. 49141cc406Sopenharmony_ci * 50141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for 51141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE. 52141cc406Sopenharmony_ci * 53141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files 54141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the 55141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public 56141cc406Sopenharmony_ci * License. Your use of that executable is in no way restricted on 57141cc406Sopenharmony_ci * account of linking the SANE library code into it. 58141cc406Sopenharmony_ci * 59141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why 60141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public 61141cc406Sopenharmony_ci * License. 62141cc406Sopenharmony_ci * 63141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in 64141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that 65141cc406Sopenharmony_ci * those changes may be distributed with this exception intact. 66141cc406Sopenharmony_ci * 67141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice 68141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications. 69141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice. 70141cc406Sopenharmony_ci * <hr> 71141cc406Sopenharmony_ci */ 72141cc406Sopenharmony_ci 73141cc406Sopenharmony_ci#define DIVIDER 8 74141cc406Sopenharmony_ci 75141cc406Sopenharmony_ci/** array used to get motor-settings and mclk-settings 76141cc406Sopenharmony_ci */ 77141cc406Sopenharmony_cistatic int dpi_ranges[] = { 75,100,150,200,300,400,600,800,1200,2400 }; 78141cc406Sopenharmony_ci 79141cc406Sopenharmony_cistatic u_char bMaxITA; 80141cc406Sopenharmony_ci 81141cc406Sopenharmony_cistatic SANE_Bool m_fAutoPark; 82141cc406Sopenharmony_cistatic SANE_Bool m_fFirst; 83141cc406Sopenharmony_cistatic double m_dHDPIDivider; 84141cc406Sopenharmony_cistatic double m_dMCLKDivider; 85141cc406Sopenharmony_cistatic ScanParam *m_pParam; 86141cc406Sopenharmony_cistatic u_char m_bLineRateColor; 87141cc406Sopenharmony_cistatic u_char m_bCM; 88141cc406Sopenharmony_cistatic u_char m_bIntTimeAdjust; 89141cc406Sopenharmony_cistatic u_char m_bOldScanData; 90141cc406Sopenharmony_cistatic u_short m_wFastFeedStepSize; 91141cc406Sopenharmony_cistatic u_short m_wLineLength; 92141cc406Sopenharmony_cistatic u_short m_wStepSize; 93141cc406Sopenharmony_cistatic u_long m_dwPauseLimit; 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_cistatic SANE_Bool m_fStart = SANE_FALSE; 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci/* Prototype... */ 98141cc406Sopenharmony_cistatic SANE_Bool usb_DownloadShadingData( Plustek_Device*, u_char ); 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_ci/** returns the min of the two values val1 and val2 101141cc406Sopenharmony_ci * @param val1 - first parameter 102141cc406Sopenharmony_ci * @param val2 - second parameter 103141cc406Sopenharmony_ci * @return val1 if val1 < val2, else val1 104141cc406Sopenharmony_ci */ 105141cc406Sopenharmony_cistatic u_long 106141cc406Sopenharmony_ciusb_min( u_long val1, u_long val2 ) 107141cc406Sopenharmony_ci{ 108141cc406Sopenharmony_ci if( val1 > val2 ) 109141cc406Sopenharmony_ci return val2; 110141cc406Sopenharmony_ci return val1; 111141cc406Sopenharmony_ci} 112141cc406Sopenharmony_ci 113141cc406Sopenharmony_ci/** returns the max of the two values val1 and val2 114141cc406Sopenharmony_ci * @param val1 - first parameter 115141cc406Sopenharmony_ci * @param val2 - second parameter 116141cc406Sopenharmony_ci * @return val1 if val1 > val2, else val2 117141cc406Sopenharmony_ci */ 118141cc406Sopenharmony_cistatic u_long 119141cc406Sopenharmony_ciusb_max( u_long val1, u_long val2 ) 120141cc406Sopenharmony_ci{ 121141cc406Sopenharmony_ci if( val1 > val2 ) 122141cc406Sopenharmony_ci return val1; 123141cc406Sopenharmony_ci return val2; 124141cc406Sopenharmony_ci} 125141cc406Sopenharmony_ci 126141cc406Sopenharmony_ci/** function to get the possible resolution for a specific base resolution, 127141cc406Sopenharmony_ci * according to the dividers a LM983x offers. 128141cc406Sopenharmony_ci * @param base - scanners optical resolution 129141cc406Sopenharmony_ci * @param idx - which divider to use 130141cc406Sopenharmony_ci */ 131141cc406Sopenharmony_cistatic u_short 132141cc406Sopenharmony_ciusb_get_res( u_short base, u_short idx ) 133141cc406Sopenharmony_ci{ 134141cc406Sopenharmony_ci double div_list[DIVIDER] = { 12.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0 }; 135141cc406Sopenharmony_ci 136141cc406Sopenharmony_ci if( idx == 0 || idx > DIVIDER ) 137141cc406Sopenharmony_ci return 0; 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci return (u_short)((double)base/div_list[idx-1]); 140141cc406Sopenharmony_ci} 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci/** Set the horizontal DPI divider. 143141cc406Sopenharmony_ci * Affected registers:<br> 144141cc406Sopenharmony_ci * 0x09 - Horizontal DPI divider HDPI_DIV<br> 145141cc406Sopenharmony_ci * 146141cc406Sopenharmony_ci * @param dev - pointer to our device structure, 147141cc406Sopenharmony_ci * it should contain all we need 148141cc406Sopenharmony_ci * @param xdpi - user specified horizontal resolution 149141cc406Sopenharmony_ci * @return - the function returns the "normalized" horizontal resolution. 150141cc406Sopenharmony_ci */ 151141cc406Sopenharmony_cistatic u_short 152141cc406Sopenharmony_ciusb_SetAsicDpiX( Plustek_Device *dev, u_short xdpi ) 153141cc406Sopenharmony_ci{ 154141cc406Sopenharmony_ci u_short res; 155141cc406Sopenharmony_ci ScanDef *scanning = &dev->scanning; 156141cc406Sopenharmony_ci DCapsDef *scaps = &dev->usbDev.Caps; 157141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci /* limit xdpi to lower value for certain devices... 160141cc406Sopenharmony_ci */ 161141cc406Sopenharmony_ci if( scaps->OpticDpi.x == 1200 && 162141cc406Sopenharmony_ci scanning->sParam.bDataType != SCANDATATYPE_Color && 163141cc406Sopenharmony_ci xdpi < 150 && 164141cc406Sopenharmony_ci scanning->sParam.bDataType == SCANDATATYPE_BW ) { 165141cc406Sopenharmony_ci xdpi = 150; 166141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* LIMIT XDPI to %udpi\n", xdpi ); 167141cc406Sopenharmony_ci } 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci m_dHDPIDivider = (double)scaps->OpticDpi.x / xdpi; 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_ci if (m_dHDPIDivider < 1.5) 172141cc406Sopenharmony_ci { 173141cc406Sopenharmony_ci m_dHDPIDivider = 1.0; 174141cc406Sopenharmony_ci regs[0x09] = 0; 175141cc406Sopenharmony_ci } 176141cc406Sopenharmony_ci else if (m_dHDPIDivider < 2.0) 177141cc406Sopenharmony_ci { 178141cc406Sopenharmony_ci m_dHDPIDivider = 1.5; 179141cc406Sopenharmony_ci regs[0x09] = 1; 180141cc406Sopenharmony_ci } 181141cc406Sopenharmony_ci else if (m_dHDPIDivider < 3.0) 182141cc406Sopenharmony_ci { 183141cc406Sopenharmony_ci m_dHDPIDivider = 2.0; 184141cc406Sopenharmony_ci regs[0x09] = 2; 185141cc406Sopenharmony_ci } 186141cc406Sopenharmony_ci else if (m_dHDPIDivider < 4.0) 187141cc406Sopenharmony_ci { 188141cc406Sopenharmony_ci m_dHDPIDivider = 3.0; 189141cc406Sopenharmony_ci regs[0x09] = 3; 190141cc406Sopenharmony_ci } 191141cc406Sopenharmony_ci else if (m_dHDPIDivider < 6.0) 192141cc406Sopenharmony_ci { 193141cc406Sopenharmony_ci m_dHDPIDivider = 4.0; 194141cc406Sopenharmony_ci regs[0x09] = 4; 195141cc406Sopenharmony_ci } 196141cc406Sopenharmony_ci else if (m_dHDPIDivider < 8.0) 197141cc406Sopenharmony_ci { 198141cc406Sopenharmony_ci m_dHDPIDivider = 6.0; 199141cc406Sopenharmony_ci regs[0x09] = 5; 200141cc406Sopenharmony_ci } 201141cc406Sopenharmony_ci else if (m_dHDPIDivider < 12.0) 202141cc406Sopenharmony_ci { 203141cc406Sopenharmony_ci m_dHDPIDivider = 8.0; 204141cc406Sopenharmony_ci regs[0x09] = 6; 205141cc406Sopenharmony_ci } 206141cc406Sopenharmony_ci else 207141cc406Sopenharmony_ci { 208141cc406Sopenharmony_ci m_dHDPIDivider = 12.0; 209141cc406Sopenharmony_ci regs[0x09] = 7; 210141cc406Sopenharmony_ci } 211141cc406Sopenharmony_ci 212141cc406Sopenharmony_ci /* adjust, if any turbo/preview mode is set, should be 0 here... */ 213141cc406Sopenharmony_ci if( regs[0x0a] ) 214141cc406Sopenharmony_ci regs[0x09] -= ((regs[0x0a] >> 2) + 2); 215141cc406Sopenharmony_ci 216141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* HDPI: %.3f\n", m_dHDPIDivider ); 217141cc406Sopenharmony_ci res = (u_short)((double)scaps->OpticDpi.x / m_dHDPIDivider); 218141cc406Sopenharmony_ci 219141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* XDPI=%u, HDPI=%.3f\n", res, m_dHDPIDivider ); 220141cc406Sopenharmony_ci return res; 221141cc406Sopenharmony_ci} 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci/** 224141cc406Sopenharmony_ci * @param dev - pointer to our device structure, 225141cc406Sopenharmony_ci * it should contain all we need 226141cc406Sopenharmony_ci * @param ydpi - user specified vertical resolution 227141cc406Sopenharmony_ci * @return - 228141cc406Sopenharmony_ci */ 229141cc406Sopenharmony_cistatic u_short 230141cc406Sopenharmony_ciusb_SetAsicDpiY( Plustek_Device *dev, u_short ydpi ) 231141cc406Sopenharmony_ci{ 232141cc406Sopenharmony_ci ScanDef *scanning = &dev->scanning; 233141cc406Sopenharmony_ci DCapsDef *sCaps = &dev->usbDev.Caps; 234141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 235141cc406Sopenharmony_ci 236141cc406Sopenharmony_ci u_short wMinDpi, wDpi; 237141cc406Sopenharmony_ci 238141cc406Sopenharmony_ci if(0 != sCaps->bSensorDistance ) 239141cc406Sopenharmony_ci wMinDpi = sCaps->OpticDpi.y / sCaps->bSensorDistance; 240141cc406Sopenharmony_ci else 241141cc406Sopenharmony_ci wMinDpi = 75; 242141cc406Sopenharmony_ci 243141cc406Sopenharmony_ci /* Here we might have to check against the MinDpi value ! */ 244141cc406Sopenharmony_ci wDpi = (ydpi + wMinDpi - 1) / wMinDpi * wMinDpi; 245141cc406Sopenharmony_ci 246141cc406Sopenharmony_ci /* 247141cc406Sopenharmony_ci * HEINER: added '*2' 248141cc406Sopenharmony_ci */ 249141cc406Sopenharmony_ci if( wDpi > sCaps->OpticDpi.y * 2 ) 250141cc406Sopenharmony_ci wDpi = sCaps->OpticDpi.y * 2; 251141cc406Sopenharmony_ci 252141cc406Sopenharmony_ci if( (hw->motorModel == MODEL_Tokyo600) || 253141cc406Sopenharmony_ci !_IS_PLUSTEKMOTOR(hw->motorModel)) { 254141cc406Sopenharmony_ci /* return wDpi; */ 255141cc406Sopenharmony_ci } else if( sCaps->wFlags & DEVCAPSFLAG_Adf && sCaps->OpticDpi.x == 600 ) { 256141cc406Sopenharmony_ci /* for ADF scanner color mode 300 dpi big noise */ 257141cc406Sopenharmony_ci if( scanning->sParam.bDataType == SCANDATATYPE_Color && 258141cc406Sopenharmony_ci scanning->sParam.bBitDepth > 8 && wDpi < 300 ) { 259141cc406Sopenharmony_ci wDpi = 300; 260141cc406Sopenharmony_ci } 261141cc406Sopenharmony_ci } else if( sCaps->OpticDpi.x == 1200 ) { 262141cc406Sopenharmony_ci if( scanning->sParam.bDataType != SCANDATATYPE_Color && wDpi < 200) { 263141cc406Sopenharmony_ci wDpi = 200; 264141cc406Sopenharmony_ci } 265141cc406Sopenharmony_ci } 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* YDPI=%u, MinDPIY=%u\n", wDpi, wMinDpi ); 268141cc406Sopenharmony_ci return wDpi; 269141cc406Sopenharmony_ci} 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci/** set color mode and sensor configuration stuff, according to the data mode 272141cc406Sopenharmony_ci * Affected registers:<br> 273141cc406Sopenharmony_ci * 0x26 - 0x27 - Color Mode settings<br> 274141cc406Sopenharmony_ci * 0x0f - 0x18 - Sensor Configuration - directly from the HwDefs<br> 275141cc406Sopenharmony_ci * 0x09 - add Data Mode and Pixel Packing<br> 276141cc406Sopenharmony_ci * 277141cc406Sopenharmony_ci * @param dev - pointer to our device structure, 278141cc406Sopenharmony_ci * it should contain all we need 279141cc406Sopenharmony_ci * @param pParam - pointer to the current scan parameters 280141cc406Sopenharmony_ci * @return - Nothing 281141cc406Sopenharmony_ci */ 282141cc406Sopenharmony_cistatic void 283141cc406Sopenharmony_ciusb_SetColorAndBits( Plustek_Device *dev, ScanParam *pParam ) 284141cc406Sopenharmony_ci{ 285141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 286141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 287141cc406Sopenharmony_ci 288141cc406Sopenharmony_ci /* Set pixel packing, data mode and AFE operation */ 289141cc406Sopenharmony_ci switch( pParam->bDataType ) { 290141cc406Sopenharmony_ci case SCANDATATYPE_Color: 291141cc406Sopenharmony_ci m_bCM = 3; 292141cc406Sopenharmony_ci regs[0x26] = hw->bReg_0x26 & 0x7; 293141cc406Sopenharmony_ci 294141cc406Sopenharmony_ci /* if set to one channel color, we select the blue channel 295141cc406Sopenharmony_ci * as input source, this is the default, but I don't know 296141cc406Sopenharmony_ci * what happens, if we deselect this 297141cc406Sopenharmony_ci */ 298141cc406Sopenharmony_ci if( regs[0x26] & _ONE_CH_COLOR ) 299141cc406Sopenharmony_ci regs[0x26] |= (_BLUE_CH | 0x01); 300141cc406Sopenharmony_ci 301141cc406Sopenharmony_ci memcpy( ®s[0x0f], hw->bReg_0x0f_Color, 10 ); 302141cc406Sopenharmony_ci break; 303141cc406Sopenharmony_ci 304141cc406Sopenharmony_ci case SCANDATATYPE_Gray: 305141cc406Sopenharmony_ci m_bCM = 1; 306141cc406Sopenharmony_ci regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04; 307141cc406Sopenharmony_ci memcpy( ®s[0x0f], hw->bReg_0x0f_Mono, 10 ); 308141cc406Sopenharmony_ci break; 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci case SCANDATATYPE_BW: 311141cc406Sopenharmony_ci m_bCM = 1; 312141cc406Sopenharmony_ci regs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04; 313141cc406Sopenharmony_ci memcpy( ®s[0x0f], hw->bReg_0x0f_Mono, 10 ); 314141cc406Sopenharmony_ci break; 315141cc406Sopenharmony_ci } 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_ci regs[0x27] = hw->bReg_0x27; 318141cc406Sopenharmony_ci 319141cc406Sopenharmony_ci if( pParam->bBitDepth > 8 ) { 320141cc406Sopenharmony_ci regs[0x09] |= 0x20; /* 14/16bit image data */ 321141cc406Sopenharmony_ci 322141cc406Sopenharmony_ci } else if( pParam->bBitDepth == 8 ) { 323141cc406Sopenharmony_ci regs[0x09] |= 0x18; /* 8bits/per pixel */ 324141cc406Sopenharmony_ci } 325141cc406Sopenharmony_ci} 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci/** 328141cc406Sopenharmony_ci * Data output from NS983X should be times of 2-byte and every line 329141cc406Sopenharmony_ci * will append 2 status bytes 330141cc406Sopenharmony_ci */ 331141cc406Sopenharmony_cistatic void 332141cc406Sopenharmony_ciusb_GetPhyPixels( Plustek_Device *dev, ScanParam *sp ) 333141cc406Sopenharmony_ci{ 334141cc406Sopenharmony_ci sp->Size.dwValidPixels = sp->Size.dwPixels * sp->PhyDpi.x / sp->UserDpi.x; 335141cc406Sopenharmony_ci 336141cc406Sopenharmony_ci if (sp->bBitDepth == 1) { 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci /* Pixels should be times of 16 */ 339141cc406Sopenharmony_ci sp->Size.dwPhyPixels = 340141cc406Sopenharmony_ci (sp->Size.dwValidPixels + 15UL) & 0xfffffff0UL; 341141cc406Sopenharmony_ci sp->Size.dwPhyBytes = sp->Size.dwPhyPixels / 8UL + 2UL; 342141cc406Sopenharmony_ci 343141cc406Sopenharmony_ci } else if (sp->bBitDepth == 8) { 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ci /* Pixels should be times of 2 */ 346141cc406Sopenharmony_ci sp->Size.dwPhyPixels = (sp->Size.dwValidPixels + 1UL) & 0xfffffffeUL; 347141cc406Sopenharmony_ci sp->Size.dwPhyBytes = sp->Size.dwPhyPixels * sp->bChannels + 2UL; 348141cc406Sopenharmony_ci 349141cc406Sopenharmony_ci /* need to be adjusted for CIS devices in color mode */ 350141cc406Sopenharmony_ci if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) { 351141cc406Sopenharmony_ci sp->Size.dwPhyBytes *= 3; 352141cc406Sopenharmony_ci } 353141cc406Sopenharmony_ci } 354141cc406Sopenharmony_ci else /* sp->bBitDepth == 16 */ 355141cc406Sopenharmony_ci { 356141cc406Sopenharmony_ci sp->Size.dwPhyPixels = sp->Size.dwValidPixels; 357141cc406Sopenharmony_ci sp->Size.dwPhyBytes = sp->Size.dwPhyPixels * 2 * sp->bChannels + 2UL; 358141cc406Sopenharmony_ci 359141cc406Sopenharmony_ci /* need to be adjusted for CIS devices in color mode */ 360141cc406Sopenharmony_ci if(usb_IsCISDevice( dev ) && (sp->bDataType == SCANDATATYPE_Color)) { 361141cc406Sopenharmony_ci sp->Size.dwPhyBytes *= 3; 362141cc406Sopenharmony_ci } 363141cc406Sopenharmony_ci } 364141cc406Sopenharmony_ci} 365141cc406Sopenharmony_ci 366141cc406Sopenharmony_ci/** Calculate basic image settings like the number of physical bytes per line 367141cc406Sopenharmony_ci * etc... 368141cc406Sopenharmony_ci * Affected registers:<br> 369141cc406Sopenharmony_ci * 0x22/0x23 - Data Pixels Start<br> 370141cc406Sopenharmony_ci * 0x24/0x25 - Data Pixels End<br> 371141cc406Sopenharmony_ci * 0x4a/0x4b - Full Steps to Skip at Start of Scan 372141cc406Sopenharmony_ci * 373141cc406Sopenharmony_ci * @param dev - pointer to our device structure, 374141cc406Sopenharmony_ci * it should contain all we need 375141cc406Sopenharmony_ci * @param pParam - pointer to the current scan parameters 376141cc406Sopenharmony_ci * @return - Nothing 377141cc406Sopenharmony_ci */ 378141cc406Sopenharmony_cistatic void 379141cc406Sopenharmony_ciusb_GetScanRect( Plustek_Device *dev, ScanParam *sp ) 380141cc406Sopenharmony_ci{ 381141cc406Sopenharmony_ci u_short wDataPixelStart, wLineEnd; 382141cc406Sopenharmony_ci 383141cc406Sopenharmony_ci DCapsDef *sCaps = &dev->usbDev.Caps; 384141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 385141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 386141cc406Sopenharmony_ci 387141cc406Sopenharmony_ci /* Convert pixels to physical dpi based */ 388141cc406Sopenharmony_ci usb_GetPhyPixels( dev, sp ); 389141cc406Sopenharmony_ci 390141cc406Sopenharmony_ci /* Compute data start pixel */ 391141cc406Sopenharmony_ci#if 0 392141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */ 393141cc406Sopenharmony_ci if(sp->bCalibration != PARAM_Gain && 394141cc406Sopenharmony_ci sp->bCalibration != PARAM_Offset && ScanInf.m_fADF) 395141cc406Sopenharmony_ci wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL - 396141cc406Sopenharmony_ci (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5); 397141cc406Sopenharmony_ci else 398141cc406Sopenharmony_ci#endif 399141cc406Sopenharmony_ci wDataPixelStart = (u_short)((u_long)sp->Origin.x * 400141cc406Sopenharmony_ci sCaps->OpticDpi.x / 300UL); 401141cc406Sopenharmony_ci 402141cc406Sopenharmony_ci /* during the calibration steps, we read the entire CCD data 403141cc406Sopenharmony_ci */ 404141cc406Sopenharmony_ci if((sp->bCalibration != PARAM_Gain)&&(sp->bCalibration != PARAM_Offset)) { 405141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */ 406141cc406Sopenharmony_ci#if 0 407141cc406Sopenharmony_ci if(ScanInf.m_fADF) { 408141cc406Sopenharmony_ci wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL - 409141cc406Sopenharmony_ci (u_short)(m_dHDPIDivider * sp->Size.dwValidPixels + 0.5); 410141cc406Sopenharmony_ci } 411141cc406Sopenharmony_ci#endif 412141cc406Sopenharmony_ci wDataPixelStart += hw->wActivePixelsStart; 413141cc406Sopenharmony_ci } 414141cc406Sopenharmony_ci 415141cc406Sopenharmony_ci wLineEnd = wDataPixelStart + (u_short)(m_dHDPIDivider * 416141cc406Sopenharmony_ci sp->Size.dwPhyPixels + 0.5); 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u\n", 419141cc406Sopenharmony_ci wDataPixelStart, wLineEnd ); 420141cc406Sopenharmony_ci if( wDataPixelStart & 1 ) { 421141cc406Sopenharmony_ci 422141cc406Sopenharmony_ci wDataPixelStart++; 423141cc406Sopenharmony_ci wLineEnd++; 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u (ADJ)\n", 426141cc406Sopenharmony_ci wDataPixelStart, wLineEnd ); 427141cc406Sopenharmony_ci } 428141cc406Sopenharmony_ci 429141cc406Sopenharmony_ci regs[0x22] = _HIBYTE( wDataPixelStart ); 430141cc406Sopenharmony_ci regs[0x23] = _LOBYTE( wDataPixelStart ); 431141cc406Sopenharmony_ci 432141cc406Sopenharmony_ci /* should match: wLineEnd-wDataPixelStart%(m_dHDPIDivider*2) = 0!! */ 433141cc406Sopenharmony_ci regs[0x24] = _HIBYTE( wLineEnd ); 434141cc406Sopenharmony_ci regs[0x25] = _LOBYTE( wLineEnd ); 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_ci DBG( _DBG_INFO2, ">> End-Start=%u, HDPI=%.2f\n", 437141cc406Sopenharmony_ci wLineEnd-wDataPixelStart, m_dHDPIDivider); 438141cc406Sopenharmony_ci 439141cc406Sopenharmony_ci /* Y origin */ 440141cc406Sopenharmony_ci if( sp->bCalibration == PARAM_Scan ) { 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci if( hw->motorModel == MODEL_Tokyo600 ) { 443141cc406Sopenharmony_ci 444141cc406Sopenharmony_ci if(sp->PhyDpi.x <= 75) 445141cc406Sopenharmony_ci sp->Origin.y += 20; 446141cc406Sopenharmony_ci else if(sp->PhyDpi.x <= 100) 447141cc406Sopenharmony_ci { 448141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Color) 449141cc406Sopenharmony_ci sp->Origin.y += 0; 450141cc406Sopenharmony_ci else 451141cc406Sopenharmony_ci sp->Origin.y -= 6; 452141cc406Sopenharmony_ci } 453141cc406Sopenharmony_ci else if(sp->PhyDpi.x <= 150) 454141cc406Sopenharmony_ci { 455141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Color) 456141cc406Sopenharmony_ci sp->Origin.y -= 0; 457141cc406Sopenharmony_ci } 458141cc406Sopenharmony_ci else if(sp->PhyDpi.x <= 200) 459141cc406Sopenharmony_ci { 460141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Color) 461141cc406Sopenharmony_ci sp->Origin.y -= 10; 462141cc406Sopenharmony_ci else 463141cc406Sopenharmony_ci sp->Origin.y -= 4; 464141cc406Sopenharmony_ci } 465141cc406Sopenharmony_ci else if(sp->PhyDpi.x <= 300) 466141cc406Sopenharmony_ci { 467141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Color) 468141cc406Sopenharmony_ci sp->Origin.y += 16; 469141cc406Sopenharmony_ci else 470141cc406Sopenharmony_ci sp->Origin.y -= 18; 471141cc406Sopenharmony_ci } 472141cc406Sopenharmony_ci else if(sp->PhyDpi.x <= 400) 473141cc406Sopenharmony_ci { 474141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Color) 475141cc406Sopenharmony_ci sp->Origin.y += 15; 476141cc406Sopenharmony_ci else if(sp->bDataType == SCANDATATYPE_BW) 477141cc406Sopenharmony_ci sp->Origin.y += 4; 478141cc406Sopenharmony_ci } 479141cc406Sopenharmony_ci else /* if(sp->PhyDpi.x <= 600) */ 480141cc406Sopenharmony_ci { 481141cc406Sopenharmony_ci if (sp->bDataType == SCANDATATYPE_Gray) 482141cc406Sopenharmony_ci sp->Origin.y += 4; 483141cc406Sopenharmony_ci } 484141cc406Sopenharmony_ci } 485141cc406Sopenharmony_ci 486141cc406Sopenharmony_ci /* Add gray mode offset (Green offset, we assume the CCD are 487141cc406Sopenharmony_ci * always be RGB or BGR order). 488141cc406Sopenharmony_ci */ 489141cc406Sopenharmony_ci if (sp->bDataType != SCANDATATYPE_Color) 490141cc406Sopenharmony_ci sp->Origin.y += (u_long)(300UL * 491141cc406Sopenharmony_ci sCaps->bSensorDistance / sCaps->OpticDpi.y); 492141cc406Sopenharmony_ci } 493141cc406Sopenharmony_ci 494141cc406Sopenharmony_ci sp->Origin.y=(u_short)((u_long)sp->Origin.y * hw->wMotorDpi/300UL); 495141cc406Sopenharmony_ci 496141cc406Sopenharmony_ci /* Something wrong, but I can not find it. */ 497141cc406Sopenharmony_ci if( hw->motorModel == MODEL_HuaLien && sCaps->OpticDpi.x == 600) 498141cc406Sopenharmony_ci sp->Origin.y = sp->Origin.y * 297 / 298; 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci DBG(_DBG_INFO2,"* Full Steps to Skip at Start = 0x%04x\n", 501141cc406Sopenharmony_ci sp->Origin.y); 502141cc406Sopenharmony_ci 503141cc406Sopenharmony_ci regs[0x4a] = _HIBYTE( sp->Origin.y ); 504141cc406Sopenharmony_ci regs[0x4b] = _LOBYTE( sp->Origin.y ); 505141cc406Sopenharmony_ci} 506141cc406Sopenharmony_ci 507141cc406Sopenharmony_ci/** preset scan stepsize and fastfeed stepsize 508141cc406Sopenharmony_ci */ 509141cc406Sopenharmony_cistatic void 510141cc406Sopenharmony_ciusb_PresetStepSize( Plustek_Device *dev, ScanParam *pParam ) 511141cc406Sopenharmony_ci{ 512141cc406Sopenharmony_ci u_short ssize; 513141cc406Sopenharmony_ci double mclkdiv = pParam->dMCLK; 514141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 515141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 516141cc406Sopenharmony_ci 517141cc406Sopenharmony_ci ssize = (u_short)((double)CRYSTAL_FREQ / ( mclkdiv * 8.0 * 518141cc406Sopenharmony_ci (double)m_bCM * hw->dMaxMotorSpeed * 4.0 * (double)hw->wMotorDpi)); 519141cc406Sopenharmony_ci 520141cc406Sopenharmony_ci regs[0x46] = _HIBYTE( ssize ); 521141cc406Sopenharmony_ci regs[0x47] = _LOBYTE( ssize ); 522141cc406Sopenharmony_ci regs[0x48] = _HIBYTE( ssize ); 523141cc406Sopenharmony_ci regs[0x49] = _LOBYTE( ssize ); 524141cc406Sopenharmony_ci 525141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* StepSize(Preset) = %u (0x%04x)\n", ssize, ssize ); 526141cc406Sopenharmony_ci} 527141cc406Sopenharmony_ci 528141cc406Sopenharmony_ci/** calculate default phase difference DPD 529141cc406Sopenharmony_ci */ 530141cc406Sopenharmony_cistatic void 531141cc406Sopenharmony_ciusb_GetDPD( Plustek_Device *dev ) 532141cc406Sopenharmony_ci{ 533141cc406Sopenharmony_ci int qtcnt; /* quarter speed count count reg 51 b2..3 */ 534141cc406Sopenharmony_ci int hfcnt; /* half speed count reg 51 b0..1 */ 535141cc406Sopenharmony_ci int strev; /* steps to reverse reg 50 */ 536141cc406Sopenharmony_ci int dpd; /* calculated dpd reg 52:53 */ 537141cc406Sopenharmony_ci int st; /* step size reg 46:47 */ 538141cc406Sopenharmony_ci 539141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 540141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 541141cc406Sopenharmony_ci 542141cc406Sopenharmony_ci qtcnt = (regs[0x51] & 0x30) >> 4; /* quarter speed count */ 543141cc406Sopenharmony_ci hfcnt = (regs[0x51] & 0xc0) >> 6; /* half speed count */ 544141cc406Sopenharmony_ci 545141cc406Sopenharmony_ci if( _LM9831 == hw->chip ) 546141cc406Sopenharmony_ci strev = regs[0x50] & 0x3f; /* steps to reverse */ 547141cc406Sopenharmony_ci else /* LM9832/3 */ 548141cc406Sopenharmony_ci { 549141cc406Sopenharmony_ci if (qtcnt == 3) 550141cc406Sopenharmony_ci qtcnt = 8; 551141cc406Sopenharmony_ci if (hfcnt == 3) 552141cc406Sopenharmony_ci hfcnt = 8; 553141cc406Sopenharmony_ci strev = regs[0x50]; /* steps to reverse */ 554141cc406Sopenharmony_ci } 555141cc406Sopenharmony_ci 556141cc406Sopenharmony_ci st = regs[0x46] * 256 + regs[0x47]; /* scan step size */ 557141cc406Sopenharmony_ci 558141cc406Sopenharmony_ci if (m_wLineLength == 0) 559141cc406Sopenharmony_ci dpd = 0; 560141cc406Sopenharmony_ci else 561141cc406Sopenharmony_ci { 562141cc406Sopenharmony_ci dpd = (((qtcnt * 4) + (hfcnt * 2) + strev) * 4 * st) % 563141cc406Sopenharmony_ci (m_wLineLength * m_bLineRateColor); 564141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* DPD =%u (0x%04x)\n", dpd, dpd ); 565141cc406Sopenharmony_ci dpd = m_wLineLength * m_bLineRateColor - dpd; 566141cc406Sopenharmony_ci } 567141cc406Sopenharmony_ci 568141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* DPD =%u (0x%04x), step size=%u, steps2rev=%u\n", 569141cc406Sopenharmony_ci dpd, dpd, st, strev); 570141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* llen=%u, lineRateColor=%u, qtcnt=%u, hfcnt=%u\n", 571141cc406Sopenharmony_ci m_wLineLength, m_bLineRateColor, qtcnt, hfcnt ); 572141cc406Sopenharmony_ci 573141cc406Sopenharmony_ci regs[0x51] |= (u_char)((dpd >> 16) & 0x03); 574141cc406Sopenharmony_ci regs[0x52] = (u_char)(dpd >> 8); 575141cc406Sopenharmony_ci regs[0x53] = (u_char)(dpd & 0xFF); 576141cc406Sopenharmony_ci} 577141cc406Sopenharmony_ci 578141cc406Sopenharmony_ci#define MCLKDIV_SCALING 2 579141cc406Sopenharmony_ci#define _MIN(a,b) ((a) < (b) ? (a) : (b)) 580141cc406Sopenharmony_ci#define _MAX(a,b) ((a) > (b) ? (a) : (b)) 581141cc406Sopenharmony_ci 582141cc406Sopenharmony_ci/** 583141cc406Sopenharmony_ci */ 584141cc406Sopenharmony_cistatic int 585141cc406Sopenharmony_ciusb_GetMCLKDiv( Plustek_Device *dev ) 586141cc406Sopenharmony_ci{ 587141cc406Sopenharmony_ci int j, pixelbits, pixelsperline, r; 588141cc406Sopenharmony_ci int minmclk, maxmclk, mclkdiv; 589141cc406Sopenharmony_ci double hdpi, min_int_time; 590141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 591141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_GetMCLKDiv()\n" ); 594141cc406Sopenharmony_ci 595141cc406Sopenharmony_ci r = 8; /* line rate */ 596141cc406Sopenharmony_ci if ((regs[0x26] & 7) == 0) 597141cc406Sopenharmony_ci r = 24; /* pixel rate */ 598141cc406Sopenharmony_ci 599141cc406Sopenharmony_ci /* use high or low res min integration time */ 600141cc406Sopenharmony_ci min_int_time = ((regs[0x9]&7) > 2 ? hw->dMinIntegrationTimeLowres: 601141cc406Sopenharmony_ci hw->dMinIntegrationTimeHighres); 602141cc406Sopenharmony_ci 603141cc406Sopenharmony_ci minmclk = (int)ceil((double) MCLKDIV_SCALING * CRYSTAL_FREQ * 604141cc406Sopenharmony_ci min_int_time /((double)1000. * r * m_wLineLength)); 605141cc406Sopenharmony_ci minmclk = _MAX(minmclk,MCLKDIV_SCALING); 606141cc406Sopenharmony_ci 607141cc406Sopenharmony_ci maxmclk = (int)(32.5*MCLKDIV_SCALING + .5); 608141cc406Sopenharmony_ci 609141cc406Sopenharmony_ci DBG(_DBG_INFO2,"- lower mclkdiv limit=%f\n",(double)minmclk/MCLKDIV_SCALING); 610141cc406Sopenharmony_ci DBG(_DBG_INFO2,"- upper mclkdiv limit=%f\n",(double)maxmclk/MCLKDIV_SCALING); 611141cc406Sopenharmony_ci 612141cc406Sopenharmony_ci /* get the bits per pixel */ 613141cc406Sopenharmony_ci switch (regs[0x9] & 0x38) { 614141cc406Sopenharmony_ci case 0: pixelbits=1; break; 615141cc406Sopenharmony_ci case 0x8: pixelbits=2; break; 616141cc406Sopenharmony_ci case 0x10: pixelbits=4; break; 617141cc406Sopenharmony_ci case 0x18: pixelbits=8; break; 618141cc406Sopenharmony_ci default: pixelbits=16;break; 619141cc406Sopenharmony_ci } 620141cc406Sopenharmony_ci 621141cc406Sopenharmony_ci /* compute the horizontal dpi (pixels per inch) */ 622141cc406Sopenharmony_ci j = regs[0x9] & 0x7; 623141cc406Sopenharmony_ci hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1); 624141cc406Sopenharmony_ci 625141cc406Sopenharmony_ci pixelsperline = (int)((256*regs[0x24]+regs[0x25]-256*regs[0x22]-regs[0x23]) 626141cc406Sopenharmony_ci *pixelbits/(hdpi * 8)); 627141cc406Sopenharmony_ci mclkdiv = (int)ceil((double)MCLKDIV_SCALING * pixelsperline * CRYSTAL_FREQ 628141cc406Sopenharmony_ci /((double) 8. * m_wLineLength * dev->transferRate)); 629141cc406Sopenharmony_ci 630141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- hdpi = %.3f\n", hdpi ); 631141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- pixelbits = %u\n", pixelbits ); 632141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- pixelsperline = %u\n", pixelsperline ); 633141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- linelen = %u\n", m_wLineLength ); 634141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- transferrate = %lu\n", dev->transferRate ); 635141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING ); 636141cc406Sopenharmony_ci 637141cc406Sopenharmony_ci mclkdiv = _MAX(mclkdiv,minmclk); 638141cc406Sopenharmony_ci mclkdiv = _MIN(mclkdiv,maxmclk); 639141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- Current MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING ); 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ci if( dev->transferRate == 2000000 ) { 642141cc406Sopenharmony_ci while (mclkdiv * hdpi < 6.*MCLKDIV_SCALING) { 643141cc406Sopenharmony_ci mclkdiv++; 644141cc406Sopenharmony_ci } 645141cc406Sopenharmony_ci DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n", 646141cc406Sopenharmony_ci mclkdiv/MCLKDIV_SCALING ); 647141cc406Sopenharmony_ci } 648141cc406Sopenharmony_ci 649141cc406Sopenharmony_ci return mclkdiv; 650141cc406Sopenharmony_ci} 651141cc406Sopenharmony_ci 652141cc406Sopenharmony_ci/** Plusteks' poor-man MCLK calculation... 653141cc406Sopenharmony_ci * at least we give the master clock divider and adjust the step size 654141cc406Sopenharmony_ci * and integration time (for 14/16 bit modes) 655141cc406Sopenharmony_ci */ 656141cc406Sopenharmony_cistatic double 657141cc406Sopenharmony_ciusb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam ) 658141cc406Sopenharmony_ci{ 659141cc406Sopenharmony_ci double dMaxIntegrationTime; 660141cc406Sopenharmony_ci double dMaxMCLKDivider; 661141cc406Sopenharmony_ci 662141cc406Sopenharmony_ci DCapsDef *sCaps = &dev->usbDev.Caps; 663141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 664141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 665141cc406Sopenharmony_ci 666141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_GetMCLKDivider()\n" ); 667141cc406Sopenharmony_ci 668141cc406Sopenharmony_ci if( dev->transferRate == 2000000 ) { 669141cc406Sopenharmony_ci int mclkdiv = usb_GetMCLKDiv(dev); 670141cc406Sopenharmony_ci pParam->dMCLK = (double)mclkdiv/MCLKDIV_SCALING; 671141cc406Sopenharmony_ci } 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci m_dMCLKDivider = pParam->dMCLK; 674141cc406Sopenharmony_ci 675141cc406Sopenharmony_ci if (m_dHDPIDivider*m_dMCLKDivider >= 5.3/*6*/) 676141cc406Sopenharmony_ci m_bIntTimeAdjust = 0; 677141cc406Sopenharmony_ci else 678141cc406Sopenharmony_ci m_bIntTimeAdjust = ceil( 5.3/*6.0*/ / (m_dHDPIDivider*m_dMCLKDivider)); 679141cc406Sopenharmony_ci 680141cc406Sopenharmony_ci if( pParam->bCalibration == PARAM_Scan ) { 681141cc406Sopenharmony_ci 682141cc406Sopenharmony_ci usb_GetMCLKDiv(dev); 683141cc406Sopenharmony_ci 684141cc406Sopenharmony_ci /* Compare Integration with USB speed to find the best ITA value */ 685141cc406Sopenharmony_ci if( pParam->bBitDepth > 8 ) { 686141cc406Sopenharmony_ci 687141cc406Sopenharmony_ci while( pParam->Size.dwPhyBytes > 688141cc406Sopenharmony_ci (m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) * 689141cc406Sopenharmony_ci (1 + m_bIntTimeAdjust)) { 690141cc406Sopenharmony_ci m_bIntTimeAdjust++; 691141cc406Sopenharmony_ci } 692141cc406Sopenharmony_ci 693141cc406Sopenharmony_ci if( hw->motorModel == MODEL_HuaLien && 694141cc406Sopenharmony_ci sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) { 695141cc406Sopenharmony_ci m_bIntTimeAdjust = bMaxITA; 696141cc406Sopenharmony_ci } 697141cc406Sopenharmony_ci 698141cc406Sopenharmony_ci if(((hw->motorModel == MODEL_HP) && (sCaps->bCCD == kNECSLIM))/* || 699141cc406Sopenharmony_ci ( regs[0x26] & _ONE_CH_COLOR )*/) { 700141cc406Sopenharmony_ci 701141cc406Sopenharmony_ci bMaxITA = (u_char)floor((m_dMCLKDivider + 1) / 2.0); 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* MaxITA (HP) = %u\n", bMaxITA ); 704141cc406Sopenharmony_ci if( m_bIntTimeAdjust > bMaxITA ) { 705141cc406Sopenharmony_ci DBG( _DBG_INFO, "* ITA (%u) limited\n", m_bIntTimeAdjust ); 706141cc406Sopenharmony_ci m_bIntTimeAdjust = bMaxITA; 707141cc406Sopenharmony_ci } 708141cc406Sopenharmony_ci } 709141cc406Sopenharmony_ci } 710141cc406Sopenharmony_ci } 711141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Integration Time Adjust = %u (HDPI=%.3f,MCLKD=%.3f)\n", 712141cc406Sopenharmony_ci m_bIntTimeAdjust, m_dHDPIDivider, m_dMCLKDivider ); 713141cc406Sopenharmony_ci 714141cc406Sopenharmony_ci regs[0x08] = (u_char)((m_dMCLKDivider - 1) * 2); 715141cc406Sopenharmony_ci regs[0x19] = m_bIntTimeAdjust; 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci if( m_bIntTimeAdjust != 0 ) { 718141cc406Sopenharmony_ci 719141cc406Sopenharmony_ci m_wStepSize = (u_short)((u_long) m_wStepSize * 720141cc406Sopenharmony_ci (m_bIntTimeAdjust + 1) / m_bIntTimeAdjust); 721141cc406Sopenharmony_ci if( m_wStepSize < 2 ) 722141cc406Sopenharmony_ci m_wStepSize = 2; 723141cc406Sopenharmony_ci 724141cc406Sopenharmony_ci regs[0x46] = _HIBYTE(m_wStepSize); 725141cc406Sopenharmony_ci regs[0x47] = _LOBYTE(m_wStepSize); 726141cc406Sopenharmony_ci 727141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n", 728141cc406Sopenharmony_ci m_wStepSize, regs[0x46], regs[0x47] ); 729141cc406Sopenharmony_ci usb_GetDPD( dev ); 730141cc406Sopenharmony_ci } 731141cc406Sopenharmony_ci 732141cc406Sopenharmony_ci /* Compute maximum MCLK divider base on maximum integration time for 733141cc406Sopenharmony_ci * high lamp PWM, use equation 4 734141cc406Sopenharmony_ci */ 735141cc406Sopenharmony_ci dMaxIntegrationTime = hw->dIntegrationTimeHighLamp; 736141cc406Sopenharmony_ci dMaxMCLKDivider = (double)CRYSTAL_FREQ * dMaxIntegrationTime / 737141cc406Sopenharmony_ci (1000 * 8 * m_bCM * m_wLineLength); 738141cc406Sopenharmony_ci 739141cc406Sopenharmony_ci /* Determine lamp PWM setting */ 740141cc406Sopenharmony_ci if( m_dMCLKDivider > dMaxMCLKDivider ) { 741141cc406Sopenharmony_ci 742141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleLow\n" ); 743141cc406Sopenharmony_ci regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleLow ); 744141cc406Sopenharmony_ci regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleLow ); 745141cc406Sopenharmony_ci 746141cc406Sopenharmony_ci } else { 747141cc406Sopenharmony_ci 748141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleHigh\n" ); 749141cc406Sopenharmony_ci regs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleHigh ); 750141cc406Sopenharmony_ci regs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleHigh ); 751141cc406Sopenharmony_ci } 752141cc406Sopenharmony_ci 753141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Current MCLK Divider = %f\n", m_dMCLKDivider ); 754141cc406Sopenharmony_ci return m_dMCLKDivider; 755141cc406Sopenharmony_ci} 756141cc406Sopenharmony_ci 757141cc406Sopenharmony_ci/** calculate the step size of each scan step 758141cc406Sopenharmony_ci */ 759141cc406Sopenharmony_cistatic void 760141cc406Sopenharmony_ciusb_GetStepSize( Plustek_Device *dev, ScanParam *pParam ) 761141cc406Sopenharmony_ci{ 762141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 763141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci /* Compute step size using equation 1 */ 766141cc406Sopenharmony_ci if (m_bIntTimeAdjust != 0) { 767141cc406Sopenharmony_ci m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength * 768141cc406Sopenharmony_ci m_bLineRateColor * (m_bIntTimeAdjust + 1)) / 769141cc406Sopenharmony_ci (4 * hw->wMotorDpi * m_bIntTimeAdjust)); 770141cc406Sopenharmony_ci } else { 771141cc406Sopenharmony_ci m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength * 772141cc406Sopenharmony_ci m_bLineRateColor) / (4 * hw->wMotorDpi)); 773141cc406Sopenharmony_ci } 774141cc406Sopenharmony_ci 775141cc406Sopenharmony_ci if (m_wStepSize < 2) 776141cc406Sopenharmony_ci m_wStepSize = 2; 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_ci m_wStepSize = m_wStepSize * 298 / 297; 779141cc406Sopenharmony_ci 780141cc406Sopenharmony_ci regs[0x46] = _HIBYTE( m_wStepSize ); 781141cc406Sopenharmony_ci regs[0x47] = _LOBYTE( m_wStepSize ); 782141cc406Sopenharmony_ci 783141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n", 784141cc406Sopenharmony_ci m_wStepSize, regs[0x46], regs[0x47] ); 785141cc406Sopenharmony_ci} 786141cc406Sopenharmony_ci 787141cc406Sopenharmony_ci/** 788141cc406Sopenharmony_ci */ 789141cc406Sopenharmony_cistatic void 790141cc406Sopenharmony_ciusb_GetLineLength( Plustek_Device *dev, ScanParam *param ) 791141cc406Sopenharmony_ci{ 792141cc406Sopenharmony_ci/* [note] 793141cc406Sopenharmony_ci * The ITA in this moment is always 0, it will be changed later when we 794141cc406Sopenharmony_ci * calculate MCLK. This is very strange why this routine will not call 795141cc406Sopenharmony_ci * again to get all new value after ITA was changed? If this routine 796141cc406Sopenharmony_ci * never call again, maybe we remove all factor with ITA here. 797141cc406Sopenharmony_ci */ 798141cc406Sopenharmony_ci int tr; 799141cc406Sopenharmony_ci int tpspd; /* turbo/preview mode speed reg 0a b2..3 */ 800141cc406Sopenharmony_ci int tpsel; /* turbo/preview mode select reg 0a b0..1 */ 801141cc406Sopenharmony_ci int gbnd; /* guardband duration reg 0e b4..7 */ 802141cc406Sopenharmony_ci int dur; /* pulse duration reg 0e b0..3 */ 803141cc406Sopenharmony_ci int ntr; /* number of tr pulses reg 0d b7 */ 804141cc406Sopenharmony_ci int afeop; /* scan mode, 0=pixel rate, 1=line rate, */ 805141cc406Sopenharmony_ci /* 4=1 channel mode a, 5=1 channel mode b, reg 26 b0..2 */ 806141cc406Sopenharmony_ci int ctmode; /* CIS tr timing mode reg 19 b0..1 */ 807141cc406Sopenharmony_ci int tp; /* tpspd or 1 if tpsel=0 */ 808141cc406Sopenharmony_ci int b; /* if ctmode=0, (ntr+1)*((2*gbnd)+dur+1), otherwise 1 */ 809141cc406Sopenharmony_ci int tradj; /* ITA */ 810141cc406Sopenharmony_ci int en_tradj; 811141cc406Sopenharmony_ci u_short le; 812141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 813141cc406Sopenharmony_ci ClkMotorDef *motor = usb_GetMotorSet( hw->motorModel ); 814141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 815141cc406Sopenharmony_ci 816141cc406Sopenharmony_ci tpspd = (regs[0x0a] & 0x0c) >> 2; /* turbo/preview mode speed */ 817141cc406Sopenharmony_ci tpsel = regs[0x0a] & 3; /* turbo/preview mode select */ 818141cc406Sopenharmony_ci 819141cc406Sopenharmony_ci gbnd = (regs[0x0e] & 0xf0) >> 4; /* TR fi1 guardband duration */ 820141cc406Sopenharmony_ci dur = (regs[0x0e] & 0xf); /* TR pulse duration */ 821141cc406Sopenharmony_ci 822141cc406Sopenharmony_ci ntr = regs[0x0d] / 128; /* number of tr pulses */ 823141cc406Sopenharmony_ci 824141cc406Sopenharmony_ci afeop = regs[0x26] & 7; /* afe op - 3 channel or 1 channel */ 825141cc406Sopenharmony_ci 826141cc406Sopenharmony_ci tradj = regs[0x19] & 0x7f; /* integration time adjust */ 827141cc406Sopenharmony_ci en_tradj = (tradj) ? 1 : 0; 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci ctmode = (regs[0x0b] >> 3) & 3; /* cis tr timing mode */ 830141cc406Sopenharmony_ci 831141cc406Sopenharmony_ci m_bLineRateColor = 1; 832141cc406Sopenharmony_ci if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */ 833141cc406Sopenharmony_ci m_bLineRateColor = 3; 834141cc406Sopenharmony_ci 835141cc406Sopenharmony_ci /* according to turbo/preview mode to set value */ 836141cc406Sopenharmony_ci if( tpsel == 0 ) { 837141cc406Sopenharmony_ci tp = 1; 838141cc406Sopenharmony_ci } else { 839141cc406Sopenharmony_ci tp = tpspd + 2; 840141cc406Sopenharmony_ci if( tp == 5 ) 841141cc406Sopenharmony_ci tp++; 842141cc406Sopenharmony_ci } 843141cc406Sopenharmony_ci 844141cc406Sopenharmony_ci b = 1; 845141cc406Sopenharmony_ci if( ctmode == 0 ) { /* CCD mode scanner*/ 846141cc406Sopenharmony_ci 847141cc406Sopenharmony_ci b = (ntr + 1) * ((2 * gbnd) + dur + 1); 848141cc406Sopenharmony_ci b += (1 - ntr) * en_tradj; 849141cc406Sopenharmony_ci } 850141cc406Sopenharmony_ci if( ctmode == 2 ) /* CIS mode scanner */ 851141cc406Sopenharmony_ci b = 3; 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_ci /* it might be necessary to tweak this value, to keep the 854141cc406Sopenharmony_ci * MCLK constant - see some sheet-fed devices 855141cc406Sopenharmony_ci */ 856141cc406Sopenharmony_ci le = hw->wLineEnd; 857141cc406Sopenharmony_ci if (motor->dpi_thresh != 0) { 858141cc406Sopenharmony_ci if( param->PhyDpi.y <= motor->dpi_thresh) { 859141cc406Sopenharmony_ci le = motor->lineend; 860141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Adjusting lineend: %u\n", le); 861141cc406Sopenharmony_ci } 862141cc406Sopenharmony_ci regs[0x20] = _HIBYTE( le ); 863141cc406Sopenharmony_ci regs[0x21] = _LOBYTE( le ); 864141cc406Sopenharmony_ci } 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci tr = m_bLineRateColor * (le + tp * (b + 3 - ntr)); 867141cc406Sopenharmony_ci 868141cc406Sopenharmony_ci if( tradj == 0 ) { 869141cc406Sopenharmony_ci if( ctmode == 0 ) 870141cc406Sopenharmony_ci tr += m_bLineRateColor; 871141cc406Sopenharmony_ci } else { 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix; 874141cc406Sopenharmony_ci 875141cc406Sopenharmony_ci /* Line color or gray mode */ 876141cc406Sopenharmony_ci if( afeop != 0 ) { 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci le_phi = (tradj + 1) / 2 + 1 + 6; 879141cc406Sopenharmony_ci num_byteclk = ((le_phi + 8 * le + 8 * b + 4) / 880141cc406Sopenharmony_ci (8 * tradj)) + 1; 881141cc406Sopenharmony_ci num_mclkf = 8 * tradj * num_byteclk; 882141cc406Sopenharmony_ci tr_fast_pix = num_byteclk; 883141cc406Sopenharmony_ci extra_pix = (num_mclkf - le_phi) % 8; 884141cc406Sopenharmony_ci } 885141cc406Sopenharmony_ci else /* 3 channel pixel rate color */ 886141cc406Sopenharmony_ci { 887141cc406Sopenharmony_ci le_phi = (tradj + 1) / 2 + 1 + 10 + 12; 888141cc406Sopenharmony_ci num_byteclk = ((le_phi + 3 * 8 * le + 3 * 8 * b + 3 * 4) / 889141cc406Sopenharmony_ci (3 * 8 * tradj)) + 1; 890141cc406Sopenharmony_ci num_mclkf = 3 * 8 * tradj * num_byteclk; 891141cc406Sopenharmony_ci tr_fast_pix = num_byteclk; 892141cc406Sopenharmony_ci extra_pix = (num_mclkf - le_phi) % (3 * 8); 893141cc406Sopenharmony_ci } 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_ci tr = b + le + 4 + tr_fast_pix; 896141cc406Sopenharmony_ci if (extra_pix == 0) 897141cc406Sopenharmony_ci tr++; 898141cc406Sopenharmony_ci tr *= m_bLineRateColor; 899141cc406Sopenharmony_ci } 900141cc406Sopenharmony_ci m_wLineLength = tr / m_bLineRateColor; 901141cc406Sopenharmony_ci 902141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* LineLength=%d, LineRateColor=%u\n", 903141cc406Sopenharmony_ci m_wLineLength, m_bLineRateColor ); 904141cc406Sopenharmony_ci} 905141cc406Sopenharmony_ci 906141cc406Sopenharmony_ci/** usb_GetMotorParam 907141cc406Sopenharmony_ci * registers 0x56, 0x57 908141cc406Sopenharmony_ci */ 909141cc406Sopenharmony_cistatic void 910141cc406Sopenharmony_ciusb_GetMotorParam( Plustek_Device *dev, ScanParam *pParam ) 911141cc406Sopenharmony_ci{ 912141cc406Sopenharmony_ci int idx, i; 913141cc406Sopenharmony_ci ClkMotorDef *clk; 914141cc406Sopenharmony_ci MDef *md; 915141cc406Sopenharmony_ci DCapsDef *sCaps = &dev->usbDev.Caps; 916141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 917141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 918141cc406Sopenharmony_ci 919141cc406Sopenharmony_ci if (!_IS_PLUSTEKMOTOR(hw->motorModel)) { 920141cc406Sopenharmony_ci 921141cc406Sopenharmony_ci clk = usb_GetMotorSet( hw->motorModel ); 922141cc406Sopenharmony_ci md = clk->motor_sets; 923141cc406Sopenharmony_ci idx = 0; 924141cc406Sopenharmony_ci for( i = 0; i < _MAX_CLK; i++ ) { 925141cc406Sopenharmony_ci if( pParam->PhyDpi.y <= dpi_ranges[i] ) 926141cc406Sopenharmony_ci break; 927141cc406Sopenharmony_ci idx++; 928141cc406Sopenharmony_ci } 929141cc406Sopenharmony_ci if( idx >= _MAX_CLK ) 930141cc406Sopenharmony_ci idx = _MAX_CLK - 1; 931141cc406Sopenharmony_ci 932141cc406Sopenharmony_ci regs[0x56] = md[idx].pwm; 933141cc406Sopenharmony_ci regs[0x57] = md[idx].pwm_duty; 934141cc406Sopenharmony_ci 935141cc406Sopenharmony_ci regs[0x43] = 0; 936141cc406Sopenharmony_ci regs[0x44] = 0; 937141cc406Sopenharmony_ci 938141cc406Sopenharmony_ci if( md[idx].scan_lines_per_line > 1 ) { 939141cc406Sopenharmony_ci 940141cc406Sopenharmony_ci if((pParam->bBitDepth > 8) && 941141cc406Sopenharmony_ci (pParam->bDataType == SCANDATATYPE_Color)) { 942141cc406Sopenharmony_ci 943141cc406Sopenharmony_ci regs[0x43] = 0xff; 944141cc406Sopenharmony_ci regs[0x44] = md[idx].scan_lines_per_line; 945141cc406Sopenharmony_ci 946141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Line Skipping : 0x43=0x%02x, 0x44=0x%02x\n", 947141cc406Sopenharmony_ci regs[0x43], regs[0x44] ); 948141cc406Sopenharmony_ci } 949141cc406Sopenharmony_ci } 950141cc406Sopenharmony_ci } else { 951141cc406Sopenharmony_ci 952141cc406Sopenharmony_ci if( sCaps->OpticDpi.x == 1200 ) { 953141cc406Sopenharmony_ci 954141cc406Sopenharmony_ci switch( hw->motorModel ) { 955141cc406Sopenharmony_ci 956141cc406Sopenharmony_ci case MODEL_HuaLien: 957141cc406Sopenharmony_ci case MODEL_KaoHsiung: 958141cc406Sopenharmony_ci default: 959141cc406Sopenharmony_ci if(pParam->PhyDpi.x <= 200) 960141cc406Sopenharmony_ci { 961141cc406Sopenharmony_ci regs[0x56] = 1; 962141cc406Sopenharmony_ci regs[0x57] = 48; /* 63; */ 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 300) 965141cc406Sopenharmony_ci { 966141cc406Sopenharmony_ci regs[0x56] = 2; /* 8; */ 967141cc406Sopenharmony_ci regs[0x57] = 48; /* 56; */ 968141cc406Sopenharmony_ci } 969141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 400) 970141cc406Sopenharmony_ci { 971141cc406Sopenharmony_ci regs[0x56] = 8; 972141cc406Sopenharmony_ci regs[0x57] = 48; 973141cc406Sopenharmony_ci } 974141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 600) 975141cc406Sopenharmony_ci { 976141cc406Sopenharmony_ci regs[0x56] = 2; /* 10; */ 977141cc406Sopenharmony_ci regs[0x57] = 48; /* 56; */ 978141cc406Sopenharmony_ci } 979141cc406Sopenharmony_ci else /* pParam->PhyDpi.x == 1200) */ 980141cc406Sopenharmony_ci { 981141cc406Sopenharmony_ci regs[0x56] = 1; /* 8; */ 982141cc406Sopenharmony_ci regs[0x57] = 48; /* 56; */ 983141cc406Sopenharmony_ci } 984141cc406Sopenharmony_ci break; 985141cc406Sopenharmony_ci } 986141cc406Sopenharmony_ci } else { 987141cc406Sopenharmony_ci switch ( hw->motorModel ) { 988141cc406Sopenharmony_ci 989141cc406Sopenharmony_ci case MODEL_Tokyo600: 990141cc406Sopenharmony_ci regs[0x56] = 16; 991141cc406Sopenharmony_ci regs[0x57] = 4; /* 2; */ 992141cc406Sopenharmony_ci break; 993141cc406Sopenharmony_ci case MODEL_HuaLien: 994141cc406Sopenharmony_ci { 995141cc406Sopenharmony_ci if(pParam->PhyDpi.x <= 200) 996141cc406Sopenharmony_ci { 997141cc406Sopenharmony_ci regs[0x56] = 64; /* 24; */ 998141cc406Sopenharmony_ci regs[0x57] = 4; /* 16; */ 999141cc406Sopenharmony_ci } 1000141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 300) 1001141cc406Sopenharmony_ci { 1002141cc406Sopenharmony_ci regs[0x56] = 64; /* 16; */ 1003141cc406Sopenharmony_ci regs[0x57] = 4; /* 16; */ 1004141cc406Sopenharmony_ci } 1005141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 400) 1006141cc406Sopenharmony_ci { 1007141cc406Sopenharmony_ci regs[0x56] = 64; /* 16; */ 1008141cc406Sopenharmony_ci regs[0x57] = 4; /* 16; */ 1009141cc406Sopenharmony_ci } 1010141cc406Sopenharmony_ci else /* if(pParam->PhyDpi.x <= 600) */ 1011141cc406Sopenharmony_ci { 1012141cc406Sopenharmony_ci/* HEINER: check ADF stuff... */ 1013141cc406Sopenharmony_ci#if 0 1014141cc406Sopenharmony_ci if(ScanInf.m_fADF) 1015141cc406Sopenharmony_ci { 1016141cc406Sopenharmony_ci regs[0x56] = 8; 1017141cc406Sopenharmony_ci regs[0x57] = 48; 1018141cc406Sopenharmony_ci } 1019141cc406Sopenharmony_ci else 1020141cc406Sopenharmony_ci#endif 1021141cc406Sopenharmony_ci { 1022141cc406Sopenharmony_ci regs[0x56] = 64; /* 2; */ 1023141cc406Sopenharmony_ci regs[0x57] = 4; /* 48; */ 1024141cc406Sopenharmony_ci } 1025141cc406Sopenharmony_ci } 1026141cc406Sopenharmony_ci } 1027141cc406Sopenharmony_ci break; 1028141cc406Sopenharmony_ci case MODEL_KaoHsiung: 1029141cc406Sopenharmony_ci default: 1030141cc406Sopenharmony_ci if(pParam->PhyDpi.x <= 200) 1031141cc406Sopenharmony_ci { 1032141cc406Sopenharmony_ci regs[0x56] = 24; 1033141cc406Sopenharmony_ci regs[0x57] = 16; 1034141cc406Sopenharmony_ci } 1035141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 300) 1036141cc406Sopenharmony_ci { 1037141cc406Sopenharmony_ci regs[0x56] = 16; 1038141cc406Sopenharmony_ci regs[0x57] = 16; 1039141cc406Sopenharmony_ci } 1040141cc406Sopenharmony_ci else if(pParam->PhyDpi.x <= 400) 1041141cc406Sopenharmony_ci { 1042141cc406Sopenharmony_ci regs[0x56] = 16; 1043141cc406Sopenharmony_ci regs[0x57] = 16; 1044141cc406Sopenharmony_ci } 1045141cc406Sopenharmony_ci else /* if(pParam->PhyDpi.x <= 600) */ 1046141cc406Sopenharmony_ci { 1047141cc406Sopenharmony_ci regs[0x56] = 2; 1048141cc406Sopenharmony_ci regs[0x57] = 48; 1049141cc406Sopenharmony_ci } 1050141cc406Sopenharmony_ci break; 1051141cc406Sopenharmony_ci } 1052141cc406Sopenharmony_ci } 1053141cc406Sopenharmony_ci } 1054141cc406Sopenharmony_ci 1055141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* MOTOR-Settings: PWM=0x%02x, PWM_DUTY=0x%02x\n", 1056141cc406Sopenharmony_ci regs[0x56], regs[0x57] ); 1057141cc406Sopenharmony_ci} 1058141cc406Sopenharmony_ci 1059141cc406Sopenharmony_ci/** 1060141cc406Sopenharmony_ci */ 1061141cc406Sopenharmony_cistatic void 1062141cc406Sopenharmony_ciusb_GetPauseLimit( Plustek_Device *dev, ScanParam *pParam ) 1063141cc406Sopenharmony_ci{ 1064141cc406Sopenharmony_ci int coeffsize, scaler; 1065141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 1066141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 1067141cc406Sopenharmony_ci 1068141cc406Sopenharmony_ci scaler = 1; 1069141cc406Sopenharmony_ci if( hw->bReg_0x26 & _ONE_CH_COLOR ) { 1070141cc406Sopenharmony_ci if( pParam->bDataType == SCANDATATYPE_Color ) { 1071141cc406Sopenharmony_ci scaler = 3; 1072141cc406Sopenharmony_ci } 1073141cc406Sopenharmony_ci } 1074141cc406Sopenharmony_ci 1075141cc406Sopenharmony_ci /* compute size of coefficient ram */ 1076141cc406Sopenharmony_ci coeffsize = 4 + 16 + 16; /* gamma and shading and offset */ 1077141cc406Sopenharmony_ci 1078141cc406Sopenharmony_ci /* if 16 bit, then not all is used */ 1079141cc406Sopenharmony_ci if( regs[0x09] & 0x20 ) { 1080141cc406Sopenharmony_ci coeffsize = 16 + 16; /* no gamma */ 1081141cc406Sopenharmony_ci } 1082141cc406Sopenharmony_ci coeffsize *= (2*3); /* 3 colors and 2 bytes/word */ 1083141cc406Sopenharmony_ci 1084141cc406Sopenharmony_ci 1085141cc406Sopenharmony_ci /* Get available buffer size in KB 1086141cc406Sopenharmony_ci * for 512kb this will be 296 1087141cc406Sopenharmony_ci * for 2Mb this will be 1832 1088141cc406Sopenharmony_ci */ 1089141cc406Sopenharmony_ci m_dwPauseLimit = (u_long)(hw->wDRAMSize - (u_long)(coeffsize)); 1090141cc406Sopenharmony_ci m_dwPauseLimit -= ((pParam->Size.dwPhyBytes*scaler) / 1024 + 1); 1091141cc406Sopenharmony_ci 1092141cc406Sopenharmony_ci /* If not reversing, take into account the steps to reverse */ 1093141cc406Sopenharmony_ci if( regs[0x50] == 0 ) 1094141cc406Sopenharmony_ci m_dwPauseLimit -= ((regs[0x54] & 7) * 1095141cc406Sopenharmony_ci (pParam->Size.dwPhyBytes * scaler) + 1023) / 1024; 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* PL=%lu, coeffsize=%u, scaler=%u\n", 1098141cc406Sopenharmony_ci m_dwPauseLimit, coeffsize, scaler ); 1099141cc406Sopenharmony_ci 1100141cc406Sopenharmony_ci m_dwPauseLimit = usb_max( usb_min(m_dwPauseLimit, 1101141cc406Sopenharmony_ci (u_long)ceil(pParam->Size.dwTotalBytes / 1024.0)), 2); 1102141cc406Sopenharmony_ci 1103141cc406Sopenharmony_ci regs[0x4e] = (u_char)floor((m_dwPauseLimit*512.0)/(2.0*hw->wDRAMSize)); 1104141cc406Sopenharmony_ci 1105141cc406Sopenharmony_ci if( regs[0x4e] > 1 ) { 1106141cc406Sopenharmony_ci regs[0x4e]--; 1107141cc406Sopenharmony_ci if(regs[0x4e] > 1) 1108141cc406Sopenharmony_ci regs[0x4e]--; 1109141cc406Sopenharmony_ci } else 1110141cc406Sopenharmony_ci regs[0x4e] = 1; 1111141cc406Sopenharmony_ci 1112141cc406Sopenharmony_ci /* resume, when buffer is 2/8 kbytes full (512k/2M memory) 1113141cc406Sopenharmony_ci */ 1114141cc406Sopenharmony_ci regs[0x4f] = 1; 1115141cc406Sopenharmony_ci 1116141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* PauseLimit = %lu, [0x4e] = 0x%02x, [0x4f] = 0x%02x\n", 1117141cc406Sopenharmony_ci m_dwPauseLimit, regs[0x4e], regs[0x4f] ); 1118141cc406Sopenharmony_ci} 1119141cc406Sopenharmony_ci 1120141cc406Sopenharmony_ci/** usb_GetScanLinesAndSize 1121141cc406Sopenharmony_ci */ 1122141cc406Sopenharmony_cistatic void 1123141cc406Sopenharmony_ciusb_GetScanLinesAndSize( Plustek_Device *dev, ScanParam *pParam ) 1124141cc406Sopenharmony_ci{ 1125141cc406Sopenharmony_ci DCapsDef *sCaps = &dev->usbDev.Caps; 1126141cc406Sopenharmony_ci 1127141cc406Sopenharmony_ci pParam->Size.dwPhyLines = (u_long)ceil((double) pParam->Size.dwLines * 1128141cc406Sopenharmony_ci pParam->PhyDpi.y / pParam->UserDpi.y); 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ci /* Calculate color offset */ 1131141cc406Sopenharmony_ci if (pParam->bCalibration == PARAM_Scan && pParam->bChannels == 3) { 1132141cc406Sopenharmony_ci 1133141cc406Sopenharmony_ci dev->scanning.bLineDistance = sCaps->bSensorDistance * 1134141cc406Sopenharmony_ci pParam->PhyDpi.y / sCaps->OpticDpi.x; 1135141cc406Sopenharmony_ci pParam->Size.dwPhyLines += (dev->scanning.bLineDistance << 1); 1136141cc406Sopenharmony_ci } 1137141cc406Sopenharmony_ci else 1138141cc406Sopenharmony_ci dev->scanning.bLineDistance = 0; 1139141cc406Sopenharmony_ci 1140141cc406Sopenharmony_ci pParam->Size.dwTotalBytes = pParam->Size.dwPhyBytes * pParam->Size.dwPhyLines; 1141141cc406Sopenharmony_ci 1142141cc406Sopenharmony_ci DBG( _DBG_INFO, "* PhyBytes = %lu\n", pParam->Size.dwPhyBytes ); 1143141cc406Sopenharmony_ci DBG( _DBG_INFO, "* PhyLines = %lu\n", pParam->Size.dwPhyLines ); 1144141cc406Sopenharmony_ci DBG( _DBG_INFO, "* TotalBytes = %lu\n", pParam->Size.dwTotalBytes ); 1145141cc406Sopenharmony_ci} 1146141cc406Sopenharmony_ci 1147141cc406Sopenharmony_ci/** function to preset/reset the merlin registers 1148141cc406Sopenharmony_ci */ 1149141cc406Sopenharmony_cistatic SANE_Bool 1150141cc406Sopenharmony_ciusb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam ) 1151141cc406Sopenharmony_ci{ 1152141cc406Sopenharmony_ci static u_char reg8, reg38[6], reg48[2]; 1153141cc406Sopenharmony_ci 1154141cc406Sopenharmony_ci ScanDef *scan = &dev->scanning; 1155141cc406Sopenharmony_ci ScanParam *pdParam = &dev->scanning.sParam; 1156141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 1157141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_ci m_pParam = pParam; 1160141cc406Sopenharmony_ci 1161141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_SetScanParameters()\n" ); 1162141cc406Sopenharmony_ci 1163141cc406Sopenharmony_ci if( !usb_IsScannerReady(dev)) 1164141cc406Sopenharmony_ci return SANE_FALSE; 1165141cc406Sopenharmony_ci 1166141cc406Sopenharmony_ci if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) { 1167141cc406Sopenharmony_ci/* HEINER: dSaveMoveSpeed is only used in func EjectPaper!!! 1168141cc406Sopenharmony_ci dSaveMoveSpeed = hw->dMaxMoveSpeed; 1169141cc406Sopenharmony_ci*/ 1170141cc406Sopenharmony_ci hw->dMaxMoveSpeed = 1.0; 1171141cc406Sopenharmony_ci usb_MotorSelect( dev, SANE_TRUE ); 1172141cc406Sopenharmony_ci usb_MotorOn( dev, SANE_TRUE ); 1173141cc406Sopenharmony_ci } 1174141cc406Sopenharmony_ci 1175141cc406Sopenharmony_ci /* 1176141cc406Sopenharmony_ci * calculate the basic settings... 1177141cc406Sopenharmony_ci */ 1178141cc406Sopenharmony_ci pParam->PhyDpi.x = usb_SetAsicDpiX( dev, pParam->UserDpi.x ); 1179141cc406Sopenharmony_ci pParam->PhyDpi.y = usb_SetAsicDpiY( dev, pParam->UserDpi.y ); 1180141cc406Sopenharmony_ci 1181141cc406Sopenharmony_ci usb_SetColorAndBits( dev, pParam ); 1182141cc406Sopenharmony_ci usb_GetScanRect ( dev, pParam ); 1183141cc406Sopenharmony_ci 1184141cc406Sopenharmony_ci usb_PresetStepSize( dev, pParam ); 1185141cc406Sopenharmony_ci 1186141cc406Sopenharmony_ci if( dev->caps.dwFlag & SFLAG_ADF ) { 1187141cc406Sopenharmony_ci 1188141cc406Sopenharmony_ci if( pParam->bCalibration == PARAM_Scan ) { 1189141cc406Sopenharmony_ci 1190141cc406Sopenharmony_ci if( pdParam->bSource == SOURCE_ADF ) { 1191141cc406Sopenharmony_ci regs[0x50] = 0; 1192141cc406Sopenharmony_ci regs[0x51] = 0x40; 1193141cc406Sopenharmony_ci if( pParam->PhyDpi.x <= 300) 1194141cc406Sopenharmony_ci regs[0x54] = (regs[0x54] & ~7) | 4; /* 3; */ 1195141cc406Sopenharmony_ci else 1196141cc406Sopenharmony_ci regs[0x54] = (regs[0x54] & ~7) | 5; /* 4; */ 1197141cc406Sopenharmony_ci } else { 1198141cc406Sopenharmony_ci regs[0x50] = hw->bStepsToReverse; 1199141cc406Sopenharmony_ci regs[0x51] = hw->bReg_0x51; 1200141cc406Sopenharmony_ci regs[0x54] &= ~7; 1201141cc406Sopenharmony_ci } 1202141cc406Sopenharmony_ci } else 1203141cc406Sopenharmony_ci regs[0x50] = 0; 1204141cc406Sopenharmony_ci } else { 1205141cc406Sopenharmony_ci if( pParam->bCalibration == PARAM_Scan ) 1206141cc406Sopenharmony_ci regs[0x50] = hw->bStepsToReverse; 1207141cc406Sopenharmony_ci else 1208141cc406Sopenharmony_ci regs[0x50] = 0; 1209141cc406Sopenharmony_ci } 1210141cc406Sopenharmony_ci 1211141cc406Sopenharmony_ci /* Assume we will not use ITA */ 1212141cc406Sopenharmony_ci regs[0x19] = m_bIntTimeAdjust = 0; 1213141cc406Sopenharmony_ci 1214141cc406Sopenharmony_ci /* Get variables from calculation algorithms */ 1215141cc406Sopenharmony_ci if(!(pParam->bCalibration == PARAM_Scan && 1216141cc406Sopenharmony_ci pParam->bSource == SOURCE_ADF && dev->usbDev.fLastScanIsAdf )) { 1217141cc406Sopenharmony_ci 1218141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* Scan calculations...\n" ); 1219141cc406Sopenharmony_ci usb_GetLineLength ( dev, pParam ); 1220141cc406Sopenharmony_ci usb_GetStepSize ( dev, pParam ); 1221141cc406Sopenharmony_ci usb_GetDPD ( dev ); 1222141cc406Sopenharmony_ci usb_GetMCLKDivider( dev, pParam ); 1223141cc406Sopenharmony_ci usb_GetMotorParam ( dev, pParam ); 1224141cc406Sopenharmony_ci } 1225141cc406Sopenharmony_ci 1226141cc406Sopenharmony_ci /* Compute fast feed step size, use equation 3 and equation 8 */ 1227141cc406Sopenharmony_ci if( m_dMCLKDivider < 1.0) 1228141cc406Sopenharmony_ci m_dMCLKDivider = 1.0; 1229141cc406Sopenharmony_ci 1230141cc406Sopenharmony_ci m_wFastFeedStepSize = (u_short)(CRYSTAL_FREQ / 1231141cc406Sopenharmony_ci (m_dMCLKDivider * 8 * m_bCM * hw->dMaxMoveSpeed * 1232141cc406Sopenharmony_ci 4 * hw->wMotorDpi)); 1233141cc406Sopenharmony_ci /* CIS special ;-) */ 1234141cc406Sopenharmony_ci if((hw->bReg_0x26 & _ONE_CH_COLOR) && (m_bCM == 1)) { 1235141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* CIS FFStep-Speedup\n" ); 1236141cc406Sopenharmony_ci m_wFastFeedStepSize /= 3; 1237141cc406Sopenharmony_ci } 1238141cc406Sopenharmony_ci 1239141cc406Sopenharmony_ci if( m_bIntTimeAdjust != 0 ) 1240141cc406Sopenharmony_ci m_wFastFeedStepSize /= m_bIntTimeAdjust; 1241141cc406Sopenharmony_ci 1242141cc406Sopenharmony_ci if(regs[0x0a]) 1243141cc406Sopenharmony_ci m_wFastFeedStepSize *= ((regs[0x0a] >> 2) + 2); 1244141cc406Sopenharmony_ci regs[0x48] = _HIBYTE( m_wFastFeedStepSize ); 1245141cc406Sopenharmony_ci regs[0x49] = _LOBYTE( m_wFastFeedStepSize ); 1246141cc406Sopenharmony_ci 1247141cc406Sopenharmony_ci DBG( _DBG_INFO2, "* FFStepSize = %u, [0x48] = 0x%02x, [0x49] = 0x%02x\n", 1248141cc406Sopenharmony_ci m_wFastFeedStepSize, regs[0x48], regs[0x49] ); 1249141cc406Sopenharmony_ci 1250141cc406Sopenharmony_ci /* Compute the number of lines to scan using actual Y resolution */ 1251141cc406Sopenharmony_ci usb_GetScanLinesAndSize( dev, pParam ); 1252141cc406Sopenharmony_ci 1253141cc406Sopenharmony_ci /* Pause limit should be bounded by total bytes to read 1254141cc406Sopenharmony_ci * so that the chassis will not move too far. 1255141cc406Sopenharmony_ci */ 1256141cc406Sopenharmony_ci usb_GetPauseLimit( dev, pParam ); 1257141cc406Sopenharmony_ci 1258141cc406Sopenharmony_ci /* For ADF .... */ 1259141cc406Sopenharmony_ci if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) { 1260141cc406Sopenharmony_ci 1261141cc406Sopenharmony_ci if( dev->usbDev.fLastScanIsAdf ) { 1262141cc406Sopenharmony_ci 1263141cc406Sopenharmony_ci regs[0x08] = reg8; 1264141cc406Sopenharmony_ci memcpy( ®s[0x38], reg38, sizeof(reg38)); 1265141cc406Sopenharmony_ci memcpy( ®s[0x48], reg48, sizeof(reg48)); 1266141cc406Sopenharmony_ci 1267141cc406Sopenharmony_ci } else { 1268141cc406Sopenharmony_ci 1269141cc406Sopenharmony_ci reg8 = regs[0x08]; 1270141cc406Sopenharmony_ci memcpy( reg38, ®s[0x38], sizeof(reg38)); 1271141cc406Sopenharmony_ci memcpy( reg48, ®s[0x48], sizeof(reg48)); 1272141cc406Sopenharmony_ci } 1273141cc406Sopenharmony_ci usb_MotorSelect( dev, SANE_TRUE ); 1274141cc406Sopenharmony_ci } 1275141cc406Sopenharmony_ci 1276141cc406Sopenharmony_ci /* Reset LM983x's state machine before setting register values */ 1277141cc406Sopenharmony_ci if( !usbio_WriteReg( dev->fd, 0x18, 0x18 )) 1278141cc406Sopenharmony_ci return SANE_FALSE; 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci usleep(200 * 1000); /* Need to delay at least xxx microseconds */ 1281141cc406Sopenharmony_ci 1282141cc406Sopenharmony_ci if( !usbio_WriteReg( dev->fd, 0x07, 0x20 )) 1283141cc406Sopenharmony_ci return SANE_FALSE; 1284141cc406Sopenharmony_ci 1285141cc406Sopenharmony_ci if( !usbio_WriteReg( dev->fd, 0x19, 6 )) 1286141cc406Sopenharmony_ci return SANE_FALSE; 1287141cc406Sopenharmony_ci 1288141cc406Sopenharmony_ci regs[0x07] = 0; 1289141cc406Sopenharmony_ci regs[0x28] = 0; 1290141cc406Sopenharmony_ci 1291141cc406Sopenharmony_ci /* set unused registers to 0 */ 1292141cc406Sopenharmony_ci memset( ®s[0x03], 0, 3 ); 1293141cc406Sopenharmony_ci memset( ®s[0x5f], 0, 0x7f-0x5f+1 ); 1294141cc406Sopenharmony_ci 1295141cc406Sopenharmony_ci if( !usb_IsSheetFedDevice(dev)) { 1296141cc406Sopenharmony_ci /* we limit the possible scansteps to avoid, that the sensors bumps 1297141cc406Sopenharmony_ci * against the scanbed - not necessary for sheet-fed devices 1298141cc406Sopenharmony_ci */ 1299141cc406Sopenharmony_ci if(pParam->bCalibration==PARAM_Scan && pParam->bSource!=SOURCE_ADF) { 1300141cc406Sopenharmony_ci 1301141cc406Sopenharmony_ci u_long lines = pParam->Size.dwPhyLines + scan->bLinesToSkip + 1302141cc406Sopenharmony_ci scan->dwLinesDiscard + 5; 1303141cc406Sopenharmony_ci u_short scansteps = (u_short)ceil((double)lines* 1304141cc406Sopenharmony_ci hw->wMotorDpi / pParam->PhyDpi.y); 1305141cc406Sopenharmony_ci DBG( _DBG_INFO, "* Scansteps=%u (%lu*%u/%u)\n", scansteps, lines, 1306141cc406Sopenharmony_ci hw->wMotorDpi, pParam->PhyDpi.y ); 1307141cc406Sopenharmony_ci regs[0x4c] = _HIBYTE(scansteps); 1308141cc406Sopenharmony_ci regs[0x4d] = _LOBYTE(scansteps); 1309141cc406Sopenharmony_ci } 1310141cc406Sopenharmony_ci } 1311141cc406Sopenharmony_ci 1312141cc406Sopenharmony_ci /* set the merlin registers */ 1313141cc406Sopenharmony_ci _UIO(sanei_lm983x_write( dev->fd, 0x03, ®s[0x03], 3, SANE_TRUE)); 1314141cc406Sopenharmony_ci _UIO(sanei_lm983x_write( dev->fd, 0x08, ®s[0x08], 0x7f - 0x08+1, SANE_TRUE)); 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci usleep(100); 1317141cc406Sopenharmony_ci 1318141cc406Sopenharmony_ci if( !usbio_WriteReg( dev->fd, 0x07, 0 )) 1319141cc406Sopenharmony_ci return SANE_FALSE; 1320141cc406Sopenharmony_ci 1321141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_SetScanParameters() done.\n" ); 1322141cc406Sopenharmony_ci return SANE_TRUE; 1323141cc406Sopenharmony_ci} 1324141cc406Sopenharmony_ci 1325141cc406Sopenharmony_ci/** 1326141cc406Sopenharmony_ci */ 1327141cc406Sopenharmony_cistatic SANE_Bool 1328141cc406Sopenharmony_ciusb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park ) 1329141cc406Sopenharmony_ci{ 1330141cc406Sopenharmony_ci u_char value; 1331141cc406Sopenharmony_ci u_short inches; 1332141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 1333141cc406Sopenharmony_ci DCapsDef *sc = &dev->usbDev.Caps; 1334141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 1335141cc406Sopenharmony_ci 1336141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_ScanBegin()\n" ); 1337141cc406Sopenharmony_ci 1338141cc406Sopenharmony_ci if( !usb_Wait4ScanSample( dev )) 1339141cc406Sopenharmony_ci return SANE_FALSE; 1340141cc406Sopenharmony_ci 1341141cc406Sopenharmony_ci /* save the request for usb_ScanEnd () */ 1342141cc406Sopenharmony_ci m_fAutoPark = auto_park; 1343141cc406Sopenharmony_ci 1344141cc406Sopenharmony_ci /* Disable home sensor during scan, or the chassis cannot move */ 1345141cc406Sopenharmony_ci value = ((m_pParam->bCalibration == PARAM_Scan && 1346141cc406Sopenharmony_ci m_pParam->bSource == SOURCE_ADF)? (regs[0x58] & ~7): 0); 1347141cc406Sopenharmony_ci 1348141cc406Sopenharmony_ci if(!usbio_WriteReg( dev->fd, 0x58, value )) 1349141cc406Sopenharmony_ci return SANE_FALSE; 1350141cc406Sopenharmony_ci 1351141cc406Sopenharmony_ci /* Check if scanner is ready for receiving command */ 1352141cc406Sopenharmony_ci if( !usb_IsScannerReady(dev)) 1353141cc406Sopenharmony_ci return SANE_FALSE; 1354141cc406Sopenharmony_ci 1355141cc406Sopenharmony_ci /* Flush cache - only LM9831 (Source: National Semiconductors) */ 1356141cc406Sopenharmony_ci if( _LM9831 == hw->chip ) { 1357141cc406Sopenharmony_ci 1358141cc406Sopenharmony_ci for(;;) { 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci if( SANE_TRUE == cancelRead ) { 1361141cc406Sopenharmony_ci DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" ); 1362141cc406Sopenharmony_ci return SANE_FALSE; 1363141cc406Sopenharmony_ci } 1364141cc406Sopenharmony_ci 1365141cc406Sopenharmony_ci _UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData )); 1366141cc406Sopenharmony_ci if( m_bOldScanData ) { 1367141cc406Sopenharmony_ci 1368141cc406Sopenharmony_ci u_long dwBytesToRead = m_bOldScanData * hw->wDRAMSize * 4; 1369141cc406Sopenharmony_ci u_char *pBuffer = malloc( sizeof(u_char) * dwBytesToRead ); 1370141cc406Sopenharmony_ci 1371141cc406Sopenharmony_ci DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n", 1372141cc406Sopenharmony_ci dwBytesToRead, m_bOldScanData ); 1373141cc406Sopenharmony_ci 1374141cc406Sopenharmony_ci _UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer, 1375141cc406Sopenharmony_ci dwBytesToRead, SANE_FALSE )); 1376141cc406Sopenharmony_ci free( pBuffer ); 1377141cc406Sopenharmony_ci 1378141cc406Sopenharmony_ci } else 1379141cc406Sopenharmony_ci break; 1380141cc406Sopenharmony_ci } 1381141cc406Sopenharmony_ci } 1382141cc406Sopenharmony_ci 1383141cc406Sopenharmony_ci /* Download map & Shading data */ 1384141cc406Sopenharmony_ci if(( m_pParam->bCalibration == PARAM_Scan && !usb_MapDownload( dev )) || 1385141cc406Sopenharmony_ci !usb_DownloadShadingData( dev, m_pParam->bCalibration )) { 1386141cc406Sopenharmony_ci return SANE_FALSE; 1387141cc406Sopenharmony_ci } 1388141cc406Sopenharmony_ci 1389141cc406Sopenharmony_ci /* Move chassis and start to read image data */ 1390141cc406Sopenharmony_ci if (!usbio_WriteReg( dev->fd, 0x07, 3 )) 1391141cc406Sopenharmony_ci return SANE_FALSE; 1392141cc406Sopenharmony_ci 1393141cc406Sopenharmony_ci usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData ); 1394141cc406Sopenharmony_ci m_bOldScanData = 0; /* No data at all */ 1395141cc406Sopenharmony_ci 1396141cc406Sopenharmony_ci m_fStart = m_fFirst = SANE_TRUE; /* Prepare to read */ 1397141cc406Sopenharmony_ci 1398141cc406Sopenharmony_ci DBG( _DBG_DREGS, "Register Dump before reading data:\n" ); 1399141cc406Sopenharmony_ci dumpregs( dev->fd, NULL ); 1400141cc406Sopenharmony_ci 1401141cc406Sopenharmony_ci inches = (u_short)((m_pParam->Origin.y *300UL)/hw->wMotorDpi); 1402141cc406Sopenharmony_ci DBG( _DBG_INFO2, ">>> INCH=%u, DOY=%u\n", inches, sc->Normal.DataOrigin.y ); 1403141cc406Sopenharmony_ci if( inches > sc->Normal.DataOrigin.y ) 1404141cc406Sopenharmony_ci usb_WaitPos( dev, 150, SANE_FALSE ); 1405141cc406Sopenharmony_ci 1406141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_ScanBegin() done.\n" ); 1407141cc406Sopenharmony_ci return SANE_TRUE; 1408141cc406Sopenharmony_ci} 1409141cc406Sopenharmony_ci 1410141cc406Sopenharmony_ci/** usb_ScanEnd 1411141cc406Sopenharmony_ci * stop all the processing stuff and reposition sensor back home 1412141cc406Sopenharmony_ci */ 1413141cc406Sopenharmony_cistatic SANE_Bool 1414141cc406Sopenharmony_ciusb_ScanEnd( Plustek_Device *dev ) 1415141cc406Sopenharmony_ci{ 1416141cc406Sopenharmony_ci u_char value; 1417141cc406Sopenharmony_ci 1418141cc406Sopenharmony_ci DBG( _DBG_INFO, "usbDev_ScanEnd(), start=%u, park=%u\n", 1419141cc406Sopenharmony_ci m_fStart, m_fAutoPark ); 1420141cc406Sopenharmony_ci usbio_ReadReg( dev->fd, 0x07, &value ); 1421141cc406Sopenharmony_ci if( value == 3 || value != 2 ) 1422141cc406Sopenharmony_ci usbio_WriteReg( dev->fd, 0x07, 0 ); 1423141cc406Sopenharmony_ci 1424141cc406Sopenharmony_ci if( m_fStart ) { 1425141cc406Sopenharmony_ci m_fStart = SANE_FALSE; 1426141cc406Sopenharmony_ci 1427141cc406Sopenharmony_ci if( m_fAutoPark ) 1428141cc406Sopenharmony_ci usb_ModuleToHome( dev, SANE_FALSE ); 1429141cc406Sopenharmony_ci } 1430141cc406Sopenharmony_ci else if( SANE_TRUE == cancelRead ) { 1431141cc406Sopenharmony_ci 1432141cc406Sopenharmony_ci usb_ModuleToHome( dev, SANE_FALSE ); 1433141cc406Sopenharmony_ci } 1434141cc406Sopenharmony_ci return SANE_TRUE; 1435141cc406Sopenharmony_ci} 1436141cc406Sopenharmony_ci 1437141cc406Sopenharmony_ci/** 1438141cc406Sopenharmony_ci */ 1439141cc406Sopenharmony_cistatic SANE_Bool 1440141cc406Sopenharmony_ciusb_IsDataAvailableInDRAM( Plustek_Device *dev ) 1441141cc406Sopenharmony_ci{ 1442141cc406Sopenharmony_ci /* Compute polling timeout 1443141cc406Sopenharmony_ci * Height (Inches) / MaxScanSpeed (Inches/Second) = Seconds to move the 1444141cc406Sopenharmony_ci * module from top to bottom. Then convert the seconds to milliseconds 1445141cc406Sopenharmony_ci * by multiply 1000. We add extra 2 seconds to get some tolerance. 1446141cc406Sopenharmony_ci */ 1447141cc406Sopenharmony_ci u_char a_bBand[3]; 1448141cc406Sopenharmony_ci long dwTicks; 1449141cc406Sopenharmony_ci struct timeval t; 1450141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 1451141cc406Sopenharmony_ci 1452141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" ); 1453141cc406Sopenharmony_ci 1454141cc406Sopenharmony_ci gettimeofday( &t, NULL); 1455141cc406Sopenharmony_ci dwTicks = t.tv_sec + 30; 1456141cc406Sopenharmony_ci 1457141cc406Sopenharmony_ci for(;;) { 1458141cc406Sopenharmony_ci 1459141cc406Sopenharmony_ci _UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE )); 1460141cc406Sopenharmony_ci 1461141cc406Sopenharmony_ci gettimeofday( &t, NULL); 1462141cc406Sopenharmony_ci if( t.tv_sec > dwTicks ) 1463141cc406Sopenharmony_ci break; 1464141cc406Sopenharmony_ci 1465141cc406Sopenharmony_ci if( usb_IsEscPressed()) { 1466141cc406Sopenharmony_ci DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n"); 1467141cc406Sopenharmony_ci return SANE_FALSE; 1468141cc406Sopenharmony_ci } 1469141cc406Sopenharmony_ci 1470141cc406Sopenharmony_ci /* It is not stable for read */ 1471141cc406Sopenharmony_ci if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2])) 1472141cc406Sopenharmony_ci continue; 1473141cc406Sopenharmony_ci 1474141cc406Sopenharmony_ci if( a_bBand[0] > m_bOldScanData ) { 1475141cc406Sopenharmony_ci 1476141cc406Sopenharmony_ci if( m_pParam->bSource != SOURCE_Reflection ) 1477141cc406Sopenharmony_ci 1478141cc406Sopenharmony_ci usleep(1000*(30 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600)); 1479141cc406Sopenharmony_ci else 1480141cc406Sopenharmony_ci usleep(1000*(20 * regs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600)); 1481141cc406Sopenharmony_ci 1482141cc406Sopenharmony_ci DBG( _DBG_INFO, "Data is available\n" ); 1483141cc406Sopenharmony_ci return SANE_TRUE; 1484141cc406Sopenharmony_ci } 1485141cc406Sopenharmony_ci } 1486141cc406Sopenharmony_ci 1487141cc406Sopenharmony_ci DBG( _DBG_INFO, "NO Data available\n" ); 1488141cc406Sopenharmony_ci return SANE_FALSE; 1489141cc406Sopenharmony_ci} 1490141cc406Sopenharmony_ci 1491141cc406Sopenharmony_ci/** 1492141cc406Sopenharmony_ci */ 1493141cc406Sopenharmony_cistatic SANE_Bool 1494141cc406Sopenharmony_ciusb_ScanReadImage( Plustek_Device *dev, void *pBuf, u_long dwSize ) 1495141cc406Sopenharmony_ci{ 1496141cc406Sopenharmony_ci u_char *regs = dev->usbDev.a_bRegs; 1497141cc406Sopenharmony_ci SANE_Status res; 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci DBG( _DBG_READ, "usb_ScanReadImage(%lu)\n", dwSize ); 1500141cc406Sopenharmony_ci 1501141cc406Sopenharmony_ci if( m_fFirst ) { 1502141cc406Sopenharmony_ci 1503141cc406Sopenharmony_ci m_fFirst = SANE_FALSE; 1504141cc406Sopenharmony_ci 1505141cc406Sopenharmony_ci /* Wait for data band ready */ 1506141cc406Sopenharmony_ci if (!usb_IsDataAvailableInDRAM( dev )) { 1507141cc406Sopenharmony_ci DBG( _DBG_ERROR, "Nothing to read...\n" ); 1508141cc406Sopenharmony_ci return SANE_FALSE; 1509141cc406Sopenharmony_ci } 1510141cc406Sopenharmony_ci 1511141cc406Sopenharmony_ci /* restore the fast forward stepsize...*/ 1512141cc406Sopenharmony_ci sanei_lm983x_write(dev->fd, 0x48, ®s[0x48], 2, SANE_TRUE); 1513141cc406Sopenharmony_ci } 1514141cc406Sopenharmony_ci res = sanei_lm983x_read(dev->fd, 0x00, (u_char *)pBuf, dwSize, SANE_FALSE); 1515141cc406Sopenharmony_ci 1516141cc406Sopenharmony_ci /* check for pressed ESC button, as sanei_lm983x_read() may take some time 1517141cc406Sopenharmony_ci */ 1518141cc406Sopenharmony_ci if( usb_IsEscPressed()) { 1519141cc406Sopenharmony_ci DBG(_DBG_INFO,"usb_ScanReadImage() - Cancel detected...\n"); 1520141cc406Sopenharmony_ci return SANE_FALSE; 1521141cc406Sopenharmony_ci } 1522141cc406Sopenharmony_ci 1523141cc406Sopenharmony_ci DBG( _DBG_READ, "usb_ScanReadImage() done, result: %d\n", res ); 1524141cc406Sopenharmony_ci if( SANE_STATUS_GOOD == res ) { 1525141cc406Sopenharmony_ci return SANE_TRUE; 1526141cc406Sopenharmony_ci } 1527141cc406Sopenharmony_ci 1528141cc406Sopenharmony_ci DBG( _DBG_ERROR, "usb_ScanReadImage() failed\n" ); 1529141cc406Sopenharmony_ci return SANE_FALSE; 1530141cc406Sopenharmony_ci} 1531141cc406Sopenharmony_ci 1532141cc406Sopenharmony_ci/** calculate the number of pixels per line and lines out of a given 1533141cc406Sopenharmony_ci * crop-area. The size of the area is given on a 300dpi base! 1534141cc406Sopenharmony_ci */ 1535141cc406Sopenharmony_cistatic void 1536141cc406Sopenharmony_ciusb_GetImageInfo( Plustek_Device *dev, ImgDef *pInfo, WinInfo *pSize ) 1537141cc406Sopenharmony_ci{ 1538141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_GetImageInfo()\n" ); 1539141cc406Sopenharmony_ci 1540141cc406Sopenharmony_ci pSize->dwPixels = (u_long)pInfo->crArea.cx * pInfo->xyDpi.x / 300UL; 1541141cc406Sopenharmony_ci pSize->dwLines = (u_long)pInfo->crArea.cy * pInfo->xyDpi.y / 300UL; 1542141cc406Sopenharmony_ci 1543141cc406Sopenharmony_ci DBG( _DBG_INFO2,"Area: cx=%u, cy=%u\n",pInfo->crArea.cx,pInfo->crArea.cy); 1544141cc406Sopenharmony_ci 1545141cc406Sopenharmony_ci switch( pInfo->wDataType ) { 1546141cc406Sopenharmony_ci 1547141cc406Sopenharmony_ci case COLOR_TRUE48: 1548141cc406Sopenharmony_ci pSize->dwBytes = pSize->dwPixels * 6UL; 1549141cc406Sopenharmony_ci break; 1550141cc406Sopenharmony_ci 1551141cc406Sopenharmony_ci case COLOR_TRUE24: 1552141cc406Sopenharmony_ci if( dev->scanning.fGrayFromColor > 7 ){ 1553141cc406Sopenharmony_ci pSize->dwBytes = (pSize->dwPixels + 7UL) >> 3; 1554141cc406Sopenharmony_ci pSize->dwPixels = pSize->dwBytes * 8; 1555141cc406Sopenharmony_ci } else { 1556141cc406Sopenharmony_ci pSize->dwBytes = pSize->dwPixels * 3UL; 1557141cc406Sopenharmony_ci } 1558141cc406Sopenharmony_ci break; 1559141cc406Sopenharmony_ci 1560141cc406Sopenharmony_ci case COLOR_GRAY16: 1561141cc406Sopenharmony_ci pSize->dwBytes = pSize->dwPixels << 1; 1562141cc406Sopenharmony_ci break; 1563141cc406Sopenharmony_ci 1564141cc406Sopenharmony_ci case COLOR_256GRAY: 1565141cc406Sopenharmony_ci pSize->dwBytes = pSize->dwPixels; 1566141cc406Sopenharmony_ci break; 1567141cc406Sopenharmony_ci 1568141cc406Sopenharmony_ci default: 1569141cc406Sopenharmony_ci pSize->dwBytes = (pSize->dwPixels + 7UL) >> 3; 1570141cc406Sopenharmony_ci pSize->dwPixels = pSize->dwBytes * 8; 1571141cc406Sopenharmony_ci break; 1572141cc406Sopenharmony_ci } 1573141cc406Sopenharmony_ci} 1574141cc406Sopenharmony_ci 1575141cc406Sopenharmony_ci/** 1576141cc406Sopenharmony_ci */ 1577141cc406Sopenharmony_cistatic void 1578141cc406Sopenharmony_ciusb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo ) 1579141cc406Sopenharmony_ci{ 1580141cc406Sopenharmony_ci HWDef *hw = &dev->usbDev.HwSetting; 1581141cc406Sopenharmony_ci ScanParam *pParam = &dev->scanning.sParam; 1582141cc406Sopenharmony_ci 1583141cc406Sopenharmony_ci DBG( _DBG_INFO, "usb_SaveImageInfo()\n" ); 1584141cc406Sopenharmony_ci 1585141cc406Sopenharmony_ci /* Dpi & Origins */ 1586141cc406Sopenharmony_ci pParam->UserDpi = pInfo->xyDpi; 1587141cc406Sopenharmony_ci pParam->Origin.x = pInfo->crArea.x; 1588141cc406Sopenharmony_ci pParam->Origin.y = pInfo->crArea.y; 1589141cc406Sopenharmony_ci 1590141cc406Sopenharmony_ci /* Source & Bits */ 1591141cc406Sopenharmony_ci pParam->bBitDepth = 8; 1592141cc406Sopenharmony_ci 1593141cc406Sopenharmony_ci switch( pInfo->wDataType ) { 1594141cc406Sopenharmony_ci 1595141cc406Sopenharmony_ci case COLOR_TRUE48: 1596141cc406Sopenharmony_ci pParam->bBitDepth = 16; 1597141cc406Sopenharmony_ci /* fall through... */ 1598141cc406Sopenharmony_ci 1599141cc406Sopenharmony_ci case COLOR_TRUE24: 1600141cc406Sopenharmony_ci pParam->bDataType = SCANDATATYPE_Color; 1601141cc406Sopenharmony_ci 1602141cc406Sopenharmony_ci /* AFE operation: one or 3 channels ! */ 1603141cc406Sopenharmony_ci if( hw->bReg_0x26 & _ONE_CH_COLOR ) 1604141cc406Sopenharmony_ci pParam->bChannels = 1; 1605141cc406Sopenharmony_ci else 1606141cc406Sopenharmony_ci pParam->bChannels = 3; 1607141cc406Sopenharmony_ci break; 1608141cc406Sopenharmony_ci 1609141cc406Sopenharmony_ci case COLOR_GRAY16: 1610141cc406Sopenharmony_ci pParam->bBitDepth = 16; 1611141cc406Sopenharmony_ci /* fall through... */ 1612141cc406Sopenharmony_ci 1613141cc406Sopenharmony_ci case COLOR_256GRAY: 1614141cc406Sopenharmony_ci pParam->bDataType = SCANDATATYPE_Gray; 1615141cc406Sopenharmony_ci pParam->bChannels = 1; 1616141cc406Sopenharmony_ci break; 1617141cc406Sopenharmony_ci 1618141cc406Sopenharmony_ci default: 1619141cc406Sopenharmony_ci pParam->bBitDepth = 1; 1620141cc406Sopenharmony_ci pParam->bDataType = SCANDATATYPE_BW; 1621141cc406Sopenharmony_ci pParam->bChannels = 1; 1622141cc406Sopenharmony_ci } 1623141cc406Sopenharmony_ci 1624141cc406Sopenharmony_ci DBG( _DBG_INFO, "* dwFlag = 0x%08lx\n", pInfo->dwFlag ); 1625141cc406Sopenharmony_ci 1626141cc406Sopenharmony_ci if( pInfo->dwFlag & SCANDEF_Transparency ) 1627141cc406Sopenharmony_ci pParam->bSource = SOURCE_Transparency; 1628141cc406Sopenharmony_ci else if( pInfo->dwFlag & SCANDEF_Negative ) 1629141cc406Sopenharmony_ci pParam->bSource = SOURCE_Negative; 1630141cc406Sopenharmony_ci else if( pInfo->dwFlag & SCANDEF_Adf ) 1631141cc406Sopenharmony_ci pParam->bSource = SOURCE_ADF; 1632141cc406Sopenharmony_ci else 1633141cc406Sopenharmony_ci pParam->bSource = SOURCE_Reflection; 1634141cc406Sopenharmony_ci 1635141cc406Sopenharmony_ci /* it seems, that we need to adjust the Origin.x when we have a 1636141cc406Sopenharmony_ci * sheetfed device to avoid stripes in the resulting pictures 1637141cc406Sopenharmony_ci */ 1638141cc406Sopenharmony_ci if( usb_IsSheetFedDevice(dev)) { 1639141cc406Sopenharmony_ci 1640141cc406Sopenharmony_ci int step, div, org, xdpi; 1641141cc406Sopenharmony_ci 1642141cc406Sopenharmony_ci xdpi = usb_SetAsicDpiX( dev, pParam->UserDpi.x ); 1643141cc406Sopenharmony_ci 1644141cc406Sopenharmony_ci if ((xdpi * 2) <= 300) 1645141cc406Sopenharmony_ci div = 300; 1646141cc406Sopenharmony_ci else if ((xdpi * 2) <= 600) 1647141cc406Sopenharmony_ci div = 600; 1648141cc406Sopenharmony_ci else if ((xdpi * 2) <= 1200) 1649141cc406Sopenharmony_ci div = 1200; 1650141cc406Sopenharmony_ci else 1651141cc406Sopenharmony_ci div = 2400; 1652141cc406Sopenharmony_ci 1653141cc406Sopenharmony_ci step = div / xdpi; 1654141cc406Sopenharmony_ci org = pParam->Origin.x; 1655141cc406Sopenharmony_ci 1656141cc406Sopenharmony_ci pParam->Origin.x = (pParam->Origin.x / step) * step; 1657141cc406Sopenharmony_ci 1658141cc406Sopenharmony_ci if (org != pParam->Origin.x) 1659141cc406Sopenharmony_ci DBG(_DBG_INFO, "* Origin.x adjusted: %i -> %i\n", 1660141cc406Sopenharmony_ci org, pParam->Origin.x); 1661141cc406Sopenharmony_ci } 1662141cc406Sopenharmony_ci} 1663141cc406Sopenharmony_ci 1664141cc406Sopenharmony_ci/* END PLUSTEK-USBSCAN.C ....................................................*/ 1665