summaryrefslogtreecommitdiff
path: root/backend/plustek-pp_procfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/plustek-pp_procfs.c')
-rw-r--r--backend/plustek-pp_procfs.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/backend/plustek-pp_procfs.c b/backend/plustek-pp_procfs.c
new file mode 100644
index 0000000..ed242a8
--- /dev/null
+++ b/backend/plustek-pp_procfs.c
@@ -0,0 +1,474 @@
+/* @file plustek-pp_procfs.c
+ * @brief this is the interface to the proc filesystem
+ *
+ * Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
+ *
+ * History:
+ * - 0.37 - initial version
+ * - 0.38 - changes according to generic structure changes
+ * - 0.39 - added info about forceMode and slowIO
+ * - 0.40 - no changes
+ * - 0.41 - no changes
+ * - 0.42 - changed include names
+ * - 0.43 - replace _PTDRV_VERx by _PTDRV_VERSTR
+ * - cleanup
+ * - 0.44 - PROC_FS changes for newer kernel
+ * - fix format string issues, as Long types default to int32_t
+ * now
+ * .
+ * <hr>
+ * This file is part of the SANE package.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * As a special exception, the authors of SANE give permission for
+ * additional uses of the libraries contained in this release of SANE.
+ *
+ * The exception is that, if you link a SANE library with other files
+ * to produce an executable, this does not by itself cause the
+ * resulting executable to be covered by the GNU General Public
+ * License. Your use of that executable is in no way restricted on
+ * account of linking the SANE library code into it.
+ *
+ * This exception does not, however, invalidate any other reasons why
+ * the executable file might be covered by the GNU General Public
+ * License.
+ *
+ * If you submit changes to SANE to the maintainers to be included in
+ * a subsequent release, you agree by submitting the changes that
+ * those changes may be distributed with this exception intact.
+ *
+ * If you write modifications of your own for SANE, it is your choice
+ * whether to permit this exception to apply to your modifications.
+ * If you do not wish that, delete this exception notice.
+ * <hr>
+ */
+#ifdef __KERNEL__
+#include <linux/proc_fs.h>
+
+#include "plustek-pp_scan.h"
+
+/* toggled by your kernel configuration */
+#ifdef CONFIG_PROC_FS
+
+/****************************** static vars **********************************/
+
+/** for the proc filesystem
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+extern struct proc_dir_entry proc_root;
+#endif
+static struct proc_dir_entry *base = NULL;
+static struct proc_dir_entry *binfo = NULL;
+static ULong devcount;
+
+/** parallel port modes... */
+static char *procfsPortModes[] = {
+ "EPP",
+ "SPP",
+ "BiDi (PS/2)",
+ "ECP"
+ "unknown",
+ NULL
+};
+
+/** CCD-Types (as for ASIC 98001 based series) */
+static TabDef procfsCCDTypes98001[] = {
+
+ { _CCD_3797, "3797" },
+ { _CCD_3717, "3717" },
+ { _CCD_535, "535" },
+ { _CCD_2556, "2556" },
+ { _CCD_518, "518" },
+ { _CCD_539, "539" },
+ { -1 , "unknown" }
+};
+
+/** CCD-Types (as for ASIC 98003 based series) */
+static TabDef procfsCCDTypes98003[] = {
+
+ { _CCD_3797, "3797" },
+ { _CCD_3799, "3799" },
+ { _CCD_535, "535" },
+ { _CCD_2556, "2556" },
+ { _CCD_518, "518" },
+ { _CCD_539, "539" },
+ { _CCD_3777, "3777" },
+ { _CCD_548 , "548" },
+ { -1 , "unknown" }
+};
+
+/****************************** local functions ******************************/
+
+#ifndef LINUX_24
+/** This is called as the fill_inode function when an inode
+ * is going into (fill = 1) or out of service (fill = 0).
+ *
+ * Note: only the top-level directory needs to do this; if
+ * a lower level is referenced, the parent will be as well.
+ *
+ * Here simply a dummy function
+ */
+static void procfsFillFunc( struct inode *inode, int fill )
+{
+}
+#endif
+
+/** returns a pointer to the port-mode string
+ */
+static const char* procfsGetMode( int mode )
+{
+ if((mode < _PORT_EPP) || (mode > _PORT_ECP))
+ return procfsPortModes[_PORT_ECP+1];
+
+ return procfsPortModes[mode];
+}
+
+/** determines CCD-Type string
+ */
+static const char* procfsGetCCDType( pScanData ps )
+{
+ int i;
+ int ccd_id = ps->Device.bCCDID;
+ pTabDef tab = procfsCCDTypes98001;
+
+ if( _IS_ASIC98(ps->sCaps.AsicID)) {
+
+ if(_ASIC_IS_98003 == ps->sCaps.AsicID)
+ tab = procfsCCDTypes98003;
+
+ /* seek down the description table */
+ for( i = 0; -1 != tab[i].id; i++ ) {
+
+ if( tab[i].id == ccd_id )
+ return tab[i].desc;
+ }
+ } else {
+
+ /* for older scanners only this info is available */
+ if( ps->fSonyCCD )
+ return "SONY Type";
+ else
+ return "NEC/TOSHIBA Type";
+ }
+
+ /* return the last entry if nothing applies! */
+ return tab[(sizeof(procfsCCDTypes98001)/sizeof(TabDef)-1)].desc;
+}
+
+/** will be called when reading the proc filesystem:
+ * cat /proc/pt_drv/info
+ */
+static int procfsBInfoReadProc( char *buf, char **start, off_t offset,
+ int count, int *eof, void *data )
+{
+ int len = 0;
+
+ len += sprintf( buf, "Plustek Flatbed Scanner Driver version "_PTDRV_VERSTR"\n" );
+ len += sprintf( buf + len, "IOCTL-Version: 0x%08x\n",_PTDRV_IOCTL_VERSION);
+ return len;
+}
+
+/** will be called when reading the proc filesystem:
+ * cat /proc/pt_drv/deviceX/info
+ */
+static int procfsInfoReadProc( char *buf, char **start, off_t offset,
+ int count, int *eof, void *data )
+{
+ int len = 0;
+ pScanData ps = (pScanData)data;
+
+ /* Tell us something about the device... */
+ if( NULL != ps ) {
+ len += sprintf( buf+len, "Model : %s\n",
+ MiscGetModelName(ps->sCaps.Model));
+ len += sprintf( buf+len, "Portaddress : 0x%X\n", ps->IO.portBase );
+ len += sprintf( buf+len, "Portmode : %s (%s I/O, %s)\n",
+ procfsGetMode(ps->IO.portMode),
+ (ps->IO.slowIO == _TRUE?"delayed":"fast"),
+ (ps->IO.forceMode == 0?"autodetect":"forced"));
+ len += sprintf( buf+len, "Buttons : %u\n", ps->Device.buttons);
+ len += sprintf( buf+len, "Warmuptime : %us\n", ps->warmup );
+ len += sprintf( buf+len, "Lamp timeout: %us\n", ps->lampoff );
+ len += sprintf( buf+len, "mov-switch : %u\n", ps->ModelOverride );
+ len += sprintf( buf+len, "I/O-delay : %u\n", ps->IO.delay );
+ len += sprintf( buf+len, "CCD-Type : %s\n", procfsGetCCDType(ps));
+ len += sprintf( buf+len, "TPA : %s\n",
+ (ps->sCaps.dwFlag & SFLAG_TPA) ? "yes":"no" );
+ }
+
+ return len;
+}
+
+/** will be called when reading the proc filesystem:
+ * cat /proc/pt_drv/devicex/buttony
+ */
+static int procfsButtonsReadProc( char *buf, char **start, off_t offset,
+ int count, int *eof, void *data )
+{
+ Byte b;
+ int bc = 0;
+ int len = 0;
+ pScanData ps = (pScanData)data;
+
+ if( NULL != ps ) {
+ bc = ps->Device.buttons;
+ }
+
+ /* Check the buttons... */
+ if( 0 != bc ) {
+
+ if ( _ASIC_IS_96003 == ps->sCaps.AsicID ) {
+ MiscClaimPort( ps );
+ b = IODataRegisterFromScanner( ps, ps->RegStatus );
+ if(_FLAG_P96_KEY == (b & _FLAG_P96_KEY))
+ b = 0;
+ else
+ b = 1;
+ MiscReleasePort( ps );
+ len += sprintf( buf + len, "%u\n", b );
+ } else
+ bc = 0;
+ }
+
+ if( 0 == bc )
+ len += sprintf( buf + len, "none\n" );
+
+ return len;
+}
+
+/** create a procfs entry
+ */
+static struct proc_dir_entry *new_entry( const char *name, mode_t mode,
+ struct proc_dir_entry *parent )
+{
+#ifndef LINUX_24
+ int len;
+#endif
+ struct proc_dir_entry *ent;
+
+ if (mode == S_IFDIR)
+ mode |= S_IRUGO | S_IXUGO;
+ else if (mode == 0)
+ mode = S_IFREG | S_IRUGO;
+
+#ifndef LINUX_24
+ len = strlen(name) + 1;
+
+ /* allocate memory for the entry and the name */
+ ent = kmalloc(sizeof(struct proc_dir_entry) + len, GFP_KERNEL);
+ if( NULL == ent )
+ return NULL;
+
+ memset(ent, 0, sizeof(struct proc_dir_entry));
+
+ /* position pointer of name to end of the structure*/
+ ent->name = ((char *) ent) + sizeof(*ent);
+ strcpy((char *)ent->name, name );
+
+ ent->namelen = strlen(name);
+ ent->mode = mode;
+
+ if (S_ISDIR(mode)) {
+ ent->nlink = 2;
+ ent->fill_inode = &procfsFillFunc;
+ } else {
+ ent->nlink = 1;
+ }
+
+ proc_register( parent, ent );
+#else
+ if (mode == S_IFDIR)
+ ent = proc_mkdir( name, parent );
+ else
+ ent = create_proc_entry( name, mode, parent );
+#endif
+
+ return ent;
+}
+
+/** shutdown one proc fs entry
+ */
+static inline void destroy_proc_entry( struct proc_dir_entry *root,
+ struct proc_dir_entry **d )
+{
+#ifndef LINUX_24
+ proc_unregister( root, (*d)->low_ino );
+ kfree(*d);
+#else
+ DBG(DBG_HIGH, "pt_drv: proc del '%s' root='%s'\n", (*d)->name, root->name);
+
+ remove_proc_entry((*d)->name, root );
+#endif
+
+ *d = NULL;
+}
+
+/** shutdown the proc-tree for one device
+ */
+static void destroy_proc_tree( pScanData ps )
+{
+ int i;
+
+ DBG( DBG_HIGH, "pt_drv: destroy_proc_tree !\n" );
+
+ if( ps ) {
+
+ if( ps->procDir.entry ) {
+
+ if( ps->procDir.info )
+ destroy_proc_entry( ps->procDir.entry, &ps->procDir.info );
+
+ for( i = 0; i < ps->Device.buttons; i++ ) {
+
+ if( ps->procDir.buttons[i] )
+ destroy_proc_entry(ps->procDir.entry, &ps->procDir.buttons[i]);
+ }
+
+ destroy_proc_entry( base, &ps->procDir.entry );
+ }
+ }
+}
+
+/*************************** exported functions ******************************/
+
+/** initialize our proc-fs stuff
+ */
+int ProcFsInitialize( void )
+{
+ DBG( DBG_HIGH, "ProcFsInitialize()\n" );
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+ base = new_entry( _DRV_NAME, S_IFDIR, &proc_root );
+#else
+ base = new_entry( _DRV_NAME, S_IFDIR, NULL );
+#endif
+
+ if( NULL != base ) {
+
+ devcount = 0;
+
+ binfo = new_entry( "info", 0, base );
+ if( NULL != binfo ) {
+ binfo->read_proc = procfsBInfoReadProc;
+ binfo->data = &devcount;
+ }
+ }
+
+ return _OK;
+}
+
+/** cleanup the base entry
+ */
+void ProcFsShutdown( void )
+{
+ DBG( DBG_HIGH, "ProcFsShutdown()\n" );
+
+ if( NULL != base ) {
+
+ if( NULL != binfo )
+ destroy_proc_entry( base, &binfo );
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
+ destroy_proc_entry( &proc_root, &base );
+#else
+ destroy_proc_entry( NULL, &base );
+#endif
+ }
+
+ devcount = 0;
+}
+
+/** will be called for each device, that has been found
+ */
+void ProcFsRegisterDevice( pScanData ps )
+{
+ int i;
+ char str[20];
+
+ if( NULL == base ) {
+ printk( KERN_ERR "pt_drv : proc not initialised yet!\n");
+ return;
+ }
+
+ memset( &ps->procDir, 0, sizeof(ProcDirDef));
+
+ sprintf( str, "device%u", ps->devno );
+
+ ps->procDir.entry = new_entry( str, S_IFDIR, base );
+ if( NULL == ps->procDir.entry )
+ goto error_exit;
+
+ ps->procDir.info = new_entry( "info", 0, ps->procDir.entry );
+ if( NULL == ps->procDir.info )
+ goto error_exit;
+
+ ps->procDir.info->read_proc = procfsInfoReadProc;
+ ps->procDir.info->data = ps;
+
+ for( i = 0; i < ps->Device.buttons; i++ ) {
+
+ sprintf( str, "button%u", i );
+
+ ps->procDir.buttons[i] = new_entry( str, 0, ps->procDir.entry );
+ if( NULL == ps->procDir.buttons[i] )
+ goto error_exit;
+
+ ps->procDir.buttons[i]->read_proc = procfsButtonsReadProc;
+ ps->procDir.buttons[i]->data = ps;
+ }
+
+ devcount++;
+ return;
+
+
+error_exit:
+
+ printk(KERN_ERR "pt_drv: failure registering /proc/ entry %s.\n", str );
+ destroy_proc_tree( ps );
+}
+
+/** cleanup the proc-fs for a certain device
+ */
+void ProcFsUnregisterDevice( pScanData ps )
+{
+ destroy_proc_tree( ps );
+}
+
+#else /* CONFIG_PROC_FS */
+
+int ProcFsInitialize( void )
+{
+ return _OK;
+}
+
+void ProcFsShutdown( void )
+{
+}
+
+void ProcFsRegisterDevice( pScanData ps )
+{
+}
+
+void ProcFsUnregisterDevice( pScanData ps )
+{
+}
+
+#endif
+
+#endif /* guard __KERNEL__ */
+
+/* END PLUSTEK-PP_PROCFS.C ..................................................*/