kopia lustrzana https://gitlab.com/sane-project/backends
				
				
				
			
		
			
				
	
	
		
			1528 wiersze
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			1528 wiersze
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
| /*.............................................................................
 | |
|  * Project : SANE library for Plustek flatbed scanners.
 | |
|  *.............................................................................
 | |
|  */
 | |
| 
 | |
| /** @file plustek-usbscan.c
 | |
|  *  @brief Scanning...
 | |
|  *
 | |
|  * Based on sources acquired from Plustek Inc.<br>
 | |
|  * Copyright (C) 2001-2004 Gerhard Jaeger <gerhard@gjaeger.de>
 | |
|  *
 | |
|  * History:
 | |
|  * - 0.40 - starting version of the USB support
 | |
|  * - 0.41 - minor fixes
 | |
|  * - 0.42 - added some stuff for CIS devices
 | |
|  * - 0.43 - no changes
 | |
|  * - 0.44 - added CIS specific settings and calculations
 | |
|  *        - removed usb_IsEscPressed
 | |
|  * - 0.45 - fixed the special setting stuff for CanoScan
 | |
|  *        - fixed pixel calculation for binary modes
 | |
|  *        - fixed cancel hang problem
 | |
|  *        - fixed CIS PhyBytes adjustment
 | |
|  *        - removed CanoScan specific setting stuff
 | |
|  * - 0.46 - fixed problem in usb_SetScanParameters()
 | |
|  * - 0.47 - no changes
 | |
|  * - 0.48 - minor fixes
 | |
|  * .
 | |
|  * <hr>
 | |
|  * This file is part of the SANE package.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of the
 | |
|  * License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 | |
|  * MA 02111-1307, USA.
 | |
|  *
 | |
|  * As a special exception, the authors of SANE give permission for
 | |
|  * additional uses of the libraries contained in this release of SANE.
 | |
|  *
 | |
|  * The exception is that, if you link a SANE library with other files
 | |
|  * to produce an executable, this does not by itself cause the
 | |
|  * resulting executable to be covered by the GNU General Public
 | |
|  * License.  Your use of that executable is in no way restricted on
 | |
|  * account of linking the SANE library code into it.
 | |
|  *
 | |
|  * This exception does not, however, invalidate any other reasons why
 | |
|  * the executable file might be covered by the GNU General Public
 | |
|  * License.
 | |
|  *
 | |
|  * If you submit changes to SANE to the maintainers to be included in
 | |
|  * a subsequent release, you agree by submitting the changes that
 | |
|  * those changes may be distributed with this exception intact.
 | |
|  *
 | |
|  * If you write modifications of your own for SANE, it is your choice
 | |
|  * whether to permit this exception to apply to your modifications.
 | |
|  * If you do not wish that, delete this exception notice.
 | |
|  * <hr>
 | |
|  */
 | |
| 
 | |
| /** array used to get motor-settings and mclk-settings
 | |
|  */
 | |
| static int dpi_ranges[] = {	75,100,150,200,300,400,600,800,1200,2400 };
 | |
| 
 | |
| static u_char     bMaxITA;
 | |
| 
 | |
| static SANE_Bool  m_fAutoPark;
 | |
| static SANE_Bool  m_fFirst;
 | |
| static double     m_dHDPIDivider;
 | |
| static double     m_dMCLKDivider;
 | |
| static pScanParam m_pParam;
 | |
| static u_char     m_bLineRateColor;
 | |
| static u_char     m_bCM;
 | |
| static u_char	  m_bIntTimeAdjust;
 | |
| static u_char	  m_bOldScanData;
 | |
| static u_short    m_wFastFeedStepSize;
 | |
| static u_short    m_wLineLength;
 | |
| static u_short	  m_wStepSize;
 | |
| static u_long     m_dwPauseLimit;
 | |
| 
 | |
| static SANE_Bool  m_fStart = SANE_FALSE;
 | |
| 
 | |
| /* Prototype... */
 | |
| static SANE_Bool usb_DownloadShadingData( Plustek_Device*, u_char );
 | |
| 
 | |
| /** returns the min of the two values val1 and val2
 | |
|  * @param val1 - first parameter
 | |
|  * @param val2 - second parameter
 | |
|  * @return val1 if val1 < val2, else val1
 | |
|  */
 | |
| static u_long usb_min( u_long val1, u_long val2 )
 | |
| {
 | |
| 	if( val1 > val2 )
 | |
| 		return val2;
 | |
| 
 | |
| 	return val1;
 | |
| }
 | |
| 
 | |
| /** returns the max of the two values val1 and val2
 | |
|  * @param val1 - first parameter
 | |
|  * @param val2 - second parameter
 | |
|  * @return val1 if val1 > val2, else val2
 | |
|  */
 | |
| static u_long usb_max( u_long val1, u_long val2 )
 | |
| {
 | |
| 	if( val1 > val2 )
 | |
| 		return val1;
 | |
| 
 | |
| 	return val2;
 | |
| }
 | |
| 
 | |
| /** Set the horizontal DPI divider.
 | |
|  * Affected registers:<br>
 | |
|  * 0x09 - Horizontal DPI divider HDPI_DIV<br>
 | |
|  *
 | |
|  * @param dev  - pointer to our device structure,
 | |
|  *               it should contain all we need
 | |
|  * @param xdpi - user specified horizontal resolution
 | |
|  * @return - the function returns the "normalized" horizontal resolution.
 | |
|  */
 | |
| static u_short usb_SetAsicDpiX( Plustek_Device *dev, u_short xdpi )
 | |
| {
 | |
| 	u_short   res;
 | |
|     pScanDef  scanning = &dev->scanning;
 | |
| 	pDCapsDef scaps    = &dev->usbDev.Caps;
 | |
| 
 | |
| 	/*
 | |
|      * limit xdpi to lower value for certain devices...
 | |
|      */
 | |
| 	if( scaps->OpticDpi.x == 1200 &&
 | |
| 		scanning->sParam.bDataType != SCANDATATYPE_Color &&
 | |
| 		xdpi < 150 &&
 | |
| 		scanning->sParam.bDataType == SCANDATATYPE_BW ) {
 | |
| 		xdpi = 150;
 | |
| 		DBG( _DBG_INFO2, "* LIMIT XDPI to %udpi\n", xdpi );
 | |
| 	}
 | |
| 
 | |
| 	m_dHDPIDivider = (double)scaps->OpticDpi.x / xdpi;
 | |
| 
 | |
| 	if (m_dHDPIDivider < 1.5)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 1.0;
 | |
| 		a_bRegs[0x09]  = 0;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 2.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 1.5;
 | |
| 		a_bRegs[0x09]  = 1;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 3.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 2.0;
 | |
| 		a_bRegs[0x09]  = 2;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 4.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 3.0;
 | |
| 		a_bRegs[0x09]  = 3;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 6.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 4.0;
 | |
| 		a_bRegs[0x09]  = 4;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 8.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 6.0;
 | |
| 		a_bRegs[0x09]  = 5;
 | |
| 	}
 | |
| 	else if (m_dHDPIDivider < 12.0)
 | |
| 	{
 | |
| 		m_dHDPIDivider = 8.0;
 | |
| 		a_bRegs[0x09]  = 6;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		m_dHDPIDivider = 12.0;
 | |
| 		a_bRegs[0x09]  = 7;
 | |
| 	}
 | |
| 
 | |
| 	/* adjust, if any turbo/preview mode is set, should be 0 here... */
 | |
| 	if( a_bRegs[0x0a] )
 | |
| 		a_bRegs[0x09] -= ((a_bRegs[0x0a] >> 2) + 2);
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* HDPI: %.3f\n", m_dHDPIDivider );
 | |
| 	res = (u_short)((double)scaps->OpticDpi.x / m_dHDPIDivider);
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* XDPI=%u, HDPI=%.3f\n", res, m_dHDPIDivider );
 | |
| 
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param dev  - pointer to our device structure,
 | |
|  *               it should contain all we need
 | |
|  * @param ydpi - user specified vertical resolution
 | |
|  * @return -
 | |
|  */
 | |
| static u_short usb_SetAsicDpiY( Plustek_Device *dev, u_short ydpi )
 | |
