1 /* @file plustek-pp_p48xx.c
2  * @brief here we have all functionality according to the ASIC96001/3 based
3  *        models.
4  *
5  * based on sources acquired from Plustek Inc.
6  * Copyright (C) 1998 Plustek Inc.
7  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
8  * also based on the work done by Rick Bronson
9  *
10  * History:
11  * - 0.30 - initial version
12  * - 0.31 - fixed a bug for the return value in p48xxDoTest
13  *        - added additional debug messages
14  *        - added function p48xxCheck4800Memory
15  * - 0.32 - added debug messages
16  *        - fixed a bug in p48xxDoTest
17  *        - disabled RD_WatchDogControl, lamp will be controlled by driver
18  * - 0.33 - added function p48xxSetAsicRegisters()
19  *        - fixed a bug in p48xxDoTest (reset the ASIC registers)
20  *        - removed p48xxPositionLamp
21  * - 0.34 - added some comments
22  * - 0.35 - added some comments
23  * - 0.36 - added function p48xxInitAllModules() to allow reinit of the modules
24  *        - switching from Full- to Halfstep at ps->PhysicalDpi now in
25  *        - p48xxSetGeneralRegister
26  *        - fixed the color-inverse problem for model OP4800
27  * - 0.37 - move p48xxOpenScanPath, p48xxCloseScanPath
28  *          and p48xxRegisterToScanner to io.c
29  *        - removed // comments
30  *        - added override for A3I scanner
31  * - 0.38 - added function p48xxPutToIdleMode()
32  *        - added function p48xxCalibration
33  * - 0.39 - added A3I stuff
34  * - 0.40 - disabled A3I stuff
35  * - 0.41 - no changes
36  * - 0.42 - changed include names
37  * - 0.43 - no changes
38  * - 0.44 - fix format string issues, as Long types default to int32_t
39  *          now
40  * .
41  * <hr>
42  * This file is part of the SANE package.
43  *
44  * This program is free software; you can redistribute it and/or
45  * modify it under the terms of the GNU General Public License as
46  * published by the Free Software Foundation; either version 2 of the
47  * License, or (at your option) any later version.
48  *
49  * This program is distributed in the hope that it will be useful, but
50  * WITHOUT ANY WARRANTY; without even the implied warranty of
51  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
52  * General Public License for more details.
53  *
54  * You should have received a copy of the GNU General Public License
55  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
56  *
57  * As a special exception, the authors of SANE give permission for
58  * additional uses of the libraries contained in this release of SANE.
59  *
60  * The exception is that, if you link a SANE library with other files
61  * to produce an executable, this does not by itself cause the
62  * resulting executable to be covered by the GNU General Public
63  * License.  Your use of that executable is in no way restricted on
64  * account of linking the SANE library code into it.
65  *
66  * This exception does not, however, invalidate any other reasons why
67  * the executable file might be covered by the GNU General Public
68  * License.
69  *
70  * If you submit changes to SANE to the maintainers to be included in
71  * a subsequent release, you agree by submitting the changes that
72  * those changes may be distributed with this exception intact.
73  *
74  * If you write modifications of your own for SANE, it is your choice
75  * whether to permit this exception to apply to your modifications.
76  * If you do not wish that, delete this exception notice.
77  * <hr>
78  */
79 #include "plustek-pp_scan.h"
80 
81 /*************************** some definitions ********************************/
82 
83 #define _TEST_SZ   2048  	  /* always use 2048 for mem size (= one bank)   */
84 #define _START_VAL 0x12345678 /* pick a non-zero starting value for our long */
85 
86 #define _BankAndSizeForTest	_MemBankSize2k  /* always use 2k for mem test */
87 
88 /*************************** local functions *********************************/
89 
90 /*.............................................................................
91  * 1) Set asic to PROGRAM mode
92  * 2) Select the memory bank and size
93  * 3) Initiate data fifo
94  */
p48xxSetMemoryBankForProgram(pScanData ps,Byte bBankAndSize)95 static void p48xxSetMemoryBankForProgram( pScanData ps , Byte bBankAndSize )
96 {
97 	/* enter program mode */
98 	IODataToRegister( ps, ps->RegModeControl, _ModeProgram );
99 
100 	/* bank and size */
101     IODataToRegister( ps, ps->RegMemAccessControl, bBankAndSize );
102 
103 	/* initiate data fifo */
104     IORegisterToScanner( ps, ps->RegInitDataFifo );
105 }
106 
107 /*.............................................................................
108  * use the internal memory of a scanner to find the model
109  */
p48xxDoTest(pScanData ps)110 static int p48xxDoTest( pScanData ps )
111 {
112 	UChar  tmpByte;
113 	int	   retval;
114 	ULong  adder, ul, cntr;
115 	pULong buffer;
116 
117 	DBG( DBG_LOW, "p48xxDoTest()\n" );
118 
119 	buffer = _KALLOC( sizeof(UChar) *  _TEST_SZ, GFP_KERNEL );
120 	if( NULL == buffer )
121 		return _E_ALLOC;
122 
123 	retval = _E_NO_DEV;
124 
125 	/*
126 	 * do a memory test to determine how much memory this unit has, in the
127      * process we can figure out if it's a 4830 or a 9630.  NOTE: the ram
128      * seems to be mirrored such that if you have a unit with only 32k it's
129      * mirrored 4 times to fill the 128k (2k * (_MemBankMask + 1)) space,
130      * so we will run a 32 bit incrementing pattern over the entire 128k and
131      * look for the 1st page (2k) to fail
132   	 */
133  	adder = 0;
134     for (cntr = _BankAndSizeForTest;
135          cntr < _BankAndSizeForTest + _MemBanks; cntr++) {
136 
137     	ps->OpenScanPath( ps );
138 
139 		p48xxSetMemoryBankForProgram( ps, cntr );
140 
141 		/* prepare content, incrementing 32 val */
142    		for (ul = 0; ul < _TEST_SZ / sizeof(ULong); ul++)
143        		buffer[ul] = ul + adder + _START_VAL;
144 
145 		/* fill to buffer */
146    		IOMoveDataToScanner( ps, (pUChar)buffer, _TEST_SZ );
147 
148    		/*
149  		 * now check bank 0 to see if it got overwritten
150 		 * bank 0, size 2k
151 		 */
152 		p48xxSetMemoryBankForProgram( ps, _BankAndSizeForTest );
153 
154     	ps->CloseScanPath( ps );
155 
156 		/* read data back */
157    		IOReadScannerImageData( ps, (pUChar)buffer, _TEST_SZ );
158 
159 		/* check */
160    		for (ul = 0; ul < _TEST_SZ / sizeof(ULong); ul++) {
161       		if (buffer[ul] != ul + _START_VAL) {
162        			break;
163 			}
164 		}
165 
166 		/* if fail 	*/
167    		if (ul != _TEST_SZ / sizeof (ULong)) {
168 			DBG( DBG_LOW, "Bank 0 overwritten\n" );
169        		break;
170 		}
171 
172    		/* now check current bank */
173     	ps->OpenScanPath( ps );
174 		p48xxSetMemoryBankForProgram( ps, cntr );
175     	ps->CloseScanPath( ps );
176 
177 		/* read data back */
178    		IOReadScannerImageData( ps, (pUChar)buffer, _TEST_SZ);
179 
180 		/* check if fail */
181    		for( ul = 0; ul < _TEST_SZ / sizeof(ULong); ul++ ) {
182        		if( buffer[ul] != ul + adder + _START_VAL )
183        			break;
184 		}
185 
186 		/* check if fail */
187    		if (ul != _TEST_SZ / sizeof(ULong)) {
188 			DBG( DBG_LOW, "Bank not present, error at pos %u (%u)\n", ul,
189 				 (ULong)(_TEST_SZ / sizeof(ULong)));
190        		break;
191 		}
192 
193    		adder += _TEST_SZ / sizeof(ULong);
194    	}
195 
196 	_KFREE( buffer );
197 
198 	DBG( DBG_LOW, "found %d bytes of memory\n",
199 					_TEST_SZ * (cntr - _BankAndSizeForTest));
200 
201 	if( cntr == _BankAndSizeForTest ) {
202 		DBG( DBG_LOW, "No memory ! No scanner...\n" );
203 		return retval;
204 	}
205 
206 #ifdef DEBUG
207 	tmpByte = IODataRegisterFromScanner( ps, 0x18 );
208 	DBG( DBG_LOW, "tmpByte[0x18] = 0x%02x\n",tmpByte );
209 #endif
210 
211 	tmpByte = IODataRegisterFromScanner( ps, 0x0e );
212 	DBG( DBG_LOW, "tmpByte = 0x%02x, cntr = %u, AsicId = 0x%02x\n",
213 				   tmpByte, cntr, ps->sCaps.AsicID );
214 
215 	/* 128k */
216     if ((_TEST_SZ * (cntr - _BankAndSizeForTest) == 1 << 17) &&
217 								       (ps->sCaps.AsicID ==  _ASIC_IS_96003)) {
218 
219         /*
220 		 * if 128k then must be a 9630 or above
221 		 * hack, test for 12000P, The 9630 returns an 0x08
222 		 */
223        	if ( tmpByte == 0x02 ) {
224 
225             /*
226              * as we currently can't automagically detect an A3I we have to
227              * use the override switch
228              */
229             if( _OVR_PLUSTEK_A3I == ps->ModelOverride ) {
230 
231         		DBG( DBG_LOW, "Model Override --> A3I\n" );
232     			ModelSetA3I( ps );
233             } else {
234             	ModelSet12000( ps );
235 	    		DBG( DBG_LOW, "It seems we have a 12000P/96000P\n" );
236             }
237 
238 		}  	else {
239         	ModelSet9630( ps );
240 			DBG( DBG_LOW, "It seems we have a 9630\n" );
241 		}
242 
243 		retval = _OK;
244 
245 	} else {
246 
247 		DBG( DBG_LOW, "Scanner is not a 9630 or above\n");
248 
249       	if ( tmpByte != 0x0f  ) {
250 
251 			DBG( DBG_LOW, "Looks like a 600!\n" );
252 
253 			if (( 0x08 == tmpByte ) &&
254 				((_TEST_SZ * (cntr - _BankAndSizeForTest)) == 32768 )) {
255 	       		DBG( DBG_LOW, "But it is a 4830P!!! "
256 							  "(by mkochano@ee.pw.edu.pl)\n" );
257 				ModelSet4830( ps );
258           	} else {
259           		ModelSet600( ps );
260 			}
261 		}
262 #ifdef DEBUG
263 		else
264 			DBG( DBG_LOW, "It seems we have a 4830\n" );
265 #endif
266 
267 		retval = _OK;
268 	}
269 
270 	return retval;
271 }
272 
273 /*.............................................................................
274  * setup ASIC registers and clear all scan states (no stepping)
275  */
p48xxSetAsicRegisters(pScanData ps)276 static void p48xxSetAsicRegisters( pScanData ps )
277 {
278 	memset( &ps->AsicReg,   0, sizeof(ps->AsicReg));
279 	memset( &ps->Asic96Reg, 0, sizeof(ps->Asic96Reg));
280     memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES );
281 
282    	ps->AsicReg.RD_LineControl       = ps->TimePerLine;
283    	ps->AsicReg.RD_ScanControl       = _SCAN_LAMP_ON;
284    	ps->AsicReg.RD_ModelControl      = ps->Device.ModelCtrl | _ModelWhiteIs0;
285    	ps->AsicReg.RD_Origin 	   	     = 0;
286    	ps->AsicReg.RD_Pixels 	   	     = 5110; /*ps->RdPix;*/
287    	ps->Asic96Reg.RD_MotorControl    = 0;
288    	ps->Asic96Reg.RD_WatchDogControl = 0; /* org. val = 0x8f; */
289 
290 	IOPutOnAllRegisters( ps );
291 }
292 
293 /*.............................................................................
294  * use the internal memory of a scanner to find the model
295  */
p48xxCheck4800Memory(pScanData ps)296 static int p48xxCheck4800Memory( pScanData ps )
297 {
298 	int	   retval;
299 	ULong  ul;
300 	pUChar buffer;
301 
302 	DBG( DBG_LOW, "p48xxCheck4800Memory()\n" );
303 
304 	buffer = _KALLOC( 2560, GFP_KERNEL ); /* 1280: Read,1280:Write */
305 	if( NULL == buffer )
306 		return _E_ALLOC;
307 
308 	retval = _OK;
309 
310 	/* bank 0, size 2k */
311 	ps->OpenScanPath( ps );
312 	p48xxSetMemoryBankForProgram( ps, _BankAndSizeForTest );
313 
314 	for (ul = 0; ul < 1280; ul++)
315 	    buffer[ul] = (UChar)ul;			      /* prepare content */
316 
317 	IOMoveDataToScanner( ps, buffer, 1280 );  /* fill to buffer  */
318 	p48xxSetMemoryBankForProgram( ps, _BankAndSizeForTest );
319 	ps->CloseScanPath( ps );
320 
321 	/* read data back */
322 	IOReadScannerImageData( ps, buffer + 1280, 1280 );
323 
324 	for( ul = 0; ul < 1280; ul++ ) {
325 		if( buffer[ul] != buffer[ul+1280] ) {
326 			DBG( DBG_HIGH, "Error in memory test at pos %u (%u != %u)\n",
327 							 ul, buffer[ul], buffer[ul+1280] );
328 			retval = _E_NO_DEV;
329 			break;
330 		}
331 	}
332 
333 	_KFREE(buffer);
334 
335     return retval;
336 }
337 
338 /*.............................................................................
339  * call all other modules, to initialize themselves
340  */
p48xxInitAllModules(pScanData ps)341 static int p48xxInitAllModules( pScanData ps )
342 {
343 	int result;
344 
345 	result = DacInitialize( ps );
346 	if( _OK != result )
347 		return result;
348 
349 	result = ImageInitialize( ps );
350 	if( _OK != result )
351 		return result;
352 
353 	result = IOFuncInitialize( ps );
354 	if( _OK != result )
355 		return result;
356 
357 	result = IOInitialize( ps );
358 	if( _OK != result )
359 		return result;
360 
361 	result = MotorInitialize( ps );
362 	if( _OK != result )
363 		return result;
364 
365 	/*
366 	 * in debug version, check all function pointers
367 	 */
368 #ifdef DEBUG
369 	if(	_FALSE == MiscAllPointersSet( ps ))
370 		return _E_INTERNAL;
371 #endif
372 	return _OK;
373 }
374 
375 /*.............................................................................
376  *
377  */
p48xxReadWriteTest(pScanData ps)378 static int p48xxReadWriteTest( pScanData ps )
379 {
380 	int retval;
381 
382 	DBG( DBG_LOW, "p48xxReadWriteTest()\n" );
383 
384 	/*
385      * determine the model by the ASIC type (except for 4830/9630)
386      * might want to make a SetModelCommon() someday for this...
387    	 */
388 	ps->RedDataReady   = 0x01;  /* normal for Red and Green */
389   	ps->GreenDataReady = 0x02;
390 	ps->AsicRedColor   = 0x01;
391 	ps->AsicGreenColor = 0x03;
392 
393 	/*
394  	 * if not already set, try to find ASIC type (96001 or 96003)
395 	 */
396   	if ( _NO_BASE == ps->sCaps.wIOBase ) {
397 
398 		/* get copy of asic id */
399 	    ps->sCaps.AsicID = IODataRegisterFromScanner( ps, ps->RegAsicID );
400 
401     	if ( _ASIC_IS_96003 == ps->sCaps.AsicID ) {
402 
403 			/* actually either a 4830, 9630, 12000, find out later */
404        		DBG( DBG_LOW, "Found a 96003 ASIC at Reg 0x%x\n", ps->RegAsicID );
405       		ModelSet4830( ps );
406 
407     	} else {
408 
409       		if ( _ASIC_IS_96001 == ps->sCaps.AsicID ) {
410 	       		DBG( DBG_LOW, "Found a 96001 ASIC at Reg 0x%x\n",
411 															   ps->RegAsicID );
412         		ModelSet4800( ps );
413       		} else {
414         		DBG( DBG_LOW, "Can't find your model, asic = 0x%x\n",
415 														    ps->sCaps.AsicID );
416         		return _E_NO_ASIC;
417         	}
418 		}
419     }
420 
421 	/*
422 	 * set the registers according to the assumptions above
423 	 */
424 	p48xxSetAsicRegisters( ps );
425 
426    	if ( _ASIC_IS_96003 == ps->sCaps.AsicID ) {
427 		retval = p48xxDoTest( ps );
428 
429 		/*
430 		 * as we may now have detected another model, we have to set
431 		 * the registers to their new values...
432 		 * and maybe the modules have to be reset as well
433 		 */
434 		if( _OK == retval ) {
435 			p48xxSetAsicRegisters( ps );
436 			retval = p48xxInitAllModules( ps );
437 		}
438 
439 		return retval;
440 	}
441 
442 	/*
443 	 * this part will be reached only for the 4800 - ASIC 96001
444      * we check only the memory as the original driver does
445 	 */
446 	return p48xxCheck4800Memory( ps );
447 }
448 
449 /*.............................................................................
450  * 1) Setup the registers of asic.
451  * 2) Determine which type of CCD we are using
452  * 3) According to the CCD, prepare the CCD dependent veriables
453  *  SONY CCD:
454  *	The color exposure sequence: Red, Green (after 11 red lines),
455  *	Blue (after 8 green lines)
456  *  TOSHIBA CCD:
457  *  The color exposure sequence: Red, Blue (after 11 red lines),
458  *	Green (after 8 blue lines)
459  */
p48xxSetupScannerVariables(pScanData ps)460 static void p48xxSetupScannerVariables( pScanData ps )
461 {
462 	UChar    tmp;
463 	TimerDef timer;
464 
465 	DBG( DBG_LOW, "p48xxSetupScannerVariables()\n" );
466 
467     ps->OpenScanPath( ps );
468 
469 	IODataToRegister( ps, ps->RegModelControl2, _Model2ChannelMult );
470 
471     if( 2 == IODataFromRegister( ps, ps->RegWriteIOBusDecode1 )) {
472 
473 		DBG( DBG_LOW, "Scanner has 97003 ASIC too.\n" );
474 		ps->f97003 = _TRUE;
475 		ps->b97003DarkR = 8;
476 		ps->b97003DarkG = 8;
477 		ps->b97003DarkB = 8;
478 
479 	    ps->Asic96Reg.u26.RD_ModelControl2 = _Model2ChannelMult;
480 	} else {
481 
482 		DBG( DBG_LOW, "No ASIC 97003 found.\n" );
483 		ps->f97003 = _FALSE;
484 	    ps->Asic96Reg.u26.RD_ModelControl2 = _Model2DirectOutPort;
485 	}
486 
487 	IODataToRegister( ps, ps->RegModelControl2,
488 				  	  ps->Asic96Reg.u26.RD_ModelControl2 );
489 
490 	tmp = IODataFromRegister( ps, ps->RegStatus );
491 	DBG( DBG_LOW, "Status-Register = 0x%02X\n", tmp );
492 #ifdef DEBUG
493 	if( tmp & _FLAG_P96_MOTORTYPE ) {
494 		DBG( DBG_LOW, "Scanner has Full/Half Stepping drive\n" );
495 	} else {
496 		DBG( DBG_LOW, "Scanner has Micro Stepping drive\n" );
497 	}
498 #endif
499 
500     if( tmp & _FLAG_P96_CCDTYPE) {
501 		ps->fSonyCCD = _FALSE;
502 		DBG( DBG_LOW, "CCD is NEC/TOSHIBA Type\n" );
503 	} else {
504 		ps->fSonyCCD = _TRUE;
505 		DBG( DBG_LOW, "CCD is SONY Type\n" );
506 	}
507 
508     ps->CloseScanPath( ps );
509 
510     ps->b1stColorByte = ps->AsicRedColor;
511     ps->b1stColor 	  = ps->RedDataReady;
512 
513 	if (ps->fSonyCCD) {
514 
515 		ps->b2ndColorByte = ps->AsicGreenColor;
516 		ps->b2ndColor 	  = ps->GreenDataReady;
517 		ps->b3rdColorByte = _ASIC_BLUECOLOR;
518 		ps->b3rdColor 	  = _BLUE_DATA_READY;
519 
520 	}  else  { /* NEC/Toshiba CCD */
521 
522 		ps->b2ndColorByte = _ASIC_BLUECOLOR;
523 		ps->b2ndColor 	  = _BLUE_DATA_READY;
524 		ps->b3rdColorByte = ps->AsicGreenColor;
525 		ps->b3rdColor 	  = ps->GreenDataReady;
526 	}
527 
528     ps->b1stMask = (Byte)~ps->b1stColor;
529     ps->b2ndMask = (Byte)~ps->b2ndColor;
530 	ps->b3rdMask = (Byte)~ps->b3rdColor;
531 
532     ps->b1stLinesOffset = 17;
533     ps->b2ndLinesOffset = 9;
534 
535     /*
536 	 * calculate I/O Timer
537      * if we cannot read 200 lines within 1 second, the I/O time has to add 2
538      * CalculateIOTime ()
539 	 */
540     if( _PORT_SPP != ps->IO.portMode ) {
541 
542 		UShort wLines = 200;
543 		pUChar pBuf;
544 
545 		pBuf = _KALLOC((_BUF_SIZE_BASE_CONST * 2), GFP_KERNEL );
546 
547 		if ( NULL != pBuf ) {
548 
549 			MiscStartTimer( &timer, _SECOND );
550 
551 		    do {
552 				IOReadScannerImageData( ps, pBuf, (_BUF_SIZE_BASE_CONST * 2));
553 
554 				wLines--;
555 		    } while (!MiscCheckTimer( &timer) && wLines);
556 
557 		    if( !wLines )
558 				ps->bExtraAdd = 0;
559 		    else
560 				ps->bExtraAdd = 2;
561 
562 			_KFREE( pBuf );
563 
564 		} else {
565 	    	ps->bExtraAdd = 2;	/* poor resource */
566 		}
567 	} else {
568 		ps->bExtraAdd = 0;
569 	}
570 }
571 
572 /*.............................................................................
573  *
574  */
p48xxSetGeneralRegister(pScanData ps)575 static void p48xxSetGeneralRegister( pScanData ps )
576 {
577 	if( MODEL_OP_A3I == ps->sCaps.Model ) {
578 		ps->AsicReg.RD_ModelControl = _ModelDpi400 | _ModelWhiteIs0 |
579 									  _ModelMemSize128k4;
580     }
581 
582     ps->AsicReg.RD_ModeControl = _ModeScan;
583 
584 /* WORK: ps->PhysicalDpi should be correct, but the we have to work
585  *       on motor.c again to use other running-tables
586  *    if ( ps->DataInf.xyAppDpi.y <= ps->PhysicalDpi ) {
587  */
588 	if ( ps->DataInf.xyAppDpi.y <= 300 ) {
589 /* HEINER:A3I
590  	if ( ps->DataInf.xyAppDpi.y <= ps->PhysicalDpi ) {
591 */
592 		ps->Asic96Reg.RD_MotorControl = (ps->FullStep | ps->IgnorePF |
593 									     ps->MotorOn | _MotorDirForward);
594 	} else {
595 		ps->Asic96Reg.RD_MotorControl = (ps->IgnorePF | ps->MotorOn |
596 										 _MotorDirForward);
597 	}
598 
599     if ( ps->DataInf.wPhyDataType == COLOR_BW ) {
600         ps->AsicReg.RD_ScanControl = ps->bLampOn;
601 
602 	    if (!(ps->DataInf.dwScanFlag & SCANDEF_Inverse))
603     	    ps->AsicReg.RD_ScanControl |= _P96_SCANDATA_INVERT;
604 
605     } else {
606 
607         ps->AsicReg.RD_ScanControl = ps->bLampOn | _SCAN_BYTEMODE;
608 
609 	    if (ps->DataInf.dwScanFlag & SCANDEF_Inverse)
610     	    ps->AsicReg.RD_ScanControl |=  _P96_SCANDATA_INVERT;
611     }
612 
613     if (ps->DataInf.xyPhyDpi.x <= 200)
614         ps->AsicReg.RD_ScanControl |= _SCAN_1ST_AVERAGE;
615 
616 	DBG( DBG_LOW, "RD_ModeControl  = 0x%02x\n", ps->AsicReg.RD_ModeControl  );
617 	DBG( DBG_LOW, "RD_MotorControl = 0x%02x\n", ps->Asic96Reg.RD_MotorControl );
618 	DBG( DBG_LOW, "RD_ScanControl  = 0x%02x\n", ps->AsicReg.RD_ScanControl  );
619 }
620 
621 /*.............................................................................
622  *
623  */
p48xxSetupScanningCondition(pScanData ps)624 static void p48xxSetupScanningCondition( pScanData ps )
625 {
626 	DBG( DBG_LOW, "p48xxSetupScanningCondition()\n" );
627 
628 	IORegisterDirectToScanner( ps, ps->RegInitDataFifo );
629 
630    /* Cal64kTime (); */
631 	if( MODEL_OP_A3I == ps->sCaps.Model )
632 	    ps->wLinesPer64kTime = (UShort)(65555UL / ps->DataInf.dwAsicBytesPerPlane *
633 				 			        5UL);
634     else
635 	    ps->wLinesPer64kTime = (UShort)(65555UL / ps->DataInf.dwAsicBytesPerPlane *
636 				 			        10UL / 3UL);
637 
638 	DBG( DBG_LOW, "wLinesPer64kTime = %u\n", ps->wLinesPer64kTime );
639 
640     ps->InitialSetCurrentSpeed( ps );
641 
642 	DBG( DBG_LOW, "Current Speed = %u\n", ps->bCurrentSpeed );
643 
644     ps->bMinReadFifo = (Byte)((ps->DataInf.dwAsicBytesPerPlane + 511) / 512);
645 	DBG( DBG_LOW, "MinReadFifo = %u\n", ps->bMinReadFifo );
646 
647     p48xxSetGeneralRegister( ps );
648 
649 	/*
650 	 * if speed is not the fastest and DPI is less than 400, do half steps
651 	 */
652     if( ps->DataInf.wPhyDataType >= COLOR_256GRAY &&
653 		!(ps->bCurrentSpeed & 1) && (ps->DataInf.xyAppDpi.y <= 300)) {
654 /* HEINER:A3I
655 	if( !(ps->bCurrentSpeed & 1) && (ps->DataInf.xyAppDpi.y <= ps->PhysicalDpi)) {
656 */
657 		ps->fHalfStepTableFlag = _TRUE;
658 		ps->Asic96Reg.RD_MotorControl &= ps->StepMask;
659     }
660 
661     ps->AsicReg.RD_Dpi = ps->DataInf.xyPhyDpi.x;
662 	DBG( DBG_LOW, "RD_Dpi = %u\n", ps->AsicReg.RD_Dpi );
663 
664     /* SetStartStopRegister (ps) */
665     ps->AsicReg.RD_Origin = (UShort)(ps->Offset70 + ps->Device.DataOriginX +
666 					                 ps->DataInf.crImage.x);
667 
668     if (ps->DataInf.wPhyDataType < COLOR_256GRAY) {
669 		ps->AsicReg.RD_Pixels =
670 					(UShort)(ps->DataInf.dwAsicPixelsPerPlane + 7) & 0xfff8;
671 	} else {
672 		ps->AsicReg.RD_Pixels = (UShort)ps->DataInf.dwAsicPixelsPerPlane;
673 	}
674 
675 	DBG( DBG_LOW, "RD_Pixels = %u\n", ps->AsicReg.RD_Pixels );
676 
677     /* SetupMotorStart () */
678 	IORegisterDirectToScanner( ps, ps->RegInitDataFifo);
679     ps->SetupMotorRunTable( ps );
680 
681     IOSetToMotorRegister( ps );
682 
683     ps->pCurrentColorRunTable = ps->pColorRunTable;
684     ps->bCurrentLineCount = 0;
685 
686     IOPutOnAllRegisters( ps );
687 
688     ps->OpenScanPath( ps );
689 
690 	/*
691 	 * when using the full-step speed on 600 dpi models, then set
692 	 * the motor into half-step mode, to avoid that the scanner hits
693 	 * the back of its cover
694 	 */
695    	if((600 == ps->PhysicalDpi) && (1 == ps->bCurrentSpeed)) {
696 
697 		ps->Asic96Reg.RD_MotorControl &= ~ps->FullStep;
698 	}
699 
700  	IODataToRegister( ps, ps->RegMotorControl,
701 					    (Byte)(ps->Asic96Reg.RD_MotorControl & ~ps->MotorOn));
702 	IODataToRegister( ps, ps->RegMotorControl, ps->Asic96Reg.RD_MotorControl);
703     IORegisterToScanner( ps, ps->RegInitDataFifo );
704 
705     ps->CloseScanPath( ps );
706 }
707 
708 /*.............................................................................
709  * switch the motor off and put the scanner into idle mode
710  */
p48xxPutToIdleMode(pScanData ps)711 static void p48xxPutToIdleMode( pScanData ps )
712 {
713     DBG( DBG_LOW, "Putting Scanner (ASIC 96001/3) into Idle-Mode\n" );
714 
715     /*
716      * turn off motor
717      */
718 	ps->Asic96Reg.RD_MotorControl = 0;
719 	IOCmdRegisterToScanner( ps, ps->RegMotorControl, 0 );
720 }
721 
722 /*.............................................................................
723  * for P96001/3 ASIC
724  * do all the preliminary stuff here (calibrate the scanner and move the
725  * sensor to it´s start position, also setup the driver for the
726  * current run)
727  */
p48xxCalibration(pScanData ps)728 static int p48xxCalibration( pScanData ps )
729 {
730 	DBG( DBG_LOW, "p48xxCalibration()\n" );
731 
732     ps->Scan.bFifoSelect = ps->RegGFifoOffset;
733 
734 	while (_TRUE) {
735 
736 		_ASSERT(ps->WaitForShading);
737         if (ps->WaitForShading( ps )) {
738 
739         	if(!(ps->DataInf.dwScanFlag & SCANDEF_TPA)) {
740 
741 /* HEINER:A3I disable !! */
742 	               	MotorP96AheadToDarkArea( ps );
743 
744                     if( ps->Scan.fRefreshState ) {
745                         ps->Scan.fRefreshState = _FALSE;
746 
747           			if (!ps->fReshaded) {
748                         ps->fReshaded = _TRUE;
749 
750     	    		    if (ps->fColorMoreRedFlag || ps->fColorMoreBlueFlag) {
751            					continue;
752 						}
753     	            }
754 	    	  	}
755 	   		}
756 			break;
757 
758 	    } else {
759         	ps->fScanningStatus = _FALSE;
760         	ps->DataInf.dwAppLinesPerArea = 0;
761         	return _E_TIMEOUT;
762 	    }
763 	}
764 
765    	if((ps->sCaps.AsicID != _ASIC_IS_96001) &&
766 							       (ps->DataInf.wPhyDataType != COLOR_BW)) {
767 		DacP96WriteBackToGammaShadingRAM(ps);
768 	}
769 
770 	if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) {
771        	ps->bExtraMotorCtrl     = 0;
772     	ps->Scan.fMotorBackward = _TRUE;
773        	MotorP96ConstantMoveProc( ps, 4000 );
774 	}
775 
776 	/*
777 	 * move sensor and setup scanner for grabbing the picture
778 	 */
779 	_ASSERT(ps->WaitForPositionY);
780    	ps->WaitForPositionY(ps);
781 	return _OK;
782 }
783 
784 /************************ exported functions *********************************/
785 
786 /*.............................................................................
787  * initialize the register values and function calls for the 96001/3 asic
788  */
P48xxInitAsic(pScanData ps)789 _LOC int P48xxInitAsic( pScanData ps )
790 {
791 	DBG( DBG_LOW, "P48xxInitAsic()\n" );
792 
793 	ps->IO.bOpenCount = 0;
794 
795 	ps->RegSwitchBus			= 0;
796 	ps->RegReadDataMode			= 1;
797 	ps->RegWriteDataMode		= 2;
798 	ps->RegEPPEnable			= 3;
799 	ps->RegInitDataFifo			= 4;
800 	ps->RegForceStep			= 5;
801 	ps->RegInitScanState		= 6;
802 	ps->RegRefreshScanState		= 7;
803 	ps->RegStatus				= 0x10;
804 	ps->RegFifoOffset			= 0x11;
805 	ps->RegGetScanState			= 0x12;
806 	ps->RegAsicID				= 0x13;	/* Determine the asic */
807 	ps->RegReadIOBufBus			= 0x17;
808 	ps->RegModeControl			= 0x18;
809 	ps->RegLineControl			= 0x19;
810 	ps->RegScanControl			= 0x1a;
811 	ps->RegMotorControl			= 0x1b;
812 	ps->RegModelControl			= 0x1c;
813 	ps->RegMemAccessControl		= 0x1d;
814 	ps->RegDpiLow				= 0x1e;
815 	ps->RegDpiHigh				= 0x1f;
816 	ps->RegScanPosLow			= 0x20;
817 	ps->RegScanPosHigh			= 0x21;
818 	ps->RegWidthPixelsLow		= 0x22;
819 	ps->RegWidthPixelsHigh		= 0x23;
820 	ps->RegThresholdControl		= 0x24;
821 	ps->RegWatchDogControl		= 0x25;
822 	ps->RegModelControl2		= 0x26;
823 	ps->RegThresholdGapControl	= 0x27;
824 	ps->RegRedChShadingOffset   = 0x28;
825 	ps->RegGreenChShadingOffset = 0x29;
826 	ps->RegRedDCAdjust			= 0x27;  /* not sure why these are dup's */
827 	ps->RegGreenDCAdjust		= 0x28;
828 	ps->RegBlueDCAdjust			= 0x29;
829 	ps->RegBlueChShadingOffset	= 0x2a;
830 	ps->RegRedChDarkOffset		= 0x2b;
831 	ps->RegGreenChDarkOffset	= 0x2c;
832 	ps->RegBlueChDarkOffset		= 0x2d;
833 	ps->RegWriteIOBusDecode1	= 0x2e;
834 	ps->RegWriteIOBusDecode2	= 0x2f;
835 	ps->RegScanStateControl		= 0x30;
836 	ps->RegRedChEvenOffset		= 0x31;
837 	ps->RegGreenChEvenOffset	= 0x32;
838 	ps->RegBlueChEvenOffset		= 0x33;
839 	ps->RegRedChOddOffset		= 0x34;
840 	ps->RegGreenChOddOffset		= 0x35;
841 	ps->RegBlueChOddOffset		= 0x36;
842 	ps->RegRedGainOutDirect		= 0x37;
843 	ps->RegGreenGainOutDirect	= 0x38;
844 	ps->RegBlueGainOutDirect	= 0x39;
845 	ps->RegLedControl			= 0x3a;
846 	ps->RegShadingCorrectCtrl	= 0x3b;
847 	ps->RegScanStateBegin		= 0x40;	/* (0, 1)		*/
848 	ps->RegScanStateEnd			= 0x5f;	/* (62, 63)     */
849 
850 	/*
851 	 * setup function calls
852 	 */
853 	ps->ReadWriteTest		   = p48xxReadWriteTest;
854 	ps->SetupScannerVariables  = p48xxSetupScannerVariables;
855 	ps->SetupScanningCondition = p48xxSetupScanningCondition;
856     ps->PutToIdleMode          = p48xxPutToIdleMode;
857     ps->Calibration            = p48xxCalibration;
858 
859 	/*
860 	 * setup misc
861 	 */
862 	ps->CtrlReadHighNibble = _CTRL_GENSIGNAL + _CTRL_AUTOLF;
863 	ps->CtrlReadLowNibble  = _CTRL_GENSIGNAL + _CTRL_AUTOLF + _CTRL_STROBE;
864 
865 	ps->MotorFreeRun = 0x80;
866 	ps->bLampOn      = _SCAN_LAMP_ON;
867 	ps->f97003 	     = _FALSE;
868 
869 	/*
870 	 * initialize the other modules
871 	 */
872 	return p48xxInitAllModules( ps );
873 }
874 
875 /* END PLUSTEK-PP_P48xx.C ...................................................*/
876