1 /** @file plustek-pp_wrapper.c
2  *  @brief The interface to the parport driver-code and the kernel module.
3  *
4  * Based on sources acquired from Plustek Inc.<br>
5  * Copyright (C) 2001-2004 Gerhard Jaeger <gerhard@gjaeger.de>
6  *
7  * History:
8  * - 0.40 - initial version
9  * - 0.41 - added _PTDRV_ADJUST call
10  * - 0.42 - added setmap function
11  *        - fixed the stopscan problem, that causes a crash in the kernel module
12  * - 0.43 - added initialized setting
13  *        - cleanup
14  * .
15  * <hr>
16  * This file is part of the SANE package.
17  *
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License as
20  * published by the Free Software Foundation; either version 2 of the
21  * License, or (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
30  *
31  * As a special exception, the authors of SANE give permission for
32  * additional uses of the libraries contained in this release of SANE.
33  *
34  * The exception is that, if you link a SANE library with other files
35  * to produce an executable, this does not by itself cause the
36  * resulting executable to be covered by the GNU General Public
37  * License.  Your use of that executable is in no way restricted on
38  * account of linking the SANE library code into it.
39  *
40  * This exception does not, however, invalidate any other reasons why
41  * the executable file might be covered by the GNU General Public
42  * License.
43  *
44  * If you submit changes to SANE to the maintainers to be included in
45  * a subsequent release, you agree by submitting the changes that
46  * those changes may be distributed with this exception intact.
47  *
48  * If you write modifications of your own for SANE, it is your choice
49  * whether to permit this exception to apply to your modifications.
50  * If you do not wish that, delete this exception notice.
51  * <hr>
52  */
53 
54 /******************* wrapper functions for parport device ********************/
55 
56 #ifndef _BACKEND_ENABLED
57 
PtDrvInit( char *dev_name, unsigned short model_override )58 static int PtDrvInit( char *dev_name, unsigned short model_override )
59 {
60 	_VAR_NOT_USED( dev_name );
61 	_VAR_NOT_USED( model_override );
62 	DBG( _DBG_ERROR, "Backend does not support direct I/O!\n" );
63 	return -1;
64 }
65 
PtDrvShutdown( void )66 static int PtDrvShutdown( void )
67 {
68 	return 0;
69 }
70 
PtDrvOpen( void )71 static int PtDrvOpen( void )
72 {
73 	DBG( _DBG_ERROR, "Backend does not support direct I/O!\n" );
74 	return -1;
75 }
76 
PtDrvClose( void )77 static int PtDrvClose( void )
78 {
79 	DBG( _DBG_ERROR, "Backend does not support direct I/O!\n" );
80 	return 0;
81 }
82 
PtDrvIoctl( unsigned int cmd, void *arg )83 static int PtDrvIoctl( unsigned int cmd, void *arg )
84 {
85 	DBG( _DBG_ERROR, "Backend does not support direct I/O!\n" );
86 	_VAR_NOT_USED( cmd );
87 	if( arg == NULL )
88 		return -2;
89 	return -1;
90 }
91 
PtDrvRead( unsigned char *buffer, int count )92 static int PtDrvRead( unsigned char *buffer, int count )
93 {
94 	DBG( _DBG_ERROR, "Backend does not support direct I/O!\n" );
95 	_VAR_NOT_USED( count );
96 	if( buffer == NULL )
97 		return -2;
98 	return -1;
99 }
100 #endif /* _BACKEND_ENABLED */
101 
102 /**
103  */
ppDev_open( const char *dev_name, void *misc )104 static int ppDev_open( const char *dev_name, void *misc )
105 {
106 	int 		    result;
107 	int			    handle;
108 	CompatAdjDef    compatAdj;
109 	PPAdjDef        adj;
110 	unsigned short  version = _PTDRV_IOCTL_VERSION;
111 	Plustek_Device *dev     = (Plustek_Device *)misc;
112 
113 	if( dev->adj.direct_io ) {
114 		result = PtDrvInit( dev_name, dev->adj.mov );
115 		if( 0 != result ) {
116 			DBG( _DBG_ERROR, "open: PtDrvInit failed: %d\n", result );
117 			return -1;
118 		}
119 	}
120 
121 	if( dev->adj.direct_io )
122 		handle = PtDrvOpen();
123 	else
124 		handle = open( dev_name, O_RDONLY );
125 
126 	if ( handle  < 0 ) {
127 	    DBG( _DBG_ERROR, "open: can't open %s as a device\n", dev_name );
128     	return handle;
129 	}
130 
131 	if( dev->adj.direct_io )
132 		result = PtDrvIoctl( _PTDRV_OPEN_DEVICE, &version );
133 	else
134 		result = ioctl( handle, _PTDRV_OPEN_DEVICE, &version );
135 
136 	if( result < 0 ) {
137 
138         if( -9019 == result ) {
139 
140 			DBG( _DBG_INFO, "Version 0x%04x not supported, trying "
141                             "compatibility version 0x%04x\n",
142                             _PTDRV_IOCTL_VERSION, _PTDRV_COMPAT_IOCTL_VERSION);
143 
144 			version = _PTDRV_COMPAT_IOCTL_VERSION;
145 
146 			if( dev->adj.direct_io )
147 				result = PtDrvIoctl( _PTDRV_OPEN_DEVICE, &version );
148 			else
149 				result = ioctl( handle, _PTDRV_OPEN_DEVICE, &version );
150 
151 			if( result < 0 ) {
152 
153 				if( dev->adj.direct_io )
154 					PtDrvClose();
155 				else
156 					close( dev->fd );
157 
158 				DBG( _DBG_ERROR,
159 					 "ioctl PT_DRV_OPEN_DEVICE failed(%d)\n", result );
160 
161 		        if( -9019 == result ) {
162 	    			DBG( _DBG_ERROR,
163 						 "Version problem, please recompile driver!\n" );
164 				}
165 			} else {
166 
167 				DBG( _DBG_INFO, "Using compatibility version\n" );
168 
169 				compatAdj.lampOff      = dev->adj.lampOff;
170 				compatAdj.lampOffOnEnd = dev->adj.lampOffOnEnd;
171 				compatAdj.warmup       = dev->adj.warmup;
172 
173 				memcpy( &compatAdj.pos, &dev->adj.pos, sizeof(OffsDef));
174 				memcpy( &compatAdj.neg, &dev->adj.neg, sizeof(OffsDef));
175 				memcpy( &compatAdj.tpa, &dev->adj.tpa, sizeof(OffsDef));
176 
177 				if( dev->adj.direct_io )
178 					PtDrvIoctl( _PTDRV_ADJUST, &compatAdj );
179 				else
180 					ioctl( handle, _PTDRV_ADJUST, &compatAdj );
181 				return handle;
182 			}
183 		}
184 		return result;
185     }
186 
187 	memset( &adj, 0, sizeof(PPAdjDef));
188 
189 	adj.lampOff      = dev->adj.lampOff;
190 	adj.lampOffOnEnd = dev->adj.lampOffOnEnd;
191 	adj.warmup       = dev->adj.warmup;
192 
193 	memcpy( &adj.pos, &dev->adj.pos, sizeof(OffsDef));
194 	memcpy( &adj.neg, &dev->adj.neg, sizeof(OffsDef));
195 	memcpy( &adj.tpa, &dev->adj.tpa, sizeof(OffsDef));
196 
197 	adj.rgamma    = dev->adj.rgamma;
198 	adj.ggamma    = dev->adj.ggamma;
199 	adj.bgamma    = dev->adj.bgamma;
200 	adj.graygamma = dev->adj.graygamma;
201 
202 	if( dev->adj.direct_io )
203 		PtDrvIoctl( _PTDRV_ADJUST, &adj );
204 	else
205 		ioctl( handle, _PTDRV_ADJUST, &adj );
206 
207 	dev->initialized = SANE_TRUE;
208 	return handle;
209 }
210 
211 /**
212  */
ppDev_close( Plustek_Device *dev )213 static int ppDev_close( Plustek_Device *dev )
214 {
215 	if( dev->adj.direct_io )
216 		return PtDrvClose();
217 	else
218 		return close( dev->fd );
219 }
220 
221 /**
222  */
ppDev_getCaps( Plustek_Device *dev )223 static int ppDev_getCaps( Plustek_Device *dev )
224 {
225 	if( dev->adj.direct_io )
226 		return PtDrvIoctl( _PTDRV_GET_CAPABILITIES, &dev->caps );
227 	else
228 		return ioctl( dev->fd, _PTDRV_GET_CAPABILITIES, &dev->caps );
229 }
230 
231 /**
232  */
ppDev_getLensInfo( Plustek_Device *dev, pLensInfo lens )233 static int ppDev_getLensInfo( Plustek_Device *dev, pLensInfo lens )
234 {
235 	if( dev->adj.direct_io )
236 		return  PtDrvIoctl( _PTDRV_GET_LENSINFO, lens );
237 	else
238 		return ioctl( dev->fd, _PTDRV_GET_LENSINFO, lens );
239 }
240 
241 /**
242  */
ppDev_getCropInfo( Plustek_Device *dev, pCropInfo crop )243 static int ppDev_getCropInfo( Plustek_Device *dev, pCropInfo crop )
244 {
245 	if( dev->adj.direct_io )
246 		return PtDrvIoctl( _PTDRV_GET_CROPINFO, crop );
247 	else
248 		return ioctl( dev->fd, _PTDRV_GET_CROPINFO, crop );
249 }
250 
251 /**
252  */
ppDev_putImgInfo( Plustek_Device *dev, pImgDef img )253 static int ppDev_putImgInfo( Plustek_Device *dev, pImgDef img )
254 {
255 	if( dev->adj.direct_io )
256 		return PtDrvIoctl( _PTDRV_PUT_IMAGEINFO, img );
257 	else
258 		return ioctl( dev->fd, _PTDRV_PUT_IMAGEINFO, img );
259 }
260 
261 /**
262  */
ppDev_setScanEnv( Plustek_Device *dev, pScanInfo sinfo )263 static int ppDev_setScanEnv( Plustek_Device *dev, pScanInfo sinfo )
264 {
265 	if( dev->adj.direct_io )
266 		return PtDrvIoctl( _PTDRV_SET_ENV, sinfo );
267 	else
268 		return ioctl( dev->fd, _PTDRV_SET_ENV, sinfo );
269 }
270 
271 /**
272  */
ppDev_startScan( Plustek_Device *dev, pStartScan start )273 static int ppDev_startScan( Plustek_Device *dev, pStartScan start )
274 {
275 	if( dev->adj.direct_io )
276 		return PtDrvIoctl( _PTDRV_START_SCAN, start );
277 	else
278 		return ioctl( dev->fd, _PTDRV_START_SCAN, start );
279 }
280 
281 /** function to send a gamma table to the kernel module. As the default table
282  *  entry is 16-bit, but the maps are 8-bit, we have to copy the values...
283  */
ppDev_setMap( Plustek_Device *dev, SANE_Word *map, SANE_Word length, SANE_Word channel )284 static int ppDev_setMap( Plustek_Device *dev, SANE_Word *map,
285 						 SANE_Word length, SANE_Word channel )
286 {
287 	SANE_Byte *buf;
288 	SANE_Word  i;
289 	MapDef     m;
290 
291 	m.len    = length;
292 	m.map_id = channel;
293 
294 	m.map = (void *)map;
295 
296 	DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n", channel, (unsigned long)map);
297 
298 	buf = (SANE_Byte*)malloc( m.len );
299 
300 	if( !buf )
301 		return _E_ALLOC;
302 
303 	for( i = 0; i < m.len; i++ ) {
304 		buf[i] = (SANE_Byte)map[i];
305 
306 		if( map[i] > 0xFF )
307 			buf[i] = 0xFF;
308 	}
309 
310 	m.map = buf;
311 
312 	if( dev->adj.direct_io )
313 		PtDrvIoctl( _PTDRV_SETMAP, &m );
314 	else
315 		ioctl( dev->fd, _PTDRV_SETMAP, &m );
316 
317 	/* we ignore the return values */
318 	free( buf );
319 	return 0;
320 }
321 
322 /**
323  */
ppDev_stopScan( Plustek_Device *dev, short *mode )324 static int ppDev_stopScan( Plustek_Device *dev, short *mode )
325 {
326 	int retval, tmp;
327 
328 	/* save this one... */
329 	tmp = *mode;
330 
331 	if( dev->adj.direct_io )
332 		retval = PtDrvIoctl( _PTDRV_STOP_SCAN, mode );
333 	else
334 		retval = ioctl( dev->fd, _PTDRV_STOP_SCAN, mode );
335 
336 	/* ... and use it here */
337 	if( 0 == tmp ) {
338 		if( dev->adj.direct_io )
339 			PtDrvIoctl( _PTDRV_CLOSE_DEVICE, 0 );
340 		else
341 			ioctl( dev->fd, _PTDRV_CLOSE_DEVICE, 0);
342 	}else
343 		sleep( 1 );
344 
345 	return retval;
346 }
347 
348 /**
349  */
ppDev_readImage( Plustek_Device *dev, SANE_Byte *buf, unsigned long data_length )350 static int ppDev_readImage( Plustek_Device *dev,
351                             SANE_Byte *buf, unsigned long data_length )
352 {
353 	if( dev->adj.direct_io )
354 		return PtDrvRead( buf, data_length );
355 	else
356 		return read( dev->fd, buf, data_length );
357 }
358 
359 /* END PLUSTEK-PP_WRAPPER.C .................................................*/
360