kopia lustrzana https://gitlab.com/sane-project/backends
initial checkin.
rodzic
d05c973c18
commit
a20efe37fb
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,640 @@
|
|||
/** @file u12-hw.c
|
||||
* @brief The HW-access functions to the U12 backend stuff.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
#define _TEST_SIZE 1000
|
||||
|
||||
/*************************** some local vars *********************************/
|
||||
|
||||
static RegDef u12CcdStop[] = {
|
||||
/* this was the original sequence from parport backend*/
|
||||
#if 0
|
||||
#define _STOP_LEN 13
|
||||
|
||||
{0x41, 0xff}, {0x42, 0xff}, {0x60, 0xff}, {0x61, 0xff},
|
||||
{0x4b, 0xff}, {0x4c, 0xff}, {0x4d, 0xff}, {0x4e, 0xff},
|
||||
{0x2a, 0x01}, {0x2b, 0x00}, {0x2d, 0x00}, {0x1b, 0x19}, {0x15, 0x00}
|
||||
#else
|
||||
#define _STOP_LEN 29
|
||||
/* this is what we see from usb-snoop... */
|
||||
{0x60, 0xff}, {0x61, 0xff}, {0x1b, 0x19}, {0x15, 0x00}, {0x20, 0x14},
|
||||
{0x2c, 0x02}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00}, {0x3c, 0x00},
|
||||
{0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00}, {0x44, 0x00}, {0x45, 0x01},
|
||||
{0x46, 0x00}, {0x47, 0x00}, {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x09},
|
||||
{0x4b, 0x00}, {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x01}, {0x50, 0x00},
|
||||
{0x51, 0x00}, {0x52, 0x00}, {0x53, 0x01}, {0x67, 0x00}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12hw_SelectLampSource( U12_Device *dev )
|
||||
{
|
||||
dev->regs.RD_ScanControl &= (~_SCAN_LAMPS_ON);
|
||||
|
||||
if( dev->DataInf.dwScanFlag & (_SCANDEF_TPA)) {
|
||||
dev->regs.RD_ScanControl |= _SCAN_TPALAMP_ON;
|
||||
} else {
|
||||
dev->regs.RD_ScanControl |= _SCAN_NORMALLAMP_ON;
|
||||
}
|
||||
}
|
||||
|
||||
/** as the function name says
|
||||
*/
|
||||
static void u12hw_PutToIdleMode( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "CCD-Stop\n" );
|
||||
u12io_DataToRegs( dev, (SANE_Byte*)u12CcdStop, _STOP_LEN );
|
||||
}
|
||||
|
||||
/** program the CCD relevant stuff
|
||||
*/
|
||||
static void u12hw_ProgramCCD( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte *reg_val;
|
||||
|
||||
DBG( _DBG_INFO, "u12hw_ProgramCCD: 0x%08lx[%lu]\n",
|
||||
(u_long)dev->CCDRegs,
|
||||
((u_long)dev->numCCDRegs * dev->shade.intermediate));
|
||||
|
||||
DBG( _DBG_INFO, " * %u regs * %u (intermediate)\n",
|
||||
dev->numCCDRegs, dev->shade.intermediate );
|
||||
|
||||
reg_val = (SANE_Byte*)(dev->CCDRegs +
|
||||
(u_long)dev->numCCDRegs * dev->shade.intermediate);
|
||||
|
||||
u12io_DataToRegs( dev, reg_val, dev->numCCDRegs );
|
||||
}
|
||||
|
||||
/** init the stuff according to the buttons
|
||||
*/
|
||||
static void u12hw_ButtonSetup( U12_Device *dev, SANE_Byte numButtons )
|
||||
{
|
||||
dev->Buttons = numButtons;
|
||||
|
||||
dev->regs.RD_MotorDriverType |= _BUTTON_DISABLE;
|
||||
dev->MotorPower |= _BUTTON_DISABLE;
|
||||
}
|
||||
|
||||
/** According to what we have detected, set the other stuff
|
||||
*/
|
||||
static void u12hw_InitiateComponentModel( U12_Device *dev )
|
||||
{
|
||||
/* preset some stuff and do the differences later */
|
||||
dev->Buttons = 0;
|
||||
dev->ModelOriginY = 64;
|
||||
dev->Tpa = SANE_FALSE;
|
||||
dev->ModelCtrl = (_LED_ACTIVITY | _LED_CONTROL);
|
||||
|
||||
switch( dev->PCBID ) {
|
||||
|
||||
case _PLUSTEK_SCANNER:
|
||||
DBG( _DBG_INFO, "We have a Plustek Scanner ;-)\n" );
|
||||
break;
|
||||
|
||||
case _SCANNER_WITH_TPA:
|
||||
DBG( _DBG_INFO, "Scanner has TPA\n" );
|
||||
dev->Tpa = SANE_TRUE;
|
||||
break;
|
||||
|
||||
case _SCANNER4Button:
|
||||
DBG( _DBG_INFO, "Scanner has 4 Buttons\n" );
|
||||
u12hw_ButtonSetup( dev, 4 );
|
||||
break;
|
||||
|
||||
case _SCANNER4ButtonTPA:
|
||||
DBG( _DBG_INFO, "Scanner has 4 Buttons & TPA\n" );
|
||||
dev->Tpa = SANE_TRUE;
|
||||
u12hw_ButtonSetup( dev, 4 );
|
||||
break;
|
||||
|
||||
case _SCANNER5Button:
|
||||
DBG( _DBG_INFO, "Scanner has 5 Buttons\n" );
|
||||
dev->ModelOriginY += 20;
|
||||
u12hw_ButtonSetup( dev, 5 );
|
||||
break;
|
||||
|
||||
case _SCANNER5ButtonTPA:
|
||||
DBG( _DBG_INFO, "Scanner has 5 Buttons & TPA\n" );
|
||||
dev->ModelOriginY += 20;
|
||||
dev->Tpa = SANE_TRUE;
|
||||
u12hw_ButtonSetup( dev, 5 );
|
||||
break;
|
||||
|
||||
case _SCANNER1Button:
|
||||
DBG( _DBG_INFO, "Scanner has 1 Button\n" );
|
||||
u12hw_ButtonSetup( dev, 1 );
|
||||
break;
|
||||
|
||||
case _SCANNER1ButtonTPA:
|
||||
DBG( _DBG_INFO, "Scanner has 1 Button & TPA\n" );
|
||||
dev->Tpa = SANE_TRUE;
|
||||
u12hw_ButtonSetup( dev, 1 );
|
||||
break;
|
||||
|
||||
case _AGFA_SCANNER:
|
||||
DBG( _DBG_INFO, "Agfa Scanner\n" );
|
||||
dev->ModelOriginY = 24; /* 1200 dpi */
|
||||
break;
|
||||
|
||||
case _SCANNER2Button:
|
||||
DBG( _DBG_INFO, "Scanner has 2 Buttons\n" );
|
||||
dev->ModelOriginY -= 33;
|
||||
u12hw_ButtonSetup( dev, 2 );
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG( _DBG_INFO, "Default Model: U12\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if( _MOTOR0_2003 == dev->MotorID ) {
|
||||
dev->f2003 = SANE_TRUE;
|
||||
dev->XStepMono = 10;
|
||||
dev->XStepColor = 6;
|
||||
dev->XStepBack = 5;
|
||||
dev->regs.RD_MotorDriverType |= _MOTORR_STRONG;
|
||||
} else {
|
||||
#endif
|
||||
dev->f2003 = SANE_FALSE;
|
||||
dev->XStepMono = 8;
|
||||
dev->XStepColor = 4;
|
||||
dev->XStepBack = 5;
|
||||
dev->regs.RD_MotorDriverType |= _MOTORR_WEAK;
|
||||
/* } */
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12hw_InitAsic( U12_Device *dev, SANE_Bool shading )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12hw_InitAsic(%d)\n", shading );
|
||||
|
||||
/* get DAC and motor stuff */
|
||||
dev->DACType = u12io_DataFromRegister( dev, REG_RESETCONFIG );
|
||||
dev->MotorID = (SANE_Byte)(dev->DACType & _MOTOR0_MASK);
|
||||
|
||||
dev->regs.RD_MotorDriverType =
|
||||
(SANE_Byte)((dev->DACType & _MOTOR0_MASK) >> 3);
|
||||
dev->regs.RD_MotorDriverType |=
|
||||
(SANE_Byte)((dev->DACType & _MOTOR1_MASK) >> 1);
|
||||
dev->DACType &= _ADC_MASK;
|
||||
|
||||
dev->MotorPower = dev->regs.RD_MotorDriverType | _MOTORR_STRONG;
|
||||
|
||||
/*get CCD and PCB ID */
|
||||
dev->PCBID = u12io_DataFromRegister( dev, REG_CONFIG );
|
||||
dev->CCDID = dev->PCBID & 0x07;
|
||||
dev->PCBID &= 0xf0;
|
||||
|
||||
if( _AGFA_SCANNER == dev->PCBID )
|
||||
dev->DACType = _DA_WOLFSON8141;
|
||||
|
||||
DBG( _DBG_INFO, "* PCB-ID=0x%02x, CCD-ID=0x%02x, DAC-TYPE=0x%02x\n",
|
||||
dev->PCBID, dev->CCDID, dev->DACType );
|
||||
|
||||
u12hw_InitiateComponentModel( dev );
|
||||
u12ccd_InitCCDandDAC( dev, shading );
|
||||
|
||||
dev->regs.RD_Model1Control = _CCD_SHIFT_GATE;
|
||||
if( dev->Buttons != 0 )
|
||||
dev->regs.RD_Model1Control += _BUTTON_MODE;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_Mono )
|
||||
dev->regs.RD_Model1Control += _SCAN_GRAYTYPE;
|
||||
|
||||
DBG( _DBG_INFO, "* MotorDrvType = 0x%02x\n", dev->regs.RD_MotorDriverType);
|
||||
u12io_DataToRegister( dev, REG_MOTORDRVTYPE, dev->regs.RD_MotorDriverType);
|
||||
|
||||
u12io_DataToRegister( dev, REG_WAITSTATEINSERT, 4 );
|
||||
|
||||
DBG( _DBG_INFO, "* Model1Cntrl = 0x%02x\n", dev->regs.RD_Model1Control );
|
||||
u12io_DataToRegister( dev, REG_MODEL1CONTROL, dev->regs.RD_Model1Control );
|
||||
|
||||
u12hw_ProgramCCD( dev );
|
||||
DBG( _DBG_INFO, "u12hw_InitAsic done.\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12hw_ControlLampOnOff( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte lampStatus;
|
||||
|
||||
dev->warmupNeeded = SANE_TRUE;
|
||||
|
||||
lampStatus = dev->regs.RD_ScanControl & _SCAN_LAMPS_ON;
|
||||
|
||||
if ( dev->lastLampStatus != lampStatus ) {
|
||||
|
||||
DBG( _DBG_INFO, "* Using OTHER Lamp --> warmup needed\n" );
|
||||
dev->lastLampStatus = lampStatus;
|
||||
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
|
||||
return;
|
||||
}
|
||||
|
||||
dev->warmupNeeded = SANE_FALSE;
|
||||
DBG( _DBG_INFO, "* Using SAME Lamp --> no warmup needed\n" );
|
||||
}
|
||||
|
||||
/** set all necessary register contents
|
||||
*/
|
||||
static void u12hw_SetGeneralRegister( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12hw_SetGeneralRegister()\n" );
|
||||
|
||||
dev->scan.motorBackward = SANE_FALSE;
|
||||
dev->scan.refreshState = SANE_FALSE;
|
||||
|
||||
if( COLOR_BW == dev->DataInf.wPhyDataType )
|
||||
dev->regs.RD_ScanControl = _SCAN_BITMODE;
|
||||
else {
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_TRUE24 )
|
||||
dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
|
||||
else
|
||||
dev->regs.RD_ScanControl = _SCAN_12BITMODE;
|
||||
}
|
||||
|
||||
u12hw_SelectLampSource( dev );
|
||||
|
||||
dev->regs.RD_ModelControl = (_LED_CONTROL | _LED_ACTIVITY);
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
dev->regs.RD_ModelControl |= _MODEL_DPI300;
|
||||
else
|
||||
dev->regs.RD_ModelControl |= _MODEL_DPI600;
|
||||
|
||||
dev->regs.RD_Motor0Control = _MotorOn | _MotorHQuarterStep | _MotorPowerEnable;
|
||||
dev->regs.RD_ScanControl1 = _SCANSTOPONBUFFULL | _MFRC_BY_XSTEP;
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12hw_SetupScanningCondition( U12_Device *dev )
|
||||
{
|
||||
TimerDef timer;
|
||||
u_long channel;
|
||||
int c;
|
||||
SANE_Byte state;
|
||||
SANE_Byte rb[100];
|
||||
SANE_Byte *pState;
|
||||
|
||||
DBG( _DBG_INFO, "u12_SetupScanningCondition()\n" );
|
||||
|
||||
u12hw_SetGeneralRegister( dev );
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_RESETMTSC );
|
||||
_DODELAY(250);
|
||||
|
||||
/* ------- Setup MinRead/MaxRead Fifo size ------- */
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_TRUE24 ) {
|
||||
dev->scan.dwMaxReadFifo =
|
||||
dev->scan.dwMinReadFifo = dev->DataInf.dwAsicBytesPerPlane * 2;
|
||||
} else {
|
||||
dev->scan.dwMaxReadFifo =
|
||||
dev->scan.dwMinReadFifo = dev->DataInf.dwAppPixelsPerLine << 1;
|
||||
}
|
||||
|
||||
if( dev->scan.dwMinReadFifo < 1024)
|
||||
dev->scan.dwMinReadFifo = dev->scan.dwMaxReadFifo = 1024;
|
||||
|
||||
dev->scan.dwMaxReadFifo += (dev->DataInf.dwAsicBytesPerPlane / 2);
|
||||
|
||||
DBG( _DBG_INFO, "* MinReadFifo=%lu, MaxReadFifo=%lu\n",
|
||||
dev->scan.dwMinReadFifo, dev->scan.dwMaxReadFifo );
|
||||
|
||||
/* ------- Set the max. read fifo to asic ------- */
|
||||
if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
dev->scan.bFifoSelect = REG_BFIFOOFFSET;
|
||||
|
||||
if( !dev->scan.p48BitBuf.pb ) {
|
||||
|
||||
long lRed, lGreen;
|
||||
|
||||
lRed = (_SIZE_REDFIFO - _SIZE_BLUEFIFO) /
|
||||
dev->DataInf.dwAsicBytesPerPlane - dev->scan.bd_rk.wRedKeep;
|
||||
|
||||
lGreen = (_SIZE_GREENFIFO - _SIZE_BLUEFIFO) /
|
||||
dev->DataInf.dwAsicBytesPerPlane - dev->scan.gd_gk.wGreenKeep;
|
||||
|
||||
if((lRed < 0) || (lGreen < 0)) {
|
||||
|
||||
if( lRed < lGreen ) {
|
||||
channel = _RED_FULLSIZE << 16;
|
||||
dev->regs.RD_BufFullSize = _SIZE_REDFIFO;
|
||||
lGreen = lRed;
|
||||
} else {
|
||||
channel = _GREEN_FULLSIZE << 16;
|
||||
dev->regs.RD_BufFullSize = _SIZE_GREENFIFO;
|
||||
}
|
||||
|
||||
lGreen = (u_long)(-lGreen * dev->DataInf.dwAsicBytesPerPlane);
|
||||
|
||||
if( dev->DataInf.wPhyDataType > COLOR_TRUE24 )
|
||||
lGreen >>= 1;
|
||||
|
||||
dev->scan.dwMinReadFifo += (u_long)lGreen;
|
||||
dev->scan.dwMaxReadFifo += (u_long)lGreen;
|
||||
|
||||
} else {
|
||||
channel = _BLUE_FULLSIZE << 16;
|
||||
dev->regs.RD_BufFullSize = _SIZE_BLUEFIFO;
|
||||
}
|
||||
} else {
|
||||
channel = _BLUE_FULLSIZE << 16;
|
||||
dev->regs.RD_BufFullSize = _SIZE_BLUEFIFO;
|
||||
}
|
||||
} else {
|
||||
dev->scan.bFifoSelect = REG_GFIFOOFFSET;
|
||||
channel = _GREEN_FULLSIZE << 16;
|
||||
dev->regs.RD_BufFullSize = _SIZE_GRAYFIFO;
|
||||
}
|
||||
|
||||
dev->regs.RD_BufFullSize -= (dev->DataInf.dwAsicBytesPerPlane << 1);
|
||||
|
||||
if( dev->DataInf.wPhyDataType > COLOR_TRUE24 )
|
||||
dev->regs.RD_BufFullSize >>= 1;
|
||||
|
||||
dev->regs.RD_BufFullSize |= channel;
|
||||
|
||||
dev->scan.bRefresh = (SANE_Byte)(dev->scan.dwInterval << 1);
|
||||
dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_XStepTime = _LOBYTE(dev->shade.wXStep);
|
||||
dev->regs.RD_ExtXStepTime = _HIBYTE(dev->shade.wXStep);
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
dev->regs.RD_ModeControl = _ModeScan/*(_ModeScan | _ModeFifoGSel)*/;
|
||||
|
||||
DBG( _DBG_INFO, "* bRefresh = %i\n", dev->scan.bRefresh );
|
||||
|
||||
if( dev->DataInf.wPhyDataType == COLOR_BW ) {
|
||||
dev->regs.RD_ScanControl = _SCAN_BITMODE;
|
||||
} else if( dev->DataInf.wPhyDataType <= COLOR_TRUE24 )
|
||||
dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
|
||||
else {
|
||||
dev->regs.RD_ScanControl = _SCAN_12BITMODE;
|
||||
}
|
||||
|
||||
dev->regs.RD_ScanControl |= _SCAN_1ST_AVERAGE;
|
||||
u12hw_SelectLampSource( dev );
|
||||
|
||||
DBG( _DBG_INFO, "* RD_ScanControl = 0x%02x\n", dev->regs.RD_ScanControl );
|
||||
|
||||
DBG( _DBG_INFO, "* ImageInfo: x=%u,y=%u,dx=%u,dy=%u\n",
|
||||
dev->DataInf.crImage.x, dev->DataInf.crImage.y,
|
||||
dev->DataInf.crImage.cx, dev->DataInf.crImage.cy );
|
||||
|
||||
dev->regs.RD_MotorTotalSteps = (dev->DataInf.crImage.cy * 4) +
|
||||
(dev->f0_8_16 ? 32 : 16) +
|
||||
(dev->scan.bDiscardAll ? 32 : 0);
|
||||
DBG( _DBG_INFO, "* RD_MotorTotalSteps = 0x%04x\n",
|
||||
dev->regs.RD_MotorTotalSteps);
|
||||
|
||||
dev->regs.RD_ScanControl1 = (_MTSC_ENABLE | _SCANSTOPONBUFFULL |
|
||||
_MFRC_RUNSCANSTATE | _MFRC_BY_XSTEP);
|
||||
DBG( _DBG_INFO, "* RD_ScanControl1 = 0x%02x\n", dev->regs.RD_ScanControl1);
|
||||
|
||||
dev->regs.RD_Dpi = dev->DataInf.xyPhyDpi.x;
|
||||
|
||||
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA )) {
|
||||
dev->regs.RD_Origin = (u_short)(dev->adj.leftNormal*2+_DATA_ORIGIN_X);
|
||||
|
||||
} else if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency ) {
|
||||
dev->regs.RD_Origin = (u_short)dev->scan.posBegin;
|
||||
} else {
|
||||
dev->regs.RD_Origin = (u_short)dev->scan.negBegin;
|
||||
}
|
||||
dev->regs.RD_Origin += dev->DataInf.crImage.x;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
dev->regs.RD_Origin >>= 1;
|
||||
|
||||
if( dev->DataInf.wPhyDataType == COLOR_BW )
|
||||
dev->regs.RD_Pixels = (u_short)dev->DataInf.dwAsicBytesPerPlane;
|
||||
else
|
||||
dev->regs.RD_Pixels = (u_short)dev->DataInf.dwAppPixelsPerLine;
|
||||
|
||||
DBG( _DBG_INFO, "* RD_Origin = %u, RD_Pixels = %u\n",
|
||||
dev->regs.RD_Origin, dev->regs.RD_Pixels );
|
||||
|
||||
/* ------- Prepare scan states ------- */
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
memset( dev->bufs.b1.pReadBuf, 0, _NUMBER_OF_SCANSTEPS );
|
||||
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY )
|
||||
state = (_SS_MONO | _SS_STEP);
|
||||
else
|
||||
state = (_SS_COLOR | _SS_STEP);
|
||||
|
||||
for( channel = _NUMBER_OF_SCANSTEPS, pState = dev->bufs.b1.pReadBuf;
|
||||
channel; channel -= dev->scan.dwInterval ) {
|
||||
*pState = state;
|
||||
pState += dev->scan.dwInterval;
|
||||
}
|
||||
for( channel = 0, pState = dev->bufs.b1.pReadBuf;
|
||||
channel < _SCANSTATE_BYTES; channel++) {
|
||||
dev->a_nbNewAdrPointer[channel] = pState[0] | (pState[1] << 4);
|
||||
pState += 2;
|
||||
}
|
||||
|
||||
/* ------- Wait for scan state stop ------- */
|
||||
u12io_StartTimer( &timer, _SECOND * 2 );
|
||||
|
||||
u12io_ResetFifoLen();
|
||||
while(!(u12io_GetScanState( dev ) & _SCANSTATE_STOP) &&
|
||||
!u12io_CheckTimer(&timer));
|
||||
u12io_DownloadScanStates( dev );
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_LINECONTROL, dev->regs.RD_LineControl );
|
||||
_SET_REG( rb, c, REG_EXTENDEDLINECONTROL,
|
||||
dev->regs.RD_ExtLineControl);
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, dev->regs.RD_XStepTime );
|
||||
_SET_REG( rb, c, REG_EXTENDEDXSTEP, dev->regs.RD_ExtXStepTime );
|
||||
_SET_REG( rb, c, REG_MOTORDRVTYPE,
|
||||
dev->regs.RD_MotorDriverType );
|
||||
_SET_REG( rb, c, REG_STEPCONTROL, dev->regs.RD_StepControl );
|
||||
_SET_REG( rb, c, REG_MOTOR0CONTROL, dev->regs.RD_Motor0Control );
|
||||
_SET_REG( rb, c, REG_MODELCONTROL, dev->regs.RD_ModelControl );
|
||||
_SET_REG( rb, c, REG_DPILO, (_LOBYTE(dev->regs.RD_Dpi)));
|
||||
_SET_REG( rb, c, REG_DPIHI, (_HIBYTE(dev->regs.RD_Dpi)));
|
||||
_SET_REG( rb, c, REG_SCANPOSLO, (_LOBYTE(dev->regs.RD_Origin)));
|
||||
_SET_REG( rb, c, REG_SCANPOSHI,(_HIBYTE(dev->regs.RD_Origin)));
|
||||
_SET_REG( rb, c, REG_WIDTHPIXELLO,(_LOBYTE(dev->regs.RD_Pixels)));
|
||||
_SET_REG( rb, c, REG_WIDTHPIXELHI,(_HIBYTE(dev->regs.RD_Pixels)));
|
||||
_SET_REG( rb, c, REG_THRESHOLDLO,
|
||||
(_LOBYTE(dev->regs.RD_ThresholdControl)));
|
||||
_SET_REG( rb, c, REG_THRESHOLDHI,
|
||||
(_HIBYTE(dev->regs.RD_ThresholdControl)));
|
||||
_SET_REG( rb, c, REG_MOTORTOTALSTEP0,
|
||||
(_LOBYTE(dev->regs.RD_MotorTotalSteps)));
|
||||
_SET_REG( rb, c, REG_MOTORTOTALSTEP1,
|
||||
(_HIBYTE(dev->regs.RD_MotorTotalSteps)));
|
||||
_SET_REG( rb, c, REG_SCANCONTROL, dev->regs.RD_ScanControl);
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
_DODELAY(100);
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_INITDATAFIFO );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12hw_Memtest( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte tmp;
|
||||
SANE_Byte buf[_TEST_SIZE];
|
||||
int i;
|
||||
|
||||
DBG( _DBG_INFO, "u12hw_Memtest()\n" );
|
||||
|
||||
/* prepare buffer */
|
||||
for( i = 0; i < _TEST_SIZE; i++ ) {
|
||||
buf[i] = (SANE_Byte)((i * 3) & 0xff);
|
||||
}
|
||||
|
||||
/* avoid switching to Lamp0, when previously scanned in transp./neg mode */
|
||||
tmp = dev->lastLampStatus + _SCAN_BYTEMODE;
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL, tmp );
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeMappingMem );
|
||||
u12io_DataToRegister( dev, REG_MEMORYLO, 0 );
|
||||
u12io_DataToRegister( dev, REG_MEMORYHI, 0 );
|
||||
|
||||
/* fill to buffer */
|
||||
u12io_MoveDataToScanner( dev, buf, _TEST_SIZE );
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeMappingMem );
|
||||
u12io_DataToRegister( dev, REG_MEMORYLO, 0 );
|
||||
u12io_DataToRegister( dev, REG_MEMORYHI, 0 );
|
||||
|
||||
u12io_DataToRegister( dev, REG_WIDTHPIXELLO, 0 );
|
||||
u12io_DataToRegister( dev, REG_WIDTHPIXELHI, 5 );
|
||||
|
||||
memset( buf, 0, _TEST_SIZE );
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeReadMappingMem;
|
||||
u12io_ReadData( dev, buf, _TEST_SIZE );
|
||||
|
||||
for( i = 0; i < _TEST_SIZE; i++ ) {
|
||||
if((SANE_Byte)((i * 3) & 0xff) != buf[i] ) {
|
||||
DBG( _DBG_ERROR, "* Memtest failed at pos %u: %u != %u\n",
|
||||
i+1, buf[i], (SANE_Byte)((i * 3) & 0xff) );
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
}
|
||||
DBG( _DBG_INFO, "* Memtest passed.\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** check if ASIC can be accessed, if the version is supported and the memory
|
||||
* is also accessible...
|
||||
*/
|
||||
static SANE_Status u12hw_CheckDevice( U12_Device *dev )
|
||||
{
|
||||
#ifndef _FAKE_DEVICE
|
||||
SANE_Byte tmp;
|
||||
|
||||
if( !u12io_IsConnected( dev->fd )) {
|
||||
|
||||
if( !u12io_OpenScanPath( dev ))
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
/* some setup stuff... */
|
||||
tmp = u12io_GetExtendedStatus( dev );
|
||||
DBG( _DBG_INFO, "* REG_STATUS2 = 0x%02x\n", tmp );
|
||||
if( tmp & _REFLECTIONLAMP_ON ) {
|
||||
DBG( _DBG_INFO, "* Normal lamp is ON\n" );
|
||||
dev->lastLampStatus = _SCAN_NORMALLAMP_ON;
|
||||
} else if( tmp & _TPALAMP_ON ) {
|
||||
dev->lastLampStatus = _SCAN_TPALAMP_ON;
|
||||
DBG( _DBG_INFO, "* TPA lamp is ON\n" );
|
||||
}
|
||||
|
||||
u12io_DataToRegister( dev, REG_PLLPREDIV, 1 );
|
||||
u12io_DataToRegister( dev, REG_PLLMAINDIV, 0x20 );
|
||||
u12io_DataToRegister( dev, REG_PLLPOSTDIV, 2 );
|
||||
u12io_DataToRegister( dev, REG_CLOCKSELECTOR, 2 );
|
||||
|
||||
if( !dev->initialized )
|
||||
return u12hw_Memtest( dev );
|
||||
else
|
||||
return SANE_STATUS_GOOD;
|
||||
#else
|
||||
_VAR_NOT_USED( dev );
|
||||
return SANE_STATUS_GOOD;
|
||||
#endif
|
||||
}
|
||||
|
||||
static SANE_Status u12hw_WarmupLamp( U12_Device *dev )
|
||||
{
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "u12hw_WarmupLamp()\n" );
|
||||
|
||||
if( dev->warmupNeeded ) {
|
||||
DBG( _DBG_INFO, "* warming up...\n" );
|
||||
u12io_StartTimer( &timer, _SECOND * dev->adj.warmup );
|
||||
while( !u12io_CheckTimer( &timer )) {
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DBG( _DBG_INFO, "* skipped\n" );
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/* END U12-HW.C .............................................................*/
|
|
@ -0,0 +1,472 @@
|
|||
/** @file u12-hwdef.h
|
||||
* @brief Definitions for the ASIC.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
#ifndef __U12_HWDEF_H__
|
||||
#define __U12_HWDEF_H__
|
||||
|
||||
#define _LOWORD(x) ((u_short)(x & 0xffff))
|
||||
#define _HIWORD(x) ((u_short)(x >> 16))
|
||||
#define _LOBYTE(x) ((SANE_Byte)((x) & 0xFF))
|
||||
#define _HIBYTE(x) ((SANE_Byte)((x) >> 8))
|
||||
|
||||
#define _SET_REG(b,c,r,v) {b[c*2]=r; b[(c*2)+1]=v;c++;}
|
||||
|
||||
/** some magics for the ASIC */
|
||||
#define _ID_TO_PRINTER 0x00
|
||||
#define _ID1ST 0x69
|
||||
#define _ID2ND 0x96
|
||||
#define _ID3RD 0xa5
|
||||
#define _ID4TH 0x5a
|
||||
|
||||
/** some more for reset...
|
||||
*/
|
||||
#define _RESET1ST 0x69
|
||||
#define _RESET2ND 0x96
|
||||
#define _RESET3RD 0xaa
|
||||
#define _RESET4TH 0x55
|
||||
|
||||
/** Printer Control Port: Definitions
|
||||
*/
|
||||
#define _CTRL_STROBE 0x01
|
||||
#define _CTRL_AUTOLF 0x02
|
||||
#define _CTRL_NOT_INIT 0x04
|
||||
#define _CTRL_SELECT_IN 0x08
|
||||
#define _CTRL_ENABLE_IRQ 0x10
|
||||
#define _CTRL_DIRECTION 0x20
|
||||
#define _CTRL_RESERVED 0xc0
|
||||
|
||||
/** for Asic I/O signal control
|
||||
*/
|
||||
#define _CTRL_GENSIGNAL (_CTRL_RESERVED + _CTRL_NOT_INIT) /* 0xc4 */
|
||||
#define _CTRL_SIGNAL_REGWRITE (_CTRL_GENSIGNAL + _CTRL_SELECT_IN) /* 0xcc */
|
||||
#define _CTRL_END_REGWRITE (_CTRL_GENSIGNAL) /* 0xc4 */
|
||||
#define _CTRL_SIGNAL_DATAWRITE (_CTRL_GENSIGNAL + _CTRL_AUTOLF) /* 0xc6 */
|
||||
#define _CTRL_END_DATAWRITE (_CTRL_GENSIGNAL) /* 0xc4 */
|
||||
|
||||
#define ASIC_ID 0x83
|
||||
|
||||
/** the Register set
|
||||
*/
|
||||
#define REG_SWITCHBUS 0x00
|
||||
#define REG_EPPENABLE 0x01
|
||||
|
||||
#define REG_READDATAMODE 0x03
|
||||
#define REG_WRITEDATAMODE 0x04
|
||||
#define REG_INITDATAFIFO 0x05
|
||||
#define REG_FORCESTEP 0x06
|
||||
|
||||
#define REG_REFRESHSCANSTATE 0x08
|
||||
|
||||
#define REG_WAITSTATEINSERT 0x0a
|
||||
#define REG_RFIFOOFFSET 0x0a
|
||||
#define REG_GFIFOOFFSET 0x0b
|
||||
#define REG_BFIFOOFFSET 0x0c
|
||||
|
||||
#define REG_STEPCONTROL 0x14
|
||||
#define REG_MOTOR0CONTROL 0x15
|
||||
#define REG_XSTEPTIME 0x16
|
||||
|
||||
#define REG_GETSCANSTATE 0x17
|
||||
#define REG_ASICID 0x18
|
||||
#define REG_MEMORYLO 0x19
|
||||
#define REG_MEMORYHI 0x1a
|
||||
#define REG_MODECONTROL 0x1b
|
||||
#define REG_LINECONTROL 0x1c
|
||||
#define REG_SCANCONTROL 0x1d
|
||||
#define REG_CONFIG 0x1e
|
||||
#define REG_MODELCONTROL 0x1f
|
||||
#define REG_MODEL1CONTROL 0x20
|
||||
#define REG_DPILO 0x21
|
||||
#define REG_DPIHI 0x22
|
||||
#define REG_SCANPOSLO 0x23
|
||||
#define REG_SCANPOSHI 0x24
|
||||
#define REG_WIDTHPIXELLO 0x25
|
||||
#define REG_WIDTHPIXELHI 0x26
|
||||
#define REG_THRESHOLDLO 0x27
|
||||
#define REG_THRESHOLDHI 0x28
|
||||
|
||||
#define REG_ADCADDR 0x2a
|
||||
#define REG_ADCDATA 0x2b
|
||||
#define REG_ADCSERIALOUT 0x2d
|
||||
|
||||
#define REG_RESETCONFIG 0x2e
|
||||
|
||||
#define REG_STATUS 0x30
|
||||
#define REG_SCANSTATECONTROL 0x31
|
||||
|
||||
#define REG_REDCHDARKOFFSETLO 0x33
|
||||
#define REG_REDCHDARKOFFSETHI 0x34
|
||||
#define REG_GREENCHDARKOFFSETLO 0x35
|
||||
#define REG_GREENCHDARKOFFSETHI 0x36
|
||||
#define REG_BLUECHDARKOFFSETLO 0x37
|
||||
#define REG_BLUECHDARKOFFSETHI 0x38
|
||||
|
||||
#define REG_FIFOFULLEN0 0x54
|
||||
#define REG_FIFOFULLEN1 0x55
|
||||
#define REG_FIFOFULLEN2 0x56
|
||||
#define REG_MOTORTOTALSTEP0 0x57
|
||||
#define REG_MOTORTOTALSTEP1 0x58
|
||||
#define REG_MOTORFREERUNCOUNT0 0x59
|
||||
#define REG_MOTORFREERUNCOUNT1 0x5a
|
||||
#define REG_SCANCONTROL1 0x5b
|
||||
#define REG_MOTORFREERUNTRIGGER 0x5c
|
||||
#define REG_RESETMTSC 0x5d
|
||||
|
||||
#define REG_MOTORDRVTYPE 0x64
|
||||
|
||||
#define REG_STATUS2 0x66
|
||||
|
||||
#define REG_EXTENDEDLINECONTROL 0x6d
|
||||
#define REG_EXTENDEDXSTEP 0x6e
|
||||
|
||||
#define REG_PLLPREDIV 0x71
|
||||
#define REG_PLLMAINDIV 0x72
|
||||
#define REG_PLLPOSTDIV 0x73
|
||||
#define REG_CLOCKSELECTOR 0x74
|
||||
|
||||
#define REG_TESTMODE 0xf0
|
||||
|
||||
/* Register RegStepControl (Addr: 0x14) */
|
||||
#define _MOTOR0_ONESTEP 0x01
|
||||
#define _MOTOR0_SCANSTATE 0x02
|
||||
#define _MOTOR_FREERUN 0x40
|
||||
#define _MOTOR_NOFREERUN 0x00
|
||||
|
||||
/* Register RegGetScanState (Addr: 0x17)*/
|
||||
#define _SCANSTATE_MASK 0x3f /* bit 0-5 */
|
||||
#define _SCANSTATE_STOP 0x80
|
||||
|
||||
/* Register RegMemoryLow/High (Addr: 0x19/0x1a)*/
|
||||
#define _MAP_ADDR_RED 0x00
|
||||
#define _MAP_ADDR_GREEN 0x40
|
||||
#define _MAP_ADDR_BLUE 0x80
|
||||
#define _MAP_ADDR_SIZE 0x40
|
||||
|
||||
/* Register RegModeControl (Addr: 0x1b)*/
|
||||
#define _ModeScan 0x00
|
||||
#define _ModeIdle 0x01
|
||||
#define _ModeShadingMem 0x02
|
||||
#define _ModeMappingMem 0x03
|
||||
#define _ModeReadMappingMem 0x07
|
||||
#define _ModeFifoRSel 0x00
|
||||
#define _ModeFifoGSel 0x08
|
||||
#define _ModeFifoBSel 0x10
|
||||
#define _ModeFifoClose 0x18
|
||||
|
||||
/* Register RegLineControl (Addr: 0x1c) */
|
||||
#define _LINE_SCANTIME_MASK 0x3f /* bit 0-6 */
|
||||
#define _LINE_CDSINVERSE 0x80 /* Color Drive Signal */
|
||||
|
||||
/* Register RegScanControl (Addr: 0x1d) */
|
||||
#define _SCAN_BITMODE 0x00
|
||||
#define _SCAN_BYTEMODE 0x01 /* Gray/Color mode */
|
||||
#define _SCAN_12BITMODE 0x02
|
||||
#define _SCAN_1ST_AVERAGE 0x04 /* first pixel is averaged pixel */
|
||||
#define _SCAN_BITDIRR2L 0x08 /* bit shift from right to left */
|
||||
#define _SCAN_NORMALLAMP_ON 0x10 /* normal Lamp */
|
||||
#define _SCAN_TPALAMP_ON 0x20
|
||||
#define _SCAN_DATA_INVERT 0x40
|
||||
#define _BITALIGN_LEFT 0x80
|
||||
|
||||
#define _SCAN_LAMPS_ON (_SCAN_NORMALLAMP_ON | _SCAN_TPALAMP_ON)
|
||||
#define _SCAN_LAMP_MASK _SCAN_LAMPS_ON
|
||||
|
||||
/* Register RegMotor0Control (Addr: 0x15) */
|
||||
#define _MotorDirForward 0x01
|
||||
#define _MotorDirBackward 0x00
|
||||
#define _MotorOn 0x02
|
||||
#define _MotorHFullStepH 0x00
|
||||
#define _MotorHHalfStep 0x04
|
||||
#define _MotorHQuarterStep 0x08
|
||||
#define _MotorPowerEnable 0x40
|
||||
#define _MotorHHomeStop 0x80
|
||||
|
||||
#define _DIR_FW 1
|
||||
#define _DIR_BW 2
|
||||
#define _DIR_NONE 0
|
||||
|
||||
#define _FORWARD_MOTOR (_MotorDirForward + _MotorOn + \
|
||||
_MotorHQuarterStep + _MotorPowerEnable)
|
||||
#define _BACKWARD_MOTOR (_MotorDirBackward + _MotorOn + _MotorHHomeStop + \
|
||||
_MotorHQuarterStep + _MotorPowerEnable)
|
||||
|
||||
/* Register RegConfiguration (Addr: 0x1e) */
|
||||
#define _P98_CCD_TYPE_ID 0x07
|
||||
#define _P98_NEC_MACHINE 0x08
|
||||
#define _P98_PCBID 0xF0
|
||||
|
||||
#define _DEF_BW_THRESHOLD 111 /* default B/W mode threshold value */
|
||||
#define _NUMBER_OF_SCANSTEPS 64 /* Asic spec.: up to 64 scan steps */
|
||||
#define _SCANSTATE_BYTES (_NUMBER_OF_SCANSTEPS/2)
|
||||
|
||||
#define _CCD_3797 0
|
||||
#define _CCD_3799 1
|
||||
#define _CCD_535 2
|
||||
#define _CCD_2556 3
|
||||
#define _CCD_518 4
|
||||
#define _CCD_539 5
|
||||
#define _CCD_3777 6
|
||||
#define _CCD_548 7
|
||||
|
||||
/* PCB-IDs (from parport driver)... */
|
||||
#define _OPTICWORKS2000 0x00
|
||||
#define _PLUSTEK_SCANNER 0x10
|
||||
#define _SCANNER_WITH_TPA 0x20
|
||||
#define _SCANNER4Button 0x30
|
||||
#define _SCANNER4ButtonTPA 0x40
|
||||
#define _SCANNER5Button 0x50
|
||||
#define _SCANNER5ButtonTPA 0x60
|
||||
#define _SCANNER1Button 0x70
|
||||
#define _SCANNER1ButtonTPA 0x80
|
||||
#define _SCANNER2Button 0x90
|
||||
#define _AGFA_SCANNER 0xf0
|
||||
#define _AGFA_PCB 0x1f
|
||||
|
||||
/* Register RegModelControl (Addr: 0x1f) */
|
||||
#define _HOME_SENSOR_POLARITY 0x01
|
||||
#define _LED_CONTROL 0x02
|
||||
#define _LED_ACTIVITY 0x04
|
||||
#define _MODEL_DPI200 0x00
|
||||
#define _MODEL_DPI300 0x08
|
||||
#define _MODEL_DPI400 0x10
|
||||
#define _MODEL_DPI600 0x18
|
||||
#define _MODEL_DPI800 0x20
|
||||
#define _MODEL_DPI1200 0x28
|
||||
#define _DUMMY_12BIT 0x40
|
||||
|
||||
/* Register RegModel1Control (Addr: 0x20) */
|
||||
#define _SCAN_GRAYTYPE 0x01
|
||||
#define _CCD_SHIFT_GATE 0x02
|
||||
#define _CCD_SHIFT_PULSE 0x04
|
||||
#define _BUTTON_MODE 0x08
|
||||
#define _MOTOR_2003 0x00
|
||||
#define _MOTOR_2916 0x10
|
||||
#define _MOTOR_7042 0x20
|
||||
|
||||
/* Register RegThresholdGapControl (Addr: 0x29) */
|
||||
#define _THRESHOLDGAP_MASK 0x0f
|
||||
|
||||
/* Register RegResetConfig (Addr: 0x2e) */
|
||||
#define _ADC_MASK 0x07
|
||||
#define _DA_WOLFSON8143 0x00
|
||||
#define _DA_ESIC 0x04
|
||||
#define _DA_SAMSUNG8531 0x05
|
||||
#define _DA_WOLFSON8141 0x06
|
||||
#define _DA_SAMSUNG1224 0x07
|
||||
#define _MOTOR0_MASK 0x18
|
||||
#define _MOTOR0_2003 0x00
|
||||
#define _MOTOR0_2916 0x08
|
||||
#define _MOTOR0_7042 0x10
|
||||
#define _MOTOR1_MASK 0x60
|
||||
#define _MOTOR1_2003 0x00
|
||||
#define _MOTOR1_2916 0x20
|
||||
#define _MOTOR1_7042 0x40
|
||||
|
||||
/* Status Register (Addr: 0x30) */
|
||||
#define _FLAG_PAPER 0x01
|
||||
#define _FLAG_KEY 0x80
|
||||
|
||||
/* Register RegFifoFullLength (Addr: 0x54) */
|
||||
#define _RED_FULLSIZE 0x00
|
||||
#define _GREEN_FULLSIZE 0x08
|
||||
#define _BLUE_FULLSIZE 0x10
|
||||
|
||||
/* Register RegScanControl1 (Addr: 0x5b) */
|
||||
#define _MTSC_ENABLE 0x01
|
||||
#define _SCANSTOPONBUFFULL 0x02
|
||||
#define _MFRC_RUNSCANSTATE 0x04
|
||||
#define _MFRC_BY_XSTEP 0x08
|
||||
|
||||
/* Register RegMotorDriverType (Addr: 0x64) */
|
||||
#define _MOTORS_MASK 0x33
|
||||
#define _MOTORR_MASK 0xf3
|
||||
#define _MOTORR_WEAK 0x04
|
||||
#define _MOTORR_MEDIUM 0x08
|
||||
#define _MOTORR_STRONG 0x0c
|
||||
#define _MOTORT_WEAK 0x40
|
||||
#define _MOTORT_MEDIUM 0x80
|
||||
#define _MOTORT_STRONG 0xc0
|
||||
#define _BUTTON_SELECT1 0x40
|
||||
#define _BUTTON_SELECT2 0x80
|
||||
#define _BUTTON_DISABLE 0xc0
|
||||
|
||||
/** Register RegStatus2 (Addr: 0x66) */
|
||||
#define _REFLECTIONLAMP_ON 0x01
|
||||
#define _TPALAMP_ON 0x02
|
||||
#define _STILL_FREE_RUNNING 0x04
|
||||
#define _BUFFER_IS_FULL 0x08
|
||||
|
||||
/** Register RegTestMode (Addr: 0xf0) */
|
||||
#define _SW_TESTMODE 0x20
|
||||
|
||||
/** buffer sizes */
|
||||
#define _BYTES_PER_CHANNEL 5500UL
|
||||
#define _SIZE_DATA_BUF (u_long)(_BYTES_PER_CHANNEL * 3 * 2)
|
||||
#define _SIZE_TPA_DATA_BUF (u_long)(_BYTES_PER_CHANNEL * 3 * 2)
|
||||
#define _SIZE_SHADING_SUM_BUF (u_long)(_BYTES_PER_CHANNEL * 3 * 4)
|
||||
#define _SIZE_TOTAL_BUF (u_long)(_SIZE_DATA_BUF + _SIZE_SHADING_SUM_BUF)
|
||||
#define _SIZE_TOTAL_BUF_TPA (u_long)(_SIZE_TOTAL_BUF + _SIZE_TPA_DATA_BUF)
|
||||
|
||||
/** internal FIFO buffers */
|
||||
#define _SIZE_REDFIFO 196608UL /* 192k */
|
||||
#define _SIZE_GREENFIFO 147456UL /* 144k */
|
||||
#define _SIZE_BLUEFIFO 114688UL /* 112k */
|
||||
|
||||
#define _SIZE_GRAYFIFO (_SIZE_REDFIFO + _SIZE_GREENFIFO + _SIZE_BLUEFIFO)
|
||||
|
||||
/* Scan State Definitions */
|
||||
#define _SS_STEP 0x08
|
||||
#define _SS_RED 0x04
|
||||
#define _SS_GREEN 0x02
|
||||
#define _SS_BLUE 0x01
|
||||
|
||||
#define _SS_MONO _SS_GREEN
|
||||
#define _SS_COLOR (_SS_RED | _SS_GREEN | _SS_BLUE)
|
||||
|
||||
/** some positioning stuff
|
||||
*/
|
||||
#define _RFT_SCANNING_ORG 380U
|
||||
#define _POS_SCANNING_ORG 2840U
|
||||
#define _NEG_SCANNING_ORG 3000U
|
||||
#define _TPA_SHADINGORG 2172U
|
||||
|
||||
#define _DATA_ORIGIN_X 72
|
||||
#define _YOFFSET 300
|
||||
|
||||
#define _POS_PAGEWIDTH 450U
|
||||
#define _POS_ORG_OFFSETX 0x41C
|
||||
|
||||
#define _NEG_PAGEWIDTH 464U
|
||||
#define _NEG_PAGEWIDTH600 992U
|
||||
#define _NEG_ORG_OFFSETX 0x430
|
||||
#define _NEG_EDGE_VALUE 0x800
|
||||
#define _NEG_SHADING_OFFS 1500U
|
||||
|
||||
#define _SHADING_BEGINX 4U
|
||||
|
||||
|
||||
#define _DEFAULT_LINESCANTIME 96
|
||||
|
||||
#define _LINE_TIMEOUT (_SECOND * 5 )
|
||||
|
||||
|
||||
/** for mirroring parts of the 98003 ASIC register set
|
||||
*/
|
||||
typedef struct {
|
||||
SANE_Byte RD_Motor1Control; /* 0x0b */
|
||||
SANE_Byte RD_StepControl; /* 0x14 */
|
||||
SANE_Byte RD_Motor0Control; /* 0x15 */
|
||||
SANE_Byte RD_XStepTime; /* 0x16 */
|
||||
SANE_Byte RD_ModeControl; /* 0x1b */
|
||||
SANE_Byte RD_LineControl; /* 0x1c */
|
||||
SANE_Byte RD_ScanControl; /* 0x1d, init = 5 */
|
||||
SANE_Byte RD_ModelControl; /* 0x1f */
|
||||
SANE_Byte RD_Model1Control; /* 0x20 */
|
||||
u_short RD_Dpi; /* 0x21 */
|
||||
u_short RD_Origin; /* 0x23 */
|
||||
u_short RD_Pixels; /* 0x25 */
|
||||
u_short RD_ThresholdControl; /* 0x27 */
|
||||
SANE_Byte RD_ThresholdGapCtrl; /* 0x29 */
|
||||
u_short RD_RedDarkOff; /* 0x33 */
|
||||
u_short RD_GreenDarkOff; /* 0x35 */
|
||||
u_short RD_BlueDarkOff; /* 0x37 */
|
||||
|
||||
u_long RD_BufFullSize; /* 0x54 */
|
||||
u_short RD_MotorTotalSteps; /* 0x57 */
|
||||
|
||||
SANE_Byte RD_ScanControl1; /* 0x5b */
|
||||
SANE_Byte RD_MotorDriverType; /* 0x64 */
|
||||
SANE_Byte RD_ExtLineControl; /* 0x6d */
|
||||
SANE_Byte RD_ExtXStepTime; /* 0x6e */
|
||||
|
||||
} ShadowRegs;
|
||||
|
||||
/** to hold all the shading stuff for calibrating a scanner
|
||||
*/
|
||||
typedef struct svd
|
||||
{
|
||||
ColorWord GainResize;
|
||||
ColorWord DarkCmpHi;
|
||||
ColorWord DarkCmpLo;
|
||||
ColorWord DarkOffSub;
|
||||
ColorByte DarkDAC;
|
||||
SANE_Byte Reserved;
|
||||
} ShadingVarDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ShadingVarDef *pCcdDac;
|
||||
ColorByte DarkDAC;
|
||||
ColorWord DarkOffset;
|
||||
u_short wDarkLevels;
|
||||
SANE_Byte intermediate;
|
||||
|
||||
u_long dwDiv;
|
||||
SANE_Byte skipShadow;
|
||||
|
||||
SANE_Byte skipHilight;
|
||||
ColorByte Hilight;
|
||||
RGBUShortDef *pHilight;
|
||||
ColorByte Gain;
|
||||
SANE_Byte bGainDouble;
|
||||
SANE_Byte bUniGain;
|
||||
SANE_Byte bMinGain;
|
||||
SANE_Byte bMaxGain;
|
||||
SANE_Byte bGainHigh;
|
||||
SANE_Byte bGainLow;
|
||||
|
||||
SANE_Bool fStop;
|
||||
|
||||
u_short wExposure;
|
||||
u_short wXStep;
|
||||
|
||||
} ShadingDef;
|
||||
|
||||
#endif /* guard __U12_HWDEF_H__ */
|
||||
|
||||
/* END U12-HWDEF.H ..........................................................*/
|
|
@ -0,0 +1,606 @@
|
|||
/** @file u12-if.c
|
||||
* @brief The interface functions to the U12 backend stuff.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
#define _DEF_BRIGHTEST_SKIP 3
|
||||
#define _DEF_DARKEST_SKIP 5
|
||||
|
||||
/** useful for description tables
|
||||
*/
|
||||
typedef struct {
|
||||
int id;
|
||||
char *desc;
|
||||
} TabDef;
|
||||
|
||||
typedef struct {
|
||||
char *vp;
|
||||
char *name;
|
||||
} DevDesc;
|
||||
|
||||
#define _PLUSTEK_VENID 0x07B3
|
||||
#define _KYE_VENID 0x0458
|
||||
|
||||
/** to allow different vendors...
|
||||
*/
|
||||
static TabDef u12Vendors[] = {
|
||||
|
||||
{ _PLUSTEK_VENID, "Plustek" },
|
||||
{ _KYE_VENID, "KYE/Genius" },
|
||||
{ 0xFFFF, NULL }
|
||||
};
|
||||
|
||||
/** list of supported devices
|
||||
*/
|
||||
static DevDesc u12Devices[] = {
|
||||
{ "0x07B3-0x0001", "U12" },
|
||||
{ "0x0458-0x2004", "Colorpage HR6" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/** for autodetection */
|
||||
static SANE_Char USB_devname[1024];
|
||||
|
||||
/********************** the USB scanner interface ****************************/
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12_initDev( U12_Device *dev, int handle, int vendor )
|
||||
{
|
||||
int i;
|
||||
SANE_Status res;
|
||||
TimerDef timer;
|
||||
|
||||
/* well now we patch the vendor string...
|
||||
* if not found, the default vendor will be Plustek
|
||||
*/
|
||||
for( i = 0; u12Vendors[i].desc != NULL; i++ ) {
|
||||
|
||||
if( u12Vendors[i].id == vendor ) {
|
||||
dev->sane.vendor = u12Vendors[i].desc;
|
||||
DBG( _DBG_INFO, "Vendor adjusted to: >%s<\n", dev->sane.vendor );
|
||||
break;
|
||||
}
|
||||
}
|
||||
dev->fd = handle;
|
||||
|
||||
dev->adj.upNormal = 0;
|
||||
dev->adj.upNegative = 20;
|
||||
dev->adj.upPositive = -30;
|
||||
dev->adj.leftNormal = 51;
|
||||
|
||||
res = SANE_STATUS_IO_ERROR;
|
||||
if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) {
|
||||
|
||||
u12motor_PositionModuleToHome( dev );
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND * 20);
|
||||
do {
|
||||
if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER) {
|
||||
res = SANE_STATUS_GOOD;
|
||||
break;
|
||||
}
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
} else {
|
||||
res = u12hw_InitAsic( dev, SANE_FALSE );
|
||||
}
|
||||
|
||||
if( res == SANE_STATUS_GOOD )
|
||||
u12hw_PutToIdleMode( dev );
|
||||
return res;
|
||||
}
|
||||
|
||||
/** will be called upon sane_exit
|
||||
*/
|
||||
static void u12if_shutdown( U12_Device *dev )
|
||||
{
|
||||
SANE_Int handle;
|
||||
|
||||
DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n",
|
||||
dev->fd, dev->sane.name );
|
||||
if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) {
|
||||
|
||||
dev->fd = handle;
|
||||
u12io_OpenScanPath( dev );
|
||||
|
||||
u12hw_PutToIdleMode( dev );
|
||||
|
||||
if( 0 != dev->adj.lampOffOnEnd ) {
|
||||
|
||||
DBG( _DBG_INFO, "Switching lamp off...\n" );
|
||||
dev->regs.RD_ScanControl &= ~_SCAN_LAMPS_ON;
|
||||
u12io_DataToRegister(dev,REG_SCANCONTROL, dev->regs.RD_ScanControl );
|
||||
}
|
||||
|
||||
/* u12io_SoftwareReset( dev );
|
||||
*/ u12io_CloseScanPath( dev );
|
||||
dev->fd = -1;
|
||||
sanei_usb_close( handle );
|
||||
}
|
||||
|
||||
#if 0
|
||||
usb_StopLampTimer( dev );
|
||||
#endif
|
||||
}
|
||||
|
||||
/** This function checks wether a device, described by a given
|
||||
* string(vendor and product ID), is support by this backend or not
|
||||
*
|
||||
* @param usbIdStr - sting consisting out of product and vendor ID
|
||||
* format: "0xVVVV-0xPPPP" VVVV = Vendor ID, PPP = Product ID
|
||||
* @returns; SANE_TRUE if supported, SANE_FALSE if not
|
||||
*/
|
||||
static SANE_Bool u12if_IsDeviceSupported( char *usbIdStr )
|
||||
{
|
||||
/* Plustek U12, UT12, U1212, U12B */
|
||||
if( !strcmp( usbIdStr, "0x07B3-0x0001" ))
|
||||
return SANE_TRUE;
|
||||
|
||||
/* Genius Colorpage Vivid III V2 */
|
||||
if( !strcmp( usbIdStr, "0x0458-0x2004" ))
|
||||
return SANE_TRUE;
|
||||
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_usbattach( SANE_String_Const dev_name )
|
||||
{
|
||||
if( USB_devname[0] == '\0' ) {
|
||||
DBG( _DBG_INFO, "Found device at >%s<\n", dev_name );
|
||||
strncpy( USB_devname, dev_name, 1023 );
|
||||
USB_devname[1023] = '\0';
|
||||
} else {
|
||||
DBG( _DBG_INFO, "Device >%s< ignoring\n", dev_name );
|
||||
}
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
#ifndef _FAKE_DEVICE
|
||||
/** here we roam through our list of supported devices and
|
||||
* cross check with the ones the system reports...
|
||||
* @param vendor - pointer to receive vendor ID
|
||||
* @param product - pointer to receive product ID
|
||||
* @return SANE_TRUE if a matching device has been found or
|
||||
* SANE_FALSE if nothing supported found...
|
||||
*/
|
||||
static SANE_Bool usbDev_autodetect( SANE_Word *vendor, SANE_Word *product )
|
||||
{
|
||||
int i;
|
||||
SANE_Word p, v;
|
||||
|
||||
DBG( _DBG_INFO, "Autodetection...\n" );
|
||||
|
||||
for( i = 0; NULL != u12Devices[i].name; i++ ) {
|
||||
|
||||
v = strtol( &(u12Devices[i].name)[0], 0, 0 );
|
||||
p = strtol( &(u12Devices[i].name)[7], 0, 0 );
|
||||
DBG( _DBG_INFO, "Checking for 0x%04x-0x%04x\n", v, p );
|
||||
|
||||
sanei_usb_find_devices( v, p, u12if_usbattach );
|
||||
|
||||
if( USB_devname[0] != '\0' ) {
|
||||
|
||||
*vendor = v;
|
||||
*product = p;
|
||||
return SANE_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return SANE_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
*/
|
||||
static int u12if_open( U12_Device *dev )
|
||||
{
|
||||
char devStr[50];
|
||||
int result;
|
||||
SANE_Int handle;
|
||||
SANE_Word vendor, product;
|
||||
SANE_Bool was_empty;
|
||||
|
||||
DBG( _DBG_INFO, "u12if_open(%s,%s)\n", dev->name, dev->usbId );
|
||||
|
||||
USB_devname[0] = '\0';
|
||||
|
||||
#ifdef _FAKE_DEVICE
|
||||
dev->name = strdup( "auto" );
|
||||
dev->sane.name = dev->name;
|
||||
was_empty = SANE_FALSE;
|
||||
|
||||
result = SANE_STATUS_UNSUPPORTED;
|
||||
#else
|
||||
if( !strcmp( dev->name, "auto" )) {
|
||||
|
||||
if( dev->usbId[0] == '\0' ) {
|
||||
|
||||
if( !usbDev_autodetect( &vendor, &product )) {
|
||||
DBG( _DBG_ERROR, "No supported device found!\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
vendor = strtol( &dev->usbId[0], 0, 0 );
|
||||
product = strtol( &dev->usbId[7], 0, 0 );
|
||||
|
||||
sanei_usb_find_devices( vendor, product, u12if_usbattach );
|
||||
|
||||
if( USB_devname[0] == '\0' ) {
|
||||
DBG( _DBG_ERROR, "No matching device found!\n" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( SANE_STATUS_GOOD != sanei_usb_open( USB_devname, &handle ))
|
||||
return -1;
|
||||
|
||||
/* replace the old devname, so we are able to have multiple
|
||||
* auto-detected devices
|
||||
*/
|
||||
free( dev->name );
|
||||
dev->name = strdup( USB_devname );
|
||||
dev->sane.name = dev->name;
|
||||
|
||||
} else {
|
||||
|
||||
if( SANE_STATUS_GOOD != sanei_usb_open( dev->name, &handle ))
|
||||
return -1;
|
||||
}
|
||||
was_empty = SANE_FALSE;
|
||||
|
||||
result = sanei_usb_get_vendor_product( handle, &vendor, &product );
|
||||
#endif
|
||||
|
||||
if( SANE_STATUS_GOOD == result ) {
|
||||
|
||||
sprintf( devStr, "0x%04X-0x%04X", vendor, product );
|
||||
|
||||
DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product);
|
||||
|
||||
if( dev->usbId[0] != '\0' ) {
|
||||
|
||||
if( 0 != strcmp( dev->usbId, devStr )) {
|
||||
DBG( _DBG_ERROR, "Specified Vendor and Product ID "
|
||||
"doesn't match with the ones\n"
|
||||
"in the config file\n" );
|
||||
sanei_usb_close( handle );
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product );
|
||||
was_empty = SANE_TRUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DBG( _DBG_INFO, "Can't get vendor & product ID from driver...\n" );
|
||||
|
||||
/* if the ioctl stuff is not supported by the kernel and we have
|
||||
* nothing specified, we have to give up...
|
||||
*/
|
||||
if( dev->usbId[0] == '\0' ) {
|
||||
DBG( _DBG_ERROR, "Cannot autodetect Vendor an Product ID, "
|
||||
"please specify in config file.\n" );
|
||||
sanei_usb_close( handle );
|
||||
return -1;
|
||||
}
|
||||
|
||||
vendor = strtol( &dev->usbId[0], 0, 0 );
|
||||
product = strtol( &dev->usbId[7], 0, 0 );
|
||||
DBG( _DBG_INFO, "... using the specified: "
|
||||
"0x%04X-0x%04X\n", vendor, product );
|
||||
}
|
||||
|
||||
/* before accessing the scanner, check if supported!
|
||||
*/
|
||||
if( !u12if_IsDeviceSupported( dev->usbId )) {
|
||||
DBG( _DBG_ERROR, "Device >%s<, is not supported!\n", dev->usbId );
|
||||
sanei_usb_close( handle );
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->mode = _PP_MODE_SPP;
|
||||
dev->fd = handle;
|
||||
|
||||
/* is it accessible ? */
|
||||
if( SANE_STATUS_GOOD != u12hw_CheckDevice( dev )) {
|
||||
dev->fd = -1;
|
||||
sanei_usb_close( handle );
|
||||
return -1;
|
||||
}
|
||||
|
||||
DBG( _DBG_INFO, "Detected vendor & product ID: "
|
||||
"0x%04X-0x%04X\n", vendor, product );
|
||||
|
||||
if( was_empty )
|
||||
dev->usbId[0] = '\0';
|
||||
|
||||
/* now initialize the device */
|
||||
if( SANE_STATUS_GOOD != u12_initDev( dev, handle, vendor )) {
|
||||
dev->fd = -1;
|
||||
sanei_usb_close( handle );
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->initialized = SANE_TRUE;
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static int u12if_close( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12if_close()\n" );
|
||||
u12io_CloseScanPath( dev );
|
||||
sanei_usb_close( dev->fd );
|
||||
dev->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_getCaps( U12_Device *dev )
|
||||
{
|
||||
int cntr;
|
||||
int res_x = 600 ; /*dev->caps.OpticDpi.x */
|
||||
DBG( _DBG_INFO, "u12if_getCaps()\n" );
|
||||
|
||||
/* FIXME: set dpi_range.max, max_x & max_y on a per model base */
|
||||
dev->dpi_max_x = 600;
|
||||
dev->dpi_max_y = 1200;
|
||||
|
||||
/* A4 devices */
|
||||
dev->max_x = 8.5 * (double)_MM_PER_INCH;
|
||||
dev->max_y = 11.6934 * (double)_MM_PER_INCH;
|
||||
|
||||
/* limit the range */
|
||||
dev->dpi_range.min = _DEF_DPI;
|
||||
dev->dpi_range.max = dev->dpi_max_y;
|
||||
dev->dpi_range.quant = 0;
|
||||
dev->x_range.min = 0;
|
||||
dev->x_range.max = SANE_FIX(dev->max_x);
|
||||
dev->x_range.quant = 0;
|
||||
dev->y_range.min = 0;
|
||||
dev->y_range.max = SANE_FIX(dev->max_y);
|
||||
dev->y_range.quant = 0;
|
||||
|
||||
/* calculate the size of the resolution list +
|
||||
* one more to avoid a buffer overflow, then allocate it...
|
||||
*/
|
||||
dev->res_list = (SANE_Int *)
|
||||
calloc((((res_x * 16)-_DEF_DPI)/25+1),
|
||||
sizeof (SANE_Int));
|
||||
|
||||
if (NULL == dev->res_list) {
|
||||
DBG( _DBG_ERROR, "alloc fail, resolution problem\n" );
|
||||
u12if_close(dev);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
/* build up the resolution table */
|
||||
dev->res_list_size = 0;
|
||||
for( cntr = _DEF_DPI; cntr <= (res_x*16); cntr += 25 ) {
|
||||
dev->res_list_size++;
|
||||
dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr;
|
||||
}
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_setScanEnv( U12_Device *dev, ImgDef *img )
|
||||
{
|
||||
SANE_Status res;
|
||||
|
||||
DBG( _DBG_INFO, "u12if_setScanEnv()\n" );
|
||||
res = u12image_SetupScanSettings( dev, img );
|
||||
|
||||
if( img->wDataType <= COLOR_256GRAY ) {
|
||||
u12map_Adjust( dev, _MAP_MASTER );
|
||||
} else {
|
||||
u12map_Adjust( dev, _MAP_RED );
|
||||
u12map_Adjust( dev, _MAP_GREEN );
|
||||
u12map_Adjust( dev, _MAP_BLUE );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_stopScan( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12if_stopScan()\n" );
|
||||
|
||||
u12motor_ToHomePosition( dev );
|
||||
|
||||
dev->DataInf.dwAppLinesPerArea = 0;
|
||||
dev->DataInf.dwScanFlag &= ~_SCANDEF_SCANNING;
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_startScan( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12if_startScan()\n" );
|
||||
u12hw_SetGeneralRegister( dev );
|
||||
u12hw_ControlLampOnOff( dev );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_prepare( U12_Device *dev )
|
||||
{
|
||||
SANE_Status res;
|
||||
|
||||
DBG( _DBG_INFO, "u12if_prepare()\n" );
|
||||
|
||||
u12motor_ToHomePosition( dev );
|
||||
|
||||
res = u12hw_WarmupLamp( dev );
|
||||
if( res != SANE_STATUS_GOOD )
|
||||
return res;
|
||||
|
||||
res = u12shading_DoCalibration( dev );
|
||||
if( res != SANE_STATUS_GOOD )
|
||||
return res;
|
||||
|
||||
u12motor_ForceToLeaveHomePos( dev );
|
||||
u12hw_SetupScanningCondition( dev );
|
||||
|
||||
res = u12motor_WaitForPositionY( dev );
|
||||
|
||||
_DODELAY(100);
|
||||
u12io_ResetFifoLen();
|
||||
u12io_GetFifoLength(dev);
|
||||
|
||||
dev->scan.bModuleState = _MotorAdvancing;
|
||||
dev->scan.oldScanState = u12io_GetScanState( dev );
|
||||
dev->scan.oldScanState &= _SCANSTATE_MASK;
|
||||
dev->DataInf.dwScanFlag |= _SCANDEF_SCANNING;
|
||||
DBG( _DBG_INFO, "* oldScanState = %u\n", dev->scan.oldScanState );
|
||||
DBG( _DBG_INFO, "u12if_prepare() done.\n" );
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_readLine( U12_Device *dev, SANE_Byte *line_buffer )
|
||||
{
|
||||
SANE_Status res;
|
||||
|
||||
DBG( _DBG_READ, "u12if_readLine()\n" );
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "u12if_readLine() - cancel detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ps->Scan.dwLinesToRead = count / ps->DataInf.dwAppBytesPerLine;
|
||||
DBG( DBG_HIGH, "dwLinesToRead = %ld\n", ps->Scan.dwLinesToRead );
|
||||
|
||||
if( ps->Scan.dwLinesToRead > ps->DataInf.dwAppLinesPerArea )
|
||||
ps->Scan.dwLinesToRead = ps->DataInf.dwAppLinesPerArea;
|
||||
|
||||
ps->DataInf.dwAppLinesPerArea -= ps->Scan.dwLinesToRead;
|
||||
|
||||
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle)
|
||||
buffer += ((ps->Scan.dwLinesToRead - 1) * ps->DataInf.dwAppBytesPerLine);
|
||||
|
||||
if (ps->DataInf.dwVxdFlag & _VF_DATATOUSERBUFFER)
|
||||
ps->DataInf.pCurrentBuffer = ps->Scan.bp.pMonoBuf;
|
||||
|
||||
while(ps->fScanningStatus && ps->Scan.dwLinesToRead) {
|
||||
#endif
|
||||
|
||||
res = u12image_ReadOneImageLine( dev, line_buffer );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* as we might scan images that exceed the CCD-capabilities
|
||||
* in x-resolution, we have to enlarge the line data
|
||||
*/
|
||||
if( NULL != scaleBuf ) {
|
||||
ScaleX( ps, ps->Scan.bp.pMonoBuf, scaleBuf );
|
||||
copy_to_user( buffer, scaleBuf, ps->DataInf.dwAppPhyBytesPerLine);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
buffer += ps->Scan.lBufferAdjust;
|
||||
dwLinesRead++;
|
||||
ps->Scan.dwLinesToRead--;
|
||||
#endif
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12if_SetupBuffer( U12_Device *dev )
|
||||
{
|
||||
void *buffer;
|
||||
|
||||
DBG( _DBG_INFO, "u12if_SetupBuffer()\n" );
|
||||
buffer = malloc(_SIZE_TOTAL_BUF_TPA);
|
||||
if( buffer == NULL )
|
||||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
dev->shade.pHilight = NULL;
|
||||
dev->bufs.b1.pReadBuf = buffer;
|
||||
dev->bufs.b2.pSumBuf = dev->bufs.b1.pReadBuf + _SIZE_DATA_BUF;
|
||||
dev->bufs.TpaBuf.pb = &((SANE_Byte*)dev->bufs.b2.pSumBuf)[_SIZE_SHADING_SUM_BUF];
|
||||
|
||||
/* CHECK: We might should play around with these values... */
|
||||
dev->shade.skipHilight = _DEF_BRIGHTEST_SKIP;
|
||||
dev->shade.skipShadow = _DEF_DARKEST_SKIP;
|
||||
|
||||
if( dev->shade.skipHilight && dev->shade.skipShadow ) {
|
||||
|
||||
u_long skipSize;
|
||||
|
||||
skipSize = (u_long)((dev->shade.skipHilight + dev->shade.skipShadow)
|
||||
* _SIZE_DATA_BUF * 3);
|
||||
dev->shade.pHilight = (RGBUShortDef*)malloc( skipSize );
|
||||
if( NULL != dev->shade.pHilight ) {
|
||||
dev->shade.dwDiv = (u_long)(32UL - dev->shade.skipHilight -
|
||||
dev->shade.skipShadow);
|
||||
}
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/* END U12-IF.C .............................................................*/
|
|
@ -0,0 +1,836 @@
|
|||
/* @file u12_image.c
|
||||
* @brief functions to convert scanner data into image data
|
||||
*
|
||||
* based on sources acquired from Plustek Inc.
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
/*************************** local vars **************************************/
|
||||
|
||||
static u_short wPreviewScanned = 0;
|
||||
|
||||
static ExpXStepDef negScan[5] = {
|
||||
{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
|
||||
};
|
||||
|
||||
static ExpXStepDef posScan[5] = {
|
||||
{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
|
||||
};
|
||||
|
||||
static ExpXStepDef nmlScan[5] = {
|
||||
{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96},
|
||||
};
|
||||
|
||||
/*************************** local functions *********************************/
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Bool fnReadToDriver( U12_Device *dev )
|
||||
{
|
||||
dev->regs.RD_ModeControl = _ModeFifoBSel;
|
||||
u12io_ReadMonoData( dev, dev->scan.BufPut.blue.bp,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
||||
u12io_ReadMonoData( dev, dev->scan.BufPut.green.bp,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
|
||||
if( dev->scan.gd_gk.wGreenKeep )
|
||||
dev->scan.gd_gk.wGreenKeep--;
|
||||
else {
|
||||
dev->scan.BufPut.green.bp += dev->DataInf.dwAsicBytesPerPlane;
|
||||
|
||||
if( dev->scan.BufPut.green.bp >= dev->scan.BufEnd.green.bp )
|
||||
dev->scan.BufPut.green.bp = dev->scan.BufBegin.green.bp;
|
||||
}
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeFifoRSel;
|
||||
u12io_ReadMonoData( dev, dev->scan.BufPut.red.bp,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
|
||||
dev->scan.BufPut.red.bp += dev->DataInf.dwAsicBytesPerPlane;
|
||||
if( dev->scan.BufPut.red.bp >= dev->scan.BufEnd.red.bp )
|
||||
dev->scan.BufPut.red.bp = dev->scan.BufBegin.red.bp;
|
||||
|
||||
if( dev->scan.bd_rk.wRedKeep ) {
|
||||
dev->scan.bd_rk.wRedKeep--;
|
||||
return SANE_FALSE;
|
||||
|
||||
} else {
|
||||
|
||||
dev->scan.BufData.green.bp = dev->scan.BufGet.green.bp;
|
||||
dev->scan.BufData.red.bp = dev->scan.BufGet.red.bp;
|
||||
dev->scan.BufData.blue.bp = dev->scan.BufGet.blue.bp;
|
||||
|
||||
dev->scan.BufGet.red.bp += dev->DataInf.dwAsicBytesPerPlane;
|
||||
dev->scan.BufGet.green.bp += dev->DataInf.dwAsicBytesPerPlane;
|
||||
|
||||
if( dev->scan.BufGet.red.bp >= dev->scan.BufEnd.red.bp )
|
||||
dev->scan.BufGet.red.bp = dev->scan.BufBegin.red.bp;
|
||||
|
||||
if( dev->scan.BufGet.green.bp >= dev->scan.BufEnd.green.bp )
|
||||
dev->scan.BufGet.green.bp = dev->scan.BufBegin.green.bp;
|
||||
|
||||
return SANE_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Bool fnReadOutScanner( U12_Device *dev )
|
||||
{
|
||||
#if 1
|
||||
if( dev->scan.bd_rk.wBlueDiscard ) {
|
||||
|
||||
dev->scan.bd_rk.wBlueDiscard--;
|
||||
dev->regs.RD_ModeControl = _ModeFifoBSel;
|
||||
|
||||
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
|
||||
if( dev->scan.gd_gk.wGreenDiscard ) {
|
||||
dev->scan.gd_gk.wGreenDiscard--;
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
||||
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
}
|
||||
return SANE_FALSE;
|
||||
|
||||
} else {
|
||||
#endif
|
||||
u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
return SANE_TRUE;
|
||||
#if 1
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** some sampling functions
|
||||
*/
|
||||
static SANE_Bool fnEveryLines( U12_Device *dev )
|
||||
{
|
||||
_VAR_NOT_USED( dev );
|
||||
return SANE_TRUE;
|
||||
}
|
||||
|
||||
static SANE_Bool fnSampleLines( U12_Device *dev )
|
||||
{
|
||||
dev->DataInf.wYSum += dev->DataInf.xyAppDpi.y;
|
||||
|
||||
if( dev->DataInf.wYSum >= dev->DataInf.xyPhyDpi.y ) {
|
||||
dev->DataInf.wYSum -= dev->DataInf.xyPhyDpi.y;
|
||||
return SANE_TRUE;
|
||||
}
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
static SANE_Bool fnSamplePreview( U12_Device *dev )
|
||||
{
|
||||
dev->DataInf.wYSum += wPreviewScanned;
|
||||
if( dev->DataInf.wYSum >= 150 ) {
|
||||
|
||||
dev->DataInf.wYSum -= 150;
|
||||
return SANE_TRUE;
|
||||
}
|
||||
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/** this function is used when
|
||||
* - the data type is B/W or GrayScale.
|
||||
* - the required horizontal resolution doesn't exceed the optic spec.
|
||||
* - the required vertical resolution exceeds the optic spec.
|
||||
*/
|
||||
static void fnDataDirect( U12_Device *dev, void *src, void *dest, u_long len )
|
||||
{
|
||||
_VAR_NOT_USED( dev );
|
||||
memcpy( dest, src, len );
|
||||
}
|
||||
|
||||
/** merges the color planes to pixels style without enlarge operation.
|
||||
*/
|
||||
static void fnColorDirect( U12_Device *dev, void *pb, void *img, u_long len )
|
||||
{
|
||||
SANE_Byte *src;
|
||||
RGBByteDef *dest;
|
||||
|
||||
src = (SANE_Byte*)img;
|
||||
dest = (RGBByteDef*)pb;
|
||||
|
||||
for ( len = dev->DataInf.dwAsicPixelsPerPlane; len; len--, src++, dest++) {
|
||||
|
||||
dest->Red = *src;
|
||||
dest->Green = src[dev->DataInf.dwAsicPixelsPerPlane];
|
||||
dest->Blue = src[dev->DataInf.dwAsicPixelsPerPlane*2];
|
||||
}
|
||||
}
|
||||
|
||||
/** merges the color planes to pixels style without enlarge operation.
|
||||
* The scanner returns the pixel data in Motorola-Format, so we have to swap
|
||||
* (at least on x86)
|
||||
*/
|
||||
static void fnColor42( U12_Device *dev, void *pb, void *img, u_long len )
|
||||
{
|
||||
u_short *src;
|
||||
RGBUShortDef *dest;
|
||||
|
||||
register u_long i;
|
||||
|
||||
_VAR_NOT_USED( len );
|
||||
src = (u_short*)img;
|
||||
dest = (RGBUShortDef*)pb;
|
||||
|
||||
for ( i = dev->DataInf.dwAsicPixelsPerPlane; i; i--, src++, dest++) {
|
||||
|
||||
dest->Red = *src;
|
||||
dest->Green = src[dev->DataInf.dwAsicPixelsPerPlane];
|
||||
dest->Blue = src[dev->DataInf.dwAsicPixelsPerPlane * 2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12image_SetupScanStateVariables( U12_Device *dev, u_long index )
|
||||
{
|
||||
DataType var;
|
||||
|
||||
DBG( _DBG_INFO, "u12image_SetupScanStateVariables(%lu)\n", index );
|
||||
dev->scan.dpiIdx = index;
|
||||
|
||||
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA)) {
|
||||
|
||||
dev->shade.wExposure = nmlScan[index].exposureTime;
|
||||
dev->shade.wXStep = nmlScan[index].xStepTime;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut ) {
|
||||
dev->shade.wExposure >>= 1;
|
||||
dev->shade.wXStep >>= 1;
|
||||
}
|
||||
} else {
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency ) {
|
||||
dev->shade.wExposure = posScan[index].exposureTime;
|
||||
dev->shade.wXStep = posScan[index].xStepTime;
|
||||
} else {
|
||||
dev->shade.wExposure = dev->scan.negScan[index].exposureTime;
|
||||
dev->shade.wXStep = dev->scan.negScan[index].xStepTime;
|
||||
}
|
||||
}
|
||||
dev->scan.dwInterval = 1;
|
||||
|
||||
if( dev->DataInf.wPhyDataType == COLOR_BW )
|
||||
var.dwValue = 0;
|
||||
else {
|
||||
if( dev->DataInf.wPhyDataType == COLOR_256GRAY )
|
||||
var.dwValue = 2500;
|
||||
else
|
||||
var.dwValue = 3200;
|
||||
}
|
||||
|
||||
/* for small size/descreen */
|
||||
if((dev->DataInf.xyAppDpi.y >= 300) && var.dwValue &&
|
||||
(dev->DataInf.dwAsicBytesPerPlane <= var.dwValue)) {
|
||||
dev->scan.dwInterval <<= 1;
|
||||
}
|
||||
|
||||
if( var.dwValue && dev->DataInf.dwAsicBytesPerPlane > var.dwValue ) {
|
||||
if((var.dwValue << 1) > dev->DataInf.dwAsicBytesPerPlane)
|
||||
dev->scan.dwInterval <<= 1;
|
||||
else
|
||||
if((var.dwValue << 2) > dev->DataInf.dwAsicBytesPerPlane)
|
||||
dev->scan.dwInterval <<= 2;
|
||||
else
|
||||
dev->scan.dwInterval <<= 3;
|
||||
}
|
||||
|
||||
if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
|
||||
|
||||
if( dev->DataInf.xyPhyDpi.y > 75U ) {
|
||||
if( dev->f0_8_16 ) {
|
||||
dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 75U;
|
||||
} else {
|
||||
dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 150U;
|
||||
}
|
||||
} else {
|
||||
dev->scan.gd_gk.wGreenDiscard = 1;
|
||||
}
|
||||
|
||||
dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard << 1;
|
||||
} else {
|
||||
dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** limit the resolution
|
||||
*/
|
||||
static u_short
|
||||
u12image_GetPhysDPI( U12_Device *dev, ImgDef *img, SANE_Bool fDpiX )
|
||||
{
|
||||
if( fDpiX ) {
|
||||
|
||||
if( img->xyDpi.x > dev->dpi_max_x )
|
||||
return dev->dpi_max_x;
|
||||
else
|
||||
return img->xyDpi.x;
|
||||
|
||||
} else {
|
||||
|
||||
if( img->xyDpi.y > dev->dpi_max_y )
|
||||
return dev->dpi_max_y;
|
||||
else
|
||||
return img->xyDpi.y;
|
||||
}
|
||||
}
|
||||
|
||||
/** calculate the image properties according to the scanmode
|
||||
* set all internally needed information
|
||||
*/
|
||||
static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12image_GetImageInfo()\n" );
|
||||
|
||||
dev->DataInf.xyPhyDpi.x = u12image_GetPhysDPI(dev, image, SANE_TRUE );
|
||||
dev->DataInf.xyPhyDpi.y = u12image_GetPhysDPI(dev, image, SANE_FALSE);
|
||||
|
||||
DBG( _DBG_INFO, "* xyPhyDpi.x = %u, xyPhyDpi.y = %u\n",
|
||||
dev->DataInf.xyPhyDpi.x, dev->DataInf.xyPhyDpi.y );
|
||||
|
||||
DBG( _DBG_INFO, "* crArea.x = %u, crArea.y = %u\n",
|
||||
image->crArea.x, image->crArea.y );
|
||||
|
||||
DBG( _DBG_INFO, "* crArea.cx = %u, crArea.cy = %u\n",
|
||||
image->crArea.cx, image->crArea.cy );
|
||||
|
||||
dev->DataInf.xyRatio = (double)dev->DataInf.xyPhyDpi.y/
|
||||
(double)dev->DataInf.xyPhyDpi.x;
|
||||
|
||||
dev->DataInf.dwAppLinesPerArea = (u_long)image->crArea.cy *
|
||||
image->xyDpi.y / _MEASURE_BASE;
|
||||
|
||||
dev->DataInf.dwAppPixelsPerLine = (u_long)image->crArea.cx *
|
||||
image->xyDpi.x / _MEASURE_BASE;
|
||||
|
||||
dev->DataInf.dwPhysBytesPerLine = (u_long)image->crArea.cx *
|
||||
dev->DataInf.xyPhyDpi.x / _MEASURE_BASE;
|
||||
|
||||
if( image->wDataType <= COLOR_BW ) {
|
||||
dev->DataInf.dwAsicPixelsPerPlane =
|
||||
(dev->DataInf.dwAppPixelsPerLine+7UL) & 0xfffffff8UL;
|
||||
dev->DataInf.dwAppPhyBytesPerLine =
|
||||
dev->DataInf.dwAppBytesPerLine =
|
||||
dev->DataInf.dwAsicBytesPerLine =
|
||||
dev->DataInf.dwAsicBytesPerPlane = dev->DataInf.dwAsicPixelsPerPlane>>3;
|
||||
} else {
|
||||
dev->DataInf.dwAsicBytesPerPlane =
|
||||
dev->DataInf.dwAsicPixelsPerPlane = dev->DataInf.dwAppPixelsPerLine;
|
||||
}
|
||||
|
||||
if( COLOR_TRUE42 == image->wDataType ) {
|
||||
dev->DataInf.dwAsicBytesPerPlane *= 2;
|
||||
}
|
||||
|
||||
switch( image->wDataType ) {
|
||||
|
||||
case COLOR_BW:
|
||||
dev->scan.DataProcess = fnDataDirect;
|
||||
dev->DataInf.wPhyDataType = COLOR_BW;
|
||||
dev->shade.intermediate = _ScanMode_Mono;
|
||||
break;
|
||||
|
||||
case COLOR_256GRAY:
|
||||
dev->scan.DataProcess = fnDataDirect;
|
||||
dev->DataInf.dwAsicBytesPerLine =
|
||||
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine;
|
||||
dev->DataInf.wPhyDataType = COLOR_256GRAY;
|
||||
dev->shade.intermediate = _ScanMode_Mono;
|
||||
break;
|
||||
|
||||
case COLOR_TRUE24:
|
||||
dev->scan.DataProcess = fnColorDirect;
|
||||
dev->DataInf.dwAsicBytesPerLine =
|
||||
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 3;
|
||||
dev->DataInf.wPhyDataType = COLOR_TRUE24;
|
||||
dev->shade.intermediate = _ScanMode_Color;
|
||||
break;
|
||||
|
||||
case COLOR_TRUE42:
|
||||
dev->scan.DataProcess = fnColor42;
|
||||
dev->DataInf.dwAsicBytesPerLine =
|
||||
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 6;
|
||||
dev->DataInf.wPhyDataType = COLOR_TRUE42;
|
||||
dev->shade.intermediate = _ScanMode_Color;
|
||||
break;
|
||||
}
|
||||
|
||||
/* raus mit einem von beiden!!!!*/
|
||||
dev->DataInf.dwAppBytesPerLine = dev->DataInf.dwAppPhyBytesPerLine;
|
||||
|
||||
DBG( _DBG_INFO, "AppLinesPerArea = %lu\n", dev->DataInf.dwAppLinesPerArea );
|
||||
DBG( _DBG_INFO, "AppPixelsPerLine = %lu\n", dev->DataInf.dwAppPixelsPerLine );
|
||||
DBG( _DBG_INFO, "AppPhyBytesPerLine = %lu\n", dev->DataInf.dwAppPhyBytesPerLine );
|
||||
DBG( _DBG_INFO, "AppBytesPerLine = %lu\n", dev->DataInf.dwAppBytesPerLine );
|
||||
DBG( _DBG_INFO, "AsicPixelsPerPlane = %lu\n", dev->DataInf.dwAsicPixelsPerPlane );
|
||||
DBG( _DBG_INFO, "AsicBytesPerPlane = %lu\n", dev->DataInf.dwAsicBytesPerPlane );
|
||||
DBG( _DBG_INFO, "AsicBytesPerLine = %lu\n", dev->DataInf.dwAsicBytesPerLine );
|
||||
DBG( _DBG_INFO, "Physical Bytes = %lu\n", dev->DataInf.dwPhysBytesPerLine );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static int imageSetupScanSettings( U12_Device *dev, ImgDef *img )
|
||||
{
|
||||
u_short brightness;
|
||||
u_long xAdjust;
|
||||
|
||||
DBG( _DBG_INFO, "imageSetupScanSettings()\n" );
|
||||
|
||||
xAdjust = img->crArea.x + img->crArea.cx;
|
||||
|
||||
dev->DataInf.dwScanFlag = img->dwFlag;
|
||||
dev->DataInf.crImage = img->crArea;
|
||||
|
||||
dev->DataInf.crImage.x <<= 1;
|
||||
|
||||
dev->DataInf.xyAppDpi = img->xyDpi;
|
||||
dev->DataInf.wAppDataType = img->wDataType;
|
||||
|
||||
u12image_GetImageInfo( dev, img );
|
||||
|
||||
dev->scan.lBufferAdjust = (long)dev->DataInf.dwAppBytesPerLine;
|
||||
|
||||
DBG( _DBG_INFO, "* Scan settings:\n" );
|
||||
DBG( _DBG_INFO, "* ImageInfo: (x=%u,y=%u,dx=%u,dy=%u)\n",
|
||||
dev->DataInf.crImage.x, dev->DataInf.crImage.y,
|
||||
dev->DataInf.crImage.cx, dev->DataInf.crImage.cy );
|
||||
|
||||
/*
|
||||
* SetBwBrightness
|
||||
* [NOTE]
|
||||
*
|
||||
* 0 _DEF_BW_THRESHOLD 255
|
||||
* +-------------------------+--------------------------------+
|
||||
* |<------- Black --------->|<----------- White ------------>|
|
||||
* So, if user wish to make image darker, the threshold value should be
|
||||
* higher than _defBwThreshold, otherwise it should lower than the
|
||||
* _DefBwThreshold.
|
||||
* Darker = _DefBwThreshold + White * Input / 127;
|
||||
* Input < 0, and White = 255 - _DefBwThreshold, so
|
||||
* = _DefBwThreshold - (255 - _DefBwThreshold) * Input / 127;
|
||||
* The brighter is the same idea.
|
||||
*
|
||||
* CHECK: it seems that the brightness only works for the binary mode !
|
||||
*/
|
||||
#if 0
|
||||
if( dev->DataInf.wPhyDataType != COLOR_BW ) {/* if not line art */
|
||||
dev->wBrightness = pInf->siBrightness; /* use internal tables for */
|
||||
dev->wContrast = pInf->siContrast; /* brightness and contrast */
|
||||
|
||||
pInf->siBrightness = 0; /* don't use asic for threshold */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* CHECK: We have now two methods for setting the brightness...
|
||||
*/
|
||||
DBG( _DBG_INFO, "* brightness = %i\n", dev->DataInf.siBrightness );
|
||||
if ( dev->DataInf.siBrightness < 0) {
|
||||
brightness = (u_short)(_DEF_BW_THRESHOLD -
|
||||
(255 - _DEF_BW_THRESHOLD) * dev->DataInf.siBrightness /127);
|
||||
} else {
|
||||
brightness = (u_short)(_DEF_BW_THRESHOLD -
|
||||
_DEF_BW_THRESHOLD * dev->DataInf.siBrightness /127);
|
||||
}
|
||||
|
||||
dev->regs.RD_ThresholdControl = brightness;
|
||||
DBG( _DBG_INFO, "* 1. brightness = %i\n", brightness );
|
||||
|
||||
if( dev->DataInf.siBrightness >= 0 ) {
|
||||
brightness = (short)((long)(-(255 - _DEF_BW_THRESHOLD) *
|
||||
dev->DataInf.siBrightness) / 127 + _DEF_BW_THRESHOLD);
|
||||
} else {
|
||||
brightness = (short)((long)(_DEF_BW_THRESHOLD *
|
||||
dev->DataInf.siBrightness) / 127 + _DEF_BW_THRESHOLD);
|
||||
}
|
||||
brightness = (brightness ^ 0xff) & 0xff;
|
||||
|
||||
dev->regs.RD_ThresholdControl = brightness;
|
||||
DBG( _DBG_INFO, "* 2. brightness = %i\n", brightness );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** PrepareScanningVariables() !!!
|
||||
*/
|
||||
static SANE_Status u12image_SetupScanSettings( U12_Device *dev, ImgDef *img )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12image_SetupScanSettings()\n" );
|
||||
|
||||
wPreviewScanned = 0;
|
||||
dev->scan.dpiIdx = 0;
|
||||
dev->scan.negScan = negScan;
|
||||
|
||||
imageSetupScanSettings( dev, img );
|
||||
|
||||
if( !(dev->DataInf.dwScanFlag & _SCANDEF_TPA )) {
|
||||
|
||||
dev->scan.dwScanOrigin = dev->adj.upNormal * 4 + _RFT_SCANNING_ORG;
|
||||
|
||||
} else if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency) {
|
||||
|
||||
dev->scan.dwScanOrigin = dev->adj.upPositive * 4 + _POS_SCANNING_ORG;
|
||||
} else {
|
||||
dev->scan.dwScanOrigin = dev->adj.upNegative * 4 + _NEG_SCANNING_ORG;
|
||||
}
|
||||
dev->scan.dwScanOrigin += 64 /*dev->dwModelOriginY*/;
|
||||
|
||||
if( dev->DataInf.xyAppDpi.y <= 75 ) {
|
||||
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
|
||||
|
||||
dev->scan.bDiscardAll = 0;
|
||||
dev->DataInf.xyPhyDpi.y = 150;
|
||||
dev->shade.intermediate |= _ScanMode_AverageOut;
|
||||
u12image_SetupScanStateVariables( dev, 1 );
|
||||
dev->scan.gd_gk.wGreenDiscard = 0;
|
||||
|
||||
if( dev->DataInf.xyAppDpi.y >= 38 )
|
||||
dev->scan.bd_rk.wBlueDiscard = 1;
|
||||
else
|
||||
dev->scan.bd_rk.wBlueDiscard = 0;
|
||||
|
||||
if( dev->DataInf.wPhyDataType >= COLOR_256GRAY ) {
|
||||
dev->shade.wXStep = 6;
|
||||
dev->shade.wExposure = 8 * dev->shade.wXStep;
|
||||
}
|
||||
} else {
|
||||
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA) &&
|
||||
(dev->DataInf.xyAppDpi.y <= 50) &&
|
||||
(dev->DataInf.wPhyDataType >= COLOR_TRUE24)) {
|
||||
dev->shade.intermediate |= _ScanMode_AverageOut;
|
||||
}
|
||||
|
||||
if((dev->DataInf.wPhyDataType<COLOR_TRUE24) || dev->f0_8_16 ||
|
||||
(dev->shade.intermediate & _ScanMode_AverageOut)) {
|
||||
|
||||
dev->scan.bDiscardAll = 1;
|
||||
dev->DataInf.xyPhyDpi.y = 75;
|
||||
u12image_SetupScanStateVariables( dev, 0 );
|
||||
} else {
|
||||
dev->scan.bDiscardAll = 2;
|
||||
dev->DataInf.xyPhyDpi.y = 150;
|
||||
u12image_SetupScanStateVariables( dev, 1 );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if( dev->DataInf.xyAppDpi.y <= 150 ) {
|
||||
|
||||
dev->scan.bDiscardAll = 2;
|
||||
dev->DataInf.xyPhyDpi.y = 150;
|
||||
u12image_SetupScanStateVariables( dev, 1 );
|
||||
|
||||
} else if( dev->DataInf.xyAppDpi.y <= 300 ) {
|
||||
|
||||
dev->scan.bDiscardAll = 4;
|
||||
dev->DataInf.xyPhyDpi.y = 300;
|
||||
u12image_SetupScanStateVariables( dev, 2 );
|
||||
|
||||
} else if( dev->DataInf.xyAppDpi.y <= 600 ) {
|
||||
|
||||
dev->scan.bDiscardAll = 8;
|
||||
dev->DataInf.xyPhyDpi.y = 600;
|
||||
u12image_SetupScanStateVariables( dev, 3 );
|
||||
|
||||
} else {
|
||||
|
||||
dev->scan.bDiscardAll = 16;
|
||||
dev->DataInf.xyPhyDpi.y = 1200;
|
||||
u12image_SetupScanStateVariables( dev, 4 );
|
||||
}
|
||||
}
|
||||
|
||||
/* ------- lines to sample or not? ------- */
|
||||
if( dev->DataInf.xyAppDpi.y == dev->DataInf.xyPhyDpi.y ) {
|
||||
DBG( _DBG_INFO, "* Sample every line\n" );
|
||||
dev->scan.DoSample = fnEveryLines;
|
||||
} else {
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
|
||||
|
||||
DBG( _DBG_INFO, "* Sample preview\n" );
|
||||
dev->scan.DoSample = fnSamplePreview;
|
||||
dev->DataInf.wYSum = 150;
|
||||
|
||||
if( dev->DataInf.xyAppDpi.y >= 38 )
|
||||
wPreviewScanned = dev->DataInf.xyAppDpi.y * 2;
|
||||
else if( dev->DataInf.xyAppDpi.y >= 19 )
|
||||
wPreviewScanned = dev->DataInf.xyAppDpi.y * 4;
|
||||
else
|
||||
wPreviewScanned = dev->DataInf.xyAppDpi.y * 8;
|
||||
} else {
|
||||
|
||||
DBG( _DBG_INFO, "* Sample lines (%u - %u)...\n",
|
||||
dev->DataInf.xyPhyDpi.y, dev->DataInf.xyAppDpi.y );
|
||||
dev->scan.DoSample = fnSampleLines;
|
||||
dev->DataInf.wYSum = dev->DataInf.xyPhyDpi.y - dev->DataInf.xyAppDpi.y;
|
||||
}
|
||||
}
|
||||
|
||||
/* now assign the buffer pointers for image aquisition
|
||||
*/
|
||||
dev->scan.p48BitBuf.pb = NULL;
|
||||
|
||||
if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
|
||||
|
||||
u_long r, g, b;
|
||||
|
||||
r = (u_long)_SIZE_REDFIFO /
|
||||
dev->DataInf.dwAsicBytesPerPlane - dev->scan.bd_rk.wRedKeep;
|
||||
g = (u_long)_SIZE_GREENFIFO /
|
||||
dev->DataInf.dwAsicBytesPerPlane - dev->scan.gd_gk.wGreenKeep;
|
||||
|
||||
if((int)r < 16 || (int)g < 16) {
|
||||
|
||||
b = (u_long)(dev->scan.bd_rk.wRedKeep +
|
||||
dev->scan.gd_gk.wGreenKeep + 2U) *
|
||||
dev->DataInf.dwAsicBytesPerPlane;
|
||||
|
||||
DBG( _DBG_INFO, "48Bit buffer request: "
|
||||
"len=%lu bytes, available=%lu\n", b, _SIZE_TOTAL_BUF_TPA );
|
||||
|
||||
if( b > _SIZE_TOTAL_BUF_TPA )
|
||||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
dev->scan.p48BitBuf.pb = dev->bufs.b1.pReadBuf;
|
||||
}
|
||||
}
|
||||
|
||||
if( dev->scan.p48BitBuf.pb ){
|
||||
dev->scan.DataRead = fnReadToDriver;
|
||||
dev->scan.BufGet.red.bp =
|
||||
dev->scan.BufPut.red.bp =
|
||||
dev->scan.BufBegin.red.bp = dev->scan.p48BitBuf.pb;
|
||||
dev->scan.BufEnd.red.bp =
|
||||
dev->scan.BufBegin.green.bp =
|
||||
dev->scan.BufGet.green.bp =
|
||||
dev->scan.BufPut.green.bp = dev->scan.p48BitBuf.pb +
|
||||
dev->DataInf.dwAsicBytesPerLine *
|
||||
(dev->scan.bd_rk.wRedKeep + 1U);
|
||||
|
||||
dev->scan.BufEnd.green.bp = dev->scan.BufBegin.green.bp +
|
||||
dev->DataInf.dwAsicBytesPerLine *
|
||||
(dev->scan.gd_gk.wGreenKeep + 1U);
|
||||
dev->scan.BufPut.blue.bp =
|
||||
dev->scan.BufGet.blue.bp = dev->bufs.b1.pReadBuf +
|
||||
dev->DataInf.dwAsicBytesPerLine * 2;
|
||||
} else {
|
||||
dev->scan.DataRead = fnReadOutScanner;
|
||||
dev->scan.BufPut.red.bp = dev->bufs.b1.pReadBuf;
|
||||
dev->scan.BufData.green.bp =
|
||||
dev->scan.BufPut.green.bp = dev->scan.BufPut.red.bp +
|
||||
dev->DataInf.dwAsicBytesPerLine;
|
||||
dev->scan.BufPut.blue.bp = dev->scan.BufPut.green.bp +
|
||||
dev->DataInf.dwAsicBytesPerLine;
|
||||
|
||||
dev->scan.BufData.red.bp = dev->scan.BufPut.red.bp;
|
||||
dev->scan.BufData.blue.bp = dev->scan.BufPut.blue.bp;
|
||||
}
|
||||
|
||||
/* CHECK: maybe remove this stuff */
|
||||
#if 0
|
||||
if( ps->DataInf.dwScanFlag & _SCANDEF_Transparency) {
|
||||
posScan[1].exposureTime = 96;
|
||||
posScan[1].xStepTime = 12;
|
||||
posScan[2].exposureTime = 96;
|
||||
posScan[2].xStepTime = 24;
|
||||
posScan[3].exposureTime = 96;
|
||||
posScan[3].xStepTime = 48;
|
||||
posScan[4].exposureTime = 96;
|
||||
posScan[4].xStepTime = 96;
|
||||
|
||||
/* Reset shading Exposure Time & xStep Time */
|
||||
ps->Shade.wExposure = posScan[ps->Scan.dpiIdx].exposureTime;
|
||||
ps->Shade.wXStep = posScan[ps->Scan.dpiIdx].xStepTime;
|
||||
}
|
||||
else if( ps->DataInf.dwScanFlag & _SCANDEF_Negative) {
|
||||
ps->Scan.negScan[1].exposureTime = 96;
|
||||
ps->Scan.negScan[1].xStepTime = 12;
|
||||
ps->Scan.negScan[2].exposureTime = 96;
|
||||
ps->Scan.negScan[2].xStepTime = 24;
|
||||
ps->Scan.negScan[3].exposureTime = 96;
|
||||
ps->Scan.negScan[3].xStepTime = 48;
|
||||
ps->Scan.negScan[4].exposureTime = 96;
|
||||
ps->Scan.negScan[4].xStepTime = 96;
|
||||
|
||||
/* Reset shading Exposure Time & xStep Time */
|
||||
ps->Shade.wExposure = ps->Scan.negScan[ps->Scan.dpiIdx].exposureTime;
|
||||
ps->Shade.wXStep = ps->Scan.negScan[ps->Scan.dpiIdx].xStepTime;
|
||||
}
|
||||
#endif
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Bool u12image_DataIsReady( U12_Device *dev, void* buf )
|
||||
{
|
||||
DBG( _DBG_READ, "* DataIsReady()\n" );
|
||||
|
||||
if( dev->scan.bDiscardAll ) {
|
||||
dev->scan.bDiscardAll--;
|
||||
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
||||
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
||||
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
} else {
|
||||
u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
|
||||
dev->DataInf.dwAsicBytesPerPlane );
|
||||
}
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
||||
u12io_ReadMonoData( dev, buf, dev->DataInf.dwAsicBytesPerPlane );
|
||||
|
||||
} else {
|
||||
|
||||
if( !dev->scan.DataRead( dev )) {
|
||||
return SANE_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if( dev->scan.DoSample( dev )) {
|
||||
|
||||
if( dev->scan.dwLinesToRead == 1 &&
|
||||
!(u12io_GetScanState( dev ) & _SCANSTATE_STOP))
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
|
||||
/* direct is done here without copying...*/
|
||||
if( fnDataDirect != dev->scan.DataProcess ) {
|
||||
(*dev->scan.DataProcess)(dev, buf, (void*)(dev->scan.BufPut.red.bp),
|
||||
dev->DataInf.dwAppPhyBytesPerLine);
|
||||
}
|
||||
return SANE_TRUE;
|
||||
}
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12image_ReadOneImageLine( U12_Device *dev, void* buf )
|
||||
{
|
||||
SANE_Byte b, state;
|
||||
TimerDef timer, t2;
|
||||
|
||||
DBG( _DBG_READ, "u12image_ReadOneImageLine()\n" );
|
||||
|
||||
u12io_StartTimer( &timer, _LINE_TIMEOUT );
|
||||
u12io_StartTimer( &t2, _SECOND*2 );
|
||||
do {
|
||||
|
||||
state = u12io_GetScanState( dev );
|
||||
dev->scan.bNowScanState = (state & _SCANSTATE_MASK);
|
||||
|
||||
if( state & _SCANSTATE_STOP ) {
|
||||
|
||||
DBG( _DBG_READ, "* SCANSTATE_STOP\n" );
|
||||
u12motor_ModuleForwardBackward( dev );
|
||||
|
||||
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo )
|
||||
if( u12image_DataIsReady( dev, buf ))
|
||||
return SANE_STATUS_GOOD;
|
||||
|
||||
} else {
|
||||
|
||||
dev->scan.bModuleState = _MotorInNormalState;
|
||||
b = dev->scan.bNowScanState - dev->scan.oldScanState;
|
||||
|
||||
if((char) b < 0)
|
||||
b += _NUMBER_OF_SCANSTEPS;
|
||||
|
||||
if( b >= dev->scan.bRefresh ) {
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
dev->scan.oldScanState = u12io_GetScanState( dev );
|
||||
dev->scan.oldScanState &= _SCANSTATE_MASK;
|
||||
}
|
||||
|
||||
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMaxReadFifo ) {
|
||||
|
||||
if( u12image_DataIsReady( dev, buf ))
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
else {
|
||||
|
||||
b = dev->scan.bNowScanState - dev->scan.oldScanState;
|
||||
|
||||
if((char) b < 0)
|
||||
b += _NUMBER_OF_SCANSTEPS;
|
||||
|
||||
if( b >= dev->scan.bRefresh ) {
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
dev->scan.oldScanState = u12io_GetScanState( dev );
|
||||
dev->scan.oldScanState &= _SCANSTATE_MASK;
|
||||
}
|
||||
|
||||
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo ) {
|
||||
if( u12image_DataIsReady( dev, buf ))
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
|
||||
DBG( _DBG_ERROR, "Timeout - Scanner malfunction !!\n" );
|
||||
u12motor_ToHomePosition( dev );
|
||||
|
||||
/* timed out, scanner malfunction */
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
/* END U12_IMAGE.C ..........................................................*/
|
|
@ -0,0 +1,795 @@
|
|||
/** @file u12-io.c
|
||||
* @brief The I/O functions to the U12 backend stuff.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
* GeneSys Logic I/O stuff derived from canon630u-common.c which has
|
||||
* been written by Nathan Rutman <nathan@gordian.com>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
/** Format:
|
||||
* cacheLen[0] = ASIC-ID
|
||||
* cacheLen[1] = SCANSTATE ?
|
||||
* cacheLen[2] = REG-STATUS ?
|
||||
* cacheLen[3] = ??
|
||||
* cacheLen[4] = FIFO-LEN (RED) HiByte LW
|
||||
* cacheLen[5] = FIFO-LEN (RED) LoByte LW
|
||||
* cacheLen[6] = FIFO-LEN (RED) LoByte HW
|
||||
* cacheLen[7] = FIFO-LEN (GREEN) HiByte LW
|
||||
* cacheLen[8] = FIFO-LEN (GREEN) LoByte LW
|
||||
* cacheLen[9] = FIFO-LEN (GREEN) LoByte HW
|
||||
* cacheLen[10] = FIFO-LEN (BLUE) HiByte LW
|
||||
* cacheLen[11] = FIFO-LEN (BLUE) LoByte LW
|
||||
* cacheLen[12] = FIFO-LEN (BLUE) LoByte HW
|
||||
*/
|
||||
static SANE_Byte cacheLen[13];
|
||||
|
||||
/** This function is used to detect a cancel condition,
|
||||
* our ESC key is the SIGUSR1 signal. It is sent by the backend when the
|
||||
* cancel button has been pressed
|
||||
*
|
||||
* @param - none
|
||||
* @return the function returns SANE_TRUE if a cancel condition has been
|
||||
* detected, if not, it returns SANE_FALSE
|
||||
*/
|
||||
static SANE_Bool u12io_IsEscPressed( void )
|
||||
{
|
||||
sigset_t sigs;
|
||||
|
||||
sigpending( &sigs );
|
||||
if( sigismember( &sigs, SIGUSR1 )) {
|
||||
DBG( _DBG_INFO, "SIGUSR1 is pending --> Cancel detected\n" );
|
||||
return SANE_TRUE;
|
||||
}
|
||||
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/** fall asleep for some micro-seconds...
|
||||
*/
|
||||
static void u12io_udelay( unsigned long usec )
|
||||
{
|
||||
struct timeval now, deadline;
|
||||
|
||||
if( usec == 0 )
|
||||
return;
|
||||
|
||||
gettimeofday( &deadline, NULL );
|
||||
deadline.tv_usec += usec;
|
||||
deadline.tv_sec += deadline.tv_usec / 1000000;
|
||||
deadline.tv_usec %= 1000000;
|
||||
|
||||
do {
|
||||
gettimeofday( &now, NULL );
|
||||
} while ((now.tv_sec < deadline.tv_sec) ||
|
||||
(now.tv_sec == deadline.tv_sec && now.tv_usec < deadline.tv_usec));
|
||||
}
|
||||
|
||||
/** Initializes a timer.
|
||||
* @param timer - pointer to the timer to start
|
||||
* @param us - timeout value in micro-seconds
|
||||
*/
|
||||
static void u12io_StartTimer( TimerDef *timer , unsigned long us )
|
||||
{
|
||||
struct timeval start_time;
|
||||
|
||||
gettimeofday( &start_time, NULL );
|
||||
*timer = start_time.tv_sec * 1e6 + start_time.tv_usec + us;
|
||||
}
|
||||
|
||||
/** Checks if a timer has been expired or not.
|
||||
* @param timer - pointer to the timer to check
|
||||
* @return Function returns SANE_TRUE when the timer has been expired,
|
||||
* otherwise SANE_FALSE
|
||||
*/
|
||||
static SANE_Bool u12io_CheckTimer( TimerDef *timer )
|
||||
{
|
||||
struct timeval current_time;
|
||||
|
||||
gettimeofday(¤t_time, NULL);
|
||||
|
||||
if((current_time.tv_sec * 1e6 + current_time.tv_usec) > *timer )
|
||||
return SANE_TRUE;
|
||||
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/* GL640 communication functions for Genesys Logic GL640USB
|
||||
* USB-IEEE1284 parallel port bridge
|
||||
*/
|
||||
|
||||
/* Assign status and verify a good return code */
|
||||
#define CHK(A) {if( (status = A) != SANE_STATUS_GOOD ) { \
|
||||
DBG( _DBG_ERROR, "Failure on line of %s: %d\n", __FILE__, \
|
||||
__LINE__ ); return A; }}
|
||||
|
||||
/** Register codes for the bridge. These are NOT the registers for the ASIC
|
||||
* on the other side of the bridge.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GL640_BULK_SETUP = 0x82,
|
||||
GL640_EPP_ADDR = 0x83,
|
||||
GL640_EPP_DATA_READ = 0x84,
|
||||
GL640_EPP_DATA_WRITE = 0x85,
|
||||
GL640_SPP_STATUS = 0x86,
|
||||
GL640_SPP_CONTROL = 0x87,
|
||||
GL640_SPP_DATA = 0x88,
|
||||
GL640_GPIO_OE = 0x89,
|
||||
GL640_GPIO_READ = 0x8a,
|
||||
GL640_GPIO_WRITE = 0x8b
|
||||
} GL640_Request;
|
||||
|
||||
/** for setting up bulk transfers */
|
||||
static SANE_Byte bulk_setup_data[] = { 0, 0x11, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/** Write to the usb-parallel port bridge.
|
||||
*/
|
||||
static SANE_Status
|
||||
gl640WriteControl(int fd, GL640_Request req, u_char * data, unsigned int size)
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
status = sanei_usb_control_msg( fd,
|
||||
/* rqttype */ USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE | USB_DIR_OUT /*0x40 */ ,
|
||||
/* rqt */ (size > 1) ? 0x04 : 0x0C,
|
||||
/* val */ (SANE_Int) req,
|
||||
/* ind */ 0,
|
||||
/* len */ size,
|
||||
/* dat */ data);
|
||||
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "gl640WriteControl error\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Read from the usb-parallel port bridge.
|
||||
*/
|
||||
static SANE_Status
|
||||
gl640ReadControl( int fd, GL640_Request req, u_char *data, unsigned int size )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
status = sanei_usb_control_msg( fd,
|
||||
/* rqttype */ USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE | USB_DIR_IN /*0xc0 */ ,
|
||||
/* rqt */ (size > 1) ? 0x04 : 0x0C,
|
||||
/* val */ (SANE_Int) req,
|
||||
/* ind */ 0,
|
||||
/* len */ size,
|
||||
/* dat */ data);
|
||||
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "gl640ReadControl error\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Wrappers to write a single byte to the bridge */
|
||||
static inline SANE_Status
|
||||
gl640WriteReq( int fd, GL640_Request req, u_char data )
|
||||
{
|
||||
return gl640WriteControl( fd, req, &data, 1);
|
||||
}
|
||||
|
||||
/** Wrappers to read a single byte from the bridge */
|
||||
static inline SANE_Status
|
||||
gl640ReadReq( int fd, GL640_Request req, u_char *data )
|
||||
{
|
||||
return gl640ReadControl( fd, req, data, 1 );
|
||||
}
|
||||
|
||||
/** Write USB bulk data
|
||||
* setup is an apparently scanner-specific sequence:
|
||||
* {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00}
|
||||
* setup[1] = 0x11 --> data to register
|
||||
* setup[1] = 0x01 --> data to scanner memory
|
||||
*/
|
||||
static SANE_Status
|
||||
gl640WriteBulk( int fd, u_char *setup, u_char *data, size_t size )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
setup[0] = 1;
|
||||
setup[4] = (size) & 0xFF;
|
||||
setup[5] = (size >> 8) & 0xFF;
|
||||
setup[6] = 0;
|
||||
|
||||
CHK (gl640WriteControl (fd, GL640_BULK_SETUP, setup, 8));
|
||||
|
||||
status = sanei_usb_write_bulk (fd, data, &size);
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "gl640WriteBulk error\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Read USB bulk data
|
||||
* setup is an apparently scanner-specific sequence:
|
||||
* {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00}
|
||||
* setup[1] = 0x00 --> data from scanner memory
|
||||
* setup[1] = 0x0c --> data from scanner fifo?
|
||||
*/
|
||||
static SANE_Status
|
||||
gl640ReadBulk( int fd, u_char *setup, u_char *data, size_t size, int mod )
|
||||
{
|
||||
SANE_Byte *len_info;
|
||||
size_t complete, current, toget;
|
||||
SANE_Status status;
|
||||
|
||||
setup[0] = 0;
|
||||
setup[4] = (size) & 0xFF;
|
||||
setup[5] = (size >> 8) & 0xFF;
|
||||
setup[6] = mod;
|
||||
|
||||
CHK (gl640WriteControl (fd, GL640_BULK_SETUP, setup, 8));
|
||||
|
||||
len_info = NULL;
|
||||
toget = size;
|
||||
if( mod ) {
|
||||
toget *= mod;
|
||||
len_info = data + toget;
|
||||
toget += 13;
|
||||
}
|
||||
|
||||
for( complete = 0; complete < toget; ) {
|
||||
|
||||
current = toget - complete;
|
||||
status = sanei_usb_read_bulk( fd, data, ¤t );
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "gl640ReadBulk error\n");
|
||||
}
|
||||
data += current;
|
||||
complete += current;
|
||||
}
|
||||
if( len_info ) {
|
||||
memcpy( cacheLen, len_info, 13 );
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* now the functions to access PP registers */
|
||||
|
||||
/** read the contents of the status register */
|
||||
static SANE_Byte
|
||||
inb_status( int fd )
|
||||
{
|
||||
u_char data = 0xff;
|
||||
|
||||
gl640ReadReq( fd, GL640_SPP_STATUS, &data );
|
||||
return data;
|
||||
}
|
||||
|
||||
/** write a byte to the SPP data port */
|
||||
static SANE_Status
|
||||
outb_data( int fd, u_char data )
|
||||
{
|
||||
return gl640WriteReq( fd, GL640_SPP_DATA, data);
|
||||
}
|
||||
|
||||
/** write to the parport control register */
|
||||
static SANE_Status
|
||||
outb_ctrl( int fd, u_char data )
|
||||
{
|
||||
return gl640WriteReq( fd, GL640_SPP_CONTROL, data);
|
||||
}
|
||||
|
||||
/************************* ASIC access stuff *********************************/
|
||||
|
||||
/** write a register number to the ASIC
|
||||
*/
|
||||
static void u12io_RegisterToScanner( U12_Device *dev, SANE_Byte reg )
|
||||
{
|
||||
if( dev->mode == _PP_MODE_EPP ) {
|
||||
|
||||
gl640WriteReq( dev->fd, GL640_EPP_ADDR, reg );
|
||||
|
||||
} else {
|
||||
|
||||
/* write register number to read from to SPP data-port
|
||||
*/
|
||||
outb_data( dev->fd, reg );
|
||||
|
||||
/* signal that to the ASIC */
|
||||
outb_ctrl( dev->fd, _CTRL_SIGNAL_REGWRITE );
|
||||
outb_ctrl( dev->fd, _CTRL_END_REGWRITE );
|
||||
}
|
||||
}
|
||||
|
||||
/** as the name says, we switch to SPP mode
|
||||
*/
|
||||
static void u12io_SwitchToSPPMode( U12_Device *dev )
|
||||
{
|
||||
dev->mode = _PP_MODE_SPP;
|
||||
outb_ctrl( dev->fd, _CTRL_GENSIGNAL );
|
||||
}
|
||||
|
||||
/** as the name says, we switch to SPP mode
|
||||
*/
|
||||
static void u12io_SwitchToEPPMode( U12_Device *dev )
|
||||
{
|
||||
u12io_RegisterToScanner( dev, REG_EPPENABLE );
|
||||
dev->mode = _PP_MODE_EPP;
|
||||
}
|
||||
|
||||
/** read data from SPP status port
|
||||
*/
|
||||
static SANE_Byte u12io_DataFromSPP( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte data, tmp;
|
||||
|
||||
/* read low nibble */
|
||||
tmp = inb_status( dev->fd );
|
||||
|
||||
outb_ctrl( dev->fd, (_CTRL_GENSIGNAL + _CTRL_STROBE));
|
||||
|
||||
/* read high nibble */
|
||||
data = inb_status( dev->fd );
|
||||
data &= 0xf0;
|
||||
|
||||
/* combine with low nibble */
|
||||
data |= (tmp >> 4);
|
||||
return data;
|
||||
}
|
||||
|
||||
/** Read the content of specific ASIC register
|
||||
*/
|
||||
static SANE_Byte u12io_DataFromRegister( U12_Device *dev, SANE_Byte reg )
|
||||
{
|
||||
SANE_Byte val;
|
||||
|
||||
if( dev->mode == _PP_MODE_EPP ) {
|
||||
gl640WriteReq( dev->fd, GL640_EPP_ADDR, reg );
|
||||
gl640ReadReq ( dev->fd, GL640_EPP_DATA_READ, &val );
|
||||
} else {
|
||||
|
||||
u12io_RegisterToScanner( dev, reg );
|
||||
val = u12io_DataFromSPP( dev );
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12io_CloseScanPath( U12_Device *dev )
|
||||
{
|
||||
u12io_RegisterToScanner( dev, 0xff );
|
||||
u12io_RegisterToScanner( dev, REG_SWITCHBUS );
|
||||
|
||||
dev->mode = _PP_MODE_SPP;
|
||||
}
|
||||
|
||||
/** try to connect to scanner
|
||||
*/
|
||||
static SANE_Bool u12io_OpenScanPath( U12_Device *dev )
|
||||
{
|
||||
u_char tmp;
|
||||
|
||||
DBG( _DBG_IO, "u12io_OpenScanPath()\n" );
|
||||
|
||||
u12io_SwitchToSPPMode( dev );
|
||||
|
||||
outb_data( dev->fd, _ID_TO_PRINTER );
|
||||
|
||||
outb_data( dev->fd, _ID1ST );
|
||||
outb_data( dev->fd, _ID2ND );
|
||||
outb_data( dev->fd, _ID3RD );
|
||||
outb_data( dev->fd, _ID4TH );
|
||||
|
||||
tmp = u12io_DataFromRegister( dev, REG_ASICID );
|
||||
if( ASIC_ID == tmp ) {
|
||||
u12io_SwitchToEPPMode( dev );
|
||||
return SANE_TRUE;
|
||||
}
|
||||
|
||||
DBG( _DBG_IO, "u12io_OpenScanPath() failed!\n" );
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/** Write data to asic (SPP mode only)
|
||||
*/
|
||||
static void u12io_DataToScanner( U12_Device *dev , SANE_Byte bValue )
|
||||
{
|
||||
if( dev->mode != _PP_MODE_SPP ) {
|
||||
DBG( _DBG_ERROR, "u12io_DataToScanner() in wrong mode!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* output data */
|
||||
outb_data( dev->fd, bValue );
|
||||
|
||||
/* notify asic there is data */
|
||||
outb_ctrl( dev->fd, _CTRL_SIGNAL_DATAWRITE );
|
||||
|
||||
/* end write cycle */
|
||||
outb_ctrl( dev->fd, _CTRL_END_DATAWRITE );
|
||||
}
|
||||
|
||||
/** Write data to specific ASIC's register
|
||||
*/
|
||||
static SANE_Status u12io_DataToRegister( U12_Device *dev,
|
||||
SANE_Byte reg, SANE_Byte data )
|
||||
{
|
||||
SANE_Status status;
|
||||
SANE_Byte buf[2];
|
||||
|
||||
if( dev->mode == _PP_MODE_EPP ) {
|
||||
|
||||
buf[0] = reg;
|
||||
buf[1] = data;
|
||||
|
||||
bulk_setup_data[1] = 0x11;
|
||||
CHK( gl640WriteBulk ( dev->fd, bulk_setup_data, buf, 2 ));
|
||||
|
||||
} else {
|
||||
|
||||
u12io_RegisterToScanner( dev, reg );
|
||||
u12io_DataToScanner( dev, data );
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** Write data-buffer to specific ASIC's register
|
||||
* The format in the buffer is
|
||||
* reg(0),val(0),reg(1),val(1),..., reg(len-1),val(len-1)
|
||||
*/
|
||||
static SANE_Status u12io_DataToRegs( U12_Device *dev, SANE_Byte *buf, int len )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
if( dev->mode != _PP_MODE_EPP ) {
|
||||
DBG( _DBG_ERROR, "u12io_DataToRegsr() in wrong mode!\n" );
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
bulk_setup_data[1] = 0x11;
|
||||
CHK( gl640WriteBulk ( dev->fd, bulk_setup_data, buf, len*2 ));
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** write data to the DAC
|
||||
*/
|
||||
static void
|
||||
u12io_DataRegisterToDAC( U12_Device *dev, SANE_Byte reg, SANE_Byte val )
|
||||
{
|
||||
SANE_Byte buf[6];
|
||||
|
||||
buf[0] = REG_ADCADDR;
|
||||
buf[1] = reg;
|
||||
buf[2] = REG_ADCDATA;
|
||||
buf[3] = val;
|
||||
buf[4] = REG_ADCSERIALOUT;
|
||||
buf[5] = val;
|
||||
|
||||
u12io_DataToRegs( dev, buf, 3 );
|
||||
}
|
||||
|
||||
/** write data block to scanner
|
||||
*/
|
||||
static SANE_Status u12io_MoveDataToScanner( U12_Device *dev,
|
||||
SANE_Byte *buf, int len )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
/* u12io_IORegisterToScanner( dev, REG_INITDATAFIFO );
|
||||
*/
|
||||
u12io_RegisterToScanner( dev, REG_WRITEDATAMODE );
|
||||
|
||||
bulk_setup_data[1] = 0x01;
|
||||
CHK( gl640WriteBulk( dev->fd, bulk_setup_data, buf, len ));
|
||||
bulk_setup_data[1] = 0x11;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status u12io_ReadData( U12_Device *dev, SANE_Byte *buf, int len )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, dev->regs.RD_ModeControl );
|
||||
/* u12io_RegisterToScanner( dev, REG_INITDATAFIFO );
|
||||
*/
|
||||
u12io_RegisterToScanner( dev, REG_READDATAMODE );
|
||||
|
||||
bulk_setup_data[1] = 0x00;
|
||||
CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 0 ));
|
||||
bulk_setup_data[1] = 0x11;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** perform a SW reset of ASIC 98003
|
||||
*/
|
||||
static void u12io_SoftwareReset( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "Device reset!!!\n" );
|
||||
|
||||
u12io_DataToRegister( dev, REG_TESTMODE, _SW_TESTMODE );
|
||||
|
||||
/* u12io_SwitchToSPPMode( dev );
|
||||
*/
|
||||
outb_data( dev->fd, 0 );
|
||||
|
||||
outb_data( dev->fd, _RESET1ST );
|
||||
outb_data( dev->fd, _RESET2ND );
|
||||
outb_data( dev->fd, _RESET3RD );
|
||||
outb_data( dev->fd, _RESET4TH );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Bool u12io_IsConnected( int fd )
|
||||
{
|
||||
SANE_Byte tmp;
|
||||
|
||||
tmp = inb_status( fd );
|
||||
|
||||
gl640WriteReq( fd, GL640_EPP_ADDR, REG_ASICID );
|
||||
gl640ReadReq ( fd, GL640_EPP_DATA_READ, &tmp );
|
||||
|
||||
if( tmp != ASIC_ID ) {
|
||||
DBG( _DBG_INFO, "Scanner NOT connected!\n" );
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
DBG( _DBG_INFO, "Scanner connected!\n" );
|
||||
return SANE_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Byte u12io_GetExtendedStatus( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte b;
|
||||
|
||||
b = u12io_DataFromRegister( dev, REG_STATUS2 );
|
||||
if( b == 0xff )
|
||||
return 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12io_ReadMonoData( U12_Device *dev, SANE_Byte *buf, u_long len )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
bulk_setup_data[1] = 0x0c;
|
||||
bulk_setup_data[2] = ((dev->regs.RD_ModeControl >> 3) + 1);
|
||||
|
||||
CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 1 ));
|
||||
bulk_setup_data[1] = 0x11;
|
||||
bulk_setup_data[2] = 0;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status
|
||||
u12io_ReadColorData( U12_Device *dev, SANE_Byte *buf, u_long len )
|
||||
{
|
||||
SANE_Status status;
|
||||
|
||||
bulk_setup_data[1] = 0x0c;
|
||||
|
||||
CHK (gl640ReadBulk( dev->fd, bulk_setup_data, buf, len, 3 ));
|
||||
bulk_setup_data[1] = 0x11;
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** read the recent state count
|
||||
*/
|
||||
static SANE_Byte u12io_GetScanState( U12_Device *dev )
|
||||
{
|
||||
if( cacheLen[0] == 0x83 ) {
|
||||
DBG( _DBG_READ, "u12io_GetScanState(cached) = 0x%02x\n", cacheLen[1] );
|
||||
return cacheLen[1];
|
||||
}
|
||||
return u12io_DataFromRegister( dev, REG_GETSCANSTATE );
|
||||
}
|
||||
|
||||
/** download a scanstate-table
|
||||
*/
|
||||
static SANE_Status u12io_DownloadScanStates( U12_Device *dev )
|
||||
{
|
||||
SANE_Status status;
|
||||
TimerDef timer;
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_SCANSTATECONTROL );
|
||||
|
||||
bulk_setup_data[1] = 0x01;
|
||||
CHK( gl640WriteBulk( dev->fd, bulk_setup_data,
|
||||
dev->a_nbNewAdrPointer, _SCANSTATE_BYTES ));
|
||||
bulk_setup_data[1] = 0x11;
|
||||
|
||||
/* FIXME: refreshState probably always FALSE */
|
||||
if( dev->scan.refreshState ) {
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
|
||||
u12io_StartTimer( &timer, (_SECOND/2));
|
||||
do {
|
||||
|
||||
if (!( u12io_GetScanState( dev ) & _SCANSTATE_STOP))
|
||||
break;
|
||||
}
|
||||
while( !u12io_CheckTimer(&timer));
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** - initializes the scan states
|
||||
* - sets all necessary registers
|
||||
* FIXME: first copy to buffer, then use u12io_DataToRegs()
|
||||
*/
|
||||
static void u12io_PutOnAllRegisters( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte *val, reg;
|
||||
SANE_Byte *rb, buf[100];
|
||||
int c;
|
||||
|
||||
/* setup scan states */
|
||||
u12io_DownloadScanStates( dev );
|
||||
|
||||
c = 0;
|
||||
rb = buf;
|
||||
|
||||
*(rb++) = REG_MODECONTROL;
|
||||
*(rb++) = dev->regs.RD_ModeControl;
|
||||
c++;
|
||||
*(rb++) = REG_STEPCONTROL;
|
||||
*(rb++) = dev->regs.RD_StepControl;
|
||||
c++;
|
||||
*(rb++) = REG_MOTOR0CONTROL;
|
||||
*(rb++) = dev->regs.RD_Motor0Control;
|
||||
c++;
|
||||
*(rb++) = REG_LINECONTROL;
|
||||
*(rb++) = dev->regs.RD_LineControl;
|
||||
c++;
|
||||
*(rb++) = REG_XSTEPTIME;
|
||||
*(rb++) = dev->regs.RD_XStepTime;
|
||||
c++;
|
||||
*(rb++) = REG_MODELCONTROL;
|
||||
*(rb++) = dev->regs.RD_ModelControl;
|
||||
c++;
|
||||
/* the 1st register to write */
|
||||
val = (SANE_Byte*)&dev->regs.RD_Dpi;
|
||||
|
||||
/* 0x21 - 0x28 */
|
||||
for( reg = REG_DPILO; reg <= REG_THRESHOLDHI; reg++, val++ ) {
|
||||
*(rb++) = reg;
|
||||
*(rb++) = *val;
|
||||
c++;
|
||||
}
|
||||
|
||||
u12io_DataToRegs( dev, buf, c );
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_INITDATAFIFO );
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeScan );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12io_ResetFifoLen( void )
|
||||
{
|
||||
memset( cacheLen, 0, 13 );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static u_long u12io_GetFifoLength( U12_Device *dev )
|
||||
{
|
||||
SANE_Status status;
|
||||
size_t toget;
|
||||
SANE_Byte data[64];
|
||||
u_long len, len_r, len_g, len_b;
|
||||
|
||||
if( cacheLen[0] == 0x83 ) {
|
||||
|
||||
DBG( _DBG_READ, "Using cached FIFO len\n" );
|
||||
memcpy( data, cacheLen, 13 );
|
||||
u12io_ResetFifoLen();
|
||||
|
||||
} else {
|
||||
|
||||
memset( bulk_setup_data, 0, 8 );
|
||||
bulk_setup_data[1] = 0x0c;
|
||||
|
||||
CHK (gl640WriteControl(dev->fd, GL640_BULK_SETUP, bulk_setup_data, 8));
|
||||
|
||||
toget = 13;
|
||||
status = sanei_usb_read_bulk( dev->fd, data, &toget );
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "ReadBulk error\n");
|
||||
return SANE_FALSE;
|
||||
}
|
||||
bulk_setup_data[1] = 0x11;
|
||||
|
||||
memcpy( cacheLen, data, 13 );
|
||||
}
|
||||
len_r = (u_long)data[5] * 256 + (u_long)data[4];
|
||||
len_g = (u_long)data[8] * 256 + (u_long)data[7];
|
||||
len_b = (u_long)data[11] * 256 + (u_long)data[10];
|
||||
len = len_r /*+ len_g + len_b*/;
|
||||
|
||||
DBG( _DBG_READ, "FIFO-LEN: %lu %lu %lu = %lu\n", len_r, len_g, len_b, len );
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Bool
|
||||
u12io_ReadOneShadingLine( U12_Device *dev, SANE_Byte *buf, u_long len )
|
||||
{
|
||||
TimerDef timer;
|
||||
SANE_Status status;
|
||||
|
||||
DBG( _DBG_READ, "u12io_ReadOneShadingLine()\n" );
|
||||
u12io_StartTimer( &timer, _SECOND );
|
||||
|
||||
dev->scan.bFifoSelect = REG_GFIFOOFFSET;
|
||||
|
||||
do {
|
||||
u12io_ResetFifoLen();
|
||||
if( u12io_GetFifoLength( dev ) >= dev->regs.RD_Pixels ) {
|
||||
|
||||
status = u12io_ReadColorData( dev, buf, len );
|
||||
if( status != SANE_STATUS_GOOD ) {
|
||||
DBG( _DBG_ERROR, "ReadColorData error\n");
|
||||
return SANE_FALSE;
|
||||
}
|
||||
DBG( _DBG_READ, "* done\n" );
|
||||
return SANE_TRUE;
|
||||
}
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
|
||||
DBG( _DBG_ERROR, "u12io_ReadOneShadingLine() failed!\n" );
|
||||
return SANE_FALSE;
|
||||
}
|
||||
|
||||
/* END U12-IO.C .............................................................*/
|
|
@ -0,0 +1,189 @@
|
|||
/* @file u12_map.c
|
||||
* @brief functions to create and manipulate gamma lookup tables.
|
||||
*
|
||||
* Copyright (C) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param s - pointer to the scanner specific structure
|
||||
* @return The function always returns SANE_STATUS_GOOD
|
||||
*/
|
||||
static SANE_Status u12map_InitGammaSettings( U12_Device *dev )
|
||||
{
|
||||
int i, j, val;
|
||||
double gamma;
|
||||
|
||||
dev->gamma_length = 4096;
|
||||
dev->gamma_range.min = 0;
|
||||
dev->gamma_range.max = 255;
|
||||
dev->gamma_range.quant = 0;
|
||||
|
||||
DBG( _DBG_INFO, "Presetting Gamma tables (len=%u)\n", dev->gamma_length );
|
||||
DBG( _DBG_INFO, "----------------------------------\n" );
|
||||
|
||||
/* preset the gamma maps */
|
||||
for( i = 0; i < 4; i++ ) {
|
||||
|
||||
switch( i ) {
|
||||
case 1: gamma = dev->adj.rgamma; break;
|
||||
case 2: gamma = dev->adj.ggamma; break;
|
||||
case 3: gamma = dev->adj.bgamma; break;
|
||||
default: gamma = dev->adj.graygamma; break;
|
||||
}
|
||||
|
||||
for( j = 0; j < dev->gamma_length; j++ ) {
|
||||
|
||||
val = (dev->gamma_range.max *
|
||||
pow((double) j / ((double)dev->gamma_length - 1.0),
|
||||
1.0 / gamma ));
|
||||
|
||||
if( val > dev->gamma_range.max )
|
||||
val = dev->gamma_range.max;
|
||||
|
||||
dev->gamma_table[i][j] = val;
|
||||
}
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** Check the gamma vectors we got back and limit if necessary
|
||||
* @param s - pointer to the scanner specific structure
|
||||
* @return nothing
|
||||
*/
|
||||
static void u12map_CheckGammaSettings( U12_Device *dev )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for( i = 0; i < 4 ; i++ ) {
|
||||
for( j = 0; j < dev->gamma_length; j++ ) {
|
||||
if( dev->gamma_table[i][j] > dev->gamma_range.max ) {
|
||||
dev->gamma_table[i][j] = dev->gamma_range.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** adjust acording to brightness and contrast
|
||||
*/
|
||||
static void u12map_Adjust( U12_Device *dev, int which )
|
||||
{
|
||||
int i;
|
||||
u_long *pdw;
|
||||
double b, c, tmp;
|
||||
|
||||
DBG( _DBG_INFO, "u12map_Adjust(%u)\n", which );
|
||||
|
||||
/* adjust brightness (b) and contrast (c) using the function:
|
||||
*
|
||||
* s'(x,y) = (s(x,y) + b) * c
|
||||
* b = [-127, 127]
|
||||
* c = [0,2]
|
||||
*/
|
||||
|
||||
/* scale brightness and contrast...
|
||||
*/
|
||||
b = ((double)dev->DataInf.siBrightness * 192.0)/100.0;
|
||||
c = ((double)dev->DataInf.siContrast + 100.0)/100.0;
|
||||
|
||||
DBG( _DBG_INFO, "* brightness = %i -> %i\n",
|
||||
dev->DataInf.siBrightness, (SANE_Byte)b);
|
||||
DBG( _DBG_INFO, "* contrast*100 = %i -> %i\n",
|
||||
dev->DataInf.siContrast, (int)(c*100));
|
||||
|
||||
for( i = 0; i < dev->gamma_length; i++ ) {
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_RED == which)) {
|
||||
tmp = ((double)(dev->gamma_table[0][i] + b)) * c;
|
||||
if( tmp < 0 ) tmp = 0;
|
||||
if( tmp > 255 ) tmp = 255;
|
||||
dev->gamma_table[0][i] = (SANE_Byte)tmp;
|
||||
}
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_GREEN == which)) {
|
||||
tmp = ((double)(dev->gamma_table[1][i] + b)) * c;
|
||||
if( tmp < 0 ) tmp = 0;
|
||||
if( tmp > 255 ) tmp = 255;
|
||||
dev->gamma_table[1][i] = (SANE_Byte)tmp;
|
||||
}
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_BLUE == which)) {
|
||||
tmp = ((double)(dev->gamma_table[2][i] + b)) * c;
|
||||
if( tmp < 0 ) tmp = 0;
|
||||
if( tmp > 255 ) tmp = 255;
|
||||
dev->gamma_table[2][i] = (SANE_Byte)tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Negative ) {
|
||||
DBG( _DBG_INFO, "inverting...\n" );
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_RED == which)) {
|
||||
|
||||
DBG( _DBG_INFO, "inverting RED map\n" );
|
||||
pdw = (u_long*)&dev->gamma_table[0];
|
||||
for( i = dev->gamma_length / 4; i; i--, pdw++ )
|
||||
*pdw = ~(*pdw);
|
||||
}
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_GREEN == which)) {
|
||||
|
||||
DBG( _DBG_INFO, "inverting GREEN map\n" );
|
||||
pdw = (u_long*)&dev->gamma_table[1];
|
||||
for( i = dev->gamma_length / 4; i; i--, pdw++ )
|
||||
*pdw = ~(*pdw);
|
||||
}
|
||||
|
||||
if((_MAP_MASTER == which) || (_MAP_BLUE == which)) {
|
||||
|
||||
DBG( _DBG_INFO, "inverting BLUE map\n" );
|
||||
pdw = (u_long*)&dev->gamma_table[2];
|
||||
for( i = dev->gamma_length / 4; i; i--, pdw++ )
|
||||
*pdw = ~(*pdw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* END U12-MAP.C ............................................................*/
|
|
@ -0,0 +1,515 @@
|
|||
/* @file u12-motor.c
|
||||
* @brief all functions for motor control
|
||||
*
|
||||
* based on sources acquired from Plustek Inc.
|
||||
* Copyright (C) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
/*************************** some definitons *********************************/
|
||||
|
||||
#define _BACKSTEPS 120
|
||||
#define _FORWARDSTEPS 120
|
||||
|
||||
/**************************** local vars *************************************/
|
||||
|
||||
static TimerDef u12motor_Timer;
|
||||
|
||||
|
||||
/*************************** local functions *********************************/
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12motor_DownloadNullScanStates( U12_Device *dev )
|
||||
{
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
u12io_DownloadScanStates( dev );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12motor_Force16Steps( U12_Device *dev, int dir )
|
||||
{
|
||||
u_long dw;
|
||||
|
||||
if( dir == _DIR_FW )
|
||||
u12io_DataToRegister( dev, REG_MOTOR0CONTROL, _FORWARD_MOTOR );
|
||||
else if( dir == _DIR_BW )
|
||||
u12io_DataToRegister( dev, REG_MOTOR0CONTROL, _BACKWARD_MOTOR );
|
||||
|
||||
for( dw = 16; dw; dw-- ) {
|
||||
u12io_RegisterToScanner( dev, REG_FORCESTEP );
|
||||
_DODELAY( 10 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12motor_ModuleFreeRun( U12_Device *dev, u_long steps )
|
||||
{
|
||||
SANE_Byte rb[6];
|
||||
|
||||
rb[0] = REG_MOTORFREERUNCOUNT1; rb[1] = _HIBYTE(steps);
|
||||
rb[2] = REG_MOTORFREERUNCOUNT0; rb[3] = _LOBYTE(steps);
|
||||
rb[4] = REG_MOTORFREERUNTRIGGER; rb[5] = 0;
|
||||
|
||||
u12io_DataToRegs( dev, rb, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12motor_PositionYProc( U12_Device *dev, u_long steps )
|
||||
{
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "u12motor_PositionYProc()\n" );
|
||||
u12io_StartTimer( &timer, _SECOND * 5 );
|
||||
|
||||
u12io_ResetFifoLen();
|
||||
while(!(u12io_GetScanState( dev ) & _SCANSTATE_STOP) &&
|
||||
(!u12io_CheckTimer( &timer )));
|
||||
_DODELAY( 12 );
|
||||
u12motor_ModuleFreeRun( dev, steps );
|
||||
_DODELAY( 15 );
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND * 30 );
|
||||
do {
|
||||
if( !(u12io_GetExtendedStatus( dev ) & _STILL_FREE_RUNNING)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
DBG( _DBG_INFO, "u12motor_PositionYProc() - done\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** initialize this module and setup the correct function pointer according
|
||||
* to the ASIC
|
||||
*/
|
||||
static void u12motor_PositionModuleToHome( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte rb[50];
|
||||
SANE_Byte save, saveModel;
|
||||
int c = 0;
|
||||
|
||||
DBG( _DBG_INFO, "u12motor_PositionModuleToHome()\n" );
|
||||
saveModel = dev->regs.RD_ModelControl;
|
||||
|
||||
dev->scan.refreshState = SANE_FALSE;
|
||||
u12motor_DownloadNullScanStates( dev );
|
||||
|
||||
_DODELAY( 125 );
|
||||
save = dev->shade.intermediate;
|
||||
|
||||
dev->shade.intermediate = _ScanMode_AverageOut;
|
||||
u12hw_InitAsic( dev, SANE_FALSE );
|
||||
dev->shade.intermediate = save;
|
||||
|
||||
_SET_REG( rb, c, REG_MODECONTROL, _ModeScan );
|
||||
_SET_REG( rb, c, REG_RESETMTSC, 0 );
|
||||
_SET_REG( rb, c, REG_SCANCONTROL1, 0 );
|
||||
_SET_REG( rb, c, REG_MODELCONTROL, (dev->ModelCtrl | _MODEL_DPI300));
|
||||
_SET_REG( rb, c, REG_LINECONTROL, 80 );
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, dev->XStepBack );
|
||||
_SET_REG( rb, c, REG_MOTORDRVTYPE, dev->MotorPower );
|
||||
_SET_REG( rb, c, REG_MOTOR0CONTROL, (_MotorHHomeStop | _MotorOn |
|
||||
_MotorHQuarterStep | _MotorPowerEnable));
|
||||
_SET_REG( rb, c, REG_STEPCONTROL, (_MOTOR0_SCANSTATE | _MOTOR_FREERUN));
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
memset( dev->a_nbNewAdrPointer, 0x88, _SCANSTATE_BYTES );
|
||||
u12io_DownloadScanStates( dev );
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
dev->regs.RD_ModelControl = saveModel;
|
||||
}
|
||||
|
||||
/** function to bring the sensor back home
|
||||
*/
|
||||
static void u12motor_ToHomePosition( U12_Device *dev )
|
||||
{
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "Waiting for Sensor to be back in position\n" );
|
||||
if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) {
|
||||
|
||||
u12motor_PositionModuleToHome( dev );
|
||||
u12io_StartTimer( &timer, _SECOND * 20);
|
||||
do {
|
||||
if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)
|
||||
break;
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
}
|
||||
DBG( _DBG_INFO, "- done !\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12motor_BackToHomeSensor( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte rb[20];
|
||||
int c;
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "u12Motor_BackToHomeSensor()\n" );
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_STEPCONTROL, _MOTOR0_SCANSTATE );
|
||||
_SET_REG( rb, c, REG_MODECONTROL, _ModeScan );
|
||||
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
u12motor_Force16Steps( dev, _DIR_NONE );
|
||||
|
||||
/* stepping every state */
|
||||
memset( dev->a_nbNewAdrPointer, 0x88, _SCANSTATE_BYTES );
|
||||
u12io_DownloadScanStates( dev );
|
||||
_DODELAY(50);
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND * 2 );
|
||||
|
||||
u12io_ResetFifoLen();
|
||||
while(!(u12io_GetScanState( dev ) & _SCANSTATE_STOP) &&
|
||||
!u12io_CheckTimer( &timer )) {
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
u12motor_Force16Steps( dev, _DIR_BW );
|
||||
dev->regs.RD_ModeControl = _ModeScan;
|
||||
|
||||
c = 0;
|
||||
|
||||
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA)) {
|
||||
_SET_REG( rb, c, REG_LINECONTROL, _LOBYTE(dev->shade.wExposure));
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, _LOBYTE(dev->shade.wXStep));
|
||||
} else {
|
||||
_SET_REG( rb, c, REG_LINECONTROL, _DEFAULT_LINESCANTIME );
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, 6 );
|
||||
}
|
||||
|
||||
_SET_REG( rb, c, REG_STEPCONTROL, (_MOTOR_FREERUN | _MOTOR0_SCANSTATE));
|
||||
_SET_REG( rb, c, REG_MOTOR0CONTROL,
|
||||
(_MotorHQuarterStep | _MotorOn | _MotorDirBackward |
|
||||
_MotorPowerEnable | _MotorHHomeStop));
|
||||
_SET_REG( rb, c, REG_REFRESHSCANSTATE, 0);
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND * 5 );
|
||||
do {
|
||||
if( u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER )
|
||||
break;
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
_DODELAY( 55 );
|
||||
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_LINECONTROL, dev->regs.RD_LineControl);
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, dev->regs.RD_XStepTime);
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
DBG( _DBG_INFO, "* LineCtrl=0x%02x, XStepTime=0x%02x\n",
|
||||
dev->regs.RD_LineControl, dev->regs.RD_XStepTime );
|
||||
|
||||
u12motor_DownloadNullScanStates( dev );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12motor_ModuleToHome( U12_Device *dev )
|
||||
{
|
||||
SANE_Status res;
|
||||
|
||||
DBG( _DBG_INFO, "u12motor_ModuleToHome()\n" );
|
||||
if(!(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER)) {
|
||||
|
||||
u12io_DataToRegister( dev, REG_MOTOR0CONTROL,
|
||||
(SANE_Byte)(dev->regs.RD_Motor0Control|_MotorDirForward));
|
||||
|
||||
res = u12motor_PositionYProc( dev, 40 );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
res = u12motor_BackToHomeSensor( dev );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
_DODELAY( 250 );
|
||||
}
|
||||
DBG( _DBG_INFO, "* done.\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12motor_WaitForPositionY( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte rb[20];
|
||||
SANE_Status res;
|
||||
SANE_Byte bXStep;
|
||||
int c;
|
||||
u_long dwBeginY;
|
||||
|
||||
c = 0;
|
||||
dwBeginY = (u_long)dev->DataInf.crImage.y * 4 + dev->scan.dwScanOrigin;
|
||||
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
||||
if( dev->f0_8_16 )
|
||||
dwBeginY += 16;
|
||||
else
|
||||
dwBeginY += 8;
|
||||
}
|
||||
|
||||
bXStep = (SANE_Byte)((dev->DataInf.wPhyDataType <= COLOR_256GRAY) ?
|
||||
dev->XStepMono : dev->XStepColor);
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
bXStep = 8;
|
||||
|
||||
u12motor_Force16Steps( dev, _DIR_NONE );
|
||||
dwBeginY -= 16;
|
||||
|
||||
if( dwBeginY > (_RFT_SCANNING_ORG + _YOFFSET) &&
|
||||
bXStep < dev->regs.RD_XStepTime ) {
|
||||
|
||||
u12io_DataToRegister( dev, REG_MOTORDRVTYPE, dev->MotorPower );
|
||||
_DODELAY( 12 );
|
||||
u12io_DataToRegister( dev, REG_XSTEPTIME, bXStep);
|
||||
u12io_DataToRegister( dev, REG_EXTENDEDXSTEP, 0 );
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL1,
|
||||
(SANE_Byte)(dev->regs.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE));
|
||||
res = u12motor_PositionYProc( dev, dwBeginY - 64 );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
dwBeginY = 64;
|
||||
} else {
|
||||
_SET_REG(rb, c, REG_SCANCONTROL1, dev->regs.RD_ScanControl1 );
|
||||
}
|
||||
|
||||
_SET_REG( rb, c, REG_FIFOFULLEN0, _LOBYTE(dev->regs.RD_BufFullSize));
|
||||
_SET_REG( rb, c, REG_FIFOFULLEN1, _HIBYTE(dev->regs.RD_BufFullSize));
|
||||
_SET_REG( rb, c, REG_FIFOFULLEN2, _LOBYTE(_HIWORD(dev->regs.RD_BufFullSize)));
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
u12io_DataToRegister( dev, REG_MOTORDRVTYPE, dev->regs.RD_MotorDriverType);
|
||||
_DODELAY( 12 );
|
||||
|
||||
if(!dev->f2003 || (dev->shade.intermediate & _ScanMode_AverageOut) ||
|
||||
( dev->DataInf.xyAppDpi.y <= 75 &&
|
||||
dev->DataInf.wPhyDataType <= COLOR_256GRAY)) {
|
||||
u12io_DataToRegister( dev, REG_MOTORDRVTYPE,
|
||||
(SANE_Byte)(dev->MotorPower & (_MOTORR_MASK | _MOTORR_STRONG)));
|
||||
} else {
|
||||
u12io_DataToRegister( dev, REG_MOTORDRVTYPE,
|
||||
dev->regs.RD_MotorDriverType );
|
||||
}
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, dev->regs.RD_XStepTime );
|
||||
_SET_REG( rb, c, REG_EXTENDEDXSTEP, dev->regs.RD_ExtXStepTime );
|
||||
_SET_REG( rb, c, REG_SCANCONTROL1,
|
||||
(SANE_Byte)(dev->regs.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE));
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
|
||||
|
||||
TimerDef timer;
|
||||
|
||||
u12motor_ModuleFreeRun( dev, dwBeginY );
|
||||
_DODELAY( 15 );
|
||||
|
||||
u12io_StartTimer( &timer, (_SECOND * 20));
|
||||
|
||||
while(( u12io_GetExtendedStatus( dev ) & _STILL_FREE_RUNNING) &&
|
||||
!u12io_CheckTimer(&timer));
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeScan );
|
||||
} else {
|
||||
u12motor_PositionYProc( dev, dwBeginY );
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12motor_ForceToLeaveHomePos( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte rb[4];
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "u12motor_ForceToLeaveHomePos()\n" );
|
||||
rb[0] = REG_STEPCONTROL;
|
||||
rb[1] = _MOTOR0_ONESTEP;
|
||||
rb[2] = REG_MOTOR0CONTROL;
|
||||
rb[3] = _FORWARD_MOTOR;
|
||||
u12io_DataToRegs( dev, rb, 2 );
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND );
|
||||
|
||||
do {
|
||||
if( !(u12io_DataFromRegister( dev, REG_STATUS ) & _FLAG_PAPER))
|
||||
break;
|
||||
|
||||
u12io_RegisterToScanner( dev, REG_FORCESTEP );
|
||||
_DODELAY( 10 );
|
||||
|
||||
} while( !u12io_CheckTimer( &timer ));
|
||||
|
||||
u12io_DataToRegister( dev, REG_STEPCONTROL, _MOTOR0_SCANSTATE );
|
||||
}
|
||||
|
||||
/** move the sensor to the appropriate shading position
|
||||
*/
|
||||
static SANE_Status u12motor_GotoShadingPosition( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte rb[20];
|
||||
SANE_Status res;
|
||||
int c;
|
||||
|
||||
DBG( _DBG_INFO, "u12motor_GotoShadingPosition()\n" );
|
||||
res = u12motor_ModuleToHome( dev );
|
||||
if( SANE_STATUS_GOOD == res )
|
||||
return res;
|
||||
|
||||
/* position to somewhere under the transparency adapter */
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_TPA ) {
|
||||
|
||||
u12motor_ForceToLeaveHomePos( dev );
|
||||
u12motor_DownloadNullScanStates( dev );
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_STEPCONTROL, _MOTOR0_SCANSTATE );
|
||||
_SET_REG( rb, c, REG_MODECONTROL, _ModeScan);
|
||||
_SET_REG( rb, c, REG_MOTOR0CONTROL, _FORWARD_MOTOR );
|
||||
_SET_REG( rb, c, REG_XSTEPTIME, 6);
|
||||
_SET_REG( rb, c, REG_EXTENDEDXSTEP, 0);
|
||||
_SET_REG( rb, c, REG_SCANCONTROL1, _MFRC_BY_XSTEP);
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
res = u12motor_PositionYProc( dev, _TPA_SHADINGORG );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
}
|
||||
DBG( _DBG_INFO, "* Position reached\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12motor_ModuleForwardBackward( U12_Device *dev )
|
||||
{
|
||||
DBG( _DBG_INFO, "u12motor_ModuleForwardBackward()\n" );
|
||||
|
||||
switch( dev->scan.bModuleState ) {
|
||||
|
||||
case _MotorInNormalState:
|
||||
DBG( _DBG_INFO, "* _MotorInNormalState\n" );
|
||||
dev->scan.bModuleState = _MotorGoBackward;
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL1,
|
||||
(SANE_Byte)(dev->regs.RD_ScanControl1 & ~_MFRC_RUNSCANSTATE));
|
||||
u12io_DataToRegister( dev, REG_MOTOR0CONTROL,
|
||||
(SANE_Byte)(dev->regs.RD_Motor0Control & ~_MotorDirForward));
|
||||
|
||||
u12motor_ModuleFreeRun( dev, _BACKSTEPS );
|
||||
u12io_StartTimer( &u12motor_Timer, (15 * _MSECOND));
|
||||
break;
|
||||
|
||||
case _MotorGoBackward:
|
||||
DBG( _DBG_INFO, "* _MotorGoBackward\n" );
|
||||
if( u12io_CheckTimer( &u12motor_Timer)) {
|
||||
if(!(u12io_GetExtendedStatus( dev ) & _STILL_FREE_RUNNING )) {
|
||||
dev->scan.bModuleState = _MotorInStopState;
|
||||
u12io_StartTimer( &u12motor_Timer, (50 *_MSECOND));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case _MotorInStopState:
|
||||
DBG( _DBG_INFO, "* _MotorInStopState\n" );
|
||||
if( u12io_CheckTimer( &u12motor_Timer )) {
|
||||
|
||||
if( u12io_GetFifoLength( dev ) < dev->scan.dwMaxReadFifo ) {
|
||||
dev->scan.bModuleState = _MotorAdvancing;
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL1,
|
||||
dev->regs.RD_ScanControl1);
|
||||
u12io_DataToRegister( dev, REG_MOTOR0CONTROL,
|
||||
dev->regs.RD_Motor0Control);
|
||||
u12motor_ModuleFreeRun( dev, _FORWARDSTEPS );
|
||||
u12io_StartTimer( &u12motor_Timer, (15 * _MSECOND));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case _MotorAdvancing:
|
||||
DBG( _DBG_INFO, "* _MotorAdvancing\n" );
|
||||
if( u12io_CheckTimer( &u12motor_Timer)) {
|
||||
if( !(u12io_GetScanState( dev ) & _SCANSTATE_STOP))
|
||||
dev->scan.bModuleState = _MotorInNormalState;
|
||||
else {
|
||||
if (!(u12io_GetExtendedStatus( dev ) & _STILL_FREE_RUNNING )) {
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
dev->scan.bModuleState = _MotorInNormalState;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* END U12-MOTOR.C ..........................................................*/
|
|
@ -0,0 +1,306 @@
|
|||
/** @file u12-scanner.h
|
||||
* @brief Definitions for the devices.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
#ifndef __U12_SCANNER_H__
|
||||
#define __U12_SCANNER_H__
|
||||
|
||||
/* definitions for the timer functions
|
||||
*/
|
||||
typedef double TimerDef;
|
||||
#define _MSECOND 1000 /* based on 1 us */
|
||||
#define _SECOND (1000*_MSECOND)
|
||||
|
||||
#if 1
|
||||
#define _DO_UDELAY(usecs) u12io_udelay(usecs)
|
||||
#define _DODELAY(msecs) u12io_udelay(1000*msecs)
|
||||
/*{ int i; for( i = msecs; i--; ) _DO_UDELAY(1000); }*/
|
||||
#else
|
||||
#define _DODELAY(msecs)
|
||||
#endif
|
||||
|
||||
/* ModuleStates */
|
||||
#define _MotorInNormalState 0
|
||||
#define _MotorGoBackward 1
|
||||
#define _MotorInStopState 2
|
||||
#define _MotorAdvancing 3
|
||||
#define _MotorAdvanced 4
|
||||
|
||||
|
||||
/** some function types
|
||||
*/
|
||||
typedef struct u12d *pU12_Device;
|
||||
typedef struct svd *pShadingVarDef;
|
||||
typedef void (*pFnVoid)(pU12_Device);
|
||||
typedef void (*pFnDACOffs)(pU12_Device, pShadingVarDef, u_long);
|
||||
typedef void (*pFnDACDark)(pU12_Device, pShadingVarDef, u_long, u_short);
|
||||
typedef void (*pFnDataProcess)(pU12_Device, void*, void*, u_long);
|
||||
typedef SANE_Bool (*pFnBool)(pU12_Device);
|
||||
|
||||
|
||||
/* useful for RGB-values */
|
||||
typedef struct {
|
||||
SANE_Byte Red;
|
||||
SANE_Byte Green;
|
||||
SANE_Byte Blue;
|
||||
} RGBByteDef;
|
||||
|
||||
typedef struct {
|
||||
u_short Red;
|
||||
u_short Green;
|
||||
u_short Blue;
|
||||
} RGBUShortDef;
|
||||
|
||||
typedef struct {
|
||||
u_long Red;
|
||||
u_long Green;
|
||||
u_long Blue;
|
||||
} RGBULongDef;
|
||||
|
||||
typedef union {
|
||||
RGBByteDef Colors;
|
||||
SANE_Byte bColors[3];
|
||||
} ColorByte;
|
||||
|
||||
typedef union {
|
||||
RGBUShortDef Colors;
|
||||
u_short wColors[3];
|
||||
} ColorWord;
|
||||
|
||||
typedef union {
|
||||
SANE_Byte *pb;
|
||||
u_short *pw;
|
||||
u_long *pdw;
|
||||
RGBUShortDef *pusrgb;
|
||||
RGBULongDef *pulrgb;
|
||||
RGBByteDef *pbrgb;
|
||||
} DataPointer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union {
|
||||
SANE_Byte *bp;
|
||||
u_short *usp;
|
||||
u_long *ulp;
|
||||
} red;
|
||||
union {
|
||||
SANE_Byte *bp;
|
||||
u_short *usp;
|
||||
u_long *ulp;
|
||||
} green;
|
||||
union {
|
||||
SANE_Byte *bp;
|
||||
u_short *usp;
|
||||
u_long *ulp;
|
||||
} blue;
|
||||
|
||||
} RBGPtrDef;
|
||||
|
||||
typedef struct {
|
||||
SANE_Byte b1st;
|
||||
SANE_Byte b2nd;
|
||||
} WordVal;
|
||||
|
||||
typedef struct {
|
||||
WordVal w1st;
|
||||
WordVal w2nd;
|
||||
} DWordVal;
|
||||
|
||||
|
||||
typedef union {
|
||||
WordVal wOverlap;
|
||||
DWordVal dwOverlap;
|
||||
u_long dwValue;
|
||||
u_short wValue;
|
||||
SANE_Byte bValue;
|
||||
} DataType;
|
||||
|
||||
typedef struct {
|
||||
u_short exposureTime;
|
||||
u_short xStepTime;
|
||||
} ExpXStepDef;
|
||||
|
||||
typedef struct {
|
||||
SANE_Byte reg;
|
||||
SANE_Byte val;
|
||||
} RegDef;
|
||||
|
||||
/** for defining a point
|
||||
*/
|
||||
typedef struct {
|
||||
u_short x;
|
||||
u_short y;
|
||||
} XY;
|
||||
|
||||
/** for defining a crop area, all is 300DPI based
|
||||
*/
|
||||
typedef struct {
|
||||
u_short x; /**< x-pos of top-left corner */
|
||||
u_short y; /**< y-pos of top-left corner */
|
||||
u_short cx; /**< width */
|
||||
u_short cy; /**< height */
|
||||
} CropRect;
|
||||
|
||||
/** for defining an image
|
||||
*/
|
||||
typedef struct {
|
||||
u_long dwFlag; /**< i.e. image source */
|
||||
CropRect crArea; /**< the image size and position */
|
||||
XY xyDpi; /**< the resolution */
|
||||
u_short wDataType; /**< and the data type */
|
||||
} ImgDef;
|
||||
|
||||
/**
|
||||
*/
|
||||
typedef struct {
|
||||
u_long dwPixelsPerLine;
|
||||
u_long dwBytesPerLine;
|
||||
u_long dwLinesPerArea;
|
||||
ImgDef image;
|
||||
} CropInfo;
|
||||
|
||||
/** all we need for a scan
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
u_long dwScanFlag;
|
||||
double xyRatio; /**< for scaling */
|
||||
u_short wYSum;
|
||||
|
||||
XY xyPhyDpi; /**< physical resolution of a scan */
|
||||
u_long dwPhysBytesPerLine;
|
||||
u_long wPhyDataType; /**< how the scanner should scan */
|
||||
|
||||
u_long dwAsicPixelsPerPlane;
|
||||
u_long dwAsicBytesPerPlane;
|
||||
u_long dwAsicBytesPerLine;
|
||||
|
||||
XY xyAppDpi;
|
||||
u_long dwAppLinesPerArea;
|
||||
u_long dwAppPixelsPerLine;
|
||||
u_long dwAppPhyBytesPerLine;
|
||||
u_long dwAppBytesPerLine;
|
||||
u_short wAppDataType;
|
||||
|
||||
short siBrightness;
|
||||
short siContrast;
|
||||
|
||||
CropRect crImage;
|
||||
} DataInfo;
|
||||
|
||||
/** this will be our global "overkill" structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
pFnDataProcess DataProcess; /* to convert RGB buffers to RGB pixels */
|
||||
pFnBool DoSample;
|
||||
pFnBool DataRead; /* function to get data from scanner */
|
||||
|
||||
long lBufferAdjust;
|
||||
u_long dwScanOrigin; /* where to start the scan */
|
||||
u_long negBegin; /* used while scanning in TPA modes */
|
||||
u_long posBegin;
|
||||
SANE_Byte bDiscardAll;
|
||||
u_long dwLinesToRead;
|
||||
|
||||
union {
|
||||
u_short wGreenDiscard;
|
||||
u_short wGreenKeep;
|
||||
} gd_gk;
|
||||
union {
|
||||
u_short wBlueDiscard;
|
||||
u_short wRedKeep;
|
||||
} bd_rk;
|
||||
|
||||
u_long dpiIdx; /* index to get/set values in the table */
|
||||
ExpXStepDef *negScan; /* reference to exposure/xtep table */
|
||||
|
||||
DataPointer p48BitBuf; /* for handling 48-bit data */
|
||||
RBGPtrDef BufBegin; /* for reading/writing the scan-data */
|
||||
RBGPtrDef BufEnd;
|
||||
RBGPtrDef BufGet;
|
||||
RBGPtrDef BufData;
|
||||
RBGPtrDef BufPut;
|
||||
|
||||
/* motor movement stuff */
|
||||
u_long dwInterval;
|
||||
SANE_Bool refreshState;
|
||||
SANE_Bool motorBackward;
|
||||
SANE_Byte oldScanState;
|
||||
SANE_Byte bRefresh;
|
||||
SANE_Byte bModuleState;
|
||||
SANE_Byte bNowScanState;
|
||||
|
||||
/* internal FIFO management */
|
||||
u_long dwMinReadFifo;
|
||||
u_long dwMaxReadFifo;
|
||||
SANE_Byte bFifoSelect; /* defines which FIFO to use */
|
||||
|
||||
} ScanInfo;
|
||||
|
||||
/** structure for accessing one buffer in various ways...
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
union {
|
||||
SANE_Byte *pReadBuf;
|
||||
SANE_Byte *pShadingMap;
|
||||
u_short *pShadingRam;
|
||||
DataPointer Buf;
|
||||
} b1;
|
||||
|
||||
union {
|
||||
SANE_Byte *pSumBuf;
|
||||
RGBUShortDef *pSumRGB;
|
||||
} b2;
|
||||
|
||||
DataPointer TpaBuf;
|
||||
} BufferDef;
|
||||
|
||||
#endif /* guard __U12_SCANNER_H__ */
|
||||
|
||||
/* END U12-SCANNER.H ........................................................*/
|
|
@ -0,0 +1,883 @@
|
|||
/* @file u12-shading.c -
|
||||
* @brief all the shading functions
|
||||
*
|
||||
* based on sources acquired from Plustek Inc.
|
||||
* Copyright (C) 1998 Plustek Inc.
|
||||
* Copyright (C) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
#define _GAIN_HIGH 240 /* Volt. max. value */
|
||||
#define _GAIN_LOW 220 /* Volt. min. value */
|
||||
|
||||
#define _CHANNEL_RED 0
|
||||
#define _CHANNEL_GREEN 1
|
||||
#define _CHANNEL_BLUE 2
|
||||
|
||||
/* for DAC programming */
|
||||
#define _VALUE_CONFIG 0x51
|
||||
#define _DAC_RED (SANE_Byte)(_VALUE_CONFIG | 0x00)
|
||||
#define _DAC_GREENCOLOR (SANE_Byte)(_VALUE_CONFIG | 0x04)
|
||||
#define _DAC_GREENMONO (SANE_Byte)(_VALUE_CONFIG | 0x06)
|
||||
#define _DAC_BLUE (SANE_Byte)(_VALUE_CONFIG | 0x08)
|
||||
|
||||
|
||||
/* forward declarations ... */
|
||||
static void u12tpa_Reshading( U12_Device * );
|
||||
static void u12tpa_FindCenterPointer( U12_Device * );
|
||||
|
||||
/**
|
||||
*/
|
||||
static void
|
||||
u12shading_DownloadShadingTable( U12_Device *dev, SANE_Byte *buf, u_long len )
|
||||
{
|
||||
SANE_Byte *val, *rb;
|
||||
SANE_Byte reg, regs[20];
|
||||
int c;
|
||||
|
||||
DBG( _DBG_INFO, "u12shading_DownloadShadingTable()\n" );
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeShadingMem );
|
||||
u12io_DataToRegister( dev, REG_MEMORYLO, 0 );
|
||||
u12io_DataToRegister( dev, REG_MEMORYHI, 0 );
|
||||
|
||||
/* set 12 bits output color */
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL,
|
||||
(SANE_Byte)(dev->regs.RD_ScanControl | _SCAN_12BITMODE));
|
||||
|
||||
u12io_MoveDataToScanner( dev, buf, len );
|
||||
|
||||
regs[0] = REG_MODECONTROL;
|
||||
regs[1] = _ModeScan;
|
||||
|
||||
/* FillShadingDarkToShadingRegister() */
|
||||
dev->regs.RD_RedDarkOff = dev->shade.DarkOffset.Colors.Red;
|
||||
dev->regs.RD_GreenDarkOff = dev->shade.DarkOffset.Colors.Green;
|
||||
dev->regs.RD_BlueDarkOff = dev->shade.DarkOffset.Colors.Blue;
|
||||
|
||||
val = (SANE_Byte*)&dev->regs.RD_RedDarkOff;
|
||||
rb = ®s[2];
|
||||
c = 1;
|
||||
for( reg = REG_REDCHDARKOFFSETLO;
|
||||
reg <= REG_BLUECHDARKOFFSETHI; reg++, val++) {
|
||||
|
||||
*(rb++) = reg;
|
||||
*(rb++) = *val;
|
||||
c++;
|
||||
}
|
||||
u12io_DataToRegs( dev, regs, c );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12shadingAdjustShadingWaveform( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte b;
|
||||
u_short count, wR, wG, wB, tmp;
|
||||
DataType var;
|
||||
DataPointer pvar, psum;
|
||||
RBGPtrDef cp;
|
||||
RGBUShortDef *pRGB, *pwsum;
|
||||
u_long shadingBytes;
|
||||
|
||||
DBG( _DBG_INFO, "u12shading_AdjustShadingWaveForm()\n" );
|
||||
|
||||
memset( dev->bufs.b2.pSumBuf, 0, (5400 * 3 * 2));
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
|
||||
|
||||
dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure);
|
||||
u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL,
|
||||
dev->regs.RD_ExtLineControl );
|
||||
u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl );
|
||||
|
||||
dev->regs.RD_XStepTime = _LOBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_ExtXStepTime = _HIBYTE(dev->shade.wExposure);
|
||||
u12io_DataToRegister( dev, REG_EXTENDEDXSTEP, dev->regs.RD_ExtXStepTime );
|
||||
u12io_DataToRegister( dev, REG_XSTEPTIME, dev->regs.RD_XStepTime );
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeScan;
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut ) {
|
||||
|
||||
dev->regs.RD_Dpi = 300;
|
||||
dev->regs.RD_Pixels = 2700;
|
||||
shadingBytes = 2700 * 2;
|
||||
} else {
|
||||
dev->regs.RD_Dpi = 600;
|
||||
dev->regs.RD_Pixels = 5400;
|
||||
shadingBytes = 5400 * 2;
|
||||
}
|
||||
dev->regs.RD_Origin = _SHADING_BEGINX;
|
||||
|
||||
for( pvar.pdw = (u_long*)dev->a_nbNewAdrPointer,
|
||||
var.dwValue = _SCANSTATE_BYTES >> 2; var.dwValue--; pvar.pdw++) {
|
||||
*pvar.pdw = 0x00f00080;
|
||||
}
|
||||
|
||||
dev->scan.refreshState = SANE_FALSE;
|
||||
u12io_PutOnAllRegisters( dev );
|
||||
_DODELAY( 45 );
|
||||
|
||||
if( dev->shade.pHilight ) {
|
||||
|
||||
memset( dev->shade.pHilight, 0,
|
||||
shadingBytes * dev->shade.skipHilight * 3 );
|
||||
|
||||
memset((SANE_Byte*)dev->shade.pHilight +
|
||||
shadingBytes * dev->shade.skipHilight * 3, 0xff,
|
||||
shadingBytes * dev->shade.skipShadow * 3 );
|
||||
}
|
||||
|
||||
for( count = 32; count--; ) {
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
u12io_ReadOneShadingLine( dev, ((SANE_Byte*)dev->bufs.b1.pShadingRam)+
|
||||
_SHADING_BEGINX, shadingBytes );
|
||||
|
||||
if( dev->shade.pHilight ) {
|
||||
|
||||
if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
cp.red.usp = dev->bufs.b1.pShadingRam + _SHADING_BEGINX;
|
||||
cp.green.usp = cp.red.usp + dev->regs.RD_Pixels;
|
||||
cp.blue.usp = cp.green.usp + dev->regs.RD_Pixels;
|
||||
pvar.pusrgb = (RGBUShortDef*)dev->shade.pHilight +
|
||||
_SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
pRGB = pvar.pusrgb++;
|
||||
wR = *cp.red.usp;
|
||||
wG = *cp.green.usp;
|
||||
wB = *cp.blue.usp;
|
||||
|
||||
for( b = dev->shade.skipHilight; b--;
|
||||
pRGB += dev->regs.RD_Pixels ) {
|
||||
if( wR > pRGB->Red ) {
|
||||
tmp = wR;
|
||||
wR = pRGB->Red;
|
||||
pRGB->Red = tmp;
|
||||
}
|
||||
if( wG > pRGB->Green ) {
|
||||
tmp = wG;
|
||||
wG = pRGB->Green;
|
||||
pRGB->Green = tmp;
|
||||
}
|
||||
if( wB > pRGB->Blue ) {
|
||||
tmp = wB;
|
||||
wB = pRGB->Blue;
|
||||
pRGB->Blue = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
wR = *cp.red.usp++;
|
||||
wG = *cp.green.usp++;
|
||||
wB = *cp.blue.usp++;
|
||||
|
||||
for( b = dev->shade.skipShadow; b--;
|
||||
pRGB += dev->regs.RD_Pixels ) {
|
||||
if( wR < pRGB->Red ) {
|
||||
tmp = wR;
|
||||
wR = pRGB->Red;
|
||||
pRGB->Red = tmp;
|
||||
}
|
||||
if( wG < pRGB->Green ) {
|
||||
tmp = wG;
|
||||
wG = pRGB->Green;
|
||||
pRGB->Green = tmp;
|
||||
}
|
||||
if( wB < pRGB->Blue ) {
|
||||
tmp = wB;
|
||||
wB = pRGB->Blue;
|
||||
pRGB->Blue = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
cp.green.usp = dev->bufs.b1.pShadingRam +
|
||||
dev->regs.RD_Pixels + _SHADING_BEGINX;
|
||||
cp.blue.usp = (u_short*)dev->shade.pHilight + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
cp.red.usp = cp.blue.usp++;
|
||||
wG = *cp.green.usp;
|
||||
for( b = dev->shade.skipHilight; b--;
|
||||
cp.red.usp += dev->regs.RD_Pixels) {
|
||||
if( wG > *cp.red.usp ) {
|
||||
tmp = wG;
|
||||
wG = *cp.red.usp;
|
||||
*cp.red.usp = tmp;
|
||||
}
|
||||
}
|
||||
wG = *cp.green.usp++;
|
||||
for( b = dev->shade.skipShadow; b--;
|
||||
cp.red.usp += dev->regs.RD_Pixels ) {
|
||||
if( wG < *cp.red.usp ) {
|
||||
tmp = wG;
|
||||
wG = *cp.red.usp;
|
||||
*cp.red.usp = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* AddToSumBuffer() */
|
||||
if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
cp.red.usp = dev->bufs.b1.pShadingRam + _SHADING_BEGINX;
|
||||
cp.green.usp = cp.red.usp + dev->regs.RD_Pixels;
|
||||
cp.blue.usp = cp.green.usp + dev->regs.RD_Pixels;
|
||||
|
||||
pvar.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;
|
||||
pvar.pulrgb++, cp.red.usp++, cp.green.usp++, cp.blue.usp++) {
|
||||
pvar.pulrgb->Red += (u_long)*cp.red.usp;
|
||||
pvar.pulrgb->Green += (u_long)*cp.green.usp;
|
||||
pvar.pulrgb->Blue += (u_long)*cp.blue.usp;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
cp.green.usp = dev->bufs.b1.pShadingRam +
|
||||
dev->regs.RD_Pixels + _SHADING_BEGINX;
|
||||
pvar.pdw = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
for( var.dwValue = (u_long)dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--; pvar.pdw++, cp.green.usp++) {
|
||||
*pvar.pdw += (u_long)*cp.green.usp;
|
||||
}
|
||||
}
|
||||
|
||||
u12io_ResetFifoLen();
|
||||
if( u12io_GetFifoLength( dev ) < dev->regs.RD_Pixels )
|
||||
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
||||
}
|
||||
|
||||
/* AverageAfterSubHilightShadow() */
|
||||
if( dev->shade.pHilight ) {
|
||||
if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
pvar.pusrgb = (RGBUShortDef*)dev->shade.pHilight + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
pRGB = pvar.pusrgb++;
|
||||
|
||||
for( b = dev->shade.skipHilight + dev->shade.skipShadow;
|
||||
b--; pRGB += dev->regs.RD_Pixels ) {
|
||||
|
||||
psum.pulrgb->Red -= (u_long)pRGB->Red;
|
||||
psum.pulrgb->Green -= (u_long)pRGB->Green;
|
||||
psum.pulrgb->Blue -= (u_long)pRGB->Blue;
|
||||
}
|
||||
|
||||
pwsum->Red = (u_short)(psum.pulrgb->Red / dev->shade.dwDiv);
|
||||
pwsum->Green = (u_short)(psum.pulrgb->Green / dev->shade.dwDiv);
|
||||
pwsum->Blue = (u_short)(psum.pulrgb->Blue / dev->shade.dwDiv);
|
||||
psum.pulrgb++;
|
||||
pwsum++;
|
||||
}
|
||||
} else {
|
||||
cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
cp.blue.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
pvar.pw = (u_short*)dev->shade.pHilight + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
cp.red.usp = pvar.pw++;
|
||||
|
||||
for( b = dev->shade.skipHilight + dev->shade.skipShadow;
|
||||
b--; cp.red.usp += dev->regs.RD_Pixels )
|
||||
*cp.green.ulp -= *cp.red.usp;
|
||||
|
||||
*cp.blue.usp = (u_short)(*cp.green.ulp / dev->shade.dwDiv);
|
||||
cp.blue.usp++;
|
||||
cp.green.ulp++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
psum.pulrgb = (RGBULongDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
pwsum->Red = (u_short)(psum.pulrgb->Red >> 5);
|
||||
pwsum->Green = (u_short)(psum.pulrgb->Green >> 5);
|
||||
pwsum->Blue = (u_short)(psum.pulrgb->Blue >> 5);
|
||||
psum.pulrgb++;
|
||||
pwsum++;
|
||||
}
|
||||
} else {
|
||||
cp.green.ulp = (u_long*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
cp.blue.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
*cp.blue.usp = (u_short)(*cp.green.ulp >> 5);
|
||||
cp.blue.usp++;
|
||||
cp.green.ulp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process negative & transparency here */
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_TPA )
|
||||
u12tpa_FindCenterPointer( dev );
|
||||
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Negative )
|
||||
u12tpa_Reshading( dev );
|
||||
|
||||
pRGB = (RGBUShortDef*)&dev->shade.pCcdDac->GainResize;
|
||||
|
||||
if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
pwsum = (RGBUShortDef*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
|
||||
if ((short)(pwsum->Red -= dev->shade.DarkOffset.Colors.Red) > 0) {
|
||||
pwsum->Red = pwsum->Red * pRGB->Red / 100U;
|
||||
if( pwsum->Red > 0xfff )
|
||||
pwsum->Red = 0xfff;
|
||||
} else
|
||||
pwsum->Red = 0;
|
||||
|
||||
if((short)(pwsum->Green -= dev->shade.DarkOffset.Colors.Green) > 0) {
|
||||
pwsum->Green = pwsum->Green * pRGB->Green / 100U;
|
||||
if( pwsum->Green > 0xfff )
|
||||
pwsum->Green = 0xfff;
|
||||
} else
|
||||
pwsum->Green = 0;
|
||||
|
||||
if ((short)(pwsum->Blue -= dev->shade.DarkOffset.Colors.Blue) > 0) {
|
||||
pwsum->Blue = pwsum->Blue * pRGB->Blue / 100U;
|
||||
if( pwsum->Blue > 0xfff )
|
||||
pwsum->Blue = 0xfff;
|
||||
} else
|
||||
pwsum->Blue = 0;
|
||||
|
||||
wR = (u_short)(pwsum->Red >> 4);
|
||||
pwsum->Red <<= 12;
|
||||
pwsum->Red |= wR;
|
||||
wR = (u_short)(pwsum->Green >> 4);
|
||||
pwsum->Green <<= 12;
|
||||
pwsum->Green |= wR;
|
||||
wR = (u_short)(pwsum->Blue>> 4);
|
||||
pwsum->Blue <<= 12;
|
||||
pwsum->Blue |= wR;
|
||||
pwsum++;
|
||||
}
|
||||
} else {
|
||||
|
||||
cp.green.usp = (u_short*)dev->bufs.b2.pSumBuf + _SHADING_BEGINX;
|
||||
|
||||
for( var.dwValue = dev->regs.RD_Pixels - _SHADING_BEGINX;
|
||||
var.dwValue--;) {
|
||||
|
||||
if((short)(*cp.green.usp -= dev->shade.DarkOffset.Colors.Green) > 0) {
|
||||
|
||||
*cp.green.usp = *cp.green.usp * pRGB->Green / 100U;
|
||||
if( *cp.green.usp > 0xfff )
|
||||
*cp.green.usp = 0xfff;
|
||||
} else
|
||||
*cp.green.usp = 0;
|
||||
|
||||
wR = (u_short)(*cp.green.usp >> 4);
|
||||
*cp.green.usp <<= 12;
|
||||
*cp.green.usp |= wR;
|
||||
|
||||
cp.green.usp++;
|
||||
}
|
||||
}
|
||||
|
||||
u12shading_DownloadShadingTable(dev, dev->bufs.b2.pSumBuf, (5400 * 3 * 2));
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12shading_GainOffsetToDAC( U12_Device *dev, SANE_Byte ch,
|
||||
SANE_Byte reg, SANE_Byte d )
|
||||
{
|
||||
if( dev->DACType == _DA_SAMSUNG8531 ) {
|
||||
u12io_DataRegisterToDAC( dev, 0, ch );
|
||||
}
|
||||
u12io_DataRegisterToDAC( dev, reg, d );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void u12shading_FillToDAC( U12_Device *dev,
|
||||
RGBByteDef *regs, ColorByte *data )
|
||||
{
|
||||
if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
u12shading_GainOffsetToDAC(dev, _DAC_RED, regs->Red, data->Colors.Red);
|
||||
u12shading_GainOffsetToDAC(dev, _DAC_GREENCOLOR,
|
||||
regs->Green, data->Colors.Green);
|
||||
u12shading_GainOffsetToDAC(dev, _DAC_BLUE,
|
||||
regs->Blue, data->Colors.Blue);
|
||||
} else {
|
||||
u12shading_GainOffsetToDAC(dev, _DAC_GREENMONO, regs->Green,
|
||||
data->Colors.Green);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Byte u12shading_SumGains( SANE_Byte *pb, u_long pixelsLine )
|
||||
{
|
||||
SANE_Byte hilight, tmp;
|
||||
u_long dwPixels, dwAve;
|
||||
u_short sum;
|
||||
|
||||
hilight = 0;
|
||||
for( dwPixels = pixelsLine >> 4; dwPixels--; ) {
|
||||
|
||||
for( sum = 0, dwAve = 16; dwAve--; pb++ )
|
||||
sum += (u_short)*pb;
|
||||
|
||||
sum >>= 4;
|
||||
tmp = (SANE_Byte)sum;
|
||||
|
||||
if( tmp > hilight )
|
||||
hilight = tmp;
|
||||
}
|
||||
return hilight;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static void
|
||||
u12shading_AdjustGain( U12_Device *dev, u_long color, SANE_Byte hilight )
|
||||
{
|
||||
if( hilight < dev->shade.bGainLow ) {
|
||||
|
||||
if( dev->shade.Hilight.bColors[color] < dev->shade.bGainHigh ) {
|
||||
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
dev->shade.Hilight.bColors[color] = hilight;
|
||||
|
||||
if( hilight <= (SANE_Byte)(dev->shade.bGainLow - hilight))
|
||||
dev->shade.Gain.bColors[color] += dev->shade.bGainDouble;
|
||||
else
|
||||
dev->shade.Gain.bColors[color]++;
|
||||
}
|
||||
} else {
|
||||
if( hilight > dev->shade.bGainHigh ) {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
dev->shade.Hilight.bColors[color] = hilight;
|
||||
dev->shade.Gain.bColors[color]--;
|
||||
} else {
|
||||
dev->shade.Hilight.bColors[color] = hilight;
|
||||
}
|
||||
}
|
||||
|
||||
if( dev->shade.Gain.bColors[color] > dev->shade.bMaxGain ) {
|
||||
dev->shade.Gain.bColors[color] = dev->shade.bMaxGain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12shading_AdjustRGBGain( U12_Device *dev )
|
||||
{
|
||||
int i;
|
||||
SANE_Byte hi[3];
|
||||
|
||||
DBG( _DBG_INFO, "u12shading_AdjustRGBGain()\n" );
|
||||
|
||||
dev->shade.Gain.Colors.Red =
|
||||
dev->shade.Gain.Colors.Green =
|
||||
dev->shade.Gain.Colors.Blue = dev->shade.bUniGain;
|
||||
|
||||
dev->shade.Hilight.Colors.Red =
|
||||
dev->shade.Hilight.Colors.Green =
|
||||
dev->shade.Hilight.Colors.Blue = 0;
|
||||
|
||||
dev->shade.bGainHigh = _GAIN_HIGH;
|
||||
dev->shade.bGainLow = _GAIN_LOW;
|
||||
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
|
||||
for( i = 10; i-- && !dev->shade.fStop; ) {
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
dev->shade.fStop = SANE_TRUE;
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
|
||||
|
||||
dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
|
||||
u12hw_SelectLampSource( dev );
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
|
||||
|
||||
u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeScan;
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X >> 1;
|
||||
else
|
||||
dev->regs.RD_Origin = (u_short)_DATA_ORIGIN_X;
|
||||
|
||||
dev->regs.RD_Dpi = 300;
|
||||
dev->regs.RD_Pixels = 2560;
|
||||
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
dev->a_nbNewAdrPointer[1] = 0x77;
|
||||
|
||||
u12io_PutOnAllRegisters( dev );
|
||||
_DODELAY( 45 );
|
||||
|
||||
/* read one shading line and work on it */
|
||||
if( u12io_ReadOneShadingLine( dev,
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam, 2560)) {
|
||||
|
||||
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
||||
|
||||
hi[1] = u12shading_SumGains(
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560);
|
||||
if( hi[1] ) {
|
||||
u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] );
|
||||
} else {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
}
|
||||
} else {
|
||||
hi[0] = u12shading_SumGains(
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam, 2560);
|
||||
hi[1] = u12shading_SumGains(
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam + 2560, 2560);
|
||||
hi[2] = u12shading_SumGains(
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam + 5120, 2560);
|
||||
|
||||
if (!hi[0] || !hi[1] || !hi[2] ) {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
} else {
|
||||
u12shading_AdjustGain( dev, _CHANNEL_RED, hi[0] );
|
||||
u12shading_AdjustGain( dev, _CHANNEL_GREEN, hi[1] );
|
||||
u12shading_AdjustGain( dev, _CHANNEL_BLUE, hi[2] );
|
||||
}
|
||||
}
|
||||
} else
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
}
|
||||
|
||||
if( !dev->shade.fStop )
|
||||
DBG( _DBG_INFO, "u12shading_AdjustRGBGain() - all loops done!!!\n" );
|
||||
|
||||
u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static u_short u12shading_SumDarks( U12_Device *dev, u_short *data )
|
||||
{
|
||||
u_short i, loop;
|
||||
|
||||
if( dev->CCDID == _CCD_3799 ) {
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
data += 0x18;
|
||||
else
|
||||
data += 0x30;
|
||||
} else {
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
data += 0x18;
|
||||
else
|
||||
data += 0x20;
|
||||
}
|
||||
|
||||
for( i = 0, loop = 16; loop--; data++ )
|
||||
i += *data;
|
||||
i >>= 4;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12shadingAdjustDark( U12_Device *dev )
|
||||
{
|
||||
u_long i;
|
||||
u_short wDarks[3];
|
||||
|
||||
DBG( _DBG_INFO, "u12shadingAdjustDark()\n" );
|
||||
dev->shade.DarkDAC.Colors = dev->shade.pCcdDac->DarkDAC.Colors;
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
|
||||
for( i = 16; i-- && !dev->shade.fStop;) {
|
||||
|
||||
if( u12io_IsEscPressed()) {
|
||||
DBG( _DBG_INFO, "* CANCEL detected!\n" );
|
||||
return SANE_STATUS_CANCELLED;
|
||||
}
|
||||
|
||||
dev->shade.fStop = SANE_TRUE;
|
||||
|
||||
u12shading_FillToDAC( dev, &dev->RegDACOffset, &dev->shade.DarkDAC );
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
|
||||
|
||||
dev->regs.RD_ScanControl = (_SCAN_12BITMODE + _SCAN_1ST_AVERAGE);
|
||||
u12hw_SelectLampSource( dev );
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
|
||||
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
|
||||
dev->regs.RD_Origin = _SHADING_BEGINX;
|
||||
dev->regs.RD_Pixels = 512;
|
||||
|
||||
if( dev->shade.intermediate & _ScanMode_AverageOut )
|
||||
dev->regs.RD_Dpi = 300;
|
||||
else
|
||||
dev->regs.RD_Dpi = 600;
|
||||
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
dev->a_nbNewAdrPointer[1] = 0x77;
|
||||
|
||||
u12io_PutOnAllRegisters( dev );
|
||||
_DODELAY( 45 );
|
||||
|
||||
/* read one shading line and work on it */
|
||||
if( u12io_ReadOneShadingLine(dev,
|
||||
(SANE_Byte*)dev->bufs.b1.pShadingRam, 512*2)) {
|
||||
|
||||
if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
|
||||
wDarks[0] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam);
|
||||
wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
|
||||
dev->regs.RD_Pixels );
|
||||
wDarks[2] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
|
||||
dev->regs.RD_Pixels * 2UL);
|
||||
|
||||
if( !wDarks[0] || !wDarks[1] || !wDarks[2] ) {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
} else {
|
||||
dev->shade.DarkOffset.wColors[0] = wDarks[0];
|
||||
dev->shade.DarkOffset.wColors[1] = wDarks[1];
|
||||
dev->shade.DarkOffset.wColors[2] = wDarks[2];
|
||||
(*dev->fnDACDark)( dev,dev->shade.pCcdDac,
|
||||
_CHANNEL_RED, wDarks[0] );
|
||||
(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
|
||||
_CHANNEL_GREEN, wDarks[1] );
|
||||
(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
|
||||
_CHANNEL_BLUE, wDarks[2] );
|
||||
}
|
||||
} else {
|
||||
wDarks[1] = u12shading_SumDarks(dev, dev->bufs.b1.pShadingRam +
|
||||
dev->regs.RD_Pixels );
|
||||
if(!wDarks[1] ) {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
} else {
|
||||
dev->shade.DarkOffset.wColors[1] = wDarks[1];
|
||||
(*dev->fnDACDark)( dev, dev->shade.pCcdDac,
|
||||
_CHANNEL_GREEN, wDarks[1] );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* CalculateDarkDependOnCCD() */
|
||||
if ( dev->DataInf.wPhyDataType > COLOR_256GRAY ) {
|
||||
(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_RED );
|
||||
(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN );
|
||||
(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_BLUE );
|
||||
} else {
|
||||
(*dev->fnDarkOffset)( dev, dev->shade.pCcdDac, _CHANNEL_GREEN );
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/** here we download the current mapping table
|
||||
*/
|
||||
static void u12shading_DownloadMapTable( U12_Device *dev, SANE_Byte *buf )
|
||||
{
|
||||
SANE_Byte addr, regs[6];
|
||||
int i;
|
||||
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL,
|
||||
(SANE_Byte)((dev->regs.RD_ScanControl & 0xfc) | _SCAN_BYTEMODE));
|
||||
|
||||
/* prepare register settings... */
|
||||
regs[0] = REG_MODECONTROL;
|
||||
regs[1] = _ModeMappingMem;
|
||||
regs[2] = REG_MEMORYLO;
|
||||
regs[3] = 0;
|
||||
regs[4] = REG_MEMORYHI;
|
||||
|
||||
for( i = 3, addr = _MAP_ADDR_RED; i--; addr += _MAP_ADDR_SIZE ) {
|
||||
|
||||
regs[5] = addr;
|
||||
u12io_DataToRegs( dev, regs, 3 );
|
||||
|
||||
u12io_MoveDataToScanner( dev, buf, 4096 );
|
||||
buf += 4096;
|
||||
}
|
||||
|
||||
u12io_DataToRegister( dev, REG_SCANCONTROL, dev->regs.RD_ScanControl );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static SANE_Status u12shading_DoCalibration( U12_Device *dev )
|
||||
{
|
||||
u_long i, tmp;
|
||||
SANE_Byte bScanControl, rb[20];
|
||||
SANE_Status res;
|
||||
int c;
|
||||
|
||||
DBG( _DBG_INFO, "u12shading_DoCalibration()\n" );
|
||||
|
||||
/** before getting the shading data, (re)init the ASIC
|
||||
*/
|
||||
u12hw_InitAsic( dev, SANE_TRUE );
|
||||
|
||||
dev->shade.DarkOffset.Colors.Red = 0;
|
||||
dev->shade.DarkOffset.Colors.Green = 0;
|
||||
dev->shade.DarkOffset.Colors.Blue = 0;
|
||||
|
||||
c = 0;
|
||||
_SET_REG( rb, c, REG_RESETMTSC, 0 );
|
||||
_SET_REG( rb, c, REG_MODELCONTROL, dev->regs.RD_ModelControl);
|
||||
_SET_REG( rb, c, REG_MOTORDRVTYPE, dev->regs.RD_MotorDriverType );
|
||||
_SET_REG( rb, c, REG_SCANCONTROL1, (_SCANSTOPONBUFFULL| _MFRC_BY_XSTEP));
|
||||
|
||||
u12io_DataToRegs( dev, rb, c );
|
||||
|
||||
res = u12motor_GotoShadingPosition( dev );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
bScanControl = dev->regs.RD_ScanControl;
|
||||
|
||||
/* SetShadingMapForGainDark */
|
||||
memset( dev->bufs.b2.pSumBuf, 0xff, (5400 * 3 * 2));
|
||||
u12shading_DownloadShadingTable( dev, dev->bufs.b2.pSumBuf, (5400*3*2));
|
||||
|
||||
for( i = 0, tmp = 0; i < 1024; tmp += 0x01010101, i += 4 ) {
|
||||
dev->bufs.b1.Buf.pdw[i] =
|
||||
dev->bufs.b1.Buf.pdw[i+1] =
|
||||
dev->bufs.b1.Buf.pdw[i+2] =
|
||||
dev->bufs.b1.Buf.pdw[i+3] = tmp;
|
||||
}
|
||||
|
||||
memcpy( dev->bufs.b1.pShadingMap + 4096, dev->bufs.b1.pShadingMap, 4096 );
|
||||
memcpy( dev->bufs.b1.pShadingMap + 8192, dev->bufs.b1.pShadingMap, 4096 );
|
||||
u12shading_DownloadMapTable( dev, dev->bufs.b1.pShadingMap );
|
||||
|
||||
DBG( _DBG_INFO, "* wExposure = %u\n", dev->shade.wExposure);
|
||||
DBG( _DBG_INFO, "* wXStep = %u\n", dev->shade.wXStep);
|
||||
|
||||
dev->regs.RD_LineControl = (_LOBYTE(dev->shade.wExposure));
|
||||
dev->regs.RD_ExtLineControl = (_HIBYTE(dev->shade.wExposure));
|
||||
u12io_DataToRegister( dev, REG_EXTENDEDLINECONTROL,
|
||||
dev->regs.RD_ExtLineControl );
|
||||
u12io_DataToRegister( dev, REG_LINECONTROL, dev->regs.RD_LineControl );
|
||||
|
||||
res = u12shading_AdjustRGBGain( dev );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
res = u12shadingAdjustDark( dev );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
res = u12shadingAdjustShadingWaveform( dev );
|
||||
if( SANE_STATUS_GOOD != res )
|
||||
return res;
|
||||
|
||||
dev->regs.RD_ScanControl = bScanControl;
|
||||
|
||||
/* here we have to download the table in any case...*/
|
||||
{
|
||||
/* FIXME... */
|
||||
#if 0
|
||||
u12shading_DownloadMapTable( dev, (SANE_Byte *)dev->gamma_table );
|
||||
#else
|
||||
SANE_Byte tb[4096*3];
|
||||
int i;
|
||||
|
||||
for( i = 0; i < 4096; i++ ) {
|
||||
tb[i] = (SANE_Byte)(i >> 4);
|
||||
tb[i+4096] = (SANE_Byte)(i >> 4);
|
||||
tb[i+8192] = (SANE_Byte)(i >> 4);
|
||||
}
|
||||
|
||||
u12shading_DownloadMapTable( dev, tb );
|
||||
#endif
|
||||
}
|
||||
|
||||
u12motor_BackToHomeSensor( dev );
|
||||
DBG( _DBG_INFO, "u12shading_DoCalibration() - done.\n" );
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/* END U12-SHADING ..........................................................*/
|
|
@ -0,0 +1,439 @@
|
|||
/* @file u12-pp_tpa.c
|
||||
* @brief Here we find some adjustments according to the scan source.
|
||||
*
|
||||
* based on sources acquired from Plustek Inc.
|
||||
* Copyright (C) 1998 Plustek Inc.
|
||||
* Copyright (C) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
|
||||
/** this function does some reshading, when scanning negatives on an ASIC 98003
|
||||
* based scanner
|
||||
*/
|
||||
static void u12tpa_Reshading( U12_Device *dev )
|
||||
{
|
||||
SANE_Byte bHi[3], bHiLeft[3], bHiRight[3];
|
||||
u_long i, dwR, dwG, dwB, dwSum;
|
||||
u_long dwIndex, dwIndexRight, dwIndexLeft;
|
||||
DataPointer RedPtr, GreenPtr, BluePtr;
|
||||
TimerDef timer;
|
||||
|
||||
DBG( _DBG_INFO, "u12tpa_Reshading()\n" );
|
||||
|
||||
dev->scan.negScan[1].exposureTime = 144;
|
||||
dev->scan.negScan[1].xStepTime = 18;
|
||||
dev->scan.negScan[2].exposureTime = 144;
|
||||
dev->scan.negScan[2].xStepTime = 36;
|
||||
dev->scan.negScan[3].exposureTime = 144;
|
||||
dev->scan.negScan[3].xStepTime = 72;
|
||||
dev->scan.negScan[4].exposureTime = 144;
|
||||
dev->scan.negScan[4].xStepTime = 144;
|
||||
|
||||
dev->shade.wExposure = dev->scan.negScan[dev->scan.dpiIdx].exposureTime;
|
||||
dev->shade.wXStep = dev->scan.negScan[dev->scan.dpiIdx].xStepTime;
|
||||
|
||||
u12io_StartTimer( &timer, _SECOND );
|
||||
|
||||
u12io_ResetFifoLen();
|
||||
while(!(u12io_GetScanState( dev ) & _SCANSTATE_STOP) &&
|
||||
(!u12io_CheckTimer(&timer)));
|
||||
u12io_DataToRegister( dev, REG_XSTEPTIME,
|
||||
(SANE_Byte)(dev->regs.RD_LineControl >> 4));
|
||||
_DODELAY( 12 );
|
||||
u12motor_PositionYProc( dev, _NEG_SHADING_OFFS );
|
||||
|
||||
u12io_DataToRegister( dev, REG_XSTEPTIME, dev->regs.RD_XStepTime );
|
||||
|
||||
dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
|
||||
u12hw_SelectLampSource( dev );
|
||||
|
||||
u12io_DataToRegister( dev, REG_LINECONTROL, _LOBYTE(dev->shade.wExposure));
|
||||
u12io_DataToRegister( dev, REG_XSTEPTIME, _LOBYTE(dev->shade.wXStep));
|
||||
|
||||
dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure);
|
||||
dev->regs.RD_XStepTime = (SANE_Byte)(dev->shade.wExposure);
|
||||
dev->regs.RD_ModeControl = _ModeScan;
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
|
||||
dev->regs.RD_Origin = (u_short)dev->scan.negBegin;
|
||||
dev->regs.RD_Pixels = _NEG_PAGEWIDTH600;
|
||||
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
|
||||
/* put 9 scan states to make sure there are 8 lines available at least */
|
||||
for( i = 0; i <= 12; i++)
|
||||
dev->a_nbNewAdrPointer[i] = 0x8f;
|
||||
|
||||
u12io_PutOnAllRegisters( dev );
|
||||
_DODELAY( 70 );
|
||||
|
||||
/* prepare the buffers... */
|
||||
memset( dev->bufs.TpaBuf.pb, 0, _SIZE_TPA_DATA_BUF );
|
||||
|
||||
RedPtr.pb = dev->bufs.b1.pShadingMap;
|
||||
GreenPtr.pb = RedPtr.pb + _NEG_PAGEWIDTH600;
|
||||
BluePtr.pb = GreenPtr.pb + _NEG_PAGEWIDTH600;
|
||||
|
||||
for( dwSum = 8; dwSum--; ) {
|
||||
|
||||
u12io_ReadOneShadingLine( dev, dev->bufs.b1.pShadingMap, _NEG_PAGEWIDTH600 );
|
||||
|
||||
for( i = 0; i < _NEG_PAGEWIDTH600; i++) {
|
||||
|
||||
dev->bufs.TpaBuf.pusrgb[i].Red += RedPtr.pb[i];
|
||||
dev->bufs.TpaBuf.pusrgb[i].Green += GreenPtr.pb[i];
|
||||
dev->bufs.TpaBuf.pusrgb[i].Blue += BluePtr.pb[i];
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < (_NEG_PAGEWIDTH600 * 3UL); i++ )
|
||||
dev->bufs.TpaBuf.pb[i] = dev->bufs.TpaBuf.pw[i] >> 3;
|
||||
|
||||
RedPtr.pb = dev->bufs.TpaBuf.pb;
|
||||
|
||||
/* Convert RGB to gray scale (Brightness), and average 16 pixels */
|
||||
for( bHiRight[1] = 0, i = dwIndexRight = 0;
|
||||
i < _NEG_PAGEWIDTH600 / 2; i += 16 ) {
|
||||
bHiRight [0] =
|
||||
(SANE_Byte)(((((u_long) RedPtr.pbrgb [i].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL +
|
||||
(((u_long) RedPtr.pbrgb[i].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL +
|
||||
(((u_long) RedPtr.pbrgb[i].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL);
|
||||
|
||||
if( bHiRight[1] < bHiRight[0] ) {
|
||||
bHiRight[1] = bHiRight[0];
|
||||
dwIndexRight = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert RGB to gray scale (Brightness), and average 16 pixels */
|
||||
for( bHiLeft[1] = 0, i = dwIndexLeft = _NEG_PAGEWIDTH / 2;
|
||||
i < _NEG_PAGEWIDTH600; i += 16 ) {
|
||||
bHiLeft [0] =
|
||||
(SANE_Byte)(((((u_long) RedPtr.pbrgb[i].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Red +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL +
|
||||
(((u_long) RedPtr.pbrgb[i].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Green +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL +
|
||||
(((u_long) RedPtr.pbrgb[i].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 1].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 2].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 3].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 4].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 5].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 6].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 7].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 8].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 9].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 10].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 11].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 12].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 13].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 14].Blue +
|
||||
(u_long) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL);
|
||||
|
||||
if( bHiLeft[1] < bHiLeft[0] ) {
|
||||
bHiLeft[1] = bHiLeft[0];
|
||||
dwIndexLeft = i;
|
||||
}
|
||||
}
|
||||
|
||||
if((bHiLeft[1] < 200) && (bHiRight[1] < 200)) {
|
||||
|
||||
if( bHiLeft[1] < bHiRight[1] )
|
||||
dwIndex = dwIndexRight;
|
||||
else
|
||||
dwIndex = dwIndexLeft;
|
||||
} else {
|
||||
if( bHiLeft[1] > 200 )
|
||||
dwIndex = dwIndexRight;
|
||||
else
|
||||
dwIndex = dwIndexLeft;
|
||||
}
|
||||
|
||||
/* Get the hilight */
|
||||
RedPtr.pusrgb = dev->bufs.b2.pSumRGB + dwIndex +
|
||||
dev->regs.RD_Origin + _SHADING_BEGINX;
|
||||
|
||||
for( dwR = dwG = dwB = 0, i = 16; i--; RedPtr.pusrgb++ ) {
|
||||
dwR += RedPtr.pusrgb->Red;
|
||||
dwG += RedPtr.pusrgb->Green;
|
||||
dwB += RedPtr.pusrgb->Blue;
|
||||
}
|
||||
|
||||
dwR >>= 8;
|
||||
dwG >>= 8;
|
||||
dwB >>= 8;
|
||||
|
||||
if( dwR > dwG && dwR > dwB )
|
||||
dev->shade.bGainHigh = (SANE_Byte)dwR; /* >> 4 for average, >> 4 to 8-bit */
|
||||
else {
|
||||
if( dwG > dwR && dwG > dwB )
|
||||
dev->shade.bGainHigh = (SANE_Byte)dwG;
|
||||
else
|
||||
dev->shade.bGainHigh = (SANE_Byte)dwB;
|
||||
}
|
||||
|
||||
dev->shade.bGainHigh = (SANE_Byte)(dev->shade.bGainHigh - 0x18);
|
||||
dev->shade.bGainLow = (SANE_Byte)(dev->shade.bGainHigh - 0x10);
|
||||
|
||||
/* Reshading to get the new gain */
|
||||
dev->shade.Hilight.Colors.Red = 0;
|
||||
dev->shade.Hilight.Colors.Green = 0;
|
||||
dev->shade.Hilight.Colors.Blue = 0;
|
||||
dev->shade.Gain.Colors.Red++;
|
||||
dev->shade.Gain.Colors.Green++;
|
||||
dev->shade.Gain.Colors.Blue++;
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
|
||||
RedPtr.pb = dev->bufs.b1.pShadingMap + dwIndex;
|
||||
GreenPtr.pb = RedPtr.pb + _NEG_PAGEWIDTH600;
|
||||
BluePtr.pb = GreenPtr.pb + _NEG_PAGEWIDTH600;
|
||||
|
||||
for( i = 16; i-- && !dev->shade.fStop;) {
|
||||
|
||||
dev->shade.fStop = SANE_TRUE;
|
||||
|
||||
u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
|
||||
|
||||
u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle );
|
||||
|
||||
dev->regs.RD_ScanControl = _SCAN_BYTEMODE;
|
||||
u12hw_SelectLampSource( dev );
|
||||
|
||||
dev->regs.RD_ModeControl = _ModeScan;
|
||||
dev->regs.RD_StepControl = _MOTOR0_SCANSTATE;
|
||||
dev->regs.RD_Motor0Control = _FORWARD_MOTOR;
|
||||
|
||||
memset( dev->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
|
||||
dev->a_nbNewAdrPointer[1] = 0x77;
|
||||
|
||||
u12io_PutOnAllRegisters( dev );
|
||||
_DODELAY( 50 );
|
||||
|
||||
if(u12io_ReadOneShadingLine( dev,
|
||||
dev->bufs.b1.pShadingMap,_NEG_PAGEWIDTH600)) {
|
||||
|
||||
bHi[0] = u12shading_SumGains( RedPtr.pb, 32 );
|
||||
bHi[1] = u12shading_SumGains( GreenPtr.pb, 32 );
|
||||
bHi[2] = u12shading_SumGains( BluePtr.pb, 32 );
|
||||
|
||||
if( !bHi[0] || !bHi[1] || !bHi[2]) {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
} else {
|
||||
|
||||
u12shading_AdjustGain( dev, _CHANNEL_RED, bHi[0] );
|
||||
u12shading_AdjustGain( dev, _CHANNEL_GREEN, bHi[1] );
|
||||
u12shading_AdjustGain( dev, _CHANNEL_BLUE, bHi[2] );
|
||||
}
|
||||
} else {
|
||||
dev->shade.fStop = SANE_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain );
|
||||
|
||||
/* Set RGB Gain */
|
||||
if( dwR && dwG && dwB ) {
|
||||
|
||||
if(dev->CCDID == _CCD_3797 || dev->DACType == _DA_ESIC ) {
|
||||
dev->shade.pCcdDac->GainResize.Colors.Red =
|
||||
(u_short)((u_long)bHi[0] * 100UL / dwR);
|
||||
dev->shade.pCcdDac->GainResize.Colors.Green =
|
||||
(u_short)((u_long)bHi[1] * 100UL / dwG);
|
||||
dev->shade.pCcdDac->GainResize.Colors.Blue =
|
||||
(u_short)((u_long)bHi[2] * 100UL / dwB);
|
||||
} else {
|
||||
dev->shade.pCcdDac->GainResize.Colors.Red =
|
||||
(u_short)((u_long)bHi[0] * 90UL / dwR);
|
||||
dev->shade.pCcdDac->GainResize.Colors.Green =
|
||||
(u_short)((u_long)bHi[1] * 77UL / dwG);
|
||||
dev->shade.pCcdDac->GainResize.Colors.Blue =
|
||||
(u_short)((u_long)bHi[2] * 73UL / dwB);
|
||||
}
|
||||
|
||||
dev->shade.DarkOffset.Colors.Red +=
|
||||
(u_short)((dwR > bHi[0]) ? dwR - bHi[0] : 0);
|
||||
dev->shade.DarkOffset.Colors.Green +=
|
||||
(u_short)((dwG > bHi[1]) ? dwG - bHi[1] : 0);
|
||||
dev->shade.DarkOffset.Colors.Blue +=
|
||||
(u_short)((dwB > bHi[2]) ? dwB - bHi[2] : 0);
|
||||
|
||||
if( dev->DACType != _DA_ESIC && dev->CCDID != _CCD_3799 ) {
|
||||
dev->shade.DarkOffset.Colors.Red =
|
||||
(u_short)(dev->shade.DarkOffset.Colors.Red *
|
||||
dev->shade.pCcdDac->GainResize.Colors.Red / 100UL);
|
||||
dev->shade.DarkOffset.Colors.Green =
|
||||
(u_short)(dev->shade.DarkOffset.Colors.Green *
|
||||
dev->shade.pCcdDac->GainResize.Colors.Green / 100UL);
|
||||
dev->shade.DarkOffset.Colors.Blue =
|
||||
(u_short)(dev->shade.DarkOffset.Colors.Blue *
|
||||
dev->shade.pCcdDac->GainResize.Colors.Blue / 100UL);
|
||||
}
|
||||
}
|
||||
|
||||
/* AdjustDark () */
|
||||
dev->regs.RD_Origin = _SHADING_BEGINX;
|
||||
dev->regs.RD_Pixels = 5400;
|
||||
}
|
||||
|
||||
/** perform some adjustments according to the source (normal, transparency etc)
|
||||
*/
|
||||
static void u12tpa_FindCenterPointer( U12_Device *dev )
|
||||
{
|
||||
u_long i;
|
||||
u_long width;
|
||||
u_long left;
|
||||
u_long right;
|
||||
RGBUShortDef *pwSum = dev->bufs.b2.pSumRGB;
|
||||
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Negative )
|
||||
width = _NEG_PAGEWIDTH600;
|
||||
else
|
||||
width = _NEG_PAGEWIDTH600 - 94;
|
||||
|
||||
/* 2.54 cm tolerance */
|
||||
left = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2 - 600;
|
||||
right = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2 +
|
||||
_NEG_PAGEWIDTH600 + 600;
|
||||
|
||||
for( i = 5400UL - left, pwSum = dev->bufs.b2.pSumRGB; i--; left++)
|
||||
if( pwSum[left].Red > _NEG_EDGE_VALUE &&
|
||||
pwSum[left].Green > _NEG_EDGE_VALUE &&
|
||||
pwSum[left].Blue > _NEG_EDGE_VALUE)
|
||||
break;
|
||||
|
||||
for( i = 5400UL - left, pwSum = dev->bufs.b2.pSumRGB; i--; right--)
|
||||
if( pwSum[right].Red > _NEG_EDGE_VALUE &&
|
||||
pwSum[right].Green > _NEG_EDGE_VALUE &&
|
||||
pwSum[right].Blue > _NEG_EDGE_VALUE)
|
||||
break;
|
||||
|
||||
if((right <= left) || ((right - left) < width)) {
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Negative )
|
||||
dev->scan.negBegin = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2;
|
||||
else
|
||||
dev->scan.posBegin = _DATA_ORIGIN_X + _POS_ORG_OFFSETX * 2;
|
||||
} else {
|
||||
if( dev->DataInf.dwScanFlag & _SCANDEF_Negative )
|
||||
dev->scan.negBegin = (right + left) / 2UL - _NEG_PAGEWIDTH;
|
||||
else
|
||||
dev->scan.posBegin = (right + left) / 2UL - _POS_PAGEWIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* END U12_TPA.C ............................................................*/
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,67 @@
|
|||
# U12-SANE Backend configuration file
|
||||
#
|
||||
|
||||
# each device needs at least two lines:
|
||||
# - [usb] vendor-ID and product-ID
|
||||
# - device devicename
|
||||
# i.e. for Plustek (0x07B3) U1212 (0x0001)
|
||||
# [usb] 0x07B3 0x0001
|
||||
# device /dev/usbscanner
|
||||
# or
|
||||
# device libusb:bbb:ddd
|
||||
# where bbb is the busnumber and ddd the device number
|
||||
# make sure that your user has access to /proc/bus/usb/bbb/ddd
|
||||
#
|
||||
# additionally you can specify some options
|
||||
# warmup, lOffOnEnd, lampOff
|
||||
#
|
||||
# For autodetection use
|
||||
# [usb]
|
||||
# device /dev/usbscanner
|
||||
#
|
||||
# or simply
|
||||
# [usb]
|
||||
#
|
||||
# or if you want a specific device but you have no idea about the
|
||||
# device node or you use libusb, simply set vendor- and product-ID
|
||||
# [usb] 0x07B3 0x0001
|
||||
# device auto
|
||||
#
|
||||
# NOTE: autodetection is safe, as it uses the info it got
|
||||
# from the USB subsystem. If you're not using the
|
||||
# autodetection, you MUST have attached that device
|
||||
# at your USB-port, that you have specified...
|
||||
#
|
||||
|
||||
[usb]
|
||||
|
||||
#
|
||||
# options for the previous USB entry
|
||||
#
|
||||
# switch lamp off after xxx secs, 0 disables the feature
|
||||
option lampOff 300
|
||||
|
||||
# warmup period in seconds, 0 means no warmup
|
||||
option warmup 15
|
||||
|
||||
# 0 means leave lamp-status untouched, not 0 means switch off
|
||||
# on sane_close
|
||||
option lOffOnEnd 1
|
||||
|
||||
#
|
||||
# for adjusting the default gamma values
|
||||
#
|
||||
option redGamma 1.0
|
||||
option greenGamma 1.0
|
||||
option blueGamma 1.0
|
||||
option grayGamma 1.0
|
||||
|
||||
#
|
||||
# and of course the device-name
|
||||
#
|
||||
device auto
|
||||
|
||||
#
|
||||
# to define a new device, start with a new section:
|
||||
# [usb]
|
||||
#
|
|
@ -0,0 +1,332 @@
|
|||
/** @file u12.h
|
||||
* @brief Definitions for the backend.
|
||||
*
|
||||
* Copyright (c) 2003 Gerhard Jaeger <gerhard@gjaeger.de>
|
||||
*
|
||||
* History:
|
||||
* - 0.01 - initial version
|
||||
* .
|
||||
* <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>
|
||||
*/
|
||||
#ifndef __U12_H__
|
||||
#define __U12_H__
|
||||
|
||||
#ifndef SANE_OPTION
|
||||
/* for compatibility with older versions */
|
||||
typedef union
|
||||
{
|
||||
SANE_Word w;
|
||||
SANE_Word *wa; /* word array */
|
||||
SANE_String s;
|
||||
} Option_Value;
|
||||
#endif
|
||||
|
||||
/************************ some definitions ***********************************/
|
||||
|
||||
#define U12_CONFIG_FILE "u12.conf"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#define _MM_PER_INCH 25.4
|
||||
#define _MEASURE_BASE 300UL
|
||||
#define _DEF_DPI 50
|
||||
|
||||
/** the default image
|
||||
*/
|
||||
#define _DEFAULT_TLX 0
|
||||
#define _DEFAULT_TLY 0
|
||||
#define _DEFAULT_BRX 126
|
||||
#define _DEFAULT_BRY 76
|
||||
|
||||
#define _DEFAULT_TP_TLX 3.5
|
||||
#define _DEFAULT_TP_TLY 10.5
|
||||
#define _DEFAULT_TP_BRX 38.5
|
||||
#define _DEFAULT_TP_BRY 33.5
|
||||
|
||||
#define _DEFAULT_NEG_TLX 1.5
|
||||
#define _DEFAULT_NEG_TLY 1.5
|
||||
#define _DEFAULT_NEG_BRX 37.5
|
||||
#define _DEFAULT_NEG_BRY 25.5
|
||||
|
||||
/** image sizes for normal, transparent and negative modes
|
||||
*/
|
||||
#define _TPAPageWidth 500U
|
||||
#define _TPAPageHeight 510U
|
||||
#define _TPAMinDpi 150
|
||||
#define _TPAModeSupportMin COLOR_TRUE24
|
||||
|
||||
#define _NegativePageWidth 460UL
|
||||
#define _NegativePageHeight 350UL
|
||||
|
||||
#define _TP_X ((double)_TPAPageWidth/300.0 * _MM_PER_INCH)
|
||||
#define _TP_Y ((double)_TPAPageHeight/300.0 * _MM_PER_INCH)
|
||||
#define _NEG_X ((double)_NegativePageWidth/300.0 * _MM_PER_INCH)
|
||||
#define _NEG_Y ((double)_NegativePageHeight/300.0 * _MM_PER_INCH)
|
||||
|
||||
/** scan modes
|
||||
*/
|
||||
#define COLOR_BW 0
|
||||
#define COLOR_256GRAY 1
|
||||
#define COLOR_TRUE24 2
|
||||
#define COLOR_TRUE42 3
|
||||
|
||||
#define _VAR_NOT_USED(x) ((x)=(x))
|
||||
|
||||
|
||||
/** usb id buffer
|
||||
*/
|
||||
#define _MAX_ID_LEN 20
|
||||
|
||||
/** Scanmodes
|
||||
*/
|
||||
#define _ScanMode_Color 0
|
||||
#define _ScanMode_AverageOut 1 /* CCD averaged 2 pixels value for output*/
|
||||
#define _ScanMode_Mono 2 /* not color mode */
|
||||
|
||||
/** Scansource + additional flags
|
||||
*/
|
||||
#define _SCANDEF_PREVIEW 0x00000001
|
||||
#define _SCANDEF_Transparency 0x00000100
|
||||
#define _SCANDEF_Negative 0x00000200
|
||||
#define _SCANDEF_TPA (_SCANDEF_Transparency | _SCANDEF_Negative)
|
||||
#define _SCANDEF_SCANNING 0x8000000
|
||||
|
||||
/** for Gamma tables
|
||||
*/
|
||||
#define _MAP_RED 0
|
||||
#define _MAP_GREEN 1
|
||||
#define _MAP_BLUE 2
|
||||
#define _MAP_MASTER 3
|
||||
|
||||
/** the ASIC modes */
|
||||
#define _PP_MODE_SPP 0
|
||||
#define _PP_MODE_EPP 1
|
||||
|
||||
/************************ some structures ************************************/
|
||||
|
||||
enum {
|
||||
OPT_NUM_OPTS = 0,
|
||||
OPT_MODE_GROUP,
|
||||
#ifdef ALL_MODES
|
||||
OPT_MODE,
|
||||
OPT_EXT_MODE,
|
||||
#endif
|
||||
OPT_RESOLUTION,
|
||||
OPT_PREVIEW,
|
||||
OPT_GEOMETRY_GROUP,
|
||||
OPT_TL_X,
|
||||
OPT_TL_Y,
|
||||
OPT_BR_X,
|
||||
OPT_BR_Y,
|
||||
OPT_ENHANCEMENT_GROUP,
|
||||
OPT_BRIGHTNESS,
|
||||
OPT_CONTRAST,
|
||||
OPT_CUSTOM_GAMMA,
|
||||
OPT_GAMMA_VECTOR,
|
||||
OPT_GAMMA_VECTOR_R,
|
||||
OPT_GAMMA_VECTOR_G,
|
||||
OPT_GAMMA_VECTOR_B,
|
||||
NUM_OPTIONS
|
||||
};
|
||||
|
||||
/** for adjusting the scanner settings
|
||||
*/
|
||||
typedef struct {
|
||||
int lampOff;
|
||||
int lampOffOnEnd;
|
||||
int warmup;
|
||||
|
||||
/* for adjusting the default gamma settings */
|
||||
double rgamma;
|
||||
double ggamma;
|
||||
double bgamma;
|
||||
double graygamma;
|
||||
|
||||
/* for adjusting scan-area */
|
||||
long upNormal;
|
||||
long upPositive;
|
||||
long upNegative;
|
||||
long leftNormal;
|
||||
|
||||
} AdjDef, *pAdjDef;
|
||||
|
||||
/** for holding basic capabilities
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned short scanAreaX;
|
||||
unsigned short scanAreaY;
|
||||
unsigned long flag;
|
||||
#if 0
|
||||
RANGE rDataType; /* available scan modes */
|
||||
unsigned short wMaxExtentX; /* scanarea width */
|
||||
unsigned short wMaxExtentY; /* scanarea height */
|
||||
#endif
|
||||
} ScannerCaps, *pScannerCaps;
|
||||
|
||||
|
||||
/** for defining the scanmodes
|
||||
*/
|
||||
typedef const struct mode_param
|
||||
{
|
||||
int color;
|
||||
int depth;
|
||||
int scanmode;
|
||||
} ModeParam, *pModeParam;
|
||||
|
||||
/** Here we hold all device specific data
|
||||
*/
|
||||
typedef struct u12d
|
||||
{
|
||||
SANE_Bool initialized; /* device already initialized? */
|
||||
struct u12d *next; /* pointer to next dev in list */
|
||||
int fd; /* device handle */
|
||||
int mode;
|
||||
char *name; /* (to avoid compiler warnings!)*/
|
||||
SANE_Device sane; /* info struct */
|
||||
|
||||
/* scan-area settings */
|
||||
SANE_Int max_x; /* max XY-extension of the scan-*/
|
||||
SANE_Int max_y; /* area */
|
||||
SANE_Range x_range; /* x-range of the scan-area */
|
||||
SANE_Range y_range; /* y-range of the scan-area */
|
||||
|
||||
/* resolution settings */
|
||||
SANE_Int dpi_max_x; /* */
|
||||
SANE_Int dpi_max_y; /* */
|
||||
SANE_Range dpi_range; /* resolution range */
|
||||
|
||||
SANE_Int *res_list; /* to hold the available phys. */
|
||||
SANE_Int res_list_size; /* resolution values */
|
||||
ScannerCaps caps; /* caps reported by the driver */
|
||||
AdjDef adj; /* for driver adjustment */
|
||||
|
||||
char usbId[_MAX_ID_LEN];/* to keep Vendor and product */
|
||||
/* ID string (from conf) file */
|
||||
/* our gamma tables */
|
||||
SANE_Word gamma_table[4][4096];
|
||||
SANE_Range gamma_range;
|
||||
int gamma_length;
|
||||
|
||||
/* the shading section */
|
||||
pFnDACOffs fnDarkOffset; /**< ... */
|
||||
ShadingDef shade; /**< shading parameters */
|
||||
|
||||
/* */
|
||||
SANE_Byte PCBID; /**< which version of the PCB */
|
||||
|
||||
/* motor control section */
|
||||
SANE_Byte MotorID; /**< the type of the motor drivers */
|
||||
SANE_Byte MotorPower; /**< how to drive the motor */
|
||||
SANE_Bool f2003;
|
||||
SANE_Byte XStepMono;
|
||||
SANE_Byte XStepColor;
|
||||
SANE_Byte XStepBack;
|
||||
SANE_Bool f0_8_16;
|
||||
SANE_Byte a_nbNewAdrPointer[_SCANSTATE_BYTES];
|
||||
|
||||
/* CCD section */
|
||||
SANE_Byte CCDID; /**< what CCD do we have */
|
||||
RegDef *CCDRegs; /**< pointer to the register descr */
|
||||
u_short numCCDRegs; /**< number of values to write */
|
||||
|
||||
/* DAC section */
|
||||
SANE_Byte DACType; /**< what DAC do we have */
|
||||
RegDef *DACRegs; /**< pointer to DAC reg descr. */
|
||||
u_short numDACRegs; /**< number of values to write */
|
||||
pFnDACDark fnDACDark; /**< */
|
||||
RGBByteDef RegDACOffset;
|
||||
RGBByteDef RegDACGain;
|
||||
|
||||
ShadowRegs regs; /**< for holding ASIC register values */
|
||||
DataInfo DataInf; /**< all static info about the current scan */
|
||||
ScanInfo scan; /**< buffer and motor management during scan */
|
||||
BufferDef bufs;
|
||||
|
||||
u_long ModelOriginY;
|
||||
SANE_Byte ModelCtrl;
|
||||
|
||||
SANE_Bool Tpa; /**< do we have a TPA */
|
||||
SANE_Byte Buttons; /**< number of buttons */
|
||||
|
||||
/* lamp control section */
|
||||
SANE_Bool warmupNeeded;
|
||||
SANE_Byte lastLampStatus; /**< for keeping the lamp status */
|
||||
|
||||
#ifdef HAVE_SETITIMER
|
||||
struct itimerval saveSettings; /**< for lamp timer */
|
||||
#endif
|
||||
} U12_Device;
|
||||
|
||||
typedef struct u12s
|
||||
{
|
||||
struct u12s *next;
|
||||
pid_t reader_pid; /* process id of reader */
|
||||
SANE_Status exit_code; /* status of the reader process */
|
||||
int r_pipe; /* pipe to reader process */
|
||||
int w_pipe; /* pipe from reader process */
|
||||
unsigned long bytes_read; /* number of bytes currently read*/
|
||||
U12_Device *hw; /* pointer to current device */
|
||||
Option_Value val[NUM_OPTIONS];
|
||||
SANE_Byte *buf; /* the image buffer */
|
||||
SANE_Bool scanning; /* TRUE during scan-process */
|
||||
SANE_Parameters params; /* for keeping the parameter */
|
||||
|
||||
SANE_Option_Descriptor opt[NUM_OPTIONS];
|
||||
|
||||
} U12_Scanner;
|
||||
|
||||
/** for collecting configuration info...
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
char devName[PATH_MAX];
|
||||
char usbId[_MAX_ID_LEN];
|
||||
|
||||
/* contains the stuff to adjust... */
|
||||
AdjDef adj;
|
||||
|
||||
} CnfDef, *pCnfDef;
|
||||
|
||||
#endif /* guard __U12_H__ */
|
||||
|
||||
/* END U12.H ................................................................*/
|
|
@ -0,0 +1,45 @@
|
|||
;
|
||||
; SANE Backend description file for U12 backend
|
||||
;
|
||||
|
||||
:backend "u12"
|
||||
:version "0.01"
|
||||
:manpage "sane-plustek"
|
||||
; backend's web page
|
||||
:url "http://www.gjaeger.de/scanner/u12.html"
|
||||
|
||||
:devicetype :scanner
|
||||
|
||||
;* Plustek **********************************************************************************
|
||||
|
||||
:mfg "Plustek"
|
||||
:url "http://www.plustek.de/"
|
||||
:url "http://www.plustek.com/"
|
||||
|
||||
;name models for above-specified mfg.
|
||||
:model "OpticPro U12"
|
||||
:interface "USB"
|
||||
:status :minimal
|
||||
:comment "NOTE: Only devices with product ID 0x0001 are supported!"
|
||||
|
||||
:model "OpticPro UT12"
|
||||
:interface "USB"
|
||||
:status :untested
|
||||
:comment "NOTE: Only devices with product ID 0x0001 are supported!"
|
||||
|
||||
:model "OpticPro 1212U"
|
||||
:interface "USB"
|
||||
:status :untested
|
||||
|
||||
;* Genius/KYE *******************************************************************************************
|
||||
|
||||
:mfg "Genius"
|
||||
:url "http://www.geniusnet.com.tw/"
|
||||
|
||||
:model "ColorPage HR6 V1"
|
||||
:interface "USB"
|
||||
:status :untested
|
||||
|
||||
:model "ColorPage Vivid III V2 USB"
|
||||
:interface "USB"
|
||||
:status :untested
|
|
@ -0,0 +1,145 @@
|
|||
.TH sane-u12 5 "05 January 2004" "@PACKAGEVERSION@" "SANE Scanner Access Now Easy"
|
||||
.IX sane-u12
|
||||
.SH NAME
|
||||
sane-u12 \- SANE backend for Plustek USB flatbed scanners,
|
||||
based on older parport designs
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B sane-u12
|
||||
library implements a SANE (Scanner Access Now Easy) backend that
|
||||
provides access to USB flatbed scanners based on ...
|
||||
|
||||
.SH "SUPPORTED DEVICES"
|
||||
The backend is able to support USB scanner based on...
|
||||
|
||||
If your Plustek scanner has another Product ID, then the device is
|
||||
.B NOT
|
||||
supported by this backend.
|
||||
.br
|
||||
|
||||
Vendor Plustek - ID: 0x07B3
|
||||
.br
|
||||
----------------------------------------------------------
|
||||
.br
|
||||
USB Model: Properties: Prod-ID
|
||||
.br
|
||||
----------------------------------------------------------
|
||||
.br
|
||||
OpticPro U12 600x1200dpi 42bit 512Kb 0x0001
|
||||
.br
|
||||
OpticPro U1212 600x1200dpi 42bit 512Kb 0x0001
|
||||
.br
|
||||
OpticPro UT12 600x1200dpi 42bit 512Kb 0x0001
|
||||
.PP
|
||||
|
||||
Vendor KYE/Genius - ID: 0x0458
|
||||
.br
|
||||
------------------------------------------------------------
|
||||
.br
|
||||
USB Model: Properties: Prod-ID
|
||||
.br
|
||||
------------------------------------------------------------
|
||||
.br
|
||||
ColorPage Vivid III V2 USB 600x1200dpi 42bit 512Kb 0x????
|
||||
.br
|
||||
ColorPage HR6 V1 600x1200dpi 42bit 512Kb 0x2004
|
||||
.PP
|
||||
|
||||
.SH "CONFIGURATION"
|
||||
To use your scanner with this backend, you need at least two
|
||||
entries in the configuration file
|
||||
.br
|
||||
.I @CONFIGDIR@/u12.conf
|
||||
.TP
|
||||
.I [usb] vendor-id product-id
|
||||
.TP
|
||||
.I device /dev/usbscanner
|
||||
.PP
|
||||
.I [usb]
|
||||
tells the backend, that the following devicename (here
|
||||
.I /dev/usbscanner
|
||||
) has to be interpreted as USB scanner device. If vendor- and
|
||||
product-id has not been specified, the backend tries to
|
||||
detect this by its own. If device ist set to
|
||||
.I auto
|
||||
then the next matching device is used.
|
||||
.PP
|
||||
.B
|
||||
The Options:
|
||||
.PP
|
||||
option warmup t
|
||||
.RS
|
||||
.I t
|
||||
specifies the warmup period in seconds
|
||||
.RE
|
||||
.PP
|
||||
option lampOff t
|
||||
.RS
|
||||
.I t
|
||||
is the time in seconds for switching off the lamps in
|
||||
standby mode
|
||||
.RE
|
||||
.PP
|
||||
option lOffonEnd b
|
||||
.RS
|
||||
.I b
|
||||
specifies the behaviour when closing the backend, 1 --> switch
|
||||
lamps off, 0 --> do not change lamp status
|
||||
.RE
|
||||
|
||||
.PP
|
||||
See the u12.conf file for examples.
|
||||
.PP
|
||||
.B Note:
|
||||
.br
|
||||
You have to make sure, that the USB subsystem is loaded
|
||||
correctly and you have access to the device-node. For
|
||||
more details see
|
||||
.B sane-usb (5)
|
||||
manpage. You might use
|
||||
.B sane-find-scanner
|
||||
to check that you have access to your device.
|
||||
.PP
|
||||
.B Note:
|
||||
.br
|
||||
If there's no configuration file, the backend defaults to
|
||||
.B device auto
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
.I @CONFIGDIR@/u12.conf
|
||||
The backend configuration file
|
||||
.TP
|
||||
.I @LIBDIR@/libsane-u12.a
|
||||
The static library implementing this backend.
|
||||
.TP
|
||||
.I @LIBDIR@/libsane-u12.so
|
||||
The shared library implementing this backend (present on systems that
|
||||
support dynamic loading).
|
||||
|
||||
.SH "CONTACT AND BUG-REPORTS"
|
||||
Please send any information and bug-reports to:
|
||||
.br
|
||||
.B SANE Mailing List
|
||||
.PP
|
||||
Additional info and hints can be obtained from our
|
||||
.br
|
||||
Mailing-List archive at:
|
||||
.br
|
||||
.B http://www.sane-project.org/mailing-lists.html
|
||||
.PP
|
||||
or directly from the projects' homepage at:
|
||||
.br
|
||||
.B http://www.gjaeger.de/scanner/u12.html
|
||||
.PP
|
||||
To obtain debug messages from the backend, please set the
|
||||
environment-variable
|
||||
.I SANE_DEBUG_U12
|
||||
before calling your favorite scan-frontend (i.e. xscanimage).
|
||||
.br
|
||||
.B i.e.: export SANE_DEBUG_U12=20 ; xscanimage
|
||||
.PP
|
||||
The value controls the verbosity of the backend.
|
||||
|
||||
.SH "KNOWN BUGS & RESTRICTIONS"
|
||||
* The driver is in alpha state, so please don't expect too much!!!
|
Ładowanie…
Reference in New Issue