1141cc406Sopenharmony_ci/*.............................................................................
2141cc406Sopenharmony_ci * Project : SANE library for Plustek flatbed scanners.
3141cc406Sopenharmony_ci *.............................................................................
4141cc406Sopenharmony_ci */
5141cc406Sopenharmony_ci
6141cc406Sopenharmony_ci/** @file plustek-usbio.c
7141cc406Sopenharmony_ci *  @brief Some I/O stuff.
8141cc406Sopenharmony_ci *
9141cc406Sopenharmony_ci * Based on sources acquired from Plustek Inc.<br>
10141cc406Sopenharmony_ci * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de>
11141cc406Sopenharmony_ci *
12141cc406Sopenharmony_ci * History:
13141cc406Sopenharmony_ci * History:
14141cc406Sopenharmony_ci * - 0.40 - starting version of the USB support
15141cc406Sopenharmony_ci * - 0.41 - moved some functions to a sane library (sanei_lm983x.c)
16141cc406Sopenharmony_ci * - 0.42 - no changes
17141cc406Sopenharmony_ci * - 0.43 - no changes
18141cc406Sopenharmony_ci * - 0.44 - added dump registers and dumpPic functions
19141cc406Sopenharmony_ci *        - beautified output of ASIC detection
20141cc406Sopenharmony_ci * - 0.45 - fixed dumpRegs
21141cc406Sopenharmony_ci *        - added dimension stuff to dumpPic
22141cc406Sopenharmony_ci * - 0.46 - disabled reset prior to the detection of Merlin
23141cc406Sopenharmony_ci * - 0.47 - no changes
24141cc406Sopenharmony_ci * - 0.48 - cleanup
25141cc406Sopenharmony_ci * - 0.49 - no changes
26141cc406Sopenharmony_ci * - 0.50 - usbio_DetectLM983x() now returns error if register
27141cc406Sopenharmony_ci *          could not be red
28141cc406Sopenharmony_ci *        - usbio_ResetLM983x() checks for reg7 value before writing
29141cc406Sopenharmony_ci * - 0.51 - allow dumpRegs to be called without valid fd
30141cc406Sopenharmony_ci * - 0.52 - no changes
31141cc406Sopenharmony_ci * .
32141cc406Sopenharmony_ci * <hr>
33141cc406Sopenharmony_ci * This file is part of the SANE package.
34141cc406Sopenharmony_ci *
35141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
36141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
37141cc406Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the
38141cc406Sopenharmony_ci * License, or (at your option) any later version.
39141cc406Sopenharmony_ci *
40141cc406Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
41141cc406Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
42141cc406Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43141cc406Sopenharmony_ci * General Public License for more details.
44141cc406Sopenharmony_ci *
45141cc406Sopenharmony_ci * You should have received a copy of the GNU General Public License
46141cc406Sopenharmony_ci * along with this program.  If not, see <https://www.gnu.org/licenses/>.
47141cc406Sopenharmony_ci *
48141cc406Sopenharmony_ci * As a special exception, the authors of SANE give permission for
49141cc406Sopenharmony_ci * additional uses of the libraries contained in this release of SANE.
50141cc406Sopenharmony_ci *
51141cc406Sopenharmony_ci * The exception is that, if you link a SANE library with other files
52141cc406Sopenharmony_ci * to produce an executable, this does not by itself cause the
53141cc406Sopenharmony_ci * resulting executable to be covered by the GNU General Public
54141cc406Sopenharmony_ci * License.  Your use of that executable is in no way restricted on
55141cc406Sopenharmony_ci * account of linking the SANE library code into it.
56141cc406Sopenharmony_ci *
57141cc406Sopenharmony_ci * This exception does not, however, invalidate any other reasons why
58141cc406Sopenharmony_ci * the executable file might be covered by the GNU General Public
59141cc406Sopenharmony_ci * License.
60141cc406Sopenharmony_ci *
61141cc406Sopenharmony_ci * If you submit changes to SANE to the maintainers to be included in
62141cc406Sopenharmony_ci * a subsequent release, you agree by submitting the changes that
63141cc406Sopenharmony_ci * those changes may be distributed with this exception intact.
64141cc406Sopenharmony_ci *
65141cc406Sopenharmony_ci * If you write modifications of your own for SANE, it is your choice
66141cc406Sopenharmony_ci * whether to permit this exception to apply to your modifications.
67141cc406Sopenharmony_ci * If you do not wish that, delete this exception notice.
68141cc406Sopenharmony_ci * <hr>
69141cc406Sopenharmony_ci */
70141cc406Sopenharmony_ci
71141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h"
72141cc406Sopenharmony_ci#include "../include/sane/sanei_lm983x.h"
73141cc406Sopenharmony_ci
74141cc406Sopenharmony_ci#define _UIO(func)                            \
75141cc406Sopenharmony_ci    {                                         \
76141cc406Sopenharmony_ci        SANE_Status status;                   \
77141cc406Sopenharmony_ci        status = func;                        \
78141cc406Sopenharmony_ci        if (status != SANE_STATUS_GOOD) {     \
79141cc406Sopenharmony_ci            DBG( _DBG_ERROR, "UIO error\n" ); \
80141cc406Sopenharmony_ci            return SANE_FALSE;                \
81141cc406Sopenharmony_ci        }                                     \
82141cc406Sopenharmony_ci    }
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci#define usbio_ReadReg(fd, reg, value) \
85141cc406Sopenharmony_ci  sanei_lm983x_read (fd, reg, value, 1, 0)
86141cc406Sopenharmony_ci
87141cc406Sopenharmony_citypedef struct {
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci	u_char depth;
90141cc406Sopenharmony_ci	u_long x;
91141cc406Sopenharmony_ci	u_long y;
92141cc406Sopenharmony_ci} PicDef, *pPicDef;
93141cc406Sopenharmony_ci
94141cc406Sopenharmony_cistatic PicDef dPix;
95141cc406Sopenharmony_ci
96141cc406Sopenharmony_ci/**
97141cc406Sopenharmony_ci */
98141cc406Sopenharmony_cistatic void dumpPic( char* name, SANE_Byte *buffer, u_long len, int is_gray )
99141cc406Sopenharmony_ci{
100141cc406Sopenharmony_ci	u_short type;
101141cc406Sopenharmony_ci	FILE   *fp;
102141cc406Sopenharmony_ci
103141cc406Sopenharmony_ci	if( DBG_LEVEL < _DBG_DPIC )
104141cc406Sopenharmony_ci		return;
105141cc406Sopenharmony_ci
106141cc406Sopenharmony_ci	if( NULL == buffer ) {
107141cc406Sopenharmony_ci
108141cc406Sopenharmony_ci		DBG( _DBG_DPIC, "Creating file '%s'\n", name );
109141cc406Sopenharmony_ci
110141cc406Sopenharmony_ci		fp = fopen( name, "w+b" );
111141cc406Sopenharmony_ci
112141cc406Sopenharmony_ci		if( NULL != fp ) {
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci			if( 0 != dPix.x ) {
115141cc406Sopenharmony_ci
116141cc406Sopenharmony_ci				if (is_gray)
117141cc406Sopenharmony_ci					type = 5;
118141cc406Sopenharmony_ci				else
119141cc406Sopenharmony_ci					type = 6;
120141cc406Sopenharmony_ci
121141cc406Sopenharmony_ci				DBG( _DBG_DPIC, "> X=%lu, Y=%lu, depth=%u\n",
122141cc406Sopenharmony_ci				                 dPix.x, dPix.y, dPix.depth );
123141cc406Sopenharmony_ci				if( dPix.depth > 8 )
124141cc406Sopenharmony_ci					fprintf( fp, "P%u\n%lu %lu\n65535\n", type, dPix.x, dPix.y);
125141cc406Sopenharmony_ci    			else
126141cc406Sopenharmony_ci					fprintf( fp, "P%u\n%lu %lu\n255\n", type, dPix.x, dPix.y);
127141cc406Sopenharmony_ci			}
128141cc406Sopenharmony_ci    	}
129141cc406Sopenharmony_ci	} else {
130141cc406Sopenharmony_ci		fp = fopen( name, "a+b" );
131141cc406Sopenharmony_ci	}
132141cc406Sopenharmony_ci
133141cc406Sopenharmony_ci	if( NULL == fp ) {
134141cc406Sopenharmony_ci		DBG( _DBG_DPIC, "Can not open file '%s'\n", name );
135141cc406Sopenharmony_ci		return;
136141cc406Sopenharmony_ci	}
137141cc406Sopenharmony_ci
138141cc406Sopenharmony_ci	fwrite( buffer, 1, len, fp );
139141cc406Sopenharmony_ci	fclose( fp );
140141cc406Sopenharmony_ci}
141141cc406Sopenharmony_ci
142141cc406Sopenharmony_ci/**
143141cc406Sopenharmony_ci */
144141cc406Sopenharmony_cistatic void dumpPicInit( ScanParam *sd, char* name )
145141cc406Sopenharmony_ci{
146141cc406Sopenharmony_ci	dPix.x = sd->Size.dwPhyBytes;
147141cc406Sopenharmony_ci
148141cc406Sopenharmony_ci	if( sd->bDataType == SCANDATATYPE_Color )
149141cc406Sopenharmony_ci		dPix.x /= 3;
150141cc406Sopenharmony_ci
151141cc406Sopenharmony_ci	if( sd->bBitDepth > 8 )
152141cc406Sopenharmony_ci		dPix.x /= 2;
153141cc406Sopenharmony_ci
154141cc406Sopenharmony_ci	dPix.y	   = sd->Size.dwLines;
155141cc406Sopenharmony_ci	dPix.depth = sd->bBitDepth;
156141cc406Sopenharmony_ci
157141cc406Sopenharmony_ci	if( sd->bDataType == SCANDATATYPE_Color )
158141cc406Sopenharmony_ci		dumpPic(name, NULL, 0, 0);
159141cc406Sopenharmony_ci	else
160141cc406Sopenharmony_ci		dumpPic(name, NULL, 0, 1);
161141cc406Sopenharmony_ci}
162141cc406Sopenharmony_ci
163141cc406Sopenharmony_ci/**
164141cc406Sopenharmony_ci * dump the LM983x registers
165141cc406Sopenharmony_ci */
166141cc406Sopenharmony_cistatic void dumpregs( int fd, SANE_Byte *cmp )
167141cc406Sopenharmony_ci{
168141cc406Sopenharmony_ci	char      buf[256], b2[10];
169141cc406Sopenharmony_ci	SANE_Byte regs[0x80];
170141cc406Sopenharmony_ci	int       i;
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ci	if( DBG_LEVEL < _DBG_DREGS )
173141cc406Sopenharmony_ci		return;
174141cc406Sopenharmony_ci
175141cc406Sopenharmony_ci	buf[0] = '\0';
176141cc406Sopenharmony_ci
177141cc406Sopenharmony_ci	if( fd >= 0 ) {
178141cc406Sopenharmony_ci		usbio_ReadReg(fd, 0x01, &regs[0x01]);
179141cc406Sopenharmony_ci		usbio_ReadReg(fd, 0x02, &regs[0x02]);
180141cc406Sopenharmony_ci		usbio_ReadReg(fd, 0x03, &regs[0x03]);
181141cc406Sopenharmony_ci		usbio_ReadReg(fd, 0x04, &regs[0x04]);
182141cc406Sopenharmony_ci		usbio_ReadReg(fd, 0x07, &regs[0x07]);
183141cc406Sopenharmony_ci
184141cc406Sopenharmony_ci		sanei_lm983x_read( fd, 0x08, &regs[0x8], 0x80-0x8, SANE_TRUE );
185141cc406Sopenharmony_ci
186141cc406Sopenharmony_ci		for( i = 0x0; i < 0x80; i++ ) {
187141cc406Sopenharmony_ci
188141cc406Sopenharmony_ci			if((i%16) ==0 ) {
189141cc406Sopenharmony_ci
190141cc406Sopenharmony_ci				if( buf[0] )
191141cc406Sopenharmony_ci					DBG( _DBG_DREGS, "%s\n", buf );
192141cc406Sopenharmony_ci				sprintf( buf, "0x%02x:", i );
193141cc406Sopenharmony_ci			}
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci			if((i%8)==0)
196141cc406Sopenharmony_ci				strcat( buf, " ");
197141cc406Sopenharmony_ci
198141cc406Sopenharmony_ci			/* the dataport read returns with "0 Bytes read", of course. */
199141cc406Sopenharmony_ci			if((i == 0) || (i == 5) || (i == 6))
200141cc406Sopenharmony_ci				strcat( buf, "XX ");
201141cc406Sopenharmony_ci			else {
202141cc406Sopenharmony_ci
203141cc406Sopenharmony_ci				sprintf( b2, "%02x ", regs[i]);
204141cc406Sopenharmony_ci				strcat( buf, b2 );
205141cc406Sopenharmony_ci			}
206141cc406Sopenharmony_ci		}
207141cc406Sopenharmony_ci		DBG( _DBG_DREGS, "%s\n", buf );
208141cc406Sopenharmony_ci	}
209141cc406Sopenharmony_ci
210141cc406Sopenharmony_ci	if( cmp ) {
211141cc406Sopenharmony_ci
212141cc406Sopenharmony_ci		buf[0] = '\0';
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci		DBG( _DBG_DREGS, "Internal setting:\n" );
215141cc406Sopenharmony_ci		for( i = 0x0; i < 0x80; i++ ) {
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci			if((i%16) ==0 ) {
218141cc406Sopenharmony_ci
219141cc406Sopenharmony_ci				if( buf[0] )
220141cc406Sopenharmony_ci					DBG( _DBG_DREGS, "%s\n", buf );
221141cc406Sopenharmony_ci				sprintf( buf, "0x%02x:", i );
222141cc406Sopenharmony_ci			}
223141cc406Sopenharmony_ci
224141cc406Sopenharmony_ci			if((i%8)==0)
225141cc406Sopenharmony_ci				strcat( buf, " ");
226141cc406Sopenharmony_ci
227141cc406Sopenharmony_ci			if((i == 0) || (i == 5) || (i == 6))
228141cc406Sopenharmony_ci				strcat( buf, "XX ");
229141cc406Sopenharmony_ci			else {
230141cc406Sopenharmony_ci				sprintf( b2, "%02x ", cmp[i]);
231141cc406Sopenharmony_ci				strcat( buf, b2 );
232141cc406Sopenharmony_ci			}
233141cc406Sopenharmony_ci		}
234141cc406Sopenharmony_ci		DBG( _DBG_DREGS, "%s\n", buf );
235141cc406Sopenharmony_ci	}
236141cc406Sopenharmony_ci}
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci/**
239141cc406Sopenharmony_ci * function to read the contents of a LM983x register and regarding some
240141cc406Sopenharmony_ci * extra stuff, like flushing register 2 when writing register 0x58, etc
241141cc406Sopenharmony_ci *
242141cc406Sopenharmony_ci * @param handle -
243141cc406Sopenharmony_ci * @param reg    -
244141cc406Sopenharmony_ci * @param value  -
245141cc406Sopenharmony_ci * @return
246141cc406Sopenharmony_ci */
247141cc406Sopenharmony_cistatic SANE_Bool usbio_WriteReg( SANE_Int handle,
248141cc406Sopenharmony_ci                                 SANE_Byte reg, SANE_Byte value )
249141cc406Sopenharmony_ci{
250141cc406Sopenharmony_ci	int       i;
251141cc406Sopenharmony_ci	SANE_Byte data;
252141cc406Sopenharmony_ci
253141cc406Sopenharmony_ci	/* retry loop... */
254141cc406Sopenharmony_ci	for( i = 0; i < 100; i++ ) {
255141cc406Sopenharmony_ci
256141cc406Sopenharmony_ci		sanei_lm983x_write_byte( handle, reg, value );
257141cc406Sopenharmony_ci
258141cc406Sopenharmony_ci		/* Flush register 0x02 when register 0x58 is written */
259141cc406Sopenharmony_ci		if( 0x58 == reg ) {
260141cc406Sopenharmony_ci			_UIO( usbio_ReadReg( handle, 2, &data ));
261141cc406Sopenharmony_ci			_UIO( usbio_ReadReg( handle, 2, &data ));
262141cc406Sopenharmony_ci		}
263141cc406Sopenharmony_ci
264141cc406Sopenharmony_ci		if( reg != 7 )
265141cc406Sopenharmony_ci			return SANE_TRUE;
266141cc406Sopenharmony_ci
267141cc406Sopenharmony_ci		/* verify register 7 */
268141cc406Sopenharmony_ci		_UIO( usbio_ReadReg( handle, 7, &data ));
269141cc406Sopenharmony_ci		if( data == value ) {
270141cc406Sopenharmony_ci			return SANE_TRUE;
271141cc406Sopenharmony_ci		}
272141cc406Sopenharmony_ci	}
273141cc406Sopenharmony_ci
274141cc406Sopenharmony_ci	return SANE_FALSE;
275141cc406Sopenharmony_ci}
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci/** try and read register 0x69 from a LM983x to find out which version we have.
278141cc406Sopenharmony_ci */
279141cc406Sopenharmony_cistatic SANE_Status usbio_DetectLM983x( SANE_Int fd, SANE_Byte *version )
280141cc406Sopenharmony_ci{
281141cc406Sopenharmony_ci	char        buf[256];
282141cc406Sopenharmony_ci	SANE_Byte   value;
283141cc406Sopenharmony_ci	SANE_Status res;
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ci	DBG( _DBG_INFO, "usbio_DetectLM983x\n");
286141cc406Sopenharmony_ci
287141cc406Sopenharmony_ci	res = usbio_ReadReg(fd, 0x69, &value);
288141cc406Sopenharmony_ci	if( res != SANE_STATUS_GOOD ) {
289141cc406Sopenharmony_ci		DBG( _DBG_ERROR, " * could not read version register!\n");
290141cc406Sopenharmony_ci		return res;
291141cc406Sopenharmony_ci	}
292141cc406Sopenharmony_ci
293141cc406Sopenharmony_ci	value &= 7;
294141cc406Sopenharmony_ci	if (version)
295141cc406Sopenharmony_ci		*version = value;
296141cc406Sopenharmony_ci
297141cc406Sopenharmony_ci	res = SANE_STATUS_GOOD;
298141cc406Sopenharmony_ci
299141cc406Sopenharmony_ci	sprintf( buf, "usbio_DetectLM983x: found " );
300141cc406Sopenharmony_ci
301141cc406Sopenharmony_ci	switch((SANE_Int)value ) {
302141cc406Sopenharmony_ci
303141cc406Sopenharmony_ci		case 4:	 strcat( buf, "LM9832/3" ); break;
304141cc406Sopenharmony_ci		case 3:	 strcat( buf, "LM9831" );   break;
305141cc406Sopenharmony_ci		case 2:	 strcat( buf, "LM9830 --> unsupported!!!" );
306141cc406Sopenharmony_ci				 res =  SANE_STATUS_INVAL;
307141cc406Sopenharmony_ci				 break;
308141cc406Sopenharmony_ci		default: DBG( _DBG_INFO, "Unknown chip v%d", value );
309141cc406Sopenharmony_ci				 res = SANE_STATUS_INVAL;
310141cc406Sopenharmony_ci				 break;
311141cc406Sopenharmony_ci	}
312141cc406Sopenharmony_ci
313141cc406Sopenharmony_ci	DBG( _DBG_INFO, "%s\n", buf );
314141cc406Sopenharmony_ci	return res;
315141cc406Sopenharmony_ci}
316141cc406Sopenharmony_ci
317141cc406Sopenharmony_ci/** well, this is more or less a reset function, for LM9831 based devices
318141cc406Sopenharmony_ci * we issue a real reset command, while for LM9832/3 based devices, checking
319141cc406Sopenharmony_ci * and resetting register 7 will be enough...
320141cc406Sopenharmony_ci */
321141cc406Sopenharmony_cistatic SANE_Status usbio_ResetLM983x( Plustek_Device *dev )
322141cc406Sopenharmony_ci{
323141cc406Sopenharmony_ci	SANE_Byte value;
324141cc406Sopenharmony_ci	HWDef    *hw = &dev->usbDev.HwSetting;
325141cc406Sopenharmony_ci
326141cc406Sopenharmony_ci	if( _LM9831 == hw->chip ) {
327141cc406Sopenharmony_ci
328141cc406Sopenharmony_ci		DBG( _DBG_INFO," * resetting LM9831 device!\n");
329141cc406Sopenharmony_ci		_UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0));
330141cc406Sopenharmony_ci		_UIO( sanei_lm983x_write_byte( dev->fd, 0x07,0x20));
331141cc406Sopenharmony_ci		_UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0));
332141cc406Sopenharmony_ci		_UIO( usbio_ReadReg( dev->fd, 0x07, &value));
333141cc406Sopenharmony_ci		if (value != 0) {
334141cc406Sopenharmony_ci 			DBG( _DBG_ERROR, "usbio_ResetLM983x: reset was not "
335141cc406Sopenharmony_ci			                 "successful, status=%d\n", value );
336141cc406Sopenharmony_ci			return SANE_STATUS_INVAL;
337141cc406Sopenharmony_ci		}
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci	} else {
340141cc406Sopenharmony_ci		_UIO( usbio_ReadReg( dev->fd, 0x07, &value));
341141cc406Sopenharmony_ci		if (value != 0 ) {
342141cc406Sopenharmony_ci			DBG( _DBG_INFO," * setting device to idle state!\n");
343141cc406Sopenharmony_ci			_UIO( sanei_lm983x_write_byte( dev->fd, 0x07, 0));
344141cc406Sopenharmony_ci		}
345141cc406Sopenharmony_ci	}
346141cc406Sopenharmony_ci	return SANE_STATUS_GOOD;
347141cc406Sopenharmony_ci}
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_ci/* END PLUSTEK-USBIO.C ......................................................*/
350