| {
 | |
|     pScanDef  scanning = &dev->scanning;
 | |
| 	pDCapsDef sCaps    = &dev->usbDev.Caps;
 | |
| 	pHWDef    hw       = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	u_short	wMinDpi, wDpi;
 | |
| 
 | |
| 	if(0 != sCaps->bSensorDistance )
 | |
| 		wMinDpi = sCaps->OpticDpi.y / sCaps->bSensorDistance;
 | |
| 	else
 | |
| 		wMinDpi = 75;
 | |
| 	
 | |
| 	/* Here we might have to check against the MinDpi value ! */
 | |
| 	wDpi = (ydpi + wMinDpi - 1) / wMinDpi * wMinDpi;
 | |
| 
 | |
| 	/*
 | |
| 	 * HEINER: added '*2'
 | |
| 	 */
 | |
| 	if( wDpi > sCaps->OpticDpi.y * 2 )
 | |
| 		wDpi = sCaps->OpticDpi.y * 2;
 | |
| 
 | |
| 	if( (hw->motorModel == MODEL_Tokyo600) ||
 | |
| 		!_IS_PLUSTEKMOTOR(hw->motorModel)) {
 | |
| 		/* return wDpi; */
 | |
| 	} else if( sCaps->wFlags & DEVCAPSFLAG_Adf && sCaps->OpticDpi.x == 600 ) {
 | |
| 		/* for ADF scanner color mode 300 dpi big noise */
 | |
| 		if( scanning->sParam.bDataType == SCANDATATYPE_Color &&
 | |
| 			scanning->sParam.bBitDepth > 8 && wDpi < 300 ) {
 | |
| 			wDpi = 300;
 | |
| 		}
 | |
| 	} else if( sCaps->OpticDpi.x == 1200 ) {
 | |
| 		if( scanning->sParam.bDataType != SCANDATATYPE_Color && wDpi < 200) {
 | |
| 			wDpi = 200;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* YDPI=%u, MinDPIY=%u\n", wDpi, wMinDpi );
 | |
| 	return wDpi;
 | |
| }
 | |
| 
 | |
| /** set color mode and sensor configuration stuff, according to the data mode
 | |
|  * Affected registers:<br>
 | |
|  * 0x26 - 0x27 - Color Mode settings<br>
 | |
|  * 0x0f - 0x18 - Sensor Configuration - directly from the HwDefs<br>
 | |
|  * 0x09        - add Data Mode and Pixel Packing<br>
 | |
|  *
 | |
|  * @param dev    - pointer to our device structure,
 | |
|  *                 it should contain all we need
 | |
|  * @param pParam - pointer to the current scan parameters
 | |
|  * @return - Nothing
 | |
|  */
 | |
| static void usb_SetColorAndBits( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	pHWDef hw = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	/*
 | |
|      * Set pixel packing, data mode and AFE operation
 | |
|      */
 | |
| 	switch( pParam->bDataType ) {
 | |
| 		case SCANDATATYPE_Color:
 | |
| 			m_bCM = 3;
 | |
| 			a_bRegs[0x26] = hw->bReg_0x26 & 0x7;
 | |
| 
 | |
| 			/* if set to one channel color, we select the blue channel
 | |
|              * as input source, this is the default, but I don't know
 | |
|              * what happens, if we deselect this
 | |
|              */
 | |
| 			if( a_bRegs[0x26] & _ONE_CH_COLOR )
 | |
| 				a_bRegs[0x26] |= (_BLUE_CH | 0x01);
 | |
| 
 | |
| 			memcpy( &a_bRegs[0x0f], hw->bReg_0x0f_Color, 10 );
 | |
| 			break;
 | |
| 
 | |
| 		case SCANDATATYPE_Gray:
 | |
| 			m_bCM = 1;
 | |
| 			a_bRegs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
 | |
| 			memcpy( &a_bRegs[0x0f], hw->bReg_0x0f_Mono, 10 );
 | |
| 			break;
 | |
| 
 | |
| 		case SCANDATATYPE_BW:
 | |
| 			m_bCM = 1;
 | |
| 			a_bRegs[0x26] = (hw->bReg_0x26 & 0x18) | 0x04;
 | |
| 			memcpy( &a_bRegs[0x0f], hw->bReg_0x0f_Mono, 10 );
 | |
| 			break;
 | |
| 	}
 | |
| 			
 | |
| 	a_bRegs[0x27] = hw->bReg_0x27;
 | |
| 
 | |
| 	if( pParam->bBitDepth > 8 ) {
 | |
| 		a_bRegs[0x09] |= 0x20;         /* 14/16bit image data */
 | |
| 
 | |
| 	} else if( pParam->bBitDepth == 8 ) {
 | |
| 		a_bRegs[0x09] |= 0x18;        /* 8bits/per pixel */
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /** Calculate basic image settings like the number of physical bytes per line
 | |
|  * etc...
 | |
|  * Affected registers:<br>
 | |
|  * 0x22/0x23 - Data Pixels Start<br>
 | |
|  * 0x24/0x25 - Data Pixels End<br>
 | |
|  * 0x4a/0x4b - Full Steps to Skip at Start of Scan
 | |
|  *
 | |
|  * @param dev    - pointer to our device structure,
 | |
|  *                 it should contain all we need
 | |
|  * @param pParam - pointer to the current scan parameters
 | |
|  * @return - Nothing
 | |
|  */
 | |
| static void usb_GetScanRect( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	u_short   wDataPixelStart, wLineEnd;
 | |
| 
 | |
| 	pDCapsDef sCaps = &dev->usbDev.Caps;
 | |
| 	pHWDef    hw    = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	/* Convert pixels to physical dpi based */
 | |
| 	pParam->Size.dwValidPixels = pParam->Size.dwPixels *
 | |
| 								 pParam->PhyDpi.x / pParam->UserDpi.x;
 | |
| 
 | |
| /* HEINER: check ADF stuff... */
 | |
| #if 0
 | |
| 	if(pParam->bCalibration != PARAM_Gain &&
 | |
| 		pParam->bCalibration != PARAM_Offset && ScanInf.m_fADF)
 | |
| 		wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
 | |
| 				(u_short)(m_dHDPIDivider * pParam->Size.dwValidPixels + 0.5);
 | |
| 	else
 | |
| #endif
 | |
| 		wDataPixelStart = (u_short)((u_long) pParam->Origin.x *
 | |
| 		                                            sCaps->OpticDpi.x / 300UL);
 | |
| 
 | |
| 	/* Data output from NS983X should be times of 2-byte and every line
 | |
|      * will append 2 status bytes
 | |
|      */
 | |
| 	if (pParam->bBitDepth == 1)
 | |
| 	{
 | |
| 		/* Pixels should be times of 16 */
 | |
| 		pParam->Size.dwPhyPixels =
 | |
| 							(pParam->Size.dwValidPixels + 15UL) & 0xfffffff0UL;
 | |
| 		pParam->Size.dwPhyBytes = pParam->Size.dwPhyPixels / 8UL + 2UL;
 | |
| 	}
 | |
| 	else if (pParam->bBitDepth == 8)
 | |
| 	{
 | |
| 		/* Pixels should be times of 2 */
 | |
| 		pParam->Size.dwPhyPixels =
 | |
| 							(pParam->Size.dwValidPixels + 1UL) & 0xfffffffeUL;
 | |
| 		pParam->Size.dwPhyBytes =
 | |
| 							pParam->Size.dwPhyPixels * pParam->bChannels + 2UL;
 | |
| 
 | |
| 		if((hw->bReg_0x26 & _ONE_CH_COLOR) &&
 | |
| 								(pParam->bDataType == SCANDATATYPE_Color)) {
 | |
| 			pParam->Size.dwPhyBytes *= 3;
 | |
| 		}
 | |
| 	}
 | |
| 	else /* pParam->bBitDepth == 16 */
 | |
| 	{
 | |
| 		pParam->Size.dwPhyPixels = pParam->Size.dwValidPixels;
 | |
| 		pParam->Size.dwPhyBytes =
 | |
| 						pParam->Size.dwPhyPixels * 2 * pParam->bChannels + 2UL;
 | |
| 
 | |
| 		if((hw->bReg_0x26 & _ONE_CH_COLOR) &&
 | |
| 								(pParam->bDataType == SCANDATATYPE_Color)) {
 | |
| 			pParam->Size.dwPhyBytes *= 3;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Compute data start pixel */
 | |
| 	wDataPixelStart = (u_short)((u_long)pParam->Origin.x *
 | |
| 	                                                sCaps->OpticDpi.x / 300UL);
 | |
| 
 | |
| 	/* during the calibration steps, we read the entire CCD data
 | |
| 	 */
 | |
| 	if((pParam->bCalibration != PARAM_Gain) &&
 | |
| 	   (pParam->bCalibration != PARAM_Offset)) {
 | |
| /* HEINER: check ADF stuff... */
 | |
| #if 0
 | |
| 		if(ScanInf.m_fADF) {
 | |
| 			wDataPixelStart = 2550 * sCaps->OpticDpi.x / 300UL -
 | |
| 				(u_short)(m_dHDPIDivider * pParam->Size.dwValidPixels + 0.5);
 | |
| 		}				
 | |
| #endif
 | |
| 		wDataPixelStart += hw->wActivePixelsStart;
 | |
| 	}
 | |
| 
 | |
| 	wLineEnd = wDataPixelStart + (u_short)(m_dHDPIDivider *
 | |
| 	                                           pParam->Size.dwPhyPixels + 0.5);
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u\n",
 | |
| 	                                               wDataPixelStart, wLineEnd );
 | |
| 	if( wDataPixelStart & 1 ) {
 | |
| 
 | |
| 		wDataPixelStart++;
 | |
| 		wLineEnd++;
 | |
| 
 | |
| 		DBG( _DBG_INFO2, "* DataPixelStart=%u, LineEnd=%u (ADJ)\n",
 | |
| 		                                           wDataPixelStart, wLineEnd );
 | |
| 	}
 | |
| 
 | |
| 	a_bRegs[0x22] = _HIBYTE( wDataPixelStart );
 | |
| 	a_bRegs[0x23] = _LOBYTE( wDataPixelStart );
 | |
| 
 | |
| 	/* should match: wLineEnd-wDataPixelStart%(m_dHDPIDivider*2) = 0!! */
 | |
| 	a_bRegs[0x24] = _HIBYTE( wLineEnd );
 | |
| 	a_bRegs[0x25] = _LOBYTE( wLineEnd );
 | |
| 
 | |
| 	DBG( _DBG_INFO2, ">> End-Start=%u, HDPI=%.2f\n",
 | |
| 	                                 wLineEnd-wDataPixelStart, m_dHDPIDivider);
 | |
| 
 | |
| 	/* Y origin */
 | |
| 	if( pParam->bCalibration == PARAM_Scan ) {
 | |
| 
 | |
| 		if( hw->motorModel == MODEL_Tokyo600 ) {
 | |
| 
 | |
| 			if(pParam->PhyDpi.x <= 75)
 | |
| 				pParam->Origin.y += 20;
 | |
| 			else if(pParam->PhyDpi.x <= 100)
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Color)
 | |
| 					pParam->Origin.y += 0;
 | |
| 				else
 | |
| 					pParam->Origin.y -= 6;
 | |
| 			}
 | |
| 			else if(pParam->PhyDpi.x <= 150)
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Color)
 | |
| 					pParam->Origin.y -= 0;
 | |
| 			}
 | |
| 			else if(pParam->PhyDpi.x <= 200)
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Color)
 | |
| 					pParam->Origin.y -= 10;
 | |
| 				else
 | |
| 					pParam->Origin.y -= 4;
 | |
| 			}
 | |
| 			else if(pParam->PhyDpi.x <= 300)
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Color)
 | |
| 					pParam->Origin.y += 16;
 | |
| 				else
 | |
| 					pParam->Origin.y -= 18;
 | |
| 			}
 | |
