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