2006-07-04 09:06:20 +04:00
/*
* Drivers for the Total Impact PPC based computer " BRIQ "
* by Dr . Karsten Jeppesen
*
*/
# include <linux/module.h>
2008-05-20 21:15:41 +04:00
# include <linux/smp_lock.h>
2006-07-04 09:06:20 +04:00
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/tty.h>
# include <linux/timer.h>
# include <linux/kernel.h>
# include <linux/wait.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/miscdevice.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/init.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/prom.h>
# define BRIQ_PANEL_MINOR 156
# define BRIQ_PANEL_VFD_IOPORT 0x0390
# define BRIQ_PANEL_LED_IOPORT 0x0398
# define BRIQ_PANEL_VER "1.1 (04 / 20 / 2002)"
# define BRIQ_PANEL_MSG0 "Loading Linux"
static int vfd_is_open ;
static unsigned char vfd [ 40 ] ;
static int vfd_cursor ;
static unsigned char ledpb , led ;
static void update_vfd ( void )
{
int i ;
/* cursor home */
outb ( 0x02 , BRIQ_PANEL_VFD_IOPORT ) ;
for ( i = 0 ; i < 20 ; i + + )
outb ( vfd [ i ] , BRIQ_PANEL_VFD_IOPORT + 1 ) ;
/* cursor to next line */
outb ( 0xc0 , BRIQ_PANEL_VFD_IOPORT ) ;
for ( i = 20 ; i < 40 ; i + + )
outb ( vfd [ i ] , BRIQ_PANEL_VFD_IOPORT + 1 ) ;
}
static void set_led ( char state )
{
if ( state = = ' R ' )
led = 0x01 ;
else if ( state = = ' G ' )
led = 0x02 ;
else if ( state = = ' Y ' )
led = 0x03 ;
else if ( state = = ' X ' )
led = 0x00 ;
outb ( led , BRIQ_PANEL_LED_IOPORT ) ;
}
static int briq_panel_open ( struct inode * ino , struct file * filep )
{
2008-05-20 21:15:41 +04:00
lock_kernel ( ) ;
/* enforce single access, vfd_is_open is protected by BKL */
if ( vfd_is_open ) {
unlock_kernel ( ) ;
2006-07-04 09:06:20 +04:00
return - EBUSY ;
2008-05-20 21:15:41 +04:00
}
2006-07-04 09:06:20 +04:00
vfd_is_open = 1 ;
2008-05-20 21:15:41 +04:00
unlock_kernel ( ) ;
2006-07-04 09:06:20 +04:00
return 0 ;
}
static int briq_panel_release ( struct inode * ino , struct file * filep )
{
if ( ! vfd_is_open )
return - ENODEV ;
vfd_is_open = 0 ;
return 0 ;
}
2006-09-23 21:20:56 +04:00
static ssize_t briq_panel_read ( struct file * file , char __user * buf , size_t count ,
2006-07-04 09:06:20 +04:00
loff_t * ppos )
{
unsigned short c ;
unsigned char cp ;
if ( ! vfd_is_open )
return - ENODEV ;
c = ( inb ( BRIQ_PANEL_LED_IOPORT ) & 0x000c ) | ( ledpb & 0x0003 ) ;
set_led ( ' ' ) ;
/* upper button released */
if ( ( ! ( ledpb & 0x0004 ) ) & & ( c & 0x0004 ) ) {
cp = ' ' ;
ledpb = c ;
if ( copy_to_user ( buf , & cp , 1 ) )
return - EFAULT ;
return 1 ;
}
/* lower button released */
else if ( ( ! ( ledpb & 0x0008 ) ) & & ( c & 0x0008 ) ) {
cp = ' \r ' ;
ledpb = c ;
if ( copy_to_user ( buf , & cp , 1 ) )
return - EFAULT ;
return 1 ;
} else {
ledpb = c ;
return 0 ;
}
}
static void scroll_vfd ( void )
{
int i ;
for ( i = 0 ; i < 20 ; i + + ) {
vfd [ i ] = vfd [ i + 20 ] ;
vfd [ i + 20 ] = ' ' ;
}
vfd_cursor = 20 ;
}
2006-09-23 21:20:56 +04:00
static ssize_t briq_panel_write ( struct file * file , const char __user * buf , size_t len ,
2006-07-04 09:06:20 +04:00
loff_t * ppos )
{
size_t indx = len ;
int i , esc = 0 ;
if ( ! vfd_is_open )
return - EBUSY ;
for ( ; ; ) {
2006-09-23 21:20:56 +04:00
char c ;
2006-07-04 09:06:20 +04:00
if ( ! indx )
break ;
2006-09-23 21:20:56 +04:00
if ( get_user ( c , buf ) )
return - EFAULT ;
2006-07-04 09:06:20 +04:00
if ( esc ) {
2006-09-23 21:20:56 +04:00
set_led ( c ) ;
2006-07-04 09:06:20 +04:00
esc = 0 ;
2006-09-23 21:20:56 +04:00
} else if ( c = = 27 ) {
2006-07-04 09:06:20 +04:00
esc = 1 ;
2006-09-23 21:20:56 +04:00
} else if ( c = = 12 ) {
2006-07-04 09:06:20 +04:00
/* do a form feed */
for ( i = 0 ; i < 40 ; i + + )
vfd [ i ] = ' ' ;
vfd_cursor = 0 ;
2006-09-23 21:20:56 +04:00
} else if ( c = = 10 ) {
2006-07-04 09:06:20 +04:00
if ( vfd_cursor < 20 )
vfd_cursor = 20 ;
else if ( vfd_cursor < 40 )
vfd_cursor = 40 ;
else if ( vfd_cursor < 60 )
vfd_cursor = 60 ;
if ( vfd_cursor > 59 )
scroll_vfd ( ) ;
} else {
/* just a character */
if ( vfd_cursor > 39 )
scroll_vfd ( ) ;
2006-09-23 21:20:56 +04:00
vfd [ vfd_cursor + + ] = c ;
2006-07-04 09:06:20 +04:00
}
indx - - ;
buf + + ;
}
update_vfd ( ) ;
return len ;
}
2007-02-12 11:55:32 +03:00
static const struct file_operations briq_panel_fops = {
2006-07-04 09:06:20 +04:00
. owner = THIS_MODULE ,
. read = briq_panel_read ,
. write = briq_panel_write ,
. open = briq_panel_open ,
. release = briq_panel_release ,
} ;
static struct miscdevice briq_panel_miscdev = {
BRIQ_PANEL_MINOR ,
" briq_panel " ,
& briq_panel_fops
} ;
static int __init briq_panel_init ( void )
{
2007-04-24 07:50:55 +04:00
struct device_node * root = of_find_node_by_path ( " / " ) ;
2006-09-23 19:44:58 +04:00
const char * machine ;
2006-07-04 09:06:20 +04:00
int i ;
2007-05-01 07:54:02 +04:00
machine = of_get_property ( root , " model " , NULL ) ;
2007-04-24 07:50:55 +04:00
if ( ! machine | | strncmp ( machine , " TotalImpact,BRIQ-1 " , 18 ) ! = 0 ) {
of_node_put ( root ) ;
2006-07-04 09:06:20 +04:00
return - ENODEV ;
2007-04-24 07:50:55 +04:00
}
of_node_put ( root ) ;
2006-07-04 09:06:20 +04:00
printk ( KERN_INFO
" briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com) \n " ,
BRIQ_PANEL_VER ) ;
if ( ! request_region ( BRIQ_PANEL_VFD_IOPORT , 4 , " BRIQ Front Panel " ) )
return - EBUSY ;
if ( ! request_region ( BRIQ_PANEL_LED_IOPORT , 2 , " BRIQ Front Panel " ) ) {
release_region ( BRIQ_PANEL_VFD_IOPORT , 4 ) ;
return - EBUSY ;
}
ledpb = inb ( BRIQ_PANEL_LED_IOPORT ) & 0x000c ;
if ( misc_register ( & briq_panel_miscdev ) < 0 ) {
release_region ( BRIQ_PANEL_VFD_IOPORT , 4 ) ;
release_region ( BRIQ_PANEL_LED_IOPORT , 2 ) ;
return - EBUSY ;
}
outb ( 0x38 , BRIQ_PANEL_VFD_IOPORT ) ; /* Function set */
outb ( 0x01 , BRIQ_PANEL_VFD_IOPORT ) ; /* Clear display */
outb ( 0x0c , BRIQ_PANEL_VFD_IOPORT ) ; /* Display on */
outb ( 0x06 , BRIQ_PANEL_VFD_IOPORT ) ; /* Entry normal */
for ( i = 0 ; i < 40 ; i + + )
vfd [ i ] = ' ' ;
# ifndef MODULE
vfd [ 0 ] = ' L ' ;
vfd [ 1 ] = ' o ' ;
vfd [ 2 ] = ' a ' ;
vfd [ 3 ] = ' d ' ;
vfd [ 4 ] = ' i ' ;
vfd [ 5 ] = ' n ' ;
vfd [ 6 ] = ' g ' ;
vfd [ 7 ] = ' ' ;
vfd [ 8 ] = ' . ' ;
vfd [ 9 ] = ' . ' ;
vfd [ 10 ] = ' . ' ;
# endif /* !MODULE */
update_vfd ( ) ;
return 0 ;
}
static void __exit briq_panel_exit ( void )
{
misc_deregister ( & briq_panel_miscdev ) ;
release_region ( BRIQ_PANEL_VFD_IOPORT , 4 ) ;
release_region ( BRIQ_PANEL_LED_IOPORT , 2 ) ;
}
module_init ( briq_panel_init ) ;
module_exit ( briq_panel_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Karsten Jeppesen <karsten@jeppesens.com> " ) ;
MODULE_DESCRIPTION ( " Driver for the Total Impact briQ front panel " ) ;