| 			else if(pParam->PhyDpi.x <= 400)
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Color)
 | |
| 					pParam->Origin.y += 15;
 | |
| 				else if(pParam->bDataType == SCANDATATYPE_BW)
 | |
| 					pParam->Origin.y += 4;
 | |
| 			}
 | |
| 			else /* if(pParam->PhyDpi.x <= 600) */
 | |
| 			{
 | |
| 				if (pParam->bDataType == SCANDATATYPE_Gray)
 | |
| 					pParam->Origin.y += 4;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/* Add gray mode offset (Green offset, we assume the CCD are
 | |
| 		 * always be RGB or BGR order).
 | |
| 		 */
 | |
| 		if (pParam->bDataType != SCANDATATYPE_Color)
 | |
| 			pParam->Origin.y += (u_long)(300UL *
 | |
| 							       sCaps->bSensorDistance / sCaps->OpticDpi.y);
 | |
| 	}
 | |
| 
 | |
| 	pParam->Origin.y=(u_short)((u_long)pParam->Origin.y * hw->wMotorDpi/300UL);
 | |
| 
 | |
| 	/* Something wrong, but I can not find it. */
 | |
| 	if( hw->motorModel == MODEL_HuaLien && sCaps->OpticDpi.x == 600)
 | |
| 		pParam->Origin.y = pParam->Origin.y * 297 / 298;
 | |
| 
 | |
| 	DBG(_DBG_INFO2,"* Full Steps to Skip at Start = 0x%04x\n",pParam->Origin.y);
 | |
| 
 | |
| 	a_bRegs[0x4a] = _HIBYTE( pParam->Origin.y );
 | |
| 	a_bRegs[0x4b] = _LOBYTE( pParam->Origin.y );
 | |
| }
 | |
| 
 | |
| /** preset scan stepsize and fastfeed stepsize
 | |
|  */
 | |
| static void usb_PresetStepSize( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	u_short ssize;
 | |
| 	double  mclkdiv = pParam->dMCLK;
 | |
| 	pHWDef  hw      = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	ssize = (u_short)((double)dwCrystalFrequency / ( mclkdiv * 8.0 *
 | |
|             (double)m_bCM * hw->dMaxMotorSpeed * 4.0 * (double)hw->wMotorDpi));
 | |
| 
 | |
| 	a_bRegs[0x46] = _HIBYTE( ssize );
 | |
| 	a_bRegs[0x47] = _LOBYTE( ssize );
 | |
| 	a_bRegs[0x48] = _HIBYTE( ssize );
 | |
| 	a_bRegs[0x49] = _LOBYTE( ssize );
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* StepSize(Preset) = %u (0x%04x)\n", ssize, ssize );
 | |
| }
 | |
| 
 | |
| /** calculate default phase difference DPD
 | |
|  */
 | |
| static void usb_GetDPD( Plustek_Device *dev  )
 | |
| {
 | |
| 	int    qtcnt;	/* quarter speed count count reg 51 b2..3 */
 | |
| 	int    hfcnt;	/* half speed count reg 51 b0..1          */
 | |
| 	int    strev;	/* steps to reverse reg 50                */
 | |
| 	int    dpd;	    /* calculated dpd reg 52:53               */
 | |
| 	int    st;		/* step size reg 46:47                    */
 | |
| 
 | |
| 	pHWDef hw = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	qtcnt = (a_bRegs [0x51] & 0x30) >> 4;	/* quarter speed count */
 | |
| 	hfcnt = (a_bRegs [0x51] & 0xc0) >> 6;	/* half speed count    */
 | |
| 
 | |
| 	if( _LM9831 == hw->chip )
 | |
| 		strev = a_bRegs [0x50] & 0x3f;		/* steps to reverse */
 | |
| 	else /* LM9832/3 */
 | |
| 	{
 | |
| 		if (qtcnt == 3)
 | |
| 			qtcnt = 8;
 | |
| 		if (hfcnt == 3)
 | |
| 			hfcnt = 8;
 | |
| 		strev = a_bRegs[0x50]; /* steps to reverse */
 | |
| 	}
 | |
| 
 | |
| 	st = a_bRegs[0x46] * 256 + a_bRegs[0x47]; /* scan step size */
 | |
| 
 | |
| 	if (m_wLineLength == 0)
 | |
| 		dpd = 0;
 | |
| 	else
 | |
| 	{
 | |
| 		dpd = (((qtcnt * 4) + (hfcnt * 2) + strev) * 4 * st) %
 | |
| 					 (m_wLineLength * m_bLineRateColor);
 | |
| 		DBG( _DBG_INFO2, "* DPD =%u (0x%04x)\n", dpd, dpd );
 | |
| 		dpd = m_wLineLength * m_bLineRateColor - dpd;
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* DPD =%u (0x%04x), step size=%u, steps2rev=%u\n",
 | |
| 														dpd, dpd, st, strev);
 | |
| 	DBG( _DBG_INFO2, "* llen=%u, lineRateColor=%u, qtcnt=%u, hfcnt=%u\n",
 | |
| 						  m_wLineLength, m_bLineRateColor, qtcnt, hfcnt );
 | |
| 
 | |
| 	a_bRegs[0x51] |= (u_char)((dpd >> 16) & 0x03);
 | |
| 	a_bRegs[0x52] = (u_char)(dpd >> 8);
 | |
| 	a_bRegs[0x53] = (u_char)(dpd & 0xFF);
 | |
| }
 | |
| 
 | |
| /** Plusteks' poor-man MCLK calculation...
 | |
|  * at least we give the master clock divider and adjust the step size
 | |
|  * and integration time (for 14/16 bit modes)
 | |
|  */
 | |
