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