2007-08-22 00:34:16 +04:00
/*
* Picvue PVC160206 display driver
*
* Brian Murphy < brian . murphy @ eicon . com >
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/proc_fs.h>
# include <linux/interrupt.h>
# include <linux/timer.h>
2008-01-11 07:53:21 +03:00
# include <linux/mutex.h>
2007-08-22 00:34:16 +04:00
# include "picvue.h"
2008-01-11 07:53:21 +03:00
static DEFINE_MUTEX ( pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
static char pvc_lines [ PVC_NLINES ] [ PVC_LINELEN + 1 ] ;
static int pvc_linedata [ PVC_NLINES ] ;
static struct proc_dir_entry * pvc_display_dir ;
static char * pvc_linename [ PVC_NLINES ] = { " line1 " , " line2 " } ;
# define DISPLAY_DIR_NAME "display"
static int scroll_dir , scroll_interval ;
static struct timer_list timer ;
static void pvc_display ( unsigned long data )
{
int i ;
pvc_clear ( ) ;
for ( i = 0 ; i < PVC_NLINES ; i + + )
pvc_write_string ( pvc_lines [ i ] , 0 , i ) ;
}
static DECLARE_TASKLET ( pvc_display_tasklet , & pvc_display , 0 ) ;
static int pvc_proc_read_line ( char * page , char * * start ,
off_t off , int count ,
int * eof , void * data )
{
char * origpage = page ;
int lineno = * ( int * ) data ;
if ( lineno < 0 | | lineno > PVC_NLINES ) {
printk ( KERN_WARNING " proc_read_line: invalid lineno %d \n " , lineno ) ;
return 0 ;
}
2008-01-11 07:53:21 +03:00
mutex_lock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
page + = sprintf ( page , " %s \n " , pvc_lines [ lineno ] ) ;
2008-01-11 07:53:21 +03:00
mutex_unlock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
return page - origpage ;
}
static int pvc_proc_write_line ( struct file * file , const char * buffer ,
unsigned long count , void * data )
{
int origcount = count ;
int lineno = * ( int * ) data ;
if ( lineno < 0 | | lineno > PVC_NLINES ) {
printk ( KERN_WARNING " proc_write_line: invalid lineno %d \n " ,
lineno ) ;
return origcount ;
}
if ( count > PVC_LINELEN )
count = PVC_LINELEN ;
if ( buffer [ count - 1 ] = = ' \n ' )
count - - ;
2008-01-11 07:53:21 +03:00
mutex_lock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
strncpy ( pvc_lines [ lineno ] , buffer , count ) ;
pvc_lines [ lineno ] [ count ] = ' \0 ' ;
2008-01-11 07:53:21 +03:00
mutex_unlock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
tasklet_schedule ( & pvc_display_tasklet ) ;
return origcount ;
}
static int pvc_proc_write_scroll ( struct file * file , const char * buffer ,
unsigned long count , void * data )
{
int origcount = count ;
int cmd = simple_strtol ( buffer , NULL , 10 ) ;
2008-01-11 07:53:21 +03:00
mutex_lock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
if ( scroll_interval ! = 0 )
del_timer ( & timer ) ;
if ( cmd = = 0 ) {
scroll_dir = 0 ;
scroll_interval = 0 ;
} else {
if ( cmd < 0 ) {
scroll_dir = - 1 ;
scroll_interval = - cmd ;
} else {
scroll_dir = 1 ;
scroll_interval = cmd ;
}
add_timer ( & timer ) ;
}
2008-01-11 07:53:21 +03:00
mutex_unlock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
return origcount ;
}
static int pvc_proc_read_scroll ( char * page , char * * start ,
off_t off , int count ,
int * eof , void * data )
{
char * origpage = page ;
2008-01-11 07:53:21 +03:00
mutex_lock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
page + = sprintf ( page , " %d \n " , scroll_dir * scroll_interval ) ;
2008-01-11 07:53:21 +03:00
mutex_unlock ( & pvc_mutex ) ;
2007-08-22 00:34:16 +04:00
return page - origpage ;
}
void pvc_proc_timerfunc ( unsigned long data )
{
if ( scroll_dir < 0 )
pvc_move ( DISPLAY | RIGHT ) ;
else if ( scroll_dir > 0 )
pvc_move ( DISPLAY | LEFT ) ;
timer . expires = jiffies + scroll_interval ;
add_timer ( & timer ) ;
}
static void pvc_proc_cleanup ( void )
{
int i ;
for ( i = 0 ; i < PVC_NLINES ; i + + )
remove_proc_entry ( pvc_linename [ i ] , pvc_display_dir ) ;
remove_proc_entry ( " scroll " , pvc_display_dir ) ;
remove_proc_entry ( DISPLAY_DIR_NAME , NULL ) ;
del_timer ( & timer ) ;
}
static int __init pvc_proc_init ( void )
{
struct proc_dir_entry * proc_entry ;
int i ;
pvc_display_dir = proc_mkdir ( DISPLAY_DIR_NAME , NULL ) ;
if ( pvc_display_dir = = NULL )
goto error ;
for ( i = 0 ; i < PVC_NLINES ; i + + ) {
strcpy ( pvc_lines [ i ] , " " ) ;
pvc_linedata [ i ] = i ;
}
for ( i = 0 ; i < PVC_NLINES ; i + + ) {
proc_entry = create_proc_entry ( pvc_linename [ i ] , 0644 ,
pvc_display_dir ) ;
if ( proc_entry = = NULL )
goto error ;
proc_entry - > read_proc = pvc_proc_read_line ;
proc_entry - > write_proc = pvc_proc_write_line ;
proc_entry - > data = & pvc_linedata [ i ] ;
}
proc_entry = create_proc_entry ( " scroll " , 0644 , pvc_display_dir ) ;
if ( proc_entry = = NULL )
goto error ;
proc_entry - > write_proc = pvc_proc_write_scroll ;
proc_entry - > read_proc = pvc_proc_read_scroll ;
init_timer ( & timer ) ;
timer . function = pvc_proc_timerfunc ;
return 0 ;
error :
pvc_proc_cleanup ( ) ;
return - ENOMEM ;
}
module_init ( pvc_proc_init ) ;
module_exit ( pvc_proc_cleanup ) ;
MODULE_LICENSE ( " GPL " ) ;