| static double usb_GetMCLKDivider( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	double dMaxIntegrationTime;
 | |
| 	double dMaxMCLKDivider;
 | |
| 
 | |
| 	pDCapsDef sCaps = &dev->usbDev.Caps;
 | |
| 	pHWDef    hw    = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_GetMCLKDivider()\n" );
 | |
| 
 | |
| 	m_dMCLKDivider = pParam->dMCLK;
 | |
| 
 | |
| 	if (m_dHDPIDivider*m_dMCLKDivider >= 5.3/*6*/)
 | |
| 		m_bIntTimeAdjust = 0;
 | |
| 	else
 | |
| 		m_bIntTimeAdjust = ceil( 5.3/*6.0*/ / (m_dHDPIDivider*m_dMCLKDivider));
 | |
| 
 | |
| 	if( pParam->bCalibration == PARAM_Scan ) {
 | |
|   
 | |
| 		/*  Compare Integration with USB speed to find the best ITA value */
 | |
| 		if( pParam->bBitDepth > 8 )	{
 | |
| 
 | |
| 			while( pParam->Size.dwPhyBytes >
 | |
| 					(m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) *
 | |
|  													  (1 + m_bIntTimeAdjust)) {
 | |
| 				m_bIntTimeAdjust++;
 | |
| 			}	
 | |
| 
 | |
| 			if( hw->motorModel == MODEL_HuaLien &&
 | |
| 				sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) {
 | |
| 				m_bIntTimeAdjust = bMaxITA;
 | |
| 			}
 | |
| 
 | |
| 			if(((hw->motorModel == MODEL_HP) && (sCaps->bCCD == kNECSLIM))/* ||
 | |
| 			 	( a_bRegs[0x26] & _ONE_CH_COLOR )*/) {
 | |
| 
 | |
|        			bMaxITA = (u_char)floor((m_dMCLKDivider + 1) / 2.0);
 | |
| 
 | |
| 				DBG( _DBG_INFO2, "* MaxITA (HP) = %u\n", bMaxITA );
 | |
| 				if( m_bIntTimeAdjust > bMaxITA ) {
 | |
| 					DBG( _DBG_INFO, "* ITA (%u) limited\n", m_bIntTimeAdjust );
 | |
| 					m_bIntTimeAdjust = bMaxITA;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	DBG( _DBG_INFO2, "* Integration Time Adjust = %u (HDPI=%.3f,MCLKD=%.3f)\n",
 | |
| 							m_bIntTimeAdjust, m_dHDPIDivider, m_dMCLKDivider );
 | |
| 
 | |
| 	a_bRegs[0x08] = (u_char)((m_dMCLKDivider - 1) * 2);
 | |
| 	a_bRegs[0x19] = m_bIntTimeAdjust;
 | |
| 
 | |
| 	if( m_bIntTimeAdjust != 0 ) {
 | |
| 
 | |
| 		m_wStepSize = (u_short)((u_long) m_wStepSize *
 | |
| 									(m_bIntTimeAdjust + 1) / m_bIntTimeAdjust);
 | |
| 		if( m_wStepSize < 2 )
 | |
| 			m_wStepSize = 2;
 | |
| 
 | |
| 		a_bRegs[0x46] = _HIBYTE(m_wStepSize);
 | |
| 		a_bRegs[0x47] = _LOBYTE(m_wStepSize);
 | |
| 
 | |
| 		DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
 | |
| 		                   m_wStepSize, a_bRegs[0x46], a_bRegs[0x47] );
 | |
| 	    usb_GetDPD( dev );
 | |
| 	}
 | |
| 	
 | |
| 	/* Compute maximum MCLK divider base on maximum integration time for
 | |
|      * high lamp PWM, use equation 4
 | |
|      */
 | |
| 	dMaxIntegrationTime = hw->dIntegrationTimeHighLamp;
 | |
| 	dMaxMCLKDivider = (double)dwCrystalFrequency * dMaxIntegrationTime /
 | |
| 					   (1000 * 8 * m_bCM * m_wLineLength);
 | |
| 
 | |
| 	/* Determine lamp PWM setting */
 | |
| 	if( m_dMCLKDivider > dMaxMCLKDivider ) {
 | |
| 
 | |
| 		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleLow\n" );
 | |
| 		a_bRegs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleLow );
 | |
| 		a_bRegs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleLow );
 | |
| 
 | |
| 	} else {
 | |
| 
 | |
| 		DBG( _DBG_INFO2, "* Setting GreenPWMDutyCycleHigh\n" );
 | |
| 		a_bRegs[0x2a] = _HIBYTE( hw->wGreenPWMDutyCycleHigh );
 | |
| 		a_bRegs[0x2b] = _LOBYTE( hw->wGreenPWMDutyCycleHigh );
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* Current MCLK Divider = %f\n", m_dMCLKDivider );
 | |
| 	return m_dMCLKDivider;
 | |
| }
 | |
| 
 | |
| /** calculate the step size of each scan step
 | |
|  */
 | |
| static void usb_GetStepSize( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	pHWDef hw = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	/* Compute step size using equation 1 */
 | |
| 	if (m_bIntTimeAdjust != 0) {
 | |
| 		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
 | |
| 								   m_bLineRateColor * (m_bIntTimeAdjust + 1)) /
 | |
| 									 (4 * hw->wMotorDpi * m_bIntTimeAdjust));
 | |
| 	} else {
 | |
| 		m_wStepSize = (u_short)(((u_long) pParam->PhyDpi.y * m_wLineLength *
 | |
| 								   m_bLineRateColor) / (4 * hw->wMotorDpi));
 | |
| 	}
 | |
| 									   
 | |
| 	if (m_wStepSize < 2)
 | |
| 		m_wStepSize = 2;
 | |
| 
 | |
| 	m_wStepSize = m_wStepSize * 298 / 297;
 | |
| 
 | |
| 	a_bRegs[0x46] = _HIBYTE( m_wStepSize );
 | |
| 	a_bRegs[0x47] = _LOBYTE( m_wStepSize );
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* Stepsize = %u, 0x46=0x%02x 0x47=0x%02x\n",
 | |
| 	                  m_wStepSize, a_bRegs[0x46], a_bRegs[0x47] );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static void usb_GetLineLength( Plustek_Device *dev )
 | |
| {
 | |
| /* [note]
 | |
|  *	The ITA in this moment is always 0, it will be changed later when we
 | |
|  *  calculate MCLK. This is very strange why this routine will not call
 | |
|  *  again to get all new value after ITA was changed? If this routine
 | |
|  *  never call again, maybe we remove all factor with ITA here.
 | |
|  */
 | |
| 	int tr;
 | |
| 	int tpspd;	/* turbo/preview mode speed reg 0a b2..3                 */
 | |
| 	int tpsel;	/* turbo/preview mode select reg 0a b0..1                */
 | |
| 	int gbnd;	/* guardband duration reg 0e b4..7                       */
 | |
| 	int dur;	/* pulse duration reg 0e b0..3                           */
 | |
| 	int ntr;	/* number of tr pulses reg 0d b7                         */
 | |
| 	int afeop;	/* scan mode, 0=pixel rate, 1=line rate,                 */
 | |
| 				/* 4=1 channel mode a, 5=1 channel mode b, reg 26 b0..2  */
 | |
| 	int ctmode;	/* CIS tr timing mode reg 19 b0..1                       */
 | |
| 	int tp;		/* tpspd or 1 if tpsel=0                                 */
 | |
| 	int b;		/* if ctmode=0, (ntr+1)*((2*gbnd)+dur+1), otherwise 1    */
 | |
| 	int tradj;	/* ITA                                                   */
 | |
| 	int en_tradj;
 | |
| 
 | |
| 	pHWDef hw = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	tpspd = (a_bRegs[0x0a] & 0x0c) >> 2; /* turbo/preview mode speed  */
 | |
| 	tpsel = a_bRegs[0x0a] & 3; 			 /* turbo/preview mode select */
 | |
| 
 | |
| 	gbnd = (a_bRegs[0x0e] & 0xf0) >> 4;	 /* TR fi1 guardband duration */
 | |
| 	dur = (a_bRegs[0x0e] & 0xf);		 /* TR pulse duration         */
 | |
| 
 | |
| 	ntr = a_bRegs[0x0d] / 128;			 /* number of tr pulses       */
 | |
| 
 | |
| 	afeop = a_bRegs[0x26] & 7;			 /* afe op - 3 channel or 1 channel */
 | |
| 
 | |
| 	tradj = a_bRegs[0x19] & 0x7f;		 /* integration time adjust */
 | |
| 	en_tradj = (tradj) ? 1 : 0;
 | |
| 
 | |
| 	ctmode = (a_bRegs[0x0b] >> 3) & 3;	 /* cis tr timing mode */
 | |
| 
 | |
| 	m_bLineRateColor = 1;	
 | |
| 	if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */
 | |
| 		m_bLineRateColor = 3;	
 | |
| 
 | |
| 	/* according to turbo/preview mode to set value */
 | |
| 	if( tpsel == 0 ) {
 | |
| 		tp = 1;
 | |
| 	} else {
 | |
| 		tp = tpspd + 2;
 | |
| 		if( tp == 5 )
 | |
| 			tp++;
 | |
| 	}
 | |
| 
 | |
| 	b = 1;
 | |
| 	if( ctmode == 0 ) { /* CCD mode scanner*/
 | |
| 	
 | |
| 		b  = (ntr + 1) * ((2 * gbnd) + dur + 1);
 | |
| 		b += (1 - ntr) * en_tradj;
 | |
| 	}
 | |
| 	if( ctmode == 2 )   /* CIS mode scanner */
 | |
| 	    b = 3;
 | |
| 	
 | |
| 	tr = m_bLineRateColor * (hw->wLineEnd + tp * (b + 3 - ntr));
 | |
| 
 | |
| 	if( tradj == 0 ) {
 | |
| 		if( ctmode == 0 )
 | |
| 			tr += m_bLineRateColor;
 | |
| 	} else {
 | |
| 	
 | |
| 		int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix;
 | |
| 			
 | |
| 		/* Line color or gray mode */
 | |
| 		if( afeop != 0 ) {
 | |
| 		
 | |
| 			le_phi      = (tradj + 1) / 2 + 1 + 6;
 | |
| 			num_byteclk = ((le_phi + 8 * hw->wLineEnd + 8 * b + 4) /
 | |
| 						   (8 * tradj)) + 1;
 | |
| 			num_mclkf   = 8 * tradj * num_byteclk;
 | |
| 			tr_fast_pix = num_byteclk;
 | |
| 			extra_pix   = (num_mclkf - le_phi) % 8;
 | |
| 		}
 | |
| 		else /* 3 channel pixel rate color */
 | |
| 		{
 | |
| 			le_phi      = (tradj + 1) / 2 + 1 + 10 + 12;
 | |
| 			num_byteclk = ((le_phi + 3 * 8 * hw->wLineEnd + 3 * 8 * b + 3 * 4) /
 | |
| 						   (3 * 8 * tradj)) + 1;
 | |
| 			num_mclkf   = 3 * 8 * tradj * num_byteclk;
 | |
| 			tr_fast_pix = num_byteclk;
 | |
| 			extra_pix   = (num_mclkf - le_phi) % (3 * 8);
 | |
| 		}
 | |
| 		
 | |
| 		tr = b + hw->wLineEnd + 4 + tr_fast_pix;
 | |
| 		if (extra_pix == 0)
 | |
| 			tr++;
 | |
| 		tr *= m_bLineRateColor;
 | |
| 	}
 | |
| 	m_wLineLength = tr / m_bLineRateColor;
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* LineLength=%d, LineRateColor=%u\n",
 | |
| 											m_wLineLength, m_bLineRateColor );
 | |
