1/* sane - Scanner Access Now Easy. 2 Copyright (C) Marian Eichholz 2001 3 This file is part of the SANE package. 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 As a special exception, the authors of SANE give permission for 19 additional uses of the libraries contained in this release of SANE. 20 21 The exception is that, if you link a SANE library with other files 22 to produce an executable, this does not by itself cause the 23 resulting executable to be covered by the GNU General Public 24 License. Your use of that executable is in no way restricted on 25 account of linking the SANE library code into it. 26 27 This exception does not, however, invalidate any other reasons why 28 the executable file might be covered by the GNU General Public 29 License. 30 31 If you submit changes to SANE to the maintainers to be included in 32 a subsequent release, you agree by submitting the changes that 33 those changes may be distributed with this exception intact. 34 35 If you write modifications of your own for SANE, it is your choice 36 whether to permit this exception to apply to your modifications. 37 If you do not wish that, delete this exception notice. 38*/ 39 40/* ====================================================================== 41 42Userspace scan tool for the Microtek 3600 scanner 43 44====================================================================== */ 45 46#include "sm3600-scantool.h" 47 48static struct { 49 TModel model; 50 unsigned short idProduct; 51 } aScanners[]={ 52 { sm3600, 0x40B3 }, 53 { sm3600, 0x40CA }, 54 { sm3600, 0x40FF }, 55 { sm3700, 0x40B8 }, 56 { sm3700, 0x40CB }, 57 { sm3750, 0x40dd }, 58 { sm3600, 0x40FF }, /* unknown */ 59 { unknown, 0x0000 } }; 60 61__SM3600EXPORT__ 62TModel GetScannerModel(unsigned short idVendor, 63 unsigned short idProduct) 64{ 65 int i; 66 if (idVendor!=SCANNER_VENDOR) return unknown; 67 for (i=0; aScanners[i].model!=unknown; i++) 68 if (aScanners[i].idProduct==idProduct) 69 return aScanners[i].model; 70 return unknown; 71} 72 73/* ********************************************************************** 74 75DoInit() 76 77Replay the first initialisation block (no slider movement). 78 79********************************************************************** */ 80 81__SM3600EXPORT__ 82TState DoInit(TInstance *this) 83{ 84 unsigned char uchRegs2466[]={ 85 0x00 /*0x01*/, 0x00 /*0x02*/, 0x3F /*0x03*/, 86 0x10 /*0x04*/, 0xC0 /*0x05*/, 0x00 /*0x06*/, 87 0x00 /*0x07*/, 0xFF /*0x08*/, 0xFF /*0x09*/, 88 0x20 /*0x0A*/, 0x00 /*0x0B*/, 0x6D /*0x0C*/, 89 0x70 /*0x0D*/, 0x69 /*0x0E*/, 0xD0 /*0x0F*/, 90 0x00 /*0x10*/, 0x00 /*0x11*/, 0x40 /*0x12*/, 91 0x15 /*0x13*/, 0x80 /*0x14*/, 0x2A /*0x15*/, 92 0xC0 /*0x16*/, 0x40 /*0x17*/, 0xC0 /*0x18*/, 93 0x40 /*0x19*/, 0xFF /*0x1A*/, 0x01 /*0x1B*/, 94 0x88 /*0x1C*/, 0x40 /*0x1D*/, 0x4C /*0x1E*/, 95 0x50 /*0x1F*/, 0x00 /*0x20*/, 0x0C /*0x21*/, 96 0x21 /*0x22*/, 0xF0 /*0x23*/, 0x40 /*0x24*/, 97 0x00 /*0x25*/, 0x0A /*0x26*/, 0xF0 /*0x27*/, 98 0x00 /*0x28*/, 0x00 /*0x29*/, 0x4E /*0x2A*/, 99 0xF0 /*0x2B*/, 0x00 /*0x2C*/, 0x00 /*0x2D*/, 100 0x4E /*0x2E*/, 0x80 /*R_CCAL*/, 0x80 /*R_CCAL2*/, 101 0x80 /*R_CCAL3*/, 0x29 /* */, 0x35 /* */, 102 0x63 /*0x34*/, 0x29 /*0x35*/, 0x00 /*0x36*/, 103 0x00 /*0x37*/, 0x00 /*0x38*/, 0x00 /*0x39*/, 104 0x00 /*0x3A*/, 0x00 /*0x3B*/, 0xFF /*0x3C*/, 105 0x0F /*0x3D*/, 0x00 /*0x3E*/, 0x00 /*0x3F*/, 106 0x01 /*0x40*/, 0x00 /*0x41*/, 0x00 /*R_CSTAT*/, 107 0x03 /*R_SPD*/, 0x01 /*0x44*/, 0x00 /*0x45*/, 108 0x39 /*R_CTL*/, 0xC0 /*0x47*/, 0x40 /*0x48*/, 109 0x96 /*0x49*/, 0xD8 /*0x4A*/ }; 110 dprintf(DEBUG_SCAN,"general init...\n"); 111 return RegWriteArray(this, R_ALL, 74, uchRegs2466); 112} 113 114/* ********************************************************************** 115 116DoReset() 117 118Resets Scanner after CANCEL in current scan job. 119 120********************************************************************** */ 121 122__SM3600EXPORT__ 123TState DoReset(TInstance *this) 124{ 125 RegWrite(this,0x43, 1, 0x03); /* #1533[038.1] */ 126 RegWrite(this,0x43, 1, 0x03); /* #1534[038.1] */ 127 RegRead(this,R_POS, 2); /*=0x1375*/ /* #1535[038.6] */ 128 RegWrite(this,R_CTL, 1, 0x39); /* #1536[038.6] */ 129 { 130 unsigned char uchRegs1537[]={ 131 /*R_SPOS*/ 0x00, /*R_SPOSH*/ 0x00, /*0x03*/ 0x00, 132 /*R_SWID*/ 0x00, /*R_SWIDH*/ 0x00, /*R_STPS*/ 0x00, 133 /*R_STPSH*/ 0x00, /*0x08*/ 0x00, /*0x09*/ 0x00, 134 /*R_LEN*/ 0x00, /*R_LENH*/ 0x00, /*0x0C*/ 0x6D, 135 /*0x0D*/ 0x70, /*0x0E*/ 0x69, /*0x0F*/ 0xD0, 136 /*0x10*/ 0x00, /*0x11*/ 0x00, /*0x12*/ 0x40, 137 /*0x13*/ 0x15, /*0x14*/ 0x80, /*0x15*/ 0x2A, 138 /*0x16*/ 0xC0, /*0x17*/ 0x40, /*0x18*/ 0xC0, 139 /*0x19*/ 0x40, /*0x1A*/ 0xFF, /*0x1B*/ 0x01, 140 /*0x1C*/ 0x88, /*0x1D*/ 0x40, /*0x1E*/ 0x4C, 141 /*0x1F*/ 0x50, /*0x20*/ 0x00, /*0x21*/ 0x0C, 142 /*0x22*/ 0x21, /*0x23*/ 0xF0, /*0x24*/ 0x40, 143 /*0x25*/ 0x00, /*0x26*/ 0x0A, /*0x27*/ 0xF0, 144 /*0x28*/ 0x00, /*0x29*/ 0x00, /*0x2A*/ 0x4E, 145 /*0x2B*/ 0xF0, /*0x2C*/ 0x00, /*0x2D*/ 0x00, 146 /*0x2E*/ 0x4E, /*R_CCAL*/ 0x80, /*R_CCAL2*/ 0x80, 147 /*R_CCAL3*/ 0x80, /*0x32*/ 0x4D, /*0x33*/ 0x35, 148 /*0x34*/ 0x83, /*0x35*/ 0x29, /*0x36*/ 0x00, 149 /*0x37*/ 0x00, /*0x38*/ 0x00, /*0x39*/ 0x00, 150 /*0x3A*/ 0x00, /*0x3B*/ 0x00, /*0x3C*/ 0xFF, 151 /*0x3D*/ 0x0F, /*0x3E*/ 0x00, /*0x3F*/ 0x00, 152 /*0x40*/ 0x01, /*0x41*/ 0x80, /*R_CSTAT*/ 0x00, 153 /*0x43*/ 0x03, /*R_LMP*/ 0x01, /*0x45*/ 0x00, 154 /*R_CTL*/ 0x39, /*0x47*/ 0xC0, /*0x48*/ 0x40, 155 /*0x49*/ 0x9E, /*0x4A*/ 0x8C }; 156 RegWriteArray(this,R_ALL, 74, uchRegs1537); 157 } /* #1537[038.6] */ 158 INST_ASSERT(); 159 RegWrite(this,R_CTL, 1, 0x39); /* #1538[038.6] */ 160 RegWrite(this,R_CTL, 1, 0x79); /* #1539[038.7] */ 161 RegWrite(this,R_CTL, 1, 0xF9); /* #1540[038.7] */ 162 WaitWhileScanning(this,2); 163 INST_ASSERT(); 164 RegWrite(this,R_CTL, 1, 0x39); /* #1542[038.7] */ 165 RegWrite(this,0x43, 1, 0x07); /* #1543[038.7] */ 166 WaitWhileBusy(this,2); 167 INST_ASSERT(); 168 RegWrite(this,0x32, 2, 0x354D); /* #1545[038.7] */ 169 RegWrite(this,0x34, 1, 0xC3); /* #1546[038.7] */ 170 RegWrite(this,0x49, 1, 0x9E); /* #1547[038.7] */ 171 INST_ASSERT(); 172 return SANE_STATUS_GOOD; 173} 174 175/* ********************************************************************** 176 177WaitWhileBusy() 178 179NOTE: Semantics changed: 0 on success, -1 else 180 181********************************************************************** */ 182 183__SM3600EXPORT__ 184TState WaitWhileBusy(TInstance *this, int cSecs) 185{ 186 int cTimeOut=cSecs*10; 187 int value; 188 INST_ASSERT(); 189 while (cTimeOut--) 190 { 191 if ((value=(int)RegRead(this,R_CTL,1)) & 0x80) 192 usleep(50); 193 else 194 return 0; 195 } 196 return SetError(this,SANE_STATUS_IO_ERROR,"Timeout while waiting for CTL"); 197} 198 199/* ********************************************************************** 200 201WaitWhileScanning() 202 203NOTE: Semantics changed: 0 on success, -1 else 204 205********************************************************************** */ 206 207__SM3600EXPORT__ 208TState WaitWhileScanning(TInstance *this, int cSecs) 209{ 210 int cTimeOut=cSecs*10; 211 int value; 212 INST_ASSERT(); 213 while (cTimeOut--) 214 { 215 if ((value=(int)RegRead(this,R_CSTAT, 1)) & 0x80) 216 return 0; 217 else 218 usleep(50); 219 } 220 return SetError(this,SANE_STATUS_IO_ERROR,"Timeout while waiting for CSTAT"); 221} 222 223#ifdef INSANE_VERSION 224 225/* ********************************************************************** 226 227DoLampSwitch(nRegister) 228 2290x01 should switch the lamp ON 2300x02 should swuitch it OFF 231 232********************************************************************** */ 233 234__SM3600EXPORT__ 235TState DoLampSwitch(TInstance *this, int nPattern) 236{ 237 return RegWrite(this, R_LMP, 1, nPattern); 238} 239 240#endif 241 242/* ********************************************************************** 243 244UploadGammaTable() 245 246********************************************************************** */ 247 248__SM3600EXPORT__ 249TState UploadGammaTable(TInstance *this, int iByteAddress, SANE_Int *pnGamma) 250{ 251 unsigned char *puchGamma; 252 TState rc; 253 int i; 254 rc=SANE_STATUS_GOOD; 255 INST_ASSERT(); 256 puchGamma=malloc(0x2000); 257 if (!puchGamma) return SetError(this,SANE_STATUS_NO_MEM,"gamma buffer"); 258 DBG(DEBUG_INFO,"uploading gamma to %d\n",iByteAddress); 259 for (i=0; i<0x1000; i++) 260 { 261 int nVal=pnGamma[i]; 262 /* nVal=i; */ 263 puchGamma[2*i+1]=nVal>>8; 264 puchGamma[2*i+0]=nVal&0xFF; 265 } 266 for (i=0; rc==SANE_STATUS_GOOD && i<0x2000; i+=0x1000) 267 rc=MemWriteArray(this,(i+iByteAddress)>>1,0x1000,puchGamma+i); 268 free(puchGamma); 269 return rc; 270} 271 272/* ********************************************************************** 273 274UploadGainCorrection() 275 276********************************************************************** */ 277 278__SM3600EXPORT__ 279TState UploadGainCorrection(TInstance *this, int iTableOffset) 280{ 281 { 282 struct TGain { 283 unsigned char uchLow; 284 unsigned char uchHigh; 285 } aGain[0x2000]; /* 16 KB */ 286 int i,iOff; 287 unsigned short uwGain; 288 289 /* 290 Oopsi: correction data starts at the left of the scanning window! 291 */ 292 iOff=this->param.x/2+this->calibration.xMargin; 293 memset(aGain,0xFF,sizeof(aGain)); 294 RegWrite(this,0x3D,1,0x0F | 0x80); /* 10XXXXXX : one offset table */ 295 RegWrite(this,0x3F,1, iTableOffset==0x6000 ? 0x18 : 0x08); /* 16KB gain at 0x06000 or 0x02000 */ 296 for (i=iOff; i<MAX_PIXEL_PER_SCANLINE; i++) 297 { 298 uwGain=this->calibration.achStripeY[i]<<4; 299 aGain[i-iOff].uchLow =(unsigned char)(uwGain&0xFF); 300 aGain[i-iOff].uchHigh=(unsigned char)(uwGain>>8); 301 } 302 for (i=0; i<0x4000; i+=0x1000) 303 MemWriteArray(this,(iTableOffset+i)>>1,0x1000,((unsigned char*)aGain)+i); 304 } 305 return SANE_STATUS_GOOD; 306} 307