1 /* @file plustek-pp_misc.c
2  * @brief here we have some helpful functions
3 *
4  * based on sources acquired from Plustek Inc.
5  * Copyright (C) 1998 Plustek Inc.
6  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
7  * also based on the work done by Rick Bronson
8  *
9  * History:
10  * - 0.30 - initial version
11  * - 0.31 - no changes
12  * - 0.32 - moved the parport functions inside this module
13  *        - now using the information, the parport-driver provides
14  *        - for selecting the port-mode this driver uses
15  * - 0.33 - added code to use faster portmodes
16  * - 0.34 - added sample code for changing from ECP to PS/2 bidi mode
17  * - 0.35 - added Kevins' changes (new function miscSetFastMode())
18  *        - moved function initPageSettings() to module models.c
19  * - 0.36 - added random generator
20  *        - added additional debug messages
21  *        - changed prototype of MiscInitPorts()
22  *        - added miscPreemptionCallback()
23  * - 0.37 - changed inb_p/outb_p to macro calls (kernel-mode)
24  *        - added MiscGetModelName()
25  *        - added miscShowPortModes()
26  * - 0.38 - fixed a small bug in MiscGetModelName()
27  * - 0.39 - added forceMode support
28  * - 0.40 - no changes
29  * - 0.41 - merged Kevins' patch to make EPP(ECP) work
30  * - 0.42 - changed get_fast_time to _GET_TIME
31  *        - changed include names
32  * - 0.43 - added LINUX_26 stuff
33  *        - minor fixes
34  *        - removed floating point stuff
35  * - 0.44 - fix format string issues, as Long types default to int32_t
36  *          now
37  * .
38  * <hr>
39  * This file is part of the SANE package.
40  *
41  * This program is free software; you can redistribute it and/or
42  * modify it under the terms of the GNU General Public License as
43  * published by the Free Software Foundation; either version 2 of the
44  * License, or (at your option) any later version.
45  *
46  * This program is distributed in the hope that it will be useful, but
47  * WITHOUT ANY WARRANTY; without even the implied warranty of
48  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
49  * General Public License for more details.
50  *
51  * You should have received a copy of the GNU General Public License
52  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
53  *
54  * As a special exception, the authors of SANE give permission for
55  * additional uses of the libraries contained in this release of SANE.
56  *
57  * The exception is that, if you link a SANE library with other files
58  * to produce an executable, this does not by itself cause the
59  * resulting executable to be covered by the GNU General Public
60  * License.  Your use of that executable is in no way restricted on
61  * account of linking the SANE library code into it.
62  *
63  * This exception does not, however, invalidate any other reasons why
64  * the executable file might be covered by the GNU General Public
65  * License.
66  *
67  * If you submit changes to SANE to the maintainers to be included in
68  * a subsequent release, you agree by submitting the changes that
69  * those changes may be distributed with this exception intact.
70  *
71  * If you write modifications of your own for SANE, it is your choice
72  * whether to permit this exception to apply to your modifications.
73  * If you do not wish that, delete this exception notice.
74  * <hr>
75  */
76 #include "plustek-pp_scan.h"
77 
78 /*************************** some definitions ********************************/
79 
80 # define PPA_PROBE_SPP   0x0001
81 # define PPA_PROBE_PS2   0x0002
82 # define PPA_PROBE_ECR   0x0010
83 # define PPA_PROBE_EPP17 0x0100
84 # define PPA_PROBE_EPP19 0x0200
85 
86 #define _PP_A 16807         /**< multiplier */
87 #define _PP_M 2147483647L   /**< 2**31 - 1  */
88 
89 /*************************** some local vars *********************************/
90 
91 static int  port_feature = 0;
92 static long randomnum    = 1;
93 
94 static int portIsClaimed[_MAX_PTDEVS] = { 0, 0, 0, 0 };
95 
96 /*************************** local functions *********************************/
97 
98 /** miscNextLongRand() -- generate 2**31-2 random numbers
99 **
100 **  public domain by Ray Gardner
101 **
102 **  based on "Random Number Generators: Good Ones Are Hard to Find",
103 **  S.K. Park and K.W. Miller, Communications of the ACM 31:10 (Oct 1988),
104 **  and "Two Fast Implementations of the 'Minimal Standard' Random
105 **  Number Generator", David G. Carta, Comm. ACM 33, 1 (Jan 1990), p. 87-88
106 **
107 **  linear congruential generator f(z) = 16807 z mod (2 ** 31 - 1)
108 **
109 **  uses L. Schrage's method to avoid overflow problems
110 */
miscNextLongRand( Long seed )111 static Long miscNextLongRand( Long seed )
112 {
113 	ULong lo, hi;
114 
115     lo = _PP_A * (Long)(seed & 0xFFFF);
116     hi = _PP_A * (Long)((ULong)seed >> 16);
117     lo += (hi & 0x7FFF) << 16;
118     if (lo > _PP_M) {
119 
120 		lo &= _PP_M;
121         ++lo;
122 	}
123     lo += hi >> 15;
124     if (lo > _PP_M) {
125 		lo &= _PP_M;
126         ++lo;
127 	}
128 
129 	return (Long)lo;
130 }
131 
132 /** initialize the random number generator
133  */
miscSeedLongRand( long seed )134 static void miscSeedLongRand( long seed )
135 {
136 	randomnum = seed ? (seed & _PP_M) : 1;  /* nonzero seed */
137 }
138 
139 /************************ exported functions *********************************/
140 
141 /** allocate and initialize some memory for the scanner structure
142  */
MiscAllocAndInitStruct( void )143 _LOC pScanData MiscAllocAndInitStruct( void )
144 {
145 	pScanData ps;
146 
147 	ps = (pScanData)_KALLOC(sizeof(ScanData), GFP_KERNEL);
148 
149 	if( NULL != ps ) {
150 		MiscReinitStruct( ps );
151 	}
152 
153 	DBG( DBG_HIGH, "ScanData = 0x%08lx\n", (unsigned long)ps );
154 	return ps;
155 }
156 
157 /** re-initialize the memory for the scanner structure
158  */
MiscReinitStruct( pScanData ps )159 _LOC int MiscReinitStruct( pScanData ps )
160 {
161 	if( NULL == ps )
162 		return _E_NULLPTR;
163 
164 	memset( ps, 0, sizeof(ScanData));
165 
166 	/* first init all constant stuff in ScanData
167 	 */
168 	ps->bCurrentSpeed = 1;
169 	ps->pbMapRed      =  ps->a_bMapTable;
170 	ps->pbMapGreen    = &ps->a_bMapTable[256];
171 	ps->pbMapBlue     = &ps->a_bMapTable[512];
172 	ps->sCaps.wIOBase = _NO_BASE;
173 
174 	/* use memory address to seed the generator */
175 	miscSeedLongRand((long)ps);
176 
177 	DBG( DBG_HIGH, "Init settings done\n" );
178 	return _OK;
179 }
180 
181 /** in USER-Mode:   probe the specified port and try to get the port-mode
182  *  in KERNEL-Mode: only use the modes, the driver returns
183  */
MiscInitPorts( pScanData ps, int port )184 _LOC int MiscInitPorts( pScanData ps, int port )
185 {
186 	int mode, mts;
187 
188 	if( NULL == ps )
189 		return _E_NULLPTR;
190 
191 	if( SANE_STATUS_GOOD != sanei_pp_getmodes( ps->pardev, &mode )) {
192 		DBG( DBG_HIGH, "Cannot get port mode!\n" );
193 		return _E_NO_PORT;
194 	}
195 
196 	ps->IO.portMode = _PORT_NONE;
197 	mts             = -1;
198 	if( mode & SANEI_PP_MODE_SPP ) {
199 		DBG( DBG_LOW, "Setting SPP-mode\n" );
200 		ps->IO.portMode = _PORT_SPP;
201 		mts = SANEI_PP_MODE_SPP;
202 	}
203 	if( mode & SANEI_PP_MODE_BIDI ) {
204 		DBG( DBG_LOW, "Setting PS/2-mode\n" );
205 		ps->IO.portMode = _PORT_BIDI;
206 		mts = SANEI_PP_MODE_BIDI;
207 	}
208 	if( mode & SANEI_PP_MODE_EPP ) {
209 		DBG( DBG_LOW, "Setting EPP-mode\n" );
210 		ps->IO.portMode = _PORT_EPP;
211 		mts = SANEI_PP_MODE_EPP;
212 	}
213 	if( mode & SANEI_PP_MODE_ECP ) {
214 		DBG( DBG_HIGH, "ECP detected --> not supported\n" );
215 	}
216 
217 	if( sanei_pp_uses_directio()) {
218 		DBG( DBG_LOW, "We're using direct I/O\n" );
219 	} else {
220 		DBG( DBG_LOW, "We're using libIEEE1284 I/O\n" );
221 	}
222 
223 	if( ps->IO.portMode == _PORT_NONE ) {
224 		DBG( DBG_HIGH, "None of the portmodes is supported.\n" );
225 		return _E_NOSUPP;
226 	}
227 
228 	sanei_pp_setmode( ps->pardev, mts );
229 	_VAR_NOT_USED( port );
230 	return _OK;
231 }
232 
233 /** Function to restore the port
234  */
MiscRestorePort( pScanData ps )235 _LOC void MiscRestorePort( pScanData ps )
236 {
237     DBG(DBG_LOW,"MiscRestorePort()\n");
238 
239 	/* don't restore if not necessary */
240 	if( 0xFFFF == ps->IO.lastPortMode ) {
241 	    DBG(DBG_LOW,"- no need to restore portmode !\n");
242 		return;
243 	}
244 
245     /*Restore Port-Mode*/
246     if( port_feature & PPA_PROBE_ECR ){
247 		_OUTB_ECTL(ps,ps->IO.lastPortMode);
248     }
249 }
250 
251 /** Initializes a timer.
252  * @param timer - pointer to the timer to start
253  * @param us    - timeout value in micro-seconds
254  */
MiscStartTimer( TimerDef *timer , unsigned long us)255 _LOC void MiscStartTimer( TimerDef *timer , unsigned long us)
256 {
257     struct timeval start_time;
258 
259 	gettimeofday(&start_time, NULL);
260 
261     *timer = (TimerDef)start_time.tv_sec * 1000000 + (TimerDef)start_time.tv_usec + us;
262 }
263 
264 /** Checks if a timer has been expired or not. In Kernel-mode, the scheduler
265  *  will also be triggered, if the timer has not been expired.
266  * @param timer - pointer to the timer to check
267  * @return Function returns _E_TIMEOUT when the timer has been expired,
268  *         otherwise _OK;
269  */
MiscCheckTimer( TimerDef *timer )270 _LOC int MiscCheckTimer( TimerDef *timer )
271 {
272     struct timeval current_time;
273 
274 	gettimeofday(&current_time, NULL);
275 
276     if ((TimerDef)current_time.tv_sec * 1000000 + (TimerDef)current_time.tv_usec > *timer) {
277 		return _E_TIMEOUT;
278     } else {
279 /*#else
280 		sched_yield();
281 */
282 		return _OK;
283 	}
284 }
285 
286 /** Checks the function pointers
287  * @param ps - pointer to the scanner data structure.
288  * @return Function returns _TRUE if everything is okay and _FALSE if a NULL
289  *         ptr has been detected.
290  */
291 #ifdef DEBUG
MiscAllPointersSet( pScanData ps )292 _LOC Bool MiscAllPointersSet( pScanData ps )
293 {
294 	int  i;
295 	unsigned long *ptr;
296 
297 	for( ptr = (unsigned long *)&ps->OpenScanPath, i = 1;
298 		 ptr <= (unsigned long *)&ps->ReadOneImageLine; ptr++, i++ ) {
299 
300 		if( NULL == (pVoid)*ptr ) {
301 			DBG( DBG_HIGH, "Function pointer not set (pos = %d) !\n", i );
302 			return _FALSE;
303 		}
304 	}
305 
306 	return _TRUE;
307 }
308 #endif
309 
310 /** registers this driver to use port "portAddr" (KERNEL-Mode only)
311  * @param ps       - pointer to the scanner data structure.
312  * @param portAddr -
313  */
MiscRegisterPort( pScanData ps, int portAddr )314 _LOC int MiscRegisterPort( pScanData ps, int portAddr )
315 {
316 	DBG( DBG_LOW, "Assigning port handle %i\n", portAddr );
317     ps->pardev = portAddr;
318 
319 	portIsClaimed[ps->devno] = 0;
320 	return _OK;
321 }
322 
323 /** unregisters the port from driver
324  */
MiscUnregisterPort( pScanData ps )325 _LOC void MiscUnregisterPort( pScanData ps )
326 {
327 	sanei_pp_close( ps->pardev );
328 }
329 
330 /** Try to claim the port
331  * @param ps - pointer to the scanner data structure.
332  * @return Function returns _OK on success, otherwise _E_BUSY.
333  */
MiscClaimPort( pScanData ps )334 _LOC int MiscClaimPort( pScanData ps )
335 {
336 	if( 0 == portIsClaimed[ps->devno] ) {
337 
338 		DBG( DBG_HIGH, "Try to claim the parport\n" );
339 		if( SANE_STATUS_GOOD != sanei_pp_claim( ps->pardev )) {
340 			return _E_BUSY;
341 		}
342 	}
343 	portIsClaimed[ps->devno]++;
344 	return _OK;
345 }
346 
347 /** Release previously claimed port
348  * @param ps - pointer to the scanner data structure
349  */
MiscReleasePort( pScanData ps )350 _LOC void MiscReleasePort( pScanData ps )
351 {
352 	if( portIsClaimed[ps->devno] > 0 ) {
353 		portIsClaimed[ps->devno]--;
354 
355 		if( 0 == portIsClaimed[ps->devno] ) {
356 			DBG( DBG_HIGH, "Releasing parport\n" );
357 			sanei_pp_release( ps->pardev );
358 		}
359 	}
360 }
361 
362 /** Get random number
363  * @return a random number.
364  */
MiscLongRand( void )365 _LOC Long MiscLongRand( void )
366 {
367 	randomnum = miscNextLongRand( randomnum );
368 
369 	return randomnum;
370 }
371 
372 /** According to the id, the function returns a pointer to the model name
373  * @param id - internal id of the various scanner models.
374  * @return a pointer to the model-string.
375  */
MiscGetModelName( UShort id )376 _LOC const char *MiscGetModelName( UShort id )
377 {
378 	DBG( DBG_HIGH, "MiscGetModelName - id = %i\n", id );
379 
380 	if( MODEL_OP_PT12 < id )
381 		return ModelStr[0];
382 
383 	return ModelStr[id];
384 }
385 
386 /* END PLUSTEK-PP_MISC.C ....................................................*/
387