| }
 | |
| 
 | |
| /** usb_GetMotorParam
 | |
|  * registers 0x56, 0x57
 | |
|  */
 | |
| static void usb_GetMotorParam( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	int       	 idx, i;
 | |
| 	pClkMotorDef clk;
 | |
| 	pMDef     	 md;
 | |
| 	pDCapsDef 	 sCaps = &dev->usbDev.Caps;
 | |
| 	pHWDef    	 hw    = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	if( !_IS_PLUSTEKMOTOR(hw->motorModel)) {
 | |
| 	
 | |
| 		clk = usb_GetMotorSet( hw->motorModel );
 | |
| 		md  = clk->motor_sets;
 | |
|  		idx = 0;
 | |
| 		for( i = 0; i < _MAX_CLK; i++ ) {
 | |
| 			if( pParam->PhyDpi.x <= dpi_ranges[i] )
 | |
|   				break;
 | |
| 			idx++;
 | |
| 		}
 | |
| 		if( idx >= _MAX_CLK )
 | |
| 			idx = _MAX_CLK - 1;
 | |
| 
 | |
| 		a_bRegs[0x56] = md[idx].pwm;
 | |
| 		a_bRegs[0x57] = md[idx].pwm_duty;
 | |
| 
 | |
| 		a_bRegs[0x43] = 0;
 | |
| 		a_bRegs[0x44] = 0;
 | |
| 
 | |
| 		if( md[idx].scan_lines_per_line > 1 ) {
 | |
| 
 | |
| 			if((pParam->bBitDepth > 8) &&
 | |
| 				(pParam->bDataType == SCANDATATYPE_Color)) {
 | |
| 
 | |
| 				a_bRegs[0x43] = 0xff;
 | |
| 				a_bRegs[0x44] = md[idx].scan_lines_per_line;
 | |
| 
 | |
| 				DBG( _DBG_INFO2, "* Line Skipping : 0x43=0x%02x, 0x44=0x%02x\n",
 | |
| 	  											a_bRegs[0x43], a_bRegs[0x44] );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
|     } else {
 | |
|         if( sCaps->OpticDpi.x == 1200 ) {
 | |
| 
 | |
|         	switch( hw->motorModel ) {
 | |
| 
 | |
|         	case MODEL_HuaLien:
 | |
|         	case MODEL_KaoHsiung:
 | |
|         	default:
 | |
|         		if(pParam->PhyDpi.x <= 200)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 1;
 | |
|         			a_bRegs[0x57] = 48;	/* 63; */
 | |
|         		}
 | |
|         		else if(pParam->PhyDpi.x <= 300)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 2;	/* 8;  */
 | |
|         			a_bRegs[0x57] = 48;	/* 56; */
 | |
|         		}
 | |
|         		else if(pParam->PhyDpi.x <= 400)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 8;	
 | |
|         			a_bRegs[0x57] = 48;	
 | |
|         		}
 | |
|         		else if(pParam->PhyDpi.x <= 600)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 2;	/* 10; */
 | |
|         			a_bRegs[0x57] = 48;	/* 56; */
 | |
|         		}
 | |
|         		else /* pParam->PhyDpi.x == 1200) */
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 1;	/* 8;  */
 | |
|         			a_bRegs[0x57] = 48;	/* 56; */
 | |
|         		}
 | |
|         		break;
 | |
|         	}
 | |
|         } else {
 | |
|         	switch ( hw->motorModel ) {
 | |
| 
 | |
|         	case MODEL_Tokyo600:
 | |
|         		a_bRegs[0x56] = 16;
 | |
|         		a_bRegs[0x57] = 4;	/* 2; */
 | |
|         		break;
 | |
|         	case MODEL_HuaLien:
 | |
|         		{
 | |
|         			if(pParam->PhyDpi.x <= 200)
 | |
|         			{
 | |
|         				a_bRegs[0x56] = 64;	/* 24; */
 | |
|         				a_bRegs[0x57] = 4;	/* 16; */
 | |
|         			}
 | |
|         			else if(pParam->PhyDpi.x <= 300)
 | |
|         			{
 | |
|         				a_bRegs[0x56] = 64;	/* 16; */
 | |
|         				a_bRegs[0x57] = 4;	/* 16; */
 | |
|         			}
 | |
|         			else if(pParam->PhyDpi.x <= 400)
 | |
|         			{
 | |
|         				a_bRegs[0x56] = 64;	/* 16; */
 | |
|         				a_bRegs[0x57] = 4;	/* 16; */
 | |
|         			}
 | |
|         			else /* if(pParam->PhyDpi.x <= 600) */
 | |
|         			{
 | |
|      /* HEINER: check ADF stuff... */
 | |
|      #if 0
 | |
|         				if(ScanInf.m_fADF)
 | |
|         				{
 | |
|         					a_bRegs[0x56] = 8;
 | |
|         					a_bRegs[0x57] = 48;
 | |
|         				}
 | |
|         				else
 | |
|      #endif
 | |
|         				{
 | |
|         					a_bRegs[0x56] = 64;	/* 2;  */
 | |
|         					a_bRegs[0x57] = 4;	/* 48; */
 | |
|         				}
 | |
|         			}
 | |
|         		}
 | |
|         		break;
 | |
|         	case MODEL_KaoHsiung:
 | |
|         	default:
 | |
|         		if(pParam->PhyDpi.x <= 200)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 24;
 | |
|         			a_bRegs[0x57] = 16;
 | |
|         		}
 | |
|         		else if(pParam->PhyDpi.x <= 300)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 16;
 | |
|         			a_bRegs[0x57] = 16;
 | |
|         		}
 | |
|         		else if(pParam->PhyDpi.x <= 400)
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 16;
 | |
|         			a_bRegs[0x57] = 16;
 | |
|         		}
 | |
|         		else /* if(pParam->PhyDpi.x <= 600) */
 | |
|         		{
 | |
|         			a_bRegs[0x56] = 2;
 | |
|         			a_bRegs[0x57] = 48;
 | |
|         		}
 | |
|         		break;
 | |
|         	}
 | |
|         }
 | |
| 	}
 | |
| 	
 | |
