// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 1997-1998 Grant R. Guenther <grant@torque.net>
*
* epia.c is a low-level protocol driver for Shuttle Technologies
* EPIA parallel to IDE adapter chip. This device is now obsolete
* and has been replaced with the EPAT chip, which is supported
* by epat.c, however, some devices based on EPIA are still
* available.
*/
#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>
#include "pata_parport.h"
/*
* mode codes: 0 nybble reads on port 1, 8-bit writes
* 1 5/3 reads on ports 1 & 2, 8-bit writes
* 2 8-bit reads and writes
* 3 8-bit EPP mode
* 4 16-bit EPP
* 5 32-bit EPP
*/
#define j44(a, b) (((a >> 4 ) & 0 x0f) + (b & 0 xf0))
#define j53(a, b) (((a >> 3 ) & 0 x1f) + ((b << 4 ) & 0 xe0))
/*
* cont = 0 IDE register file
* cont = 1 IDE control registers
*/
static int cont_map[2 ] = { 0 , 0 x80 };
static int epia_read_regr(struct pi_adapter *pi, int cont, int regr)
{
int a, b, r;
regr += cont_map[cont];
switch (pi->mode) {
case 0 :
r = regr ^ 0 x39;
w0(r); w2(1 ); w2(3 ); w0(r);
a = r1(); w2(1 ); b = r1(); w2(4 );
return j44(a, b);
case 1 :
r = regr ^ 0 x31;
w0(r); w2(1 ); w0(r & 0 x37);
w2(3 ); w2(5 ); w0(r | 0 xf0);
a = r1(); b = r2(); w2(4 );
return j53(a, b);
case 2 :
r = regr^0 x29;
w0(r); w2(1 ); w2(0 X21); w2(0 x23);
a = r0(); w2(4 );
return a;
case 3 :
case 4 :
case 5 :
w3(regr); w2(0 x24); a = r4(); w2(4 );
return a;
}
return -1 ;
}
static void epia_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
{
int r;
regr += cont_map[cont];
switch (pi->mode) {
case 0 :
case 1 :
case 2 :
r = regr ^ 0 x19;
w0(r); w2(1 ); w0(val); w2(3 ); w2(4 );
break ;
case 3 :
case 4 :
case 5 :
r = regr ^ 0 x40;
w3(r); w4(val); w2(4 );
break ;
}
}
#define WR(r, v) epia_write_regr(pi, 0 , r, v)
#define RR(r) epia_read_regr(pi, 0 , r)
/*
* The use of register 0x84 is entirely unclear - it seems to control
* some EPP counters ... currently we know about 3 different block
* sizes: the standard 512 byte reads and writes, 12 byte writes and
* 2048 byte reads (the last two being used in the CDrom drivers.
*/
static void epia_connect(struct pi_adapter *pi)
{
pi->saved_r0 = r0();
pi->saved_r2 = r2();
w2(4 ); w0(0 xa0); w0(0 x50); w0(0 xc0); w0(0 x30); w0(0 xa0); w0(0 );
w2(1 ); w2(4 );
if (pi->mode >= 3 ) {
w0(0 xa); w2(1 ); w2(4 ); w0(0 x82); w2(4 ); w2(0 xc); w2(4 );
w2(0 x24); w2(0 x26); w2(4 );
}
WR(0 x86, 8 );
}
static void epia_disconnect(struct pi_adapter *pi)
{
/* WR(0x84,0x10); */
w0(pi->saved_r0);
w2(1 ); w2(4 );
w0(pi->saved_r0);
w2(pi->saved_r2);
}
static void epia_read_block(struct pi_adapter *pi, char *buf, int count)
{
int k, ph, a, b;
switch (pi->mode) {
case 0 :
w0(0 x81); w2(1 ); w2(3 ); w0(0 xc1);
ph = 1 ;
for (k = 0 ; k < count; k++) {
w2(2 +ph); a = r1();
w2(4 +ph); b = r1();
buf[k] = j44(a, b);
ph = 1 - ph;
}
w0(0 ); w2(4 );
break ;
case 1 :
w0(0 x91); w2(1 ); w0(0 x10); w2(3 );
w0(0 x51); w2(5 ); w0(0 xd1);
ph = 1 ;
for (k = 0 ; k < count; k++) {
w2(4 + ph);
a = r1(); b = r2();
buf[k] = j53(a, b);
ph = 1 - ph;
}
w0(0 ); w2(4 );
break ;
case 2 :
w0(0 x89); w2(1 ); w2(0 x23); w2(0 x21);
ph = 1 ;
for (k = 0 ; k < count; k++) {
w2(0 x24 + ph);
buf[k] = r0();
ph = 1 - ph;
}
w2(6 ); w2(4 );
break ;
case 3 :
if (count > 512 )
WR(0 x84, 3 );
w3(0 ); w2(0 x24);
for (k = 0 ; k < count; k++)
buf[k] = r4();
w2(4 ); WR(0 x84, 0 );
break ;
case 4 :
if (count > 512 )
WR(0 x84, 3 );
w3(0 ); w2(0 x24);
for (k = 0 ; k < count / 2 ; k++)
((u16 *)buf)[k] = r4w();
w2(4 ); WR(0 x84, 0 );
break ;
case 5 :
if (count > 512 )
WR(0 x84, 3 );
w3(0 ); w2(0 x24);
for (k = 0 ; k < count / 4 ; k++)
((u32 *)buf)[k] = r4l();
w2(4 ); WR(0 x84, 0 );
break ;
}
}
static void epia_write_block(struct pi_adapter *pi, char *buf, int count)
{
int ph, k, last, d;
switch (pi->mode) {
case 0 :
case 1 :
case 2 :
w0(0 xa1); w2(1 ); w2(3 ); w2(1 ); w2(5 );
ph = 0 ; last = 0 x8000;
for (k = 0 ; k < count; k++) {
d = buf[k];
if (d != last) {
last = d;
w0(d);
}
w2(4 + ph);
ph = 1 - ph;
}
w2(7 ); w2(4 );
break ;
case 3 :
if (count < 512 )
WR(0 x84, 1 );
w3(0 x40);
for (k = 0 ; k < count; k++)
w4(buf[k]);
if (count < 512 )
WR(0 x84, 0 );
break ;
case 4 :
if (count < 512 )
WR(0 x84, 1 );
w3(0 x40);
for (k = 0 ; k < count / 2 ; k++)
w4w(((u16 *)buf)[k]);
if (count < 512 )
WR(0 x84, 0 );
break ;
case 5 :
if (count < 512 )
WR(0 x84, 1 );
w3(0 x40);
for (k = 0 ; k < count / 4 ; k++)
w4l(((u32 *)buf)[k]);
if (count < 512 )
WR(0 x84, 0 );
break ;
}
}
static int epia_test_proto(struct pi_adapter *pi)
{
int j, k, f;
int e[2 ] = { 0 , 0 };
char scratch[512 ];
epia_connect(pi);
for (j = 0 ; j < 2 ; j++) {
WR(6 , 0 xa0 + j * 0 x10);
for (k = 0 ; k < 256 ; k++) {
WR(2 , k ^ 0 xaa);
WR(3 , k ^ 0 x55);
if (RR(2 ) != (k ^ 0 xaa))
e[j]++;
}
WR(2 , 1 ); WR(3 , 1 );
}
epia_disconnect(pi);
f = 0 ;
epia_connect(pi);
WR(0 x84, 8 );
epia_read_block(pi, scratch, 512 );
for (k = 0 ; k < 256 ; k++) {
if ((scratch[2 * k] & 0 xff) != ((k + 1 ) & 0 xff))
f++;
if ((scratch[2 * k + 1 ] & 0 xff) != ((-2 - k) & 0 xff))
f++;
}
WR(0 x84, 0 );
epia_disconnect(pi);
dev_dbg(&pi->dev, "epia: port 0x%x, mode %d, test=(%d,%d,%d)\n" ,
pi->port, pi->mode, e[0 ], e[1 ], f);
return (e[0 ] && e[1 ]) || f;
}
static void epia_log_adapter(struct pi_adapter *pi)
{
char *mode[6 ] = { "4-bit" , "5/3" , "8-bit" , "EPP-8" , "EPP-16" , "EPP-32" };
dev_info(&pi->dev,
"Shuttle EPIA at 0x%x, mode %d (%s), delay %d\n" ,
pi->port, pi->mode, mode[pi->mode], pi->delay);
}
static struct pi_protocol epia = {
.owner = THIS_MODULE,
.name = "epia" ,
.max_mode = 6 ,
.epp_first = 3 ,
.default_delay = 1 ,
.max_units = 1 ,
.write_regr = epia_write_regr,
.read_regr = epia_read_regr,
.write_block = epia_write_block,
.read_block = epia_read_block,
.connect = epia_connect,
.disconnect = epia_disconnect,
.test_proto = epia_test_proto,
.log_adapter = epia_log_adapter,
};
MODULE_LICENSE("GPL" );
MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>" );
MODULE_DESCRIPTION("Shuttle Technologies EPIA parallel port IDE adapter "
"protocol driver" );
module_pata_parport_driver(epia);
Messung V0.5 in Prozent C=96 H=92 G=93
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland