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