2005-04-16 15:20:36 -07:00
/*
paride . c ( c ) 1997 - 8 Grant R . Guenther < grant @ torque . net >
Under the terms of the GNU General Public License .
This is the base module for the family of device drivers
that support parallel port IDE devices .
*/
/* Changes:
1.01 GRG 1998.05 .03 Use spinlocks
1.02 GRG 1998.05 .05 init_proto , release_proto , ktti
1.03 GRG 1998.08 .15 eliminate compiler warning
1.04 GRG 1998.11 .28 added support for FRIQ
1.05 TMW 2000.06 .06 use parport_find_number instead of
parport_enumerate
1.06 TMW 2001.03 .26 more sane parport - or - not resource management
*/
# define PI_VERSION "1.06"
# include <linux/module.h>
# include <linux/kmod.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/ioport.h>
# include <linux/string.h>
# include <linux/spinlock.h>
# include <linux/wait.h>
2005-10-30 15:03:48 -08:00
# include <linux/sched.h> /* TASK_* */
2005-04-16 15:20:36 -07:00
# include <linux/parport.h>
2015-05-20 20:57:01 +05:30
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include "paride.h"
MODULE_LICENSE ( " GPL " ) ;
# define MAX_PROTOS 32
static struct pi_protocol * protocols [ MAX_PROTOS ] ;
static DEFINE_SPINLOCK ( pi_spinlock ) ;
void pi_write_regr ( PIA * pi , int cont , int regr , int val )
{
pi - > proto - > write_regr ( pi , cont , regr , val ) ;
}
EXPORT_SYMBOL ( pi_write_regr ) ;
int pi_read_regr ( PIA * pi , int cont , int regr )
{
return pi - > proto - > read_regr ( pi , cont , regr ) ;
}
EXPORT_SYMBOL ( pi_read_regr ) ;
void pi_write_block ( PIA * pi , char * buf , int count )
{
pi - > proto - > write_block ( pi , buf , count ) ;
}
EXPORT_SYMBOL ( pi_write_block ) ;
void pi_read_block ( PIA * pi , char * buf , int count )
{
pi - > proto - > read_block ( pi , buf , count ) ;
}
EXPORT_SYMBOL ( pi_read_block ) ;
static void pi_wake_up ( void * p )
{
PIA * pi = ( PIA * ) p ;
unsigned long flags ;
void ( * cont ) ( void ) = NULL ;
spin_lock_irqsave ( & pi_spinlock , flags ) ;
if ( pi - > claim_cont & & ! parport_claim ( pi - > pardev ) ) {
cont = pi - > claim_cont ;
pi - > claim_cont = NULL ;
pi - > claimed = 1 ;
}
spin_unlock_irqrestore ( & pi_spinlock , flags ) ;
wake_up ( & ( pi - > parq ) ) ;
if ( cont )
cont ( ) ;
}
int pi_schedule_claimed ( PIA * pi , void ( * cont ) ( void ) )
{
unsigned long flags ;
spin_lock_irqsave ( & pi_spinlock , flags ) ;
if ( pi - > pardev & & parport_claim ( pi - > pardev ) ) {
pi - > claim_cont = cont ;
spin_unlock_irqrestore ( & pi_spinlock , flags ) ;
return 0 ;
}
pi - > claimed = 1 ;
spin_unlock_irqrestore ( & pi_spinlock , flags ) ;
return 1 ;
}
EXPORT_SYMBOL ( pi_schedule_claimed ) ;
void pi_do_claimed ( PIA * pi , void ( * cont ) ( void ) )
{
if ( pi_schedule_claimed ( pi , cont ) )
cont ( ) ;
}
EXPORT_SYMBOL ( pi_do_claimed ) ;
static void pi_claim ( PIA * pi )
{
if ( pi - > claimed )
return ;
pi - > claimed = 1 ;
if ( pi - > pardev )
wait_event ( pi - > parq ,
! parport_claim ( ( struct pardevice * ) pi - > pardev ) ) ;
}
static void pi_unclaim ( PIA * pi )
{
pi - > claimed = 0 ;
if ( pi - > pardev )
parport_release ( ( struct pardevice * ) ( pi - > pardev ) ) ;
}
void pi_connect ( PIA * pi )
{
pi_claim ( pi ) ;
pi - > proto - > connect ( pi ) ;
}
EXPORT_SYMBOL ( pi_connect ) ;
void pi_disconnect ( PIA * pi )
{
pi - > proto - > disconnect ( pi ) ;
pi_unclaim ( pi ) ;
}
EXPORT_SYMBOL ( pi_disconnect ) ;
static void pi_unregister_parport ( PIA * pi )
{
if ( pi - > pardev ) {
parport_unregister_device ( ( struct pardevice * ) ( pi - > pardev ) ) ;
pi - > pardev = NULL ;
}
}
void pi_release ( PIA * pi )
{
pi_unregister_parport ( pi ) ;
if ( pi - > proto - > release_proto )
pi - > proto - > release_proto ( pi ) ;
module_put ( pi - > proto - > owner ) ;
}
EXPORT_SYMBOL ( pi_release ) ;
static int default_test_proto ( PIA * pi , char * scratch , int verbose )
{
int j , k ;
int e [ 2 ] = { 0 , 0 } ;
pi - > proto - > connect ( pi ) ;
for ( j = 0 ; j < 2 ; j + + ) {
pi_write_regr ( pi , 0 , 6 , 0xa0 + j * 0x10 ) ;
for ( k = 0 ; k < 256 ; k + + ) {
pi_write_regr ( pi , 0 , 2 , k ^ 0xaa ) ;
pi_write_regr ( pi , 0 , 3 , k ^ 0x55 ) ;
if ( pi_read_regr ( pi , 0 , 2 ) ! = ( k ^ 0xaa ) )
e [ j ] + + ;
}
}
pi - > proto - > disconnect ( pi ) ;
if ( verbose )
printk ( " %s: %s: port 0x%x, mode %d, test=(%d,%d) \n " ,
pi - > device , pi - > proto - > name , pi - > port ,
pi - > mode , e [ 0 ] , e [ 1 ] ) ;
return ( e [ 0 ] & & e [ 1 ] ) ; /* not here if both > 0 */
}
static int pi_test_proto ( PIA * pi , char * scratch , int verbose )
{
int res ;
pi_claim ( pi ) ;
if ( pi - > proto - > test_proto )
res = pi - > proto - > test_proto ( pi , scratch , verbose ) ;
else
res = default_test_proto ( pi , scratch , verbose ) ;
pi_unclaim ( pi ) ;
return res ;
}
2006-12-06 20:36:20 -08:00
int paride_register ( PIP * pr )
2005-04-16 15:20:36 -07:00
{
int k ;
for ( k = 0 ; k < MAX_PROTOS ; k + + )
if ( protocols [ k ] & & ! strcmp ( pr - > name , protocols [ k ] - > name ) ) {
printk ( " paride: %s protocol already registered \n " ,
pr - > name ) ;
2006-12-06 20:36:21 -08:00
return - 1 ;
2005-04-16 15:20:36 -07:00
}
k = 0 ;
while ( ( k < MAX_PROTOS ) & & ( protocols [ k ] ) )
k + + ;
if ( k = = MAX_PROTOS ) {
printk ( " paride: protocol table full \n " ) ;
2006-12-06 20:36:21 -08:00
return - 1 ;
2005-04-16 15:20:36 -07:00
}
protocols [ k ] = pr ;
pr - > index = k ;
printk ( " paride: %s registered as protocol %d \n " , pr - > name , k ) ;
2006-12-06 20:36:21 -08:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-12-06 20:36:20 -08:00
EXPORT_SYMBOL ( paride_register ) ;
2005-04-16 15:20:36 -07:00
2006-12-06 20:36:20 -08:00
void paride_unregister ( PIP * pr )
2005-04-16 15:20:36 -07:00
{
if ( ! pr )
return ;
if ( protocols [ pr - > index ] ! = pr ) {
printk ( " paride: %s not registered \n " , pr - > name ) ;
return ;
}
protocols [ pr - > index ] = NULL ;
}
2006-12-06 20:36:20 -08:00
EXPORT_SYMBOL ( paride_unregister ) ;
2005-04-16 15:20:36 -07:00
2015-05-20 20:57:01 +05:30
static int pi_register_parport ( PIA * pi , int verbose , int unit )
2005-04-16 15:20:36 -07:00
{
struct parport * port ;
2015-05-20 20:57:01 +05:30
struct pardev_cb par_cb ;
2005-04-16 15:20:36 -07:00
port = parport_find_base ( pi - > port ) ;
if ( ! port )
return 0 ;
2015-05-20 20:57:01 +05:30
memset ( & par_cb , 0 , sizeof ( par_cb ) ) ;
par_cb . wakeup = pi_wake_up ;
par_cb . private = ( void * ) pi ;
pi - > pardev = parport_register_dev_model ( port , pi - > device , & par_cb ,
unit ) ;
2005-04-16 15:20:36 -07:00
parport_put_port ( port ) ;
if ( ! pi - > pardev )
return 0 ;
init_waitqueue_head ( & pi - > parq ) ;
if ( verbose )
printk ( " %s: 0x%x is %s \n " , pi - > device , pi - > port , port - > name ) ;
pi - > parname = ( char * ) port - > name ;
return 1 ;
}
static int pi_probe_mode ( PIA * pi , int max , char * scratch , int verbose )
{
int best , range ;
if ( pi - > mode ! = - 1 ) {
if ( pi - > mode > = max )
return 0 ;
range = 3 ;
if ( pi - > mode > = pi - > proto - > epp_first )
range = 8 ;
if ( ( range = = 8 ) & & ( pi - > port % 8 ) )
return 0 ;
pi - > reserved = range ;
return ( ! pi_test_proto ( pi , scratch , verbose ) ) ;
}
best = - 1 ;
for ( pi - > mode = 0 ; pi - > mode < max ; pi - > mode + + ) {
range = 3 ;
if ( pi - > mode > = pi - > proto - > epp_first )
range = 8 ;
if ( ( range = = 8 ) & & ( pi - > port % 8 ) )
break ;
pi - > reserved = range ;
if ( ! pi_test_proto ( pi , scratch , verbose ) )
best = pi - > mode ;
}
pi - > mode = best ;
return ( best > - 1 ) ;
}
static int pi_probe_unit ( PIA * pi , int unit , char * scratch , int verbose )
{
int max , s , e ;
s = unit ;
e = s + 1 ;
if ( s = = - 1 ) {
s = 0 ;
e = pi - > proto - > max_units ;
}
2015-05-20 20:57:01 +05:30
if ( ! pi_register_parport ( pi , verbose , s ) )
2005-04-16 15:20:36 -07:00
return 0 ;
if ( pi - > proto - > test_port ) {
pi_claim ( pi ) ;
max = pi - > proto - > test_port ( pi ) ;
pi_unclaim ( pi ) ;
} else
max = pi - > proto - > max_mode ;
if ( pi - > proto - > probe_unit ) {
pi_claim ( pi ) ;
for ( pi - > unit = s ; pi - > unit < e ; pi - > unit + + )
if ( pi - > proto - > probe_unit ( pi ) ) {
pi_unclaim ( pi ) ;
if ( pi_probe_mode ( pi , max , scratch , verbose ) )
return 1 ;
pi_unregister_parport ( pi ) ;
return 0 ;
}
pi_unclaim ( pi ) ;
pi_unregister_parport ( pi ) ;
return 0 ;
}
if ( ! pi_probe_mode ( pi , max , scratch , verbose ) ) {
pi_unregister_parport ( pi ) ;
return 0 ;
}
return 1 ;
}
int pi_init ( PIA * pi , int autoprobe , int port , int mode ,
int unit , int protocol , int delay , char * scratch ,
int devtype , int verbose , char * device )
{
int p , k , s , e ;
int lpts [ 7 ] = { 0x3bc , 0x378 , 0x278 , 0x268 , 0x27c , 0x26c , 0 } ;
s = protocol ;
e = s + 1 ;
if ( ! protocols [ 0 ] )
request_module ( " paride_protocol " ) ;
if ( autoprobe ) {
s = 0 ;
e = MAX_PROTOS ;
} else if ( ( s < 0 ) | | ( s > = MAX_PROTOS ) | | ( port < = 0 ) | |
( ! protocols [ s ] ) | | ( unit < 0 ) | |
( unit > = protocols [ s ] - > max_units ) ) {
printk ( " %s: Invalid parameters \n " , device ) ;
return 0 ;
}
for ( p = s ; p < e ; p + + ) {
struct pi_protocol * proto = protocols [ p ] ;
if ( ! proto )
continue ;
/* still racy */
if ( ! try_module_get ( proto - > owner ) )
continue ;
pi - > proto = proto ;
pi - > private = 0 ;
if ( proto - > init_proto & & proto - > init_proto ( pi ) < 0 ) {
pi - > proto = NULL ;
module_put ( proto - > owner ) ;
continue ;
}
if ( delay = = - 1 )
pi - > delay = pi - > proto - > default_delay ;
else
pi - > delay = delay ;
pi - > devtype = devtype ;
pi - > device = device ;
pi - > parname = NULL ;
pi - > pardev = NULL ;
init_waitqueue_head ( & pi - > parq ) ;
pi - > claimed = 0 ;
pi - > claim_cont = NULL ;
pi - > mode = mode ;
if ( port ! = - 1 ) {
pi - > port = port ;
if ( pi_probe_unit ( pi , unit , scratch , verbose ) )
break ;
pi - > port = 0 ;
} else {
k = 0 ;
while ( ( pi - > port = lpts [ k + + ] ) )
if ( pi_probe_unit
( pi , unit , scratch , verbose ) )
break ;
if ( pi - > port )
break ;
}
if ( pi - > proto - > release_proto )
pi - > proto - > release_proto ( pi ) ;
module_put ( proto - > owner ) ;
}
if ( ! pi - > port ) {
if ( autoprobe )
printk ( " %s: Autoprobe failed \n " , device ) ;
else
printk ( " %s: Adapter not found \n " , device ) ;
return 0 ;
}
if ( pi - > parname )
printk ( " %s: Sharing %s at 0x%x \n " , pi - > device ,
pi - > parname , pi - > port ) ;
pi - > proto - > log_adapter ( pi , scratch , verbose ) ;
return 1 ;
}
EXPORT_SYMBOL ( pi_init ) ;
2015-05-20 20:57:01 +05:30
static int pi_probe ( struct pardevice * par_dev )
{
struct device_driver * drv = par_dev - > dev . driver ;
int len = strlen ( drv - > name ) ;
if ( strncmp ( par_dev - > name , drv - > name , len ) )
return - ENODEV ;
return 0 ;
}
void * pi_register_driver ( char * name )
{
struct parport_driver * parp_drv ;
int ret ;
parp_drv = kzalloc ( sizeof ( * parp_drv ) , GFP_KERNEL ) ;
if ( ! parp_drv )
return NULL ;
parp_drv - > name = name ;
parp_drv - > probe = pi_probe ;
parp_drv - > devmodel = true ;
ret = parport_register_driver ( parp_drv ) ;
if ( ret ) {
kfree ( parp_drv ) ;
return NULL ;
}
return ( void * ) parp_drv ;
}
EXPORT_SYMBOL ( pi_register_driver ) ;
void pi_unregister_driver ( void * _drv )
{
struct parport_driver * drv = _drv ;
parport_unregister_driver ( drv ) ;
kfree ( drv ) ;
}
EXPORT_SYMBOL ( pi_unregister_driver ) ;