1 /* @file plustek-pp_procfs.c
2  * @brief this is the interface to the proc filesystem
3  *
4  * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
5  *
6  * History:
7  * - 0.37 - initial version
8  * - 0.38 - changes according to generic structure changes
9  * - 0.39 - added info about forceMode and slowIO
10  * - 0.40 - no changes
11  * - 0.41 - no changes
12  * - 0.42 - changed include names
13  * - 0.43 - replace _PTDRV_VERx by _PTDRV_VERSTR
14  *        - cleanup
15  * - 0.44 - PROC_FS changes for newer kernel
16  *        - fix format string issues, as Long types default to int32_t
17  *          now
18  * .
19  * <hr>
20  * This file is part of the SANE package.
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License as
24  * published by the Free Software Foundation; either version 2 of the
25  * License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful, but
28  * WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30  * General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
34  *
35  * As a special exception, the authors of SANE give permission for
36  * additional uses of the libraries contained in this release of SANE.
37  *
38  * The exception is that, if you link a SANE library with other files
39  * to produce an executable, this does not by itself cause the
40  * resulting executable to be covered by the GNU General Public
41  * License.  Your use of that executable is in no way restricted on
42  * account of linking the SANE library code into it.
43  *
44  * This exception does not, however, invalidate any other reasons why
45  * the executable file might be covered by the GNU General Public
46  * License.
47  *
48  * If you submit changes to SANE to the maintainers to be included in
49  * a subsequent release, you agree by submitting the changes that
50  * those changes may be distributed with this exception intact.
51  *
52  * If you write modifications of your own for SANE, it is your choice
53  * whether to permit this exception to apply to your modifications.
54  * If you do not wish that, delete this exception notice.
55  * <hr>
56  */
57 #ifdef __KERNEL__
58 #include <linux/proc_fs.h>
59 
60 #include "plustek-pp_scan.h"
61 
62 /* toggled by your kernel configuration */
63 #ifdef CONFIG_PROC_FS
64 
65 /****************************** static vars **********************************/
66 
67 /** for the proc filesystem
68  */
69 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
70 extern struct proc_dir_entry proc_root;
71 #endif
72 static struct proc_dir_entry *base  = NULL;
73 static struct proc_dir_entry *binfo = NULL;
74 static ULong                  devcount;
75 
76 /** parallel port modes... */
77 static char *procfsPortModes[] = {
78 	"EPP",
79 	"SPP",
80 	"BiDi (PS/2)",
81 	"ECP"
82 	"unknown",
83 	NULL
84 };
85 
86 /** CCD-Types (as for ASIC 98001 based series) */
87 static TabDef procfsCCDTypes98001[] = {
88 
89 	{ _CCD_3797, "3797" },
90 	{ _CCD_3717, "3717" },
91 	{ _CCD_535,  "535"  },
92 	{ _CCD_2556, "2556" },
93 	{ _CCD_518,  "518"  },
94 	{ _CCD_539,  "539"  },
95     { -1 ,       "unknown" }
96 };
97 
98 /** CCD-Types (as for ASIC 98003 based series) */
99 static TabDef procfsCCDTypes98003[] = {
100 
101 	{ _CCD_3797, "3797" },
102 	{ _CCD_3799, "3799" },
103 	{ _CCD_535,  "535"  },
104 	{ _CCD_2556, "2556" },
105 	{ _CCD_518,  "518"  },
106 	{ _CCD_539,  "539"  },
107     { _CCD_3777, "3777"	},
108     { _CCD_548 , "548"	},
109     { -1 ,       "unknown" }
110 };
111 
112 /****************************** local functions ******************************/
113 
114 #ifndef LINUX_24
115 /** This is called as the fill_inode function when an inode
116  * is going into (fill = 1) or out of service (fill = 0).
117  *
118  * Note: only the top-level directory needs to do this; if
119  * a lower level is referenced, the parent will be as well.
120  *
121  * Here simply a dummy function
122  */
procfsFillFunc( struct inode *inode, int fill )123 static void procfsFillFunc( struct inode *inode, int fill )
124 {
125 }
126 #endif
127 
128 /** returns a pointer to the port-mode string
129  */
procfsGetMode( int mode )130 static const char* procfsGetMode( int mode )
131 {
132 	if((mode < _PORT_EPP) || (mode > _PORT_ECP))
133 		return procfsPortModes[_PORT_ECP+1];
134 
135 	return procfsPortModes[mode];
136 }
137 
138 /** determines CCD-Type string
139  */
procfsGetCCDType( pScanData ps )140 static const char* procfsGetCCDType( pScanData ps )
141 {
142 	int     i;
143 	int     ccd_id = ps->Device.bCCDID;
144 	pTabDef tab = procfsCCDTypes98001;
145 
146 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
147 
148         if(_ASIC_IS_98003 == ps->sCaps.AsicID)
149             tab = procfsCCDTypes98003;
150 
151         /* seek down the description table */
152         for( i = 0; -1 != tab[i].id; i++ ) {
153 
154             if( tab[i].id == ccd_id )
155                 return tab[i].desc;
156         }
157     } else {
158 
159         /* for older scanners only this info is available */
160         if( ps->fSonyCCD )
161             return "SONY Type";
162         else
163             return "NEC/TOSHIBA Type";
164     }
165 
166 	/* return the last entry if nothing applies! */
167 	return tab[(sizeof(procfsCCDTypes98001)/sizeof(TabDef)-1)].desc;
168 }
169 
170 /** will be called when reading the proc filesystem:
171  * cat /proc/pt_drv/info
172  */
procfsBInfoReadProc( char *buf, char **start, off_t offset, int count, int *eof, void *data )173 static int procfsBInfoReadProc( char *buf, char **start, off_t offset,
174                                 int count, int *eof, void *data )
175 {
176 	int len = 0;
177 
178 	len += sprintf( buf, "Plustek Flatbed Scanner Driver version "_PTDRV_VERSTR"\n" );
179 	len += sprintf( buf + len, "IOCTL-Version: 0x%08x\n",_PTDRV_IOCTL_VERSION);
180 	return len;
181 }
182 
183 /** will be called when reading the proc filesystem:
184  * cat /proc/pt_drv/deviceX/info
185  */
procfsInfoReadProc( char *buf, char **start, off_t offset, int count, int *eof, void *data )186 static int procfsInfoReadProc( char *buf, char **start, off_t offset,
187                                int count, int *eof, void *data )
188 {
189 	int       len = 0;
190 	pScanData ps  = (pScanData)data;
191 
192 	/* Tell us something about the device... */
193 	if( NULL != ps ) {
194 		len += sprintf( buf+len, "Model       : %s\n",
195 					    MiscGetModelName(ps->sCaps.Model));
196 		len += sprintf( buf+len, "Portaddress : 0x%X\n", ps->IO.portBase );
197 		len += sprintf( buf+len, "Portmode    : %s (%s I/O, %s)\n",
198 					    procfsGetMode(ps->IO.portMode),
199 						(ps->IO.slowIO == _TRUE?"delayed":"fast"),
200                         (ps->IO.forceMode == 0?"autodetect":"forced"));
201 		len += sprintf( buf+len, "Buttons     : %u\n",  ps->Device.buttons);
202 		len += sprintf( buf+len, "Warmuptime  : %us\n", ps->warmup        );
203 		len += sprintf( buf+len, "Lamp timeout: %us\n", ps->lampoff       );
204 		len += sprintf( buf+len, "mov-switch  : %u\n",  ps->ModelOverride );
205 		len += sprintf( buf+len, "I/O-delay   : %u\n",  ps->IO.delay      );
206 		len += sprintf( buf+len, "CCD-Type    : %s\n",  procfsGetCCDType(ps));
207         len += sprintf( buf+len, "TPA         : %s\n",
208                         (ps->sCaps.dwFlag & SFLAG_TPA) ? "yes":"no" );
209 	}
210 
211 	return len;
212 }
213 
214 /** will be called when reading the proc filesystem:
215  * cat /proc/pt_drv/devicex/buttony
216  */
procfsButtonsReadProc( char *buf, char **start, off_t offset, int count, int *eof, void *data )217 static int procfsButtonsReadProc( char *buf, char **start, off_t offset,
218                                   int count, int *eof, void *data )
219 {
220 	Byte	  b;
221 	int       bc  = 0;
222 	int       len = 0;
223 	pScanData ps  = (pScanData)data;
224 
225 	if( NULL != ps ) {
226 		bc = ps->Device.buttons;
227 	}
228 
229 	/* Check the buttons... */
230 	if( 0 != bc ) {
231 
232 		if ( _ASIC_IS_96003 == ps->sCaps.AsicID ) {
233 			MiscClaimPort( ps );
234 			b = IODataRegisterFromScanner( ps, ps->RegStatus );
235 			if(_FLAG_P96_KEY == (b & _FLAG_P96_KEY))
236 				b = 0;
237 			else
238 				b = 1;
239 			MiscReleasePort( ps );
240 			len += sprintf( buf + len, "%u\n", b );
241 		} else
242 			bc = 0;
243 	}
244 
245 	if( 0 == bc )
246 		len += sprintf( buf + len, "none\n" );
247 
248 	return len;
249 }
250 
251 /** create a procfs entry
252  */
new_entry( const char *name, mode_t mode, struct proc_dir_entry *parent )253 static struct proc_dir_entry *new_entry( const char *name, mode_t mode,
254                                          struct proc_dir_entry *parent )
255 {
256 #ifndef LINUX_24
257 	int len;
258 #endif
259 	struct proc_dir_entry *ent;
260 
261 	if (mode == S_IFDIR)
262 		mode |= S_IRUGO | S_IXUGO;
263 	else if (mode == 0)
264 		mode = S_IFREG | S_IRUGO;
265 
266 #ifndef LINUX_24
267 	len = strlen(name) + 1;
268 
269 	/* allocate memory for the entry and the name */
270 	ent = kmalloc(sizeof(struct proc_dir_entry) + len, GFP_KERNEL);
271 	if( NULL == ent )
272 		return NULL;
273 
274 	memset(ent, 0, sizeof(struct proc_dir_entry));
275 
276 	/* position pointer of name to end of the structure*/
277 	ent->name = ((char *) ent) + sizeof(*ent);
278 	strcpy((char *)ent->name, name );
279 
280 	ent->namelen = strlen(name);
281 	ent->mode    = mode;
282 
283 	if (S_ISDIR(mode)) {
284 		ent->nlink      = 2;
285 		ent->fill_inode = &procfsFillFunc;
286 	} else {
287 		ent->nlink = 1;
288 	}
289 
290 	proc_register( parent, ent );
291 #else
292 	if (mode == S_IFDIR)
293 		ent = proc_mkdir( name, parent );
294 	else
295 		ent = create_proc_entry( name, mode, parent );
296 #endif
297 
298 	return ent;
299 }
300 
301 /** shutdown one proc fs entry
302  */
destroy_proc_entry( struct proc_dir_entry *root, struct proc_dir_entry **d )303 static inline void destroy_proc_entry( struct proc_dir_entry *root,
304                                        struct proc_dir_entry **d )
305 {
306 #ifndef LINUX_24
307 	proc_unregister( root, (*d)->low_ino );
308 	kfree(*d);
309 #else
310 	DBG(DBG_HIGH, "pt_drv: proc del '%s' root='%s'\n", (*d)->name, root->name);
311 
312 	remove_proc_entry((*d)->name, root );
313 #endif
314 
315 	*d = NULL;
316 }
317 
318 /** shutdown the proc-tree for one device
319  */
destroy_proc_tree( pScanData ps )320 static void destroy_proc_tree( pScanData ps )
321 {
322 	int i;
323 
324 	DBG( DBG_HIGH, "pt_drv: destroy_proc_tree !\n" );
325 
326 	if( ps ) {
327 
328 		if( ps->procDir.entry ) {
329 
330 			if( ps->procDir.info )
331 				destroy_proc_entry( ps->procDir.entry, &ps->procDir.info );
332 
333 			for( i = 0; i < ps->Device.buttons; i++ ) {
334 
335 				if( ps->procDir.buttons[i] )
336     				destroy_proc_entry(ps->procDir.entry, &ps->procDir.buttons[i]);
337 			}
338 
339 			destroy_proc_entry( base, &ps->procDir.entry );
340 		}
341 	}
342 }
343 
344 /*************************** exported functions ******************************/
345 
346 /** initialize our proc-fs stuff
347  */
ProcFsInitialize( void )348 int ProcFsInitialize( void )
349 {
350 	DBG( DBG_HIGH, "ProcFsInitialize()\n" );
351 
352 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
353 	base = new_entry( _DRV_NAME, S_IFDIR, &proc_root );
354 #else
355 	base = new_entry( _DRV_NAME, S_IFDIR, NULL );
356 #endif
357 
358 	if( NULL != base ) {
359 
360 		devcount = 0;
361 
362 		binfo = new_entry( "info", 0, base );
363 		if( NULL != binfo ) {
364 			binfo->read_proc = procfsBInfoReadProc;
365 			binfo->data      = &devcount;
366 		}
367 	}
368 
369 	return _OK;
370 }
371 
372 /** cleanup the base entry
373  */
ProcFsShutdown( void )374 void ProcFsShutdown( void )
375 {
376 	DBG( DBG_HIGH, "ProcFsShutdown()\n" );
377 
378 	if( NULL != base ) {
379 
380 		if( NULL != binfo )
381 			destroy_proc_entry( base, &binfo );
382 
383 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
384 		destroy_proc_entry( &proc_root, &base );
385 #else
386 		destroy_proc_entry( NULL, &base );
387 #endif
388 	}
389 
390 	devcount = 0;
391 }
392 
393 /** will be called for each device, that has been found
394  */
ProcFsRegisterDevice( pScanData ps )395 void ProcFsRegisterDevice( pScanData ps )
396 {
397 	int	 i;
398 	char str[20];
399 
400 	if( NULL == base ) {
401 	    printk( KERN_ERR "pt_drv : proc not initialised yet!\n");
402 		return;
403 	}
404 
405 	memset( &ps->procDir, 0, sizeof(ProcDirDef));
406 
407 	sprintf( str, "device%u", ps->devno );
408 
409 	ps->procDir.entry = new_entry( str, S_IFDIR, base );
410 	if( NULL == ps->procDir.entry )
411 		goto error_exit;
412 
413 	ps->procDir.info = new_entry( "info", 0, ps->procDir.entry );
414 	if( NULL == ps->procDir.info )
415 		goto error_exit;
416 
417 	ps->procDir.info->read_proc = procfsInfoReadProc;
418 	ps->procDir.info->data      = ps;
419 
420 	for( i = 0; i < ps->Device.buttons; i++ ) {
421 
422 		sprintf( str, "button%u", i );
423 
424 		ps->procDir.buttons[i] = new_entry( str, 0, ps->procDir.entry );
425 		if( NULL == ps->procDir.buttons[i] )
426 			goto error_exit;
427 
428 		ps->procDir.buttons[i]->read_proc = procfsButtonsReadProc;
429 		ps->procDir.buttons[i]->data      = ps;
430 	}
431 
432 	devcount++;
433 	return;
434 
435 
436 error_exit:
437 
438 	printk(KERN_ERR "pt_drv: failure registering /proc/ entry %s.\n", str );
439 	destroy_proc_tree( ps );
440 }
441 
442 /** cleanup the proc-fs for a certain device
443  */
ProcFsUnregisterDevice( pScanData ps )444 void ProcFsUnregisterDevice( pScanData ps )
445 {
446 	destroy_proc_tree( ps );
447 }
448 
449 #else 	/* CONFIG_PROC_FS */
450 
ProcFsInitialize( void )451 int  ProcFsInitialize( void )
452 {
453 	return _OK;
454 }
455 
ProcFsShutdown( void )456 void ProcFsShutdown( void )
457 {
458 }
459 
ProcFsRegisterDevice( pScanData ps )460 void ProcFsRegisterDevice( pScanData ps )
461 {
462 }
463 
ProcFsUnregisterDevice( pScanData ps )464 void ProcFsUnregisterDevice( pScanData ps )
465 {
466 }
467 
468 #endif
469 
470 #endif /* guard __KERNEL__ */
471 
472 /* END PLUSTEK-PP_PROCFS.C ..................................................*/
473