2023-05-16 12:38:47 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
2023-05-16 12:38:47 +03:00
* ( c ) 1997 - 1998 Grant R . Guenther < grant @ torque . net >
*
* This is a low - level driver for the KBIC - 951 A and KBIC - 971 A
* parallel to IDE adapter chips from KingByte Information Systems .
*
* The chips are almost identical , however , the wakeup code
* required for the 971 A interferes with the correct operation of
* the 951 A , so this driver registers itself twice , once for
* each chip .
*/
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/wait.h>
# include <asm/io.h>
2023-02-19 01:01:38 +03:00
# include "pata_parport.h"
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
# define r12w() (delay_p, inw(pi->port + 1) & 0xffff)
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
# define j44(a, b) ((((a >> 4) & 0x0f) | (b & 0xf0)) ^ 0x88)
# define j53(w) (((w >> 3) & 0x1f) | ((w >> 4) & 0xe0))
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
/*
* cont = 0 - access the IDE register file
* cont = 1 - access the IDE command set
*/
static int cont_map [ 2 ] = { 0x80 , 0x40 } ;
2005-04-17 02:20:36 +04:00
2023-02-19 01:01:28 +03:00
static int kbic_read_regr ( struct pi_adapter * pi , int cont , int regr )
2023-05-16 12:38:47 +03:00
{
int a , b , s ;
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
s = cont_map [ cont ] ;
2005-04-17 02:20:36 +04:00
switch ( pi - > mode ) {
2023-05-16 12:38:47 +03:00
case 0 :
w0 ( regr | 0x18 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w2 ( 1 ) ; w0 ( 8 ) ;
a = r1 ( ) ; w0 ( 0x28 ) ; b = r1 ( ) ; w2 ( 4 ) ;
return j44 ( a , b ) ;
case 1 :
w0 ( regr | 0x38 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w2 ( 5 ) ; w0 ( 8 ) ;
2005-04-17 02:20:36 +04:00
a = r12w ( ) ; w2 ( 4 ) ;
return j53 ( a ) ;
2023-05-16 12:38:47 +03:00
case 2 :
w0 ( regr | 0x08 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w2 ( 0xa5 ) ; w2 ( 0xa1 ) ;
2005-04-17 02:20:36 +04:00
a = r0 ( ) ; w2 ( 4 ) ;
2023-05-16 12:38:47 +03:00
return a ;
2005-04-17 02:20:36 +04:00
case 3 :
case 4 :
2023-05-16 12:38:47 +03:00
case 5 :
w0 ( 0x20 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( regr ) ;
2005-04-17 02:20:36 +04:00
a = r4 ( ) ; b = r4 ( ) ; w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
return a ;
}
2023-05-16 12:38:47 +03:00
2005-04-17 02:20:36 +04:00
return - 1 ;
2023-05-16 12:38:47 +03:00
}
2005-04-17 02:20:36 +04:00
2023-02-19 01:01:28 +03:00
static void kbic_write_regr ( struct pi_adapter * pi , int cont , int regr , int val )
2023-05-16 12:38:47 +03:00
{
int s = cont_map [ cont ] ;
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
switch ( pi - > mode ) {
case 0 :
case 1 :
case 2 :
w0 ( regr | 0x10 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ;
2005-04-17 02:20:36 +04:00
w0 ( val ) ; w2 ( 5 ) ; w2 ( 4 ) ;
break ;
case 3 :
case 4 :
2023-05-16 12:38:47 +03:00
case 5 :
w0 ( 0x20 | s ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( regr ) ;
2005-04-17 02:20:36 +04:00
w4 ( val ) ; w4 ( val ) ;
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
2023-05-16 12:38:47 +03:00
break ;
2005-04-17 02:20:36 +04:00
}
}
2023-02-19 01:01:28 +03:00
static void k951_connect ( struct pi_adapter * pi )
2023-05-16 12:38:47 +03:00
{
pi - > saved_r0 = r0 ( ) ;
pi - > saved_r2 = r2 ( ) ;
w2 ( 4 ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:28 +03:00
static void k951_disconnect ( struct pi_adapter * pi )
2023-05-16 12:38:47 +03:00
{
w0 ( pi - > saved_r0 ) ;
w2 ( pi - > saved_r2 ) ;
2005-04-17 02:20:36 +04:00
}
2023-05-16 12:38:47 +03:00
# define CCP(x) \
do { \
w2 ( 0xc4 ) ; w0 ( 0xaa ) ; w0 ( 0x55 ) ; \
w0 ( 0 ) ; w0 ( 0xff ) ; w0 ( 0x87 ) ; \
w0 ( 0x78 ) ; w0 ( x ) ; w2 ( 0xc5 ) ; \
w2 ( 0xc4 ) ; w0 ( 0xff ) ; \
} while ( 0 )
2005-04-17 02:20:36 +04:00
2023-02-19 01:01:28 +03:00
static void k971_connect ( struct pi_adapter * pi )
2023-05-16 12:38:47 +03:00
{
pi - > saved_r0 = r0 ( ) ;
pi - > saved_r2 = r2 ( ) ;
2005-04-17 02:20:36 +04:00
CCP ( 0x20 ) ;
2023-05-16 12:38:47 +03:00
w2 ( 4 ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:28 +03:00
static void k971_disconnect ( struct pi_adapter * pi )
2023-05-16 12:38:47 +03:00
{
CCP ( 0x30 ) ;
2005-04-17 02:20:36 +04:00
w0 ( pi - > saved_r0 ) ;
2023-05-16 12:38:47 +03:00
w2 ( pi - > saved_r2 ) ;
2005-04-17 02:20:36 +04:00
}
2023-05-16 12:38:47 +03:00
/*
* count must be congruent to 0 MOD 4 , but all known applications
* have this property .
*/
2023-02-19 01:01:28 +03:00
static void kbic_read_block ( struct pi_adapter * pi , char * buf , int count )
2023-05-16 12:38:47 +03:00
{
int k , a , b ;
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
switch ( pi - > mode ) {
case 0 :
w0 ( 0x98 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ;
for ( k = 0 ; k < count / 2 ; k + + ) {
w2 ( 1 ) ; w0 ( 8 ) ;
a = r1 ( ) ;
w0 ( 0x28 ) ;
b = r1 ( ) ;
buf [ 2 * k ] = j44 ( a , b ) ;
w2 ( 5 ) ;
b = r1 ( ) ;
w0 ( 8 ) ;
a = r1 ( ) ;
buf [ 2 * k + 1 ] = j44 ( a , b ) ;
2005-04-17 02:20:36 +04:00
w2 ( 4 ) ;
2023-05-16 12:38:47 +03:00
}
break ;
case 1 :
w0 ( 0xb8 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ;
for ( k = 0 ; k < count / 4 ; k + + ) {
w0 ( 0xb8 ) ;
w2 ( 4 ) ; w2 ( 5 ) ;
w0 ( 8 ) ;
buf [ 4 * k ] = j53 ( r12w ( ) ) ;
w0 ( 0xb8 ) ;
buf [ 4 * k + 1 ] = j53 ( r12w ( ) ) ;
2005-04-17 02:20:36 +04:00
w2 ( 4 ) ; w2 ( 5 ) ;
2023-05-16 12:38:47 +03:00
buf [ 4 * k + 3 ] = j53 ( r12w ( ) ) ;
w0 ( 8 ) ;
buf [ 4 * k + 2 ] = j53 ( r12w ( ) ) ;
}
w2 ( 4 ) ;
break ;
case 2 :
w0 ( 0x88 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ;
for ( k = 0 ; k < count / 2 ; k + + ) {
w2 ( 0xa0 ) ; w2 ( 0xa1 ) ;
buf [ 2 * k ] = r0 ( ) ;
w2 ( 0xa5 ) ;
buf [ 2 * k + 1 ] = r0 ( ) ;
}
w2 ( 4 ) ;
break ;
case 3 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
for ( k = 0 ; k < count ; k + + )
buf [ k ] = r4 ( ) ;
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
case 4 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
for ( k = 0 ; k < count / 2 ; k + + )
( ( u16 * ) buf ) [ k ] = r4w ( ) ;
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
case 5 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
for ( k = 0 ; k < count / 4 ; k + + )
( ( u32 * ) buf ) [ k ] = r4l ( ) ;
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
}
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:28 +03:00
static void kbic_write_block ( struct pi_adapter * pi , char * buf , int count )
2023-05-16 12:38:47 +03:00
{
int k ;
2005-04-17 02:20:36 +04:00
2023-05-16 12:38:47 +03:00
switch ( pi - > mode ) {
case 0 :
case 1 :
case 2 :
w0 ( 0x90 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ;
for ( k = 0 ; k < count / 2 ; k + + ) {
w0 ( buf [ 2 * k + 1 ] ) ;
w2 ( 0 ) ; w2 ( 4 ) ;
w0 ( buf [ 2 * k ] ) ;
w2 ( 5 ) ; w2 ( 4 ) ;
2005-04-17 02:20:36 +04:00
}
break ;
2023-05-16 12:38:47 +03:00
case 3 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
for ( k = 0 ; k < count / 2 ; k + + ) {
w4 ( buf [ 2 * k + 1 ] ) ;
w4 ( buf [ 2 * k ] ) ;
}
2005-04-17 02:20:36 +04:00
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
2023-05-16 12:38:47 +03:00
case 4 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
2023-02-19 01:01:23 +03:00
for ( k = 0 ; k < count / 2 ; k + + )
w4w ( swab16 ( ( ( u16 * ) buf ) [ k ] ) ) ;
2023-05-16 12:38:47 +03:00
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
case 5 :
w0 ( 0xa0 ) ; w2 ( 4 ) ; w2 ( 6 ) ; w2 ( 4 ) ; w3 ( 0 ) ;
2023-02-19 01:01:23 +03:00
for ( k = 0 ; k < count / 4 ; k + + )
w4l ( swab16 ( ( ( u16 * ) buf ) [ 2 * k ] ) |
swab16 ( ( ( u16 * ) buf ) [ 2 * k + 1 ] ) < < 16 ) ;
2023-05-16 12:38:47 +03:00
w2 ( 4 ) ; w2 ( 0 ) ; w2 ( 4 ) ;
break ;
}
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:30 +03:00
static void kbic_log_adapter ( struct pi_adapter * pi , char * chip )
2023-05-16 12:38:47 +03:00
{
char * mode [ 6 ] = { " 4-bit " , " 5/3 " , " 8-bit " , " EPP-8 " , " EPP_16 " , " EPP-32 " } ;
2005-04-17 02:20:36 +04:00
2023-02-19 01:01:33 +03:00
dev_info ( & pi - > dev , " KingByte %s at 0x%x, mode %d (%s), delay %d \n " ,
2023-05-16 12:38:47 +03:00
chip , pi - > port , pi - > mode , mode [ pi - > mode ] , pi - > delay ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:30 +03:00
static void k951_log_adapter ( struct pi_adapter * pi )
2023-02-19 01:01:29 +03:00
{
2023-02-19 01:01:30 +03:00
kbic_log_adapter ( pi , " KBIC-951A " ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-19 01:01:30 +03:00
static void k971_log_adapter ( struct pi_adapter * pi )
2023-02-19 01:01:29 +03:00
{
2023-02-19 01:01:30 +03:00
kbic_log_adapter ( pi , " KBIC-971A " ) ;
2005-04-17 02:20:36 +04:00
}
static struct pi_protocol k951 = {
. owner = THIS_MODULE ,
. name = " k951 " ,
. max_mode = 6 ,
. epp_first = 3 ,
. default_delay = 1 ,
. max_units = 1 ,
. write_regr = kbic_write_regr ,
. read_regr = kbic_read_regr ,
. write_block = kbic_write_block ,
. read_block = kbic_read_block ,
. connect = k951_connect ,
. disconnect = k951_disconnect ,
. log_adapter = k951_log_adapter ,
} ;
static struct pi_protocol k971 = {
. owner = THIS_MODULE ,
. name = " k971 " ,
. max_mode = 6 ,
. epp_first = 3 ,
. default_delay = 1 ,
. max_units = 1 ,
. write_regr = kbic_write_regr ,
. read_regr = kbic_read_regr ,
. write_block = kbic_write_block ,
. read_block = kbic_read_block ,
. connect = k971_connect ,
. disconnect = k971_disconnect ,
. log_adapter = k971_log_adapter ,
} ;
static int __init kbic_init ( void )
{
2006-12-07 07:36:21 +03:00
int rv ;
2023-02-19 01:01:25 +03:00
rv = pata_parport_register_driver ( & k951 ) ;
2006-12-07 07:36:21 +03:00
if ( rv < 0 )
return rv ;
2023-02-19 01:01:25 +03:00
rv = pata_parport_register_driver ( & k971 ) ;
2006-12-07 07:36:21 +03:00
if ( rv < 0 )
2023-02-19 01:01:25 +03:00
pata_parport_unregister_driver ( & k951 ) ;
2006-12-07 07:36:21 +03:00
return rv ;
2005-04-17 02:20:36 +04:00
}
static void __exit kbic_exit ( void )
{
2023-02-19 01:01:25 +03:00
pata_parport_unregister_driver ( & k951 ) ;
pata_parport_unregister_driver ( & k971 ) ;
2005-04-17 02:20:36 +04:00
}
MODULE_LICENSE ( " GPL " ) ;
2023-07-04 02:32:40 +03:00
MODULE_AUTHOR ( " Grant R. Guenther <grant@torque.net> " ) ;
MODULE_DESCRIPTION ( " KingByte Information Systems KBIC-951A and KBIC-971A "
" parallel port IDE adapter protocol driver " ) ;
2005-04-17 02:20:36 +04:00
module_init ( kbic_init )
module_exit ( kbic_exit )