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 91static int port_feature = 0; 92static long randomnum = 1; 93 94static 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*/ 111static 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 */ 134static 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 270_LOC int MiscCheckTimer( TimerDef *timer ) 271{ 272 struct timeval current_time; 273 274 gettimeofday(¤t_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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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