initial checkin.

merge-requests/1/head
Gerhard Jaeger 2004-01-05 20:34:09 +00:00
rodzic d05c973c18
commit a20efe37fb
16 zmienionych plików z 9248 dodań i 0 usunięć

1115
backend/u12-ccd.c 100644

Plik diff jest za duży Load Diff

640
backend/u12-hw.c 100644
Wyświetl plik

@ -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 .............................................................*/

472
backend/u12-hwdef.h 100644
Wyświetl plik

@ -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 ..........................................................*/

606
backend/u12-if.c 100644
Wyświetl plik

@ -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 .............................................................*/

836
backend/u12-image.c 100644
Wyświetl plik

@ -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 ..........................................................*/

795
backend/u12-io.c 100644
Wyświetl plik

@ -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(&current_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, &current );
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 .............................................................*/

189
backend/u12-map.c 100644
Wyświetl plik

@ -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 ............................................................*/

515
backend/u12-motor.c 100644
Wyświetl plik

@ -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 ..........................................................*/

Wyświetl plik

@ -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 ........................................................*/

Wyświetl plik

@ -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 = &regs[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 ..........................................................*/

439
backend/u12-tpa.c 100644
Wyświetl plik

@ -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 ............................................................*/

1863
backend/u12.c 100644

Plik diff jest za duży Load Diff

67
backend/u12.conf 100644
Wyświetl plik

@ -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]
#

332
backend/u12.h 100644
Wyświetl plik

@ -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 ................................................................*/

Wyświetl plik

@ -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

145
doc/sane-u12.man 100644
Wyświetl plik

@ -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!!!