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 
42 Userspace scan tool for the Microtek 3600 scanner
43 
44 ====================================================================== */
45 
46 #include "sm3600-scantool.h"
47 
48 static 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__
GetScannerModel(unsigned short idVendor, unsigned short idProduct)62 TModel 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 
75 DoInit()
76 
77 Replay the first initialisation block (no slider movement).
78 
79 ********************************************************************** */
80 
81 __SM3600EXPORT__
DoInit(TInstance *this)82 TState 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 
116 DoReset()
117 
118 Resets Scanner after CANCEL in current scan job.
119 
120 ********************************************************************** */
121 
122 __SM3600EXPORT__
DoReset(TInstance *this)123 TState 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 
177 WaitWhileBusy()
178 
179 NOTE: Semantics changed: 0 on success, -1 else
180 
181 ********************************************************************** */
182 
183 __SM3600EXPORT__
WaitWhileBusy(TInstance *this, int cSecs)184 TState 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 
201 WaitWhileScanning()
202 
203 NOTE: Semantics changed: 0 on success, -1 else
204 
205 ********************************************************************** */
206 
207 __SM3600EXPORT__
WaitWhileScanning(TInstance *this, int cSecs)208 TState 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 
227 DoLampSwitch(nRegister)
228 
229 0x01 should switch the lamp ON
230 0x02 should swuitch it OFF
231 
232 ********************************************************************** */
233 
234 __SM3600EXPORT__
DoLampSwitch(TInstance *this, int nPattern)235 TState DoLampSwitch(TInstance *this, int nPattern)
236 {
237   return RegWrite(this, R_LMP, 1, nPattern);
238 }
239 
240 #endif
241 
242 /* **********************************************************************
243 
244 UploadGammaTable()
245 
246 ********************************************************************** */
247 
248 __SM3600EXPORT__
UploadGammaTable(TInstance *this, int iByteAddress, SANE_Int *pnGamma)249 TState 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 
274 UploadGainCorrection()
275 
276 ********************************************************************** */
277 
278 __SM3600EXPORT__
UploadGainCorrection(TInstance *this, int iTableOffset)279 TState 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