diff options
Diffstat (limited to 'backend/sm3600-gray.c')
-rw-r--r-- | backend/sm3600-gray.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/backend/sm3600-gray.c b/backend/sm3600-gray.c new file mode 100644 index 0000000..d9fda86 --- /dev/null +++ b/backend/sm3600-gray.c @@ -0,0 +1,389 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) Marian Eichholz 2001 + 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. +*/ + +/* ====================================================================== + +Userspace scan tool for the Microtek 3600 scanner + +grayscale scan routine + +(C) Marian Eichholz 2001 + +====================================================================== */ + +#include "sm3600-scantool.h" + +/* ********************************************************************** + +DoScanGray() + +********************************************************************** */ + +#define LINE_THRESHOLD 0x800 + +static unsigned char uchRegs075[]={ + /*R_SPOS*/ 0xFC, /*R_SPOSH*/ 0x00, /*0x03*/ 0x20, + /*R_SWID*/ 0xB0, /*R_SWIDH*/ 0x04, /*R_STPS*/ 0x06, + /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x3F, + /*R_LEN*/ 0x28, /*R_LENH*/ 0x07, /*0x0C*/ 0x6D, + /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, + /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x40, + /*0x13*/ 0x15, /*0x14*/ 0x80, /*0x15*/ 0x2A, + /*0x16*/ 0xC0, /*0x17*/ 0x40, /*0x18*/ 0xC0, + /*0x19*/ 0x40, /*0x1A*/ 0xFF, /*0x1B*/ 0x01, + /*0x1C*/ 0x88, /*0x1D*/ 0x40, /*0x1E*/ 0x4C, + /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, + /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, + /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, + /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, + /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, + /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, + /*R_CCAL3*/ 0x80, /*0x32*/ 0xC9, /*0x33*/ 0x20, + /*0x34*/ 0x83, /*0x35*/ 0x29, /*0x36*/ 0x00, + /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, + /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, + /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, + /*0x40*/ 0x01, /*0x41*/ 0x00, /*R_CSTAT*/ 0x00, + /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, + /*R_CTL*/ 0x39, /*0x47*/ 0xC0, /*0x48*/ 0x40, + /*0x49*/ 0x9E, /*0x4A*/ 0x8C }; + +static unsigned char uchRegs100[]={ + /*R_SPOS*/ 0xFC, /*R_SPOSH*/ 0x00, /*0x03*/ 0x20, + /*R_SWID*/ 0xB0, /*R_SWIDH*/ 0x04, /*R_STPS*/ 0x06, + /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x3F, + /*R_LEN*/ 0x34, /*R_LENH*/ 0x07, /*0x0C*/ 0x6D, + /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, + /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x42, + /*0x13*/ 0x15, /*0x14*/ 0x84, /*0x15*/ 0x2A, + /*0x16*/ 0xC2, /*0x17*/ 0x40, /*0x18*/ 0xC2, + /*0x19*/ 0x40, /*0x1A*/ 0xFF, /*0x1B*/ 0x01, + /*0x1C*/ 0x88, /*0x1D*/ 0x40, /*0x1E*/ 0x4C, + /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, + /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, + /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, + /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, + /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, + /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, + /*R_CCAL3*/ 0x80, /*0x32*/ 0xC9, /*0x33*/ 0x20, + /*0x34*/ 0x63, /*0x35*/ 0x29, /*0x36*/ 0x00, + /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, + /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, + /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, + /*0x40*/ 0x01, /*0x41*/ 0x00, /*R_CSTAT*/ 0x80, + /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, + /*R_CTL*/ 0x39, /*0x47*/ 0xC2, /*0x48*/ 0x40, + /*0x49*/ 0x9E, /*0x4A*/ 0x8C }; + +static unsigned char uchRegs200[]={ + /*R_SPOS*/ 0xFC, /*R_SPOSH*/ 0x00, /*0x03*/ 0x24, + /*R_SWID*/ 0xB0, /*R_SWIDH*/ 0x04, /*R_STPS*/ 0x06, + /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x3F, + /*R_LEN*/ 0x22, /*R_LENH*/ 0x07, /*0x0C*/ 0x6D, + /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, + /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x42, + /*0x13*/ 0x15, /*0x14*/ 0x42, /*0x15*/ 0x15, + /*0x16*/ 0x42, /*0x17*/ 0x15, /*0x18*/ 0x42, + /*0x19*/ 0x15, /*0x1A*/ 0x07, /*0x1B*/ 0x00, + /*0x1C*/ 0x08, /*0x1D*/ 0x12, /*0x1E*/ 0x4C, + /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, + /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, + /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, + /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, + /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, + /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, + /*R_CCAL3*/ 0x80, /*0x32*/ 0xC9, /*0x33*/ 0x20, + /*0x34*/ 0x43, /*0x35*/ 0x29, /*0x36*/ 0x00, + /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, + /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, + /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, + /*0x40*/ 0x01, /*0x41*/ 0x00, /*R_CSTAT*/ 0x80, + /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, + /*R_CTL*/ 0x39, /*0x47*/ 0x42, /*0x48*/ 0x15, + /*0x49*/ 0x9E, /*0x4A*/ 0x8C }; + +static unsigned char uchRegs300[]={ + /*R_SPOS*/ 0xFC, /*R_SPOSH*/ 0x00, /*0x03*/ 0x2A, + /*R_SWID*/ 0xB0, /*R_SWIDH*/ 0x04, /*R_STPS*/ 0x06, + /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x2A, + /*R_LEN*/ 0x16, /*R_LENH*/ 0x07, /*0x0C*/ 0x6D, + /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, + /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x40, + /*0x13*/ 0x15, /*0x14*/ 0x40, /*0x15*/ 0x15, + /*0x16*/ 0x40, /*0x17*/ 0x15, /*0x18*/ 0x40, + /*0x19*/ 0x15, /*0x1A*/ 0x07, /*0x1B*/ 0x00, + /*0x1C*/ 0x08, /*0x1D*/ 0x12, /*0x1E*/ 0x4C, + /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, + /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, + /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, + /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, + /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, + /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, + /*R_CCAL3*/ 0x80, /*0x32*/ 0xC9, /*0x33*/ 0x20, + /*0x34*/ 0x03, /*0x35*/ 0x29, /*0x36*/ 0x00, + /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, + /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, + /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, + /*0x40*/ 0x01, /*0x41*/ 0x00, /*R_CSTAT*/ 0x80, + /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, + /*R_CTL*/ 0x39, /*0x47*/ 0x40, /*0x48*/ 0x15, + /*0x49*/ 0x96, /*0x4A*/ 0x8C }; + +static unsigned char uchRegs600[]={ + /*R_SPOS*/ 0xFC, /*R_SPOSH*/ 0x00, /*0x03*/ 0x3F, + /*R_SWID*/ 0xB0, /*R_SWIDH*/ 0x04, /*R_STPS*/ 0x06, + /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x3F, + /*R_LEN*/ 0x16, /*R_LENH*/ 0x07, /*0x0C*/ 0x6D, + /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, + /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x42, + /*0x13*/ 0x15, /*0x14*/ 0x42, /*0x15*/ 0x15, + /*0x16*/ 0x42, /*0x17*/ 0x15, /*0x18*/ 0x42, + /*0x19*/ 0x15, /*0x1A*/ 0x07, /*0x1B*/ 0x00, + /*0x1C*/ 0x08, /*0x1D*/ 0x12, /*0x1E*/ 0x4C, + /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, + /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, + /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, + /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, + /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, + /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, + /*R_CCAL3*/ 0x80, /*0x32*/ 0xC9, /*0x33*/ 0x20, + /*0x34*/ 0x03, /*0x35*/ 0x29, /*0x36*/ 0x00, + /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, + /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, + /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, + /*0x40*/ 0x01, /*0x41*/ 0x00, /*R_CSTAT*/ 0x80, + /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, + /*R_CTL*/ 0x39, /*0x47*/ 0x42, /*0x48*/ 0x15, + /*0x49*/ 0x96, /*0x4A*/ 0x8C }; + +/* ====================================================================== + +ReadNextGrayLine() + +====================================================================== */ + +static TState ReadNextGrayLine(PTInstance this) +{ + int iWrite; + int iDot; + unsigned char chBits; + int iRead; /* read position in raw line */ + int nInterpolator; + + iWrite=0; + + while (iWrite<this->state.cxMax) /* max 1 time in reality */ + { + while (iWrite<this->state.cxMax && + this->state.iBulkReadPos<this->state.cchBulk) + this->state.ppchLines[0][iWrite++] += /* add! */ + this->state.pchBuf[this->state.iBulkReadPos++]<<4; + if (iWrite<this->state.cxMax) /* we need an additional chunk */ + { + if (this->state.bLastBulk) + return SANE_STATUS_EOF; + this->state.cchBulk=BulkReadBuffer(this,this->state.pchBuf, + USB_CHUNK_SIZE); + dprintf(DEBUG_SCAN,"bulk read: %d byte(s), line #%d\n", + this->state.cchBulk, this->state.iLine); + if (this->bWriteRaw) + fwrite(this->state.pchBuf,1,this->state.cchBulk,this->fhScan); + INST_ASSERT(); + if (this->state.cchBulk!=USB_CHUNK_SIZE) + this->state.bLastBulk=true; + this->state.iBulkReadPos=0; + } + } /* while raw line buffer acquiring */ + this->state.iLine++; + iDot=0; chBits=0; /* init pixelbuffer */ + for (nInterpolator=50, iWrite=0, iRead=0; + iRead<this->state.cxMax; + iRead++) + { + nInterpolator+=this->state.nFixAspect; + if (nInterpolator<100) continue; /* res. reduction */ + nInterpolator-=100; + if (iWrite>=this->state.cchLineOut) continue; + /* dprintf(DEBUG_SCAN," i=%d",iTo); */ + if (this->mode==gray) + this->state.pchLineOut[iWrite++]= + this->state.ppchLines[0][iRead]>>4; + else + { + unsigned char chBit; /* 1=white */ + if (this->mode==line) + chBit=(this->state.ppchLines[0][iRead]<LINE_THRESHOLD); + else + { + short nError=this->state.ppchLines[0][iRead]; + /* printf("(%d)",nError); */ + if (nError>=0xFF0) + { + nError-=0xFF0; + chBit=0; + } + else + chBit=1; + /* since I sketched the Floyd-Steinberg + algorithm from heart, I have no idea, if + there is room for improvement in the + coefficients. If You know, please drop + me a line (eichholz@computer.org, 1.4.2001) */ +#define FASTDITHER +#ifdef FASTDITHER + this->state.ppchLines[0][iRead+1]+=(nError>>2); /* 8/16 */ + this->state.ppchLines[1][iRead+1]+=(nError>>1); + this->state.ppchLines[1][iRead] +=(nError>>2); /* 8/16 */ +#else + this->state.ppchLines[0][iRead+1]+=(nError*5)>>4; + this->state.ppchLines[1][iRead+1]+=(nError*8)>>4; + this->state.ppchLines[1][iRead] +=(nError*3)>>4; +#endif + } + chBits=(chBits<<1)|chBit; + iDot++; + if (iDot==8 && iWrite<this->state.cchLineOut) + { + this->state.pchLineOut[iWrite++]=chBits; + iDot=0; chBits=0; + } + } /* gray pixel postprocessing */ + } /* line postprocessing */ + if (iDot && iWrite<this->state.cchLineOut) + this->state.pchLineOut[iWrite++]=chBits; + /* cycle the history lines and clear the preread buffer*/ + { + short *p=this->state.ppchLines[0]; + this->state.ppchLines[0]=this->state.ppchLines[1]; + this->state.ppchLines[1]=p; + memset(this->state.ppchLines[1],0,(this->state.cxMax+1)*sizeof(short)); + } + return SANE_STATUS_GOOD; +} + +/* ====================================================================== + +StartScanGray() + +====================================================================== */ + +__SM3600EXPORT__ +TState StartScanGray(TInstance *this) +{ + unsigned char *puchRegs; + int i; + if (this->state.bScanning) + return SetError(this,SANE_STATUS_DEVICE_BUSY,"scan active"); + memset(&(this->state),0,sizeof(TScanState)); + this->state.ReadProc =ReadNextGrayLine; + puchRegs=NULL; + switch (this->param.res) + { + case 75: puchRegs=uchRegs075; break; + case 100: puchRegs=uchRegs100; break; + case 200: puchRegs=uchRegs200; break; + case 300: puchRegs=uchRegs300; break; + case 600: puchRegs=uchRegs600; break; + } + GetAreaSize(this); + this->state.cyTotalPath = this->param.y/2; + DoJog(this,this->state.cyTotalPath); + INST_ASSERT(); + this->state.cyTotalPath += this->param.cy/2; /* for jogging back */ + + /* + regular scan is asynchronously, that is, + the scanning is issued, and the driver does bulk reads, + until there are no data left. + */ + RegWriteArray(this,R_ALL, NUM_SCANREGS, puchRegs); INST_ASSERT(); + RegWrite(this,R_SPOS, 2, + this->param.x/2+this->calibration.xMargin); INST_ASSERT(); + RegWrite(this,R_SLEN, 2, this->state.cyWindow); INST_ASSERT(); + RegWrite(this,R_SWID, 2, this->state.cxWindow); INST_ASSERT(); + RegWrite(this,R_STPS, 2, 0); INST_ASSERT(); + + /* upload gamma table */ + RegWrite(this,0x41,1,0x01); /* gamma, gray */ + RegWrite(this,0x40,1,0x20); /* FIFO at 0x08000 */ + UploadGammaTable(this,0,this->agammaY); INST_ASSERT(); + + UploadGainCorrection(this, 0x2000); + INST_ASSERT(); + + /* for halftone dithering we need one history line */ + this->state.pchBuf=malloc(USB_CHUNK_SIZE); + this->state.cBacklog=2; + this->state.ppchLines=calloc(this->state.cBacklog,sizeof(short *)); + if (!this->state.pchBuf || !this->state.ppchLines) + return FreeState(this,SetError(this, + SANE_STATUS_NO_MEM,"no buffers available")); + for (i=0; i<this->state.cBacklog; i++) + { + this->state.ppchLines[i]=calloc(this->state.cxMax+1, + sizeof(short)); /* 1 dummy at right edge */ + if (!this->state.ppchLines[i]) + return FreeState(this,SetError(this, + SANE_STATUS_NO_MEM,"no buffers available")); + } + + /* calculate and prepare intermediate line transfer buffer */ + + this->state.cchLineOut=(this->mode==gray) + ? this->state.cxPixel + : (this->state.cxPixel+7)/8; + + this->state.pchLineOut = malloc(this->state.cchLineOut); + if (!this->state.pchLineOut) + return FreeState(this,SetError(this, + SANE_STATUS_NO_MEM, + "no buffers available")); + + /* start the unit, when all buffers are available */ + + RegWrite(this,R_CTL, 1, 0x39); INST_ASSERT(); + RegWrite(this,R_CTL, 1, 0x79); INST_ASSERT(); + RegWrite(this,R_CTL, 1, 0xF9); INST_ASSERT(); + + this->state.bScanning = true; + return SANE_STATUS_GOOD; +} + |