| 	DBG( _DBG_INFO2, "* MOTOR-Settings: PWM=0x%02x, PWM_DUTY=0x%02x\n",
 | |
| 	                 a_bRegs[0x56], a_bRegs[0x57] );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static void usb_GetPauseLimit( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	int    coeffsize, scaler;
 | |
| 	pHWDef hw = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	scaler = 1;
 | |
| 	if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
 | |
| 		if( pParam->bDataType == SCANDATATYPE_Color ) {
 | |
| 			scaler = 3;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* compute size of coefficient ram */
 | |
| 	coeffsize = 4 + 16 + 16;	/* gamma and shading and offset */
 | |
| 
 | |
| 	/* if 16 bit, then not all is used */
 | |
| 	if( a_bRegs[0x09] & 0x20 ) {
 | |
| 		coeffsize = 16 + 16;	/* no gamma */
 | |
| 	}
 | |
| 	coeffsize *= (2*3); /* 3 colors and 2 bytes/word */
 | |
| 
 | |
| 
 | |
| 	/* Get available buffer size in KB
 | |
| 	 * for 512kb this will be 296
 | |
| 	 * for 2Mb   this will be 1832
 | |
| 	 */
 | |
| 	m_dwPauseLimit = (u_long)(hw->wDRAMSize - (u_long)(coeffsize));
 | |
| 	m_dwPauseLimit -= ((pParam->Size.dwPhyBytes*scaler) / 1024 + 1);
 | |
| 
 | |
| 	/* If not reversing, take into account the steps to reverse */
 | |
| 	if( a_bRegs[0x50] == 0 )
 | |
| 		m_dwPauseLimit -= ((a_bRegs[0x54] & 7) *
 | |
| 							(pParam->Size.dwPhyBytes * scaler) + 1023) / 1024;
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* PL=%lu, coeffsize=%u, scaler=%u\n",
 | |
| 	                  m_dwPauseLimit, coeffsize, scaler );
 | |
| 
 | |
| 	m_dwPauseLimit = usb_max( usb_min(m_dwPauseLimit,
 | |
| 						(u_long)ceil(pParam->Size.dwTotalBytes / 1024.0)), 2);
 | |
| 
 | |
| 	a_bRegs[0x4e] = (u_char)floor((m_dwPauseLimit*512.0)/(2.0*hw->wDRAMSize));
 | |
| 
 | |
| 	if( a_bRegs[0x4e] > 1 )	{
 | |
| 		a_bRegs[0x4e]--;
 | |
| 		if(a_bRegs[0x4e] > 1)
 | |
| 			a_bRegs[0x4e]--;
 | |
| 	} else
 | |
| 		a_bRegs[0x4e] = 1;
 | |
| 
 | |
| 	/*
 | |
| 	 * resume, when buffer is 2/8 kbytes full (512k/2M memory)
 | |
| 	 */
 | |
| 	a_bRegs[0x4f] = 1;
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* PauseLimit = %lu, [0x4e] = 0x%02x, [0x4f] = 0x%02x\n",
 | |
| 	                  m_dwPauseLimit, a_bRegs[0x4e], a_bRegs[0x4f] );
 | |
| }
 | |
| 
 | |
| /** usb_GetScanLinesAndSize
 | |
|  */
 | |
