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 (C) Marian Eichholz 2001
45
46 26.4.2001: Added an abstraction layer for TransferControlMsg.
47
48 ====================================================================== */
49
50 #include "sm3600-scantool.h"
51
52 /* **********************************************************************
53
54 TransferControlMsg()
55
56 ********************************************************************** */
57
TransferControlMsg(TInstance * this,int nReqType,int nRequest,int nValue,int nIndex,void * pBuffer,int cchBuffer,int cJiffiesTimeout)58 static int TransferControlMsg(TInstance *this,
59 int nReqType,
60 int nRequest,
61 int nValue,
62 int nIndex,
63 void *pBuffer,
64 int cchBuffer,
65 int cJiffiesTimeout)
66 {
67 SANE_Status err;
68
69 (void) cJiffiesTimeout;
70
71 err = sanei_usb_control_msg (this->hScanner,
72 nReqType,
73 nRequest,
74 nValue,
75 nIndex,
76 cchBuffer,
77 pBuffer);
78 if (err)
79 return err;
80 return cchBuffer;
81 }
82
83 /* **********************************************************************
84
85 cch=BulkRead()
86
87 ********************************************************************** */
88
TransferBulkRead(TInstance * this,int nEndPoint,void * pBuffer,int cchMax,int cJiffiesTimeout)89 static int TransferBulkRead(TInstance *this,
90 int nEndPoint,
91 void *pBuffer,
92 int cchMax,
93 int cJiffiesTimeout)
94 {
95 int err;
96 size_t sz = cchMax;
97
98 (void) nEndPoint;
99 (void) cJiffiesTimeout;
100
101 err = sanei_usb_read_bulk(this->hScanner,
102 pBuffer,
103 &sz);
104 if (err)
105 return err;
106 return sz;
107 }
108
109 /* **********************************************************************
110
111 RegWrite(iRegister, cb, ulValue)
112 RegWriteArray(iRegister, cb, unsigned char uchValues)
113
114 ********************************************************************** */
115
116 __SM3600EXPORT__
RegWrite(TInstance * this,int iRegister,int cb,unsigned long ulValue)117 TState RegWrite(TInstance *this, int iRegister, int cb, unsigned long ulValue)
118 {
119 char *pchBuffer;
120 int i;
121 TBool bOk=true;
122 INST_ASSERT();
123 /* some rough assertions */
124 if (cb<1 || cb>4)
125 return SetError(this,SANE_STATUS_INVAL,"unsupported control transfer size %d",cb);
126 pchBuffer=malloc(cb);
127 CHECK_POINTER(pchBuffer);
128 for (i=0; i<cb; i++)
129 {
130 pchBuffer[i]=(char)(ulValue&0xFF);
131 ulValue=ulValue>>8;
132 }
133 if (!bOk)
134 {
135 free(pchBuffer);
136 return SetError(this,SANE_STATUS_IO_ERROR,
137 "error in reg out: %d,%d,%08X",iRegister,cb,ulValue);
138 }
139 i=TransferControlMsg(this, /* handle */
140 0x40, /* request type */
141 0x08, /* request */
142 iRegister, /* value */
143 0, /* index */
144 pchBuffer, cb, /* bytes, size */
145 USB_TIMEOUT_JIFFIES); /* TO, jiffies... */
146 free(pchBuffer);
147 if (i<0)
148 return SetError(this,SANE_STATUS_IO_ERROR,"error during register write");
149 return SANE_STATUS_GOOD;
150 }
151
152 __SM3600EXPORT__
RegWriteArray(TInstance * this,int iRegister,int cb,unsigned char * pchBuffer)153 TState RegWriteArray(TInstance *this, int iRegister, int cb, unsigned char *pchBuffer)
154 {
155 int i;
156 INST_ASSERT();
157 /* some rough assertions */
158 i=TransferControlMsg(this, /* handle */
159 0x40, /* request type */
160 0x08, /* request */
161 iRegister, /* value */
162 0, /* index */
163 pchBuffer, cb, /* bytes, size */
164 USB_TIMEOUT_JIFFIES); /* TO, jiffies... */
165 if (i<0)
166 return SetError(this,SANE_STATUS_IO_ERROR,"error during register write");
167 return SANE_STATUS_GOOD;
168 }
169
170 /* **********************************************************************
171
172 MemWriteArray(iAddress, cb, ulValue)
173
174 ********************************************************************** */
175
176 __SM3600EXPORT__
MemWriteArray(TInstance * this,int iAddress,int cb,unsigned char * pchBuffer)177 TState MemWriteArray(TInstance *this, int iAddress,
178 int cb, unsigned char *pchBuffer)
179 {
180 int i;
181 INST_ASSERT();
182 /* some rough assertions */
183 i=TransferControlMsg(this,
184 0x40, /* request type */
185 0x09, /* request */
186 iAddress, /* value */
187 0, /* index */
188 pchBuffer, cb, /* bytes, size */
189 10000); /* TO, jiffies... */
190 if (i<0)
191 return SetError(this,SANE_STATUS_IO_ERROR,"error during memory write");
192 return SANE_STATUS_GOOD;
193 }
194
195 /* **********************************************************************
196
197 MemReadArray(iRegister, cb, ulValue)
198
199 ********************************************************************** */
200
201 #ifdef INSANE_VERSION
202
203 __SM3600EXPORT__
MemReadArray(TInstance * this,int iAddress,int cb,unsigned char * pchBuffer)204 TState MemReadArray(TInstance *this, int iAddress, int cb, unsigned char *pchBuffer)
205 {
206 int i;
207 INST_ASSERT();
208 /* some rough assertions */
209 i=TransferControlMsg(this,
210 0xC0, /* request type */
211 0x01, /* request */
212 iAddress, /* value */
213 0, /* index */
214 pchBuffer, cb, /* bytes, size */
215 USB_TIMEOUT_JIFFIES); /* TO, jiffies... */
216 if (i<0)
217 return SetError(this,SANE_STATUS_IO_ERROR,"error during memory read");
218 return SANE_STATUS_GOOD;
219 }
220
221 /* **********************************************************************
222
223 RegCheck(iRegister, cb, ulValue)
224
225 ********************************************************************** */
226
227 __SM3600EXPORT__
RegCheck(TInstance * this,int iRegister,int cch,unsigned long ulValue)228 TState RegCheck(TInstance *this, int iRegister, int cch, unsigned long ulValue)
229 {
230 char *pchBuffer,*pchTransfer;
231 int i,rcCode;
232 TBool bOk;
233 INST_ASSERT();
234 if (cch<1 || cch>3)
235 return SetError(this,SANE_STATUS_INVAL,"unsupported control transfer size %d",cch);
236 pchBuffer=malloc(cch);
237 pchTransfer=calloc(1,cch);
238 rcCode=SANE_STATUS_GOOD;
239 if (!pchBuffer || !pchTransfer)
240 {
241 if (pchBuffer) free(pchBuffer);
242 if (pchTransfer) free(pchTransfer);
243 rcCode=SetError(this, SANE_STATUS_NO_MEM, "no memory in RegCheck()");
244 }
245 bOk=true;
246 for (i=0; !rcCode && i<cch; i++)
247 {
248 pchBuffer[i]=(char)(ulValue&0x00FF);
249 ulValue=(ulValue>>8);
250 }
251 if (!rcCode)
252 {
253 if (!bOk)
254 rcCode=SetError(this,SANE_STATUS_IO_ERROR,
255 "error in reg out: %d,%d,%08X",iRegister,cch,ulValue);
256 else
257 {
258 i=TransferControlMsg(this, /* handle */
259 0xC0, /* request type */
260 0x00, /* request */
261 iRegister, /* value */
262 0, /* index */
263 pchTransfer, cch, /* bytes, size */
264 USB_TIMEOUT_JIFFIES); /* TO, jiffies... */
265 if (i<0)
266 rcCode=SetError(this,SANE_STATUS_IO_ERROR,
267 "error during register check");
268 }
269 }
270 if (!rcCode && memcmp(pchTransfer,pchBuffer,cch))
271 {
272 DumpBuffer(stdout,pchTransfer,cch);
273 rcCode=SetError(this,SANE_STATUS_IO_ERROR,
274 "check register failed for %d,%d,%08X",
275 iRegister,cch,ulValue);
276 }
277 free(pchTransfer); free(pchBuffer);
278 return rcCode;
279 }
280
281 /* **********************************************************************
282
283 cchRead=BulkRead(fh,cchBulk)
284
285 ********************************************************************** */
286
287 __SM3600EXPORT__
BulkRead(TInstance * this,FILE * fhOut,unsigned int cchBulk)288 int BulkRead(TInstance *this, FILE *fhOut, unsigned int cchBulk)
289 {
290 int cchRead,rc;
291 char *pchBuffer;
292 INST_ASSERT();
293 pchBuffer=(char*)malloc(cchBulk);
294 CHECK_POINTER(pchBuffer);
295 cchRead=0;
296 rc=0;
297 while (!rc && cchBulk)
298 {
299 int cchChunk;
300 int cchReal;
301
302 cchChunk=cchBulk;
303 if (cchChunk>0x1000)
304 cchChunk=0x1000;
305 cchReal=TransferBulkRead(this,
306 0x82,
307 pchBuffer+cchRead,
308 cchChunk,
309 USB_TIMEOUT_JIFFIES);
310 dprintf(DEBUG_COMM,"bulk read: %d -> %d\n",cchChunk,cchReal);
311 if (cchReal>=0)
312 {
313 cchBulk-=cchReal;
314 cchRead+=cchReal;
315 if (cchReal<cchChunk) /* last Chunk of a series */
316 break;
317 }
318 else
319 {
320 rc=SetError(this,SANE_STATUS_IO_ERROR,
321 "bulk read of %d bytes failed: %s",
322 cchChunk,
323 "I/O error"
324 );
325 continue;
326 }
327 }
328 dprintf(DEBUG_COMM,"writing %d bytes\n",cchRead);
329 if (fhOut && !rc)
330 {
331 fwrite(pchBuffer,1,cchRead,fhOut);
332 if (ferror(fhOut))
333 rc=SetError(this,SANE_STATUS_IO_ERROR,
334 "scan file write failed: %s",
335 strerror(errno));
336 }
337 free(pchBuffer);
338 return rc ? -1 : cchRead;
339 }
340
341 #endif
342
343 /* **********************************************************************
344
345 cchRead=BulkReadBuffer(puchBuffer, cchBulk)
346
347 ********************************************************************** */
348
349 __SM3600EXPORT__
BulkReadBuffer(TInstance * this,unsigned char * puchBufferOut,unsigned int cchBulk)350 int BulkReadBuffer(TInstance *this,
351 unsigned char *puchBufferOut,
352 unsigned int cchBulk)
353 {
354 int cchRead,rc;
355 char *pchBuffer;
356 INST_ASSERT();
357 pchBuffer=(char*)malloc(cchBulk);
358 CHECK_POINTER(pchBuffer);
359 cchRead=0;
360 rc=0;
361 while (!rc && cchBulk)
362 {
363 int cchChunk;
364 int cchReal;
365
366 cchChunk=cchBulk;
367 if (cchChunk>0x1000)
368 cchChunk=0x1000;
369 cchReal=TransferBulkRead(this,
370 0x82,
371 pchBuffer+cchRead,
372 cchChunk,
373 USB_TIMEOUT_JIFFIES);
374 dprintf(DEBUG_COMM,"bulk read: %d -> %d\n",cchChunk,cchReal);
375 if (cchReal>=0)
376 {
377 cchBulk-=cchReal;
378 cchRead+=cchReal;
379 if (cchReal<cchChunk) /* last Chunk of a series */
380 break;
381 }
382 else
383 rc=SetError(this,SANE_STATUS_IO_ERROR,
384 "bulk read of %d bytes failed: %s",
385 cchChunk,
386 "I/O error"
387 );
388 }
389 dprintf(DEBUG_COMM,"writing %d bytes\n",cchRead);
390
391 if (!rc && puchBufferOut)
392 memcpy(puchBufferOut,pchBuffer,cchRead);
393 free(pchBuffer);
394 return rc ? -1 : cchRead;
395 }
396
397 /* **********************************************************************
398
399 RegRead(iRegister, int cch)
400
401 Read register in big endian (INTEL-) format.
402
403 ********************************************************************** */
404
405 __SM3600EXPORT__
RegRead(TInstance * this,int iRegister,int cch)406 unsigned int RegRead(TInstance *this, int iRegister, int cch)
407 {
408 char *pchTransfer;
409 int i;
410 unsigned int n;
411 INST_ASSERT();
412 if (cch<1 || cch>4)
413 {
414 SetError(this,SANE_STATUS_INVAL,
415 "unsupported control read size %d",cch);
416 return 0;
417 }
418 pchTransfer=calloc(1,cch);
419 CHECK_POINTER(pchTransfer);
420 i=TransferControlMsg(this, /* handle */
421 0xC0, /* request type */
422 0x00, /* request */
423 iRegister, /* value */
424 0, /* index */
425 pchTransfer, cch, /* bytes, size */
426 USB_TIMEOUT_JIFFIES); /* TO, jiffies... */
427 if (i>=0)
428 {
429 n=0;
430 for (i=cch-1; i>=0; i--)
431 n=(n<<8)|(unsigned char)pchTransfer[i];
432 free(pchTransfer);
433 return n;
434 }
435 free(pchTransfer);
436 SetError(this,SANE_STATUS_IO_ERROR,"error during register read");
437 return 0;
438 }
439