| static void usb_GetScanLinesAndSize( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	pDCapsDef sCaps = &dev->usbDev.Caps;
 | |
| 	pHWDef    hw    = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	pParam->Size.dwPhyLines = (u_long)ceil((double) pParam->Size.dwLines *
 | |
| 	                                     pParam->PhyDpi.y / pParam->UserDpi.y);
 | |
| 
 | |
| 	/* Calculate color offset */
 | |
| 	if (pParam->bCalibration == PARAM_Scan && pParam->bChannels == 3) {
 | |
| 
 | |
| 		dev->scanning.bLineDistance = sCaps->bSensorDistance *
 | |
| 		                                  pParam->PhyDpi.y / sCaps->OpticDpi.x;
 | |
| 		pParam->Size.dwPhyLines += (dev->scanning.bLineDistance << 1);
 | |
| 	}
 | |
| 	else
 | |
| 		dev->scanning.bLineDistance = 0;
 | |
| 
 | |
| 	pParam->Size.dwTotalBytes = pParam->Size.dwPhyBytes * pParam->Size.dwPhyLines;
 | |
| 
 | |
| 	if( hw->bReg_0x26 & _ONE_CH_COLOR ) {
 | |
| 
 | |
| 		if( pParam->bDataType == SCANDATATYPE_Color ) {
 | |
| 			pParam->Size.dwTotalBytes *= 3;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO, "* PhyBytes   = %lu\n", pParam->Size.dwPhyBytes );
 | |
| 	DBG( _DBG_INFO, "* PhyLines   = %lu\n", pParam->Size.dwPhyLines );
 | |
| 	DBG( _DBG_INFO, "* TotalBytes = %lu\n", pParam->Size.dwTotalBytes );
 | |
| }
 | |
| 
 | |
| /** function to preset/reset the merlin registers
 | |
|  */
 | |
| static SANE_Bool usb_SetScanParameters( Plustek_Device *dev, pScanParam pParam )
 | |
| {
 | |
| 	static u_char reg8, reg38[6], reg48[2];
 | |
| 
 | |
| 	pScanParam pdParam = &dev->scanning.sParam;
 | |
| 	pHWDef     hw      = &dev->usbDev.HwSetting;
 | |
| 
 | |
| 	m_pParam = pParam;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_SetScanParameters()\n" );
 | |
| 
 | |
| 	if( !usb_IsScannerReady(dev))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF) {
 | |
| /* HEINER: dSaveMoveSpeed is only used in func EjectPaper!!!
 | |
| 		dSaveMoveSpeed = hw->dMaxMoveSpeed;
 | |
| */
 | |
| 		hw->dMaxMoveSpeed = 1.0;
 | |
| 		usb_MotorSelect( dev, SANE_TRUE );
 | |
| 		usb_MotorOn( dev->fd, SANE_TRUE );
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
|      * calculate the basic settings...
 | |
|      */
 | |
| 	pParam->PhyDpi.x = usb_SetAsicDpiX( dev, pParam->UserDpi.x );
 | |
| 	pParam->PhyDpi.y = usb_SetAsicDpiY( dev, pParam->UserDpi.y );
 | |
| 
 | |
| 	usb_SetColorAndBits( dev, pParam );
 | |
| 	usb_GetScanRect    ( dev, pParam );
 | |
| 
 | |
| 	usb_PresetStepSize( dev, pParam );
 | |
| 	
 | |
| 	if( dev->caps.dwFlag & SFLAG_ADF ) {
 | |
| 
 | |
| 		if( pParam->bCalibration == PARAM_Scan ) {
 | |
| 
 | |
| 			if( pdParam->bSource == SOURCE_ADF ) {
 | |
| 				a_bRegs[0x50] = 0;
 | |
| 				a_bRegs[0x51] = 0x40;
 | |
| 				if( pParam->PhyDpi.x <= 300)
 | |
| 					a_bRegs[0x54] = (a_bRegs[0x54] & ~7) | 4;	/* 3; */
 | |
| 				else
 | |
| 					a_bRegs[0x54] = (a_bRegs[0x54] & ~7) | 5;	/* 4; */
 | |
| 			} else {
 | |
| 				a_bRegs[0x50] = hw->bStepsToReverse;
 | |
| 				a_bRegs[0x51] = hw->bReg_0x51;
 | |
| 				a_bRegs[0x54] &= ~7;
 | |
| 			}
 | |
| 		} else
 | |
| 			a_bRegs[0x50] = 0;
 | |
| 	} else {
 | |
| 		if( pParam->bCalibration == PARAM_Scan )
 | |
| 			a_bRegs[0x50] = hw->bStepsToReverse;
 | |
| 		else
 | |
| 			a_bRegs[0x50] = 0;
 | |
| 	}
 | |
| 
 | |
| 	/* Assume we will not use ITA */
 | |
| 	a_bRegs[0x19] = m_bIntTimeAdjust = 0;
 | |
| 
 | |
| 	/* Initiate variables */
 | |
| 
 | |
| 	/* Get variables from calculation algorithms */
 | |
| 	if(!(pParam->bCalibration == PARAM_Scan &&
 | |
|          pParam->bSource == SOURCE_ADF && fLastScanIsAdf )) {
 | |
| 
 | |
| 		DBG( _DBG_INFO2, "* Scan calculations...\n" );
 | |
| 		usb_GetLineLength ( dev );
 | |
| 		usb_GetStepSize   ( dev, pParam );
 | |
| 		usb_GetDPD        ( dev );
 | |
| 		usb_GetMCLKDivider( dev, pParam );
 | |
| 		usb_GetMotorParam ( dev, pParam );
 | |
| 	}
 | |
| 
 | |
| 	/* Compute fast feed step size, use equation 3 and equation 8 */
 | |
| 	if( m_dMCLKDivider < 1.0)
 | |
| 		m_dMCLKDivider = 1.0;
 | |
| 
 | |
| 	m_wFastFeedStepSize = (u_short)(dwCrystalFrequency /
 | |
| 							(m_dMCLKDivider * 8 * m_bCM * hw->dMaxMoveSpeed *
 | |
| 							 4 * hw->wMotorDpi));
 | |
| 	/* CIS special ;-) */
 | |
| 	if((hw->bReg_0x26 & _ONE_CH_COLOR) && (m_bCM == 1)) {
 | |
| 		DBG( _DBG_INFO2, "* CIS FFStep-Speedup\n" );
 | |
| 		m_wFastFeedStepSize /= 3;
 | |
| 	}
 | |
| 
 | |
| 	if( m_bIntTimeAdjust != 0 )
 | |
| 		m_wFastFeedStepSize /= m_bIntTimeAdjust;
 | |
| 
 | |
| 	if(a_bRegs[0x0a])
 | |
| 		m_wFastFeedStepSize *= ((a_bRegs[0x0a] >> 2) + 2);
 | |
| 	a_bRegs[0x48] = _HIBYTE( m_wFastFeedStepSize );
 | |
| 	a_bRegs[0x49] = _LOBYTE( m_wFastFeedStepSize );
 | |
| 
 | |
| 	DBG( _DBG_INFO2, "* FFStepSize = %u, [0x48] = 0x%02x, [0x49] = 0x%02x\n",
 | |
| 	                       m_wFastFeedStepSize, a_bRegs[0x48], a_bRegs[0x49] );
 | |
| 
 | |
| 	/* Compute the number of lines to scan using actual Y resolution */
 | |
| 	usb_GetScanLinesAndSize( dev, pParam );
 | |
| 	
 | |
| 	/* Pause limit should be bounded by total bytes to read
 | |
|      * so that the chassis will not move too far.
 | |
|      */
 | |
| 	usb_GetPauseLimit( dev, pParam );
 | |
| 
 | |
| 	/* For ADF .... */
 | |
| 	if(pParam->bCalibration == PARAM_Scan && pParam->bSource == SOURCE_ADF)	{
 | |
| 
 | |
| 		if( fLastScanIsAdf ) {
 | |
| 
 | |
| 			a_bRegs[0x08] = reg8;
 | |
| 			memcpy( &a_bRegs[0x38], reg38, sizeof(reg38));
 | |
| 			memcpy( &a_bRegs[0x48], reg48, sizeof(reg48));
 | |
| 
 | |
| 		} else {
 | |
| 
 | |
| 			reg8 = a_bRegs[0x08];
 | |
| 			memcpy( reg38, &a_bRegs[0x38], sizeof(reg38));
 | |
| 			memcpy( reg48, &a_bRegs[0x48], sizeof(reg48));
 | |
| 		}
 | |
| 		usb_MotorSelect( dev, SANE_TRUE );
 | |
| 	}
 | |
| 
 | |
| 	/* Reset LM983x's state machine before setting register values */
 | |
| 	if( !usbio_WriteReg( dev->fd, 0x18, 0x18 ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	usleep(200 * 1000); /* Need to delay at least xxx microseconds */
 | |
| 
 | |
| 	if( !usbio_WriteReg( dev->fd, 0x07, 0x20 ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	if( !usbio_WriteReg( dev->fd, 0x19, 6 ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	a_bRegs[0x07] = 0;
 | |
| 	a_bRegs[0x28] = 0;
 | |
| 
 | |
| 	/* set unused registers to 0 */
 | |
| 	memset( &a_bRegs[0x03], 0, 3 );
 | |
| 	memset( &a_bRegs[0x5f], 0, 0x7f-0x5f+1 );
 | |
| 
 | |
| 	/* set the merlin registers */
 | |
| 	_UIO(sanei_lm983x_write( dev->fd, 0x03, &a_bRegs[0x03], 3, SANE_TRUE));
 | |
| 	_UIO(sanei_lm983x_write( dev->fd, 0x08, &a_bRegs[0x08], 0x7f - 0x08+1, SANE_TRUE));
 | |
| 
 | |
|     usleep( 100 );
 | |
| 	
 | |
| 	if( !usbio_WriteReg( dev->fd, 0x07, 0 ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_SetScanParameters() done.\n" );
 | |
| 	return SANE_TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static SANE_Bool usb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park )
 | |
| {
 | |
| 	u_char  value;
 | |
| 	u_short inches;
 | |
| 	pHWDef       hw  = &dev->usbDev.HwSetting;
 | |
| 	pDCapsDef    sc  = &dev->usbDev.Caps;
 | |
| 	pClkMotorDef clk = usb_GetMotorSet( hw->motorModel );
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_ScanBegin()\n" );
 | |
| 
 | |
| 	/* save the request for usb_ScanEnd () */
 | |
| 	m_fAutoPark = auto_park;
 | |
| 
 | |
| 	/* Disable home sensor during scan, or the chassis cannot move */
 | |
| 	value = ((m_pParam->bCalibration == PARAM_Scan &&
 | |
| 			  m_pParam->bSource == SOURCE_ADF)? (a_bRegs[0x58] & ~7): 0);
 | |
| 
 | |
| 	if(!usbio_WriteReg( dev->fd, 0x58, value ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	/* Check if scanner is ready for receiving command */
 | |
| 	if( !usb_IsScannerReady(dev))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	/* Flush cache - only LM9831 (Source: National Semiconductors */
 | |
| 	if( _LM9831 == hw->chip ) {
 | |
| 
 | |
| 		for(;;) {
 | |
| 
 | |
| 			if( SANE_TRUE == cancelRead ) {
 | |
| 				DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" );
 | |
| 				return SANE_FALSE;
 | |
| 			}
 | |
| 			
 | |
| 			_UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData ));
 | |
| 			if( m_bOldScanData ) {
 | |
| 
 | |
| 				u_long dwBytesToRead = m_bOldScanData * hw->wDRAMSize * 4;
 | |
| 				u_char *pBuffer      = malloc( sizeof(u_char) * dwBytesToRead );
 | |
| 
 | |
| 				DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n",
 | |
| 				                                dwBytesToRead, m_bOldScanData );
 | |
| 
 | |
| 				_UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer, 
 | |
| 				                                  dwBytesToRead, SANE_FALSE ));
 | |
| 				free( pBuffer );
 | |
| 
 | |
| 			} else
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Download map & Shading data */
 | |
| 	if(( m_pParam->bCalibration == PARAM_Scan &&
 | |
| 		!usb_MapDownload( dev, m_pParam->bDataType)) ||
 | |
| 		!usb_DownloadShadingData( dev, m_pParam->bCalibration ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	/* Move chassis and start to read image data */
 | |
| 	if (!usbio_WriteReg( dev->fd, 0x07, 3 ))
 | |
| 		return SANE_FALSE;
 | |
| 
 | |
| 	usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData );
 | |
| 	m_bOldScanData = 0;                     /* No data at all  */
 | |
| 
 | |
| 	m_fStart = m_fFirst = SANE_TRUE;        /* Prepare to read */
 | |
| 
 | |
| 	DBG( _DBG_DREGS, "Register Dump before reading data:\n" );
 | |
| 	dumpregs( dev->fd, NULL );
 | |
| 
 | |
| 	inches = (u_short)((m_pParam->Origin.y *300UL)/hw->wMotorDpi);
 | |
| 	DBG( _DBG_INFO2, ">>> INC=%u, DOY=%u\n", inches, sc->Normal.DataOrigin.y );
 | |
| 	if((inches > sc->Normal.DataOrigin.y ) && (clk->min_ffstep != 0xffff))
 | |
| 		usb_WaitPos( dev, 150, SANE_FALSE );
 | |
| 	return SANE_TRUE;
 | |
| }
 | |
| 
 | |
| /** usb_ScanEnd
 | |
|  * stop all the processing stuff and reposition sensor back home
 | |
|  */
 | |
| static SANE_Bool usb_ScanEnd( Plustek_Device *dev )
 | |
| {
 | |
| 	u_char value;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usbDev_ScanEnd(), start=%u, park=%u\n",
 | |
| 	                                                   m_fStart, m_fAutoPark );
 | |
| 
 | |
| 	usbio_ReadReg( dev->fd, 0x07, &value );
 | |
| 	if( value == 3 || value != 2 )
 | |
| 		usbio_WriteReg( dev->fd, 0x07, 0 );
 | |
| 
 | |
| 	if( m_fStart ) {
 | |
| 		m_fStart = SANE_FALSE;
 | |
| 
 | |
| 		if( m_fAutoPark )
 | |
| 			usb_ModuleToHome( dev, SANE_FALSE );
 | |
| 	}
 | |
| 	else if( SANE_TRUE == cancelRead ) {
 | |
| 	
 | |
| 		usb_ModuleToHome( dev, SANE_FALSE );
 | |
| 	}
 | |
| 
 | |
| 	return SANE_TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static SANE_Bool usb_IsDataAvailableInDRAM( Plustek_Device *dev )
 | |
| {
 | |
| 	/* Compute polling timeout
 | |
| 	 *	Height (Inches) / MaxScanSpeed (Inches/Second) = Seconds to move the
 | |
|      *  module from top to bottom. Then convert the seconds to miliseconds
 | |
|      *  by multiply 1000. We add extra 2 seconds to get some tolerance.
 | |
|      */
 | |
| 	u_char         a_bBand[3];
 | |
| 	long           dwTicks;
 | |
|     struct timeval t;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" );
 | |
| 
 | |
| 	gettimeofday( &t, NULL);	
 | |
| 	dwTicks = t.tv_sec + 30;
 | |
| 
 | |
| 	for(;;)	{
 | |
| 
 | |
| 		_UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE ));
 | |
| 
 | |
| 		gettimeofday( &t, NULL);	
 | |
| 	    if( t.tv_sec > dwTicks )
 | |
| 			break;
 | |
| 
 | |
| 		if( usb_IsEscPressed()) {
 | |
| 			DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n");
 | |
| 			return SANE_FALSE;
 | |
| 		}
 | |
| 			
 | |
| 		/* It is not stable for read */
 | |
| 		if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2]))
 | |
| 			continue;
 | |
| 
 | |
| 		if( a_bBand[0] > m_bOldScanData ) {
 | |
| 
 | |
| 			if( m_pParam->bSource != SOURCE_Reflection )
 | |
| 
 | |
| 				usleep(1000*(30 * a_bRegs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
 | |
| 			else
 | |
| 				usleep(1000*(20 * a_bRegs[0x08] * dev->usbDev.Caps.OpticDpi.x / 600));
 | |
| 
 | |
| 			DBG( _DBG_INFO, "Data is available\n" );
 | |
| 			return SANE_TRUE;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO, "NO Data available\n" );
 | |
| 	return SANE_FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static SANE_Bool usb_ScanReadImage( Plustek_Device *dev,
 | |
|                                     void *pBuf, u_long dwSize )
 | |
| {
 | |
| 	static u_long dwBytes = 0;
 | |
| 	SANE_Status res;
 | |
| 
 | |
| 	DBG( _DBG_READ, "usb_ScanReadImage(%lu)\n", dwSize );
 | |
| 
 | |
| 	if( m_fFirst ) {
 | |
| 
 | |
| 		dwBytes  = 0;
 | |
| 		m_fFirst = SANE_FALSE;
 | |
| 
 | |
| 		/* Wait for data band ready */
 | |
| 		if (!usb_IsDataAvailableInDRAM( dev )) {
 | |
| 			DBG( _DBG_ERROR, "Nothing to read...\n" );
 | |
| 			return SANE_FALSE;
 | |
| 		}			
 | |
| 	}
 | |
| /* HEINER: ADF */
 | |
| #if 0
 | |
| 	if(ScanInf.m_fADF == 1 && Scanning.sParam.bCalibration == PARAM_Scan)
 | |
| 	{
 | |
| 		if(dwBytes)
 | |
| 		{
 | |
| 			DWORD dw;
 | |
| 			BOOL fRet;
 | |
| 
 | |
| 			if(dwSize < dwBytes)
 | |
| 				dw = dwSize;
 | |
| 			else
 | |
| 				dw = dwBytes;
 | |
| 
 | |
| 			fRet = ReadData(0x00, (PBYTE)pBuf, dw);
 | |
| 
 | |
| 			dwBytes -= dw;
 | |
| 
 | |
| 			if(!dwBytes)
 | |
| 			{
 | |
| 				WriteRegister(0x07, 0);	// To stop scanning
 | |
| 				ScanInf.m_fADF++;
 | |
| 				if(dwSize > dw)
 | |
| 					ScanReadImage((PBYTE)pBuf + dw, dwSize - dw);
 | |
| 			}
 | |
| 			return fRet;
 | |
| 		}
 | |
| 		else if(!Hardware.SensorPaper())
 | |
| 		{
 | |
| 			dwBytes = (Scanning.sParam.PhyDpi.y * 18 / 25) * Scanning.sParam.Size.dwPhyBytes;
 | |
| 			return ScanReadImage(pBuf, dwSize);
 | |
| 		}
 | |
| 	}
 | |
| 	else if(ScanInf.m_fADF > 1)
 | |
| 	{
 | |
| 		DWORD dw;
 | |
| 		if(Scanning.sParam.bBitDepth > 8)
 | |
| 		{
 | |
| 			for(dw = 0; dw < dwSize; dw += 2)
 | |
| 				*((PWORD)pBuf + dw) = 0xfffc;
 | |
| 		}
 | |
| 		else
 | |
| 			FillMemory(pBuf, dwSize, 0xff);
 | |
| 		return TRUE;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	res = sanei_lm983x_read(dev->fd, 0x00, (u_char *)pBuf, dwSize, SANE_FALSE);
 | |
| 
 | |
| 	/* check for pressed ESC button, as sanei_lm983x_read() may take some time
 | |
| 	 */
 | |
| 	if( usb_IsEscPressed()) {
 | |
| 		DBG(_DBG_INFO,"usb_ScanReadImage() - Cancel detected...\n");
 | |
| 		return SANE_FALSE;
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_READ, "usb_ScanReadImage() done, result: %d\n", res );
 | |
| 
 | |
| 	if( SANE_STATUS_GOOD == res ) {
 | |
| 		return SANE_TRUE;
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_ERROR, "usb_ScanReadImage() failed\n" );
 | |
| 	
 | |
| 	return SANE_FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static void usb_GetImageInfo( Plustek_Device *dev, pImgDef pInfo, pWinInfo pSize )
 | |
| {
 | |
| 	DBG( _DBG_INFO, "usb_GetImageInfo()\n" );
 | |
| 
 | |
| 	pSize->dwPixels = (u_long)pInfo->crArea.cx * pInfo->xyDpi.x / 300UL;
 | |
| 	pSize->dwLines  = (u_long)pInfo->crArea.cy * pInfo->xyDpi.y / 300UL;
 | |
| 
 | |
| 	switch( pInfo->wDataType ) {
 | |
| 
 | |
| 		case COLOR_TRUE48:
 | |
| 			pSize->dwBytes = pSize->dwPixels * 6UL;
 | |
| 			break;
 | |
| 			
 | |
| 		case COLOR_TRUE24:
 | |
| 			if( dev->scanning.fGrayFromColor > 7 ){
 | |
| 				pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
 | |
| 				pSize->dwPixels = pSize->dwBytes * 8;
 | |
| 			} else {
 | |
| 				pSize->dwBytes = pSize->dwPixels * 3UL;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case COLOR_GRAY16:
 | |
| 			pSize->dwBytes = pSize->dwPixels << 1;
 | |
| 			break;
 | |
| 
 | |
| 		case COLOR_256GRAY:
 | |
| 			pSize->dwBytes = pSize->dwPixels;
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			pSize->dwBytes  = (pSize->dwPixels + 7UL) >> 3;
 | |
| 			pSize->dwPixels = pSize->dwBytes * 8;
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  */
 | |
| static void usb_SaveImageInfo( Plustek_Device *dev, pImgDef pInfo )
 | |
| {
 | |
| 	pHWDef     hw     = &dev->usbDev.HwSetting;
 | |
| 	pScanParam pParam = &dev->scanning.sParam;
 | |
| 
 | |
| 	DBG( _DBG_INFO, "usb_SaveImageInfo()\n" );
 | |
| 
 | |
| 	/* Dpi & Origins */
 | |
| 	pParam->UserDpi  = pInfo->xyDpi;
 | |
| 	pParam->Origin.x = pInfo->crArea.x;
 | |
| 	pParam->Origin.y = pInfo->crArea.y;
 | |
| 
 | |
| 	/* Source & Bits */
 | |
| 	pParam->bBitDepth = 8;
 | |
| 
 | |
| 	switch( pInfo->wDataType ) {
 | |
| 
 | |
| 		case COLOR_TRUE48:
 | |
| 			pParam->bBitDepth = 16;
 | |
| 			/* fall through... */
 | |
| 			
 | |
| 		case COLOR_TRUE24:
 | |
| 			pParam->bDataType = SCANDATATYPE_Color;
 | |
| 
 | |
| 			/* AFE operation: one or 3 channels ! */
 | |
| 			if( hw->bReg_0x26 & _ONE_CH_COLOR )
 | |
| 				pParam->bChannels = 1;
 | |
| 			else
 | |
| 				pParam->bChannels = 3;
 | |
| 			break;
 | |
| 
 | |
| 		case COLOR_GRAY16:
 | |
| 			pParam->bBitDepth = 16;
 | |
| 			/* fall through... */
 | |
| 
 | |
| 		case COLOR_256GRAY:
 | |
| 			pParam->bDataType = SCANDATATYPE_Gray;
 | |
| 			pParam->bChannels = 1;
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			pParam->bBitDepth = 1;
 | |
| 			pParam->bDataType = SCANDATATYPE_BW;
 | |
| 			pParam->bChannels = 1;
 | |
| 	}
 | |
| 
 | |
| 	DBG( _DBG_INFO, "* dwFlag = 0x%08lx\n", pInfo->dwFlag );
 | |
| 
 | |
| 	if( pInfo->dwFlag & SCANDEF_Transparency )
 | |
| 		pParam->bSource = SOURCE_Transparency;
 | |
| 	else if( pInfo->dwFlag & SCANDEF_Negative )
 | |
| 		pParam->bSource = SOURCE_Negative;
 | |
| 	else if( pInfo->dwFlag & SCANDEF_Adf )
 | |
| 		pParam->bSource = SOURCE_ADF;
 | |
| 	else
 | |
| 		pParam->bSource = SOURCE_Reflection;
 | |
| }
 | |
| 
 | |
| /* END PLUSTEK-USBSCAN.C ....................................................*/
 |