// SPDX-License-Identifier: GPL-2.0-or-later
/*
* (c) 1996-1998 Grant R. Guenther <grant@torque.net>
*
* bpck.c is a low-level protocol driver for the MicroSolutions
* "backpack" parallel port IDE adapter.
*/
#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"
#undef r2
#undef w2
#undef PC
#define PC pi->private
#define r2() (PC=(in_p(2 ) & 0 xff))
#define w2(byte) {out_p(2 ,byte); PC = byte;}
#define t2(pat) {PC ^= pat; out_p(2 ,PC);}
#define e2() {PC &= 0 xfe; out_p(2 ,PC);}
#define o2() {PC |= 1 ; out_p(2 ,PC);}
#define j44(l,h) (((l>>3 )&0 x7)|((l>>4 )&0 x8)|((h<<1 )&0 x70)|(h&0 x80))
/*
* cont = 0 - access the IDE register file
* cont = 1 - access the IDE command set
* cont = 2 - use internal bpck register addressing
*/
static int cont_map[3 ] = { 0 x40, 0 x48, 0 };
static int bpck_read_regr(struct pi_adapter *pi, int cont, int regr)
{
int r, l, h;
r = regr + cont_map[cont];
switch (pi->mode) {
case 0 :
w0(r & 0 xf); w0(r); t2(2 ); t2(4 );
l = r1();
t2(4 );
h = r1();
return j44(l, h);
case 1 :
w0(r & 0 xf); w0(r); t2(2 );
e2(); t2(0 x20);
t2(4 ); h = r0();
t2(1 ); t2(0 x20);
return h;
case 2 :
case 3 :
case 4 :
w0(r); w2(9 ); w2(0 ); w2(0 x20);
h = r4();
w2(0 );
return h;
}
return -1 ;
}
static void bpck_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
{
int r;
r = regr + cont_map[cont];
switch (pi->mode) {
case 0 :
case 1 : w0(r);
t2(2 );
w0(val);
o2(); t2(4 ); t2(1 );
break ;
case 2 :
case 3 :
case 4 : w0(r); w2(9 ); w2(0 );
w0(val); w2(1 ); w2(3 ); w2(0 );
break ;
}
}
/* These macros access the bpck registers in native addressing */
#define WR(r,v) bpck_write_regr(pi,2 ,r,v)
#define RR(r) (bpck_read_regr(pi,2 ,r))
static void bpck_write_block(struct pi_adapter *pi, char *buf, int count)
{
int i;
switch (pi->mode) {
case 0 :
WR(4 , 0 x40);
w0(0 x40); t2(2 ); t2(1 );
for (i = 0 ; i < count; i++) {
w0(buf[i]);
t2(4 );
}
WR(4 , 0 );
break ;
case 1 :
WR(4 , 0 x50);
w0(0 x40); t2(2 ); t2(1 );
for (i = 0 ; i < count; i++) {
w0(buf[i]);
t2(4 );
}
WR(4 , 0 x10);
break ;
case 2 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(1 );
for (i = 0 ; i < count; i++)
w4(buf[i]);
w2(0 );
WR(4 , 8 );
break ;
case 3 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(1 );
for (i = 0 ; i < count / 2 ; i++)
w4w(((u16 *)buf)[i]);
w2(0 );
WR(4 , 8 );
break ;
case 4 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(1 );
for (i = 0 ; i < count / 4 ; i++)
w4l(((u32 *)buf)[i]);
w2(0 );
WR(4 , 8 );
break ;
}
}
static void bpck_read_block(struct pi_adapter *pi, char *buf, int count)
{
int i, l, h;
switch (pi->mode) {
case 0 :
WR(4 , 0 x40);
w0(0 x40); t2(2 );
for (i = 0 ; i < count; i++) {
t2(4 ); l = r1();
t2(4 ); h = r1();
buf[i] = j44(l, h);
}
WR(4 , 0 );
break ;
case 1 :
WR(4 , 0 x50);
w0(0 x40); t2(2 ); t2(0 x20);
for (i = 0 ; i < count; i++) {
t2(4 );
buf[i] = r0();
}
t2(1 ); t2(0 x20);
WR(4 , 0 x10);
break ;
case 2 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(0 x20);
for (i = 0 ; i < count; i++)
buf[i] = r4();
w2(0 );
WR(4 , 8 );
break ;
case 3 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(0 x20);
for (i = 0 ; i < count / 2 ; i++)
((u16 *)buf)[i] = r4w();
w2(0 );
WR(4 , 8 );
break ;
case 4 :
WR(4 , 0 x48);
w0(0 x40); w2(9 ); w2(0 ); w2(0 x20);
for (i = 0 ; i < count / 4 ; i++)
((u32 *)buf)[i] = r4l();
w2(0 );
WR(4 , 8 );
break ;
}
}
static int bpck_probe_unit(struct pi_adapter *pi)
{
int o1, o0, f7, id;
int t, s;
id = pi->unit;
s = 0 ;
w2(4 ); w2(0 xe); r2(); t2(2 );
o1 = r1()&0 xf8;
o0 = r0();
w0(255 -id); w2(4 ); w0(id);
t2(8 ); t2(8 ); t2(8 );
t2(2 ); t = r1()&0 xf8;
f7 = ((id % 8 ) == 7 );
if ((f7) || (t != o1)) {
t2(2 );
s = r1() & 0 xf8;
}
if ((t == o1) && ((!f7) || (s == o1))) {
w2(0 x4c); w0(o0);
return 0 ;
}
t2(8 ); w0(0 ); t2(2 ); w2(0 x4c); w0(o0);
return 1 ;
}
static void bpck_connect(struct pi_adapter *pi)
{
pi->saved_r0 = r0();
w0(0 xff-pi->unit); w2(4 ); w0(pi->unit);
t2(8 ); t2(8 ); t2(8 );
t2(2 ); t2(2 );
switch (pi->mode) {
case 0 :
t2(8 ); WR(4 , 0 );
break ;
case 1 :
t2(8 ); WR(4 , 0 x10);
break ;
case 2 :
case 3 :
case 4 :
w2(0 ); WR(4 , 8 );
break ;
}
WR(5 ,8 );
/*
* Possibly wrong, purpose unknown (fiddle with ESS logic ???)
* if (pi->devtype == PI_PCD) {
*/
WR(0 x46, 0 x10);
WR(0 x4c, 0 x38);
WR(0 x4d, 0 x88);
WR(0 x46, 0 xa0);
WR(0 x41, 0 );
WR(0 x4e, 8 );
/* } */
}
static void bpck_disconnect(struct pi_adapter *pi)
{
w0(0 );
if (pi->mode >= 2 ) {
w2(9 ); w2(0 );
} else {
t2(2 );
}
w2(0 x4c); w0(pi->saved_r0);
}
static void bpck_force_spp(struct pi_adapter *pi)
{
/* This fakes the EPP protocol to turn off EPP ... */
pi->saved_r0 = r0();
w0(0 xff-pi->unit); w2(4 ); w0(pi->unit);
t2(8 ); t2(8 ); t2(8 );
t2(2 ); t2(2 );
w2(0 );
w0(4 ); w2(9 ); w2(0 );
w0(0 ); w2(1 ); w2(3 ); w2(0 );
w0(0 ); w2(9 ); w2(0 );
w2(0 x4c); w0(pi->saved_r0);
}
#define TEST_LEN 16
static int bpck_test_proto(struct pi_adapter *pi)
{
int i, e, l, h, om;
char buf[TEST_LEN];
bpck_force_spp(pi);
switch (pi->mode) {
case 0 :
bpck_connect(pi);
WR(0 x13, 0 x7f);
w0(0 x13); t2(2 );
for (i = 0 ; i < TEST_LEN; i++) {
t2(4 ); l = r1();
t2(4 ); h = r1();
buf[i] = j44(l, h);
}
bpck_disconnect(pi);
break ;
case 1 :
bpck_connect(pi);
WR(0 x13, 0 x7f);
w0(0 x13); t2(2 ); t2(0 x20);
for (i = 0 ; i < TEST_LEN; i++) {
t2(4 );
buf[i] = r0();
}
t2(1 ); t2(0 x20);
bpck_disconnect(pi);
break ;
case 2 :
case 3 :
case 4 :
om = pi->mode;
pi->mode = 0 ;
bpck_connect(pi);
WR(7 , 3 );
WR(4 , 8 );
bpck_disconnect(pi);
pi->mode = om;
bpck_connect(pi);
w0(0 x13); w2(9 ); w2(1 ); w0(0 ); w2(3 ); w2(0 ); w2(0 xe0);
switch (pi->mode) {
case 2 :
for (i = 0 ; i < TEST_LEN; i++)
buf[i] = r4();
break ;
case 3 :
for (i = 0 ; i < TEST_LEN / 2 ; i++)
((u16 *)buf)[i] = r4w();
break ;
case 4 :
for (i = 0 ; i < TEST_LEN / 4 ; i++)
((u32 *)buf)[i] = r4l();
break ;
}
w2(0 );
WR(7 , 0 );
bpck_disconnect(pi);
break ;
}
dev_dbg(&pi->dev, "bpck: 0x%x unit %d mode %d: " ,
pi->port, pi->unit, pi->mode);
print_hex_dump_debug("bpck: " , DUMP_PREFIX_NONE, TEST_LEN, 1 , buf,
TEST_LEN, false );
e = 0 ;
for (i = 0 ; i < TEST_LEN; i++) {
if (buf[i] != i + 1 )
e++;
}
return e;
}
static void bpck_read_eeprom(struct pi_adapter *pi, char *buf)
{
int i, j, k, p, v, f, om, od;
bpck_force_spp(pi);
om = pi->mode; od = pi->delay;
pi->mode = 0 ; pi->delay = 6 ;
bpck_connect(pi);
WR(4 , 0 );
for (i = 0 ; i < 64 ; i++) {
WR(6 , 8 );
WR(6 , 0 xc);
p = 0 x100;
for (k = 0 ; k < 9 ; k++) {
f = (((i + 0 x180) & p) != 0 ) * 2 ;
WR(6 , f + 0 xc);
WR(6 , f + 0 xd);
WR(6 , f + 0 xc);
p = (p >> 1 );
}
for (j = 0 ; j < 2 ; j++) {
v = 0 ;
for (k = 0 ; k < 8 ; k++) {
WR(6 , 0 xc);
WR(6 , 0 xd);
WR(6 , 0 xc);
f = RR(0 );
v = 2 * v + (f == 0 x84);
}
buf[2 * i + 1 - j] = v;
}
}
WR(6 , 8 );
WR(6 , 0 );
WR(5 , 8 );
bpck_disconnect(pi);
if (om >= 2 ) {
bpck_connect(pi);
WR(7 , 3 );
WR(4 , 8 );
bpck_disconnect(pi);
}
pi->mode = om; pi->delay = od;
}
static int bpck_test_port(struct pi_adapter *pi)
{
int i, r, m;
/* Check for 8-bit port */
w2(0 x2c); i = r0(); w0(255 -i); r = r0(); w0(i);
m = -1 ;
if (r == i)
m = 2 ;
if (r == (255 -i))
m = 0 ;
w2(0 xc);
i = r0();
w0(255 -i);
r = r0();
w0(i);
if (r != (255 -i))
m = -1 ;
if (m == 0 ) {
w2(6 );
w2(0 xc);
r = r0();
w0(0 xaa);
w0(r);
w0(0 xaa);
}
if (m == 2 ) {
w2(0 x26);
w2(0 xc);
}
if (m == -1 )
return 0 ;
return 5 ;
}
static void bpck_log_adapter(struct pi_adapter *pi)
{
char *mode_str[5 ] = { "4-bit" , "8-bit" , "EPP-8" , "EPP-16" , "EPP-32" };
char scratch[128 ];
bpck_read_eeprom(pi,scratch);
print_hex_dump_bytes("bpck EEPROM: " , DUMP_PREFIX_NONE, scratch, 128 );
dev_info(&pi->dev,
"backpack %8.8s unit %d at 0x%x, mode %d (%s), delay %d\n" ,
&scratch[110 ], pi->unit, pi->port, pi->mode,
mode_str[pi->mode], pi->delay);
}
static struct pi_protocol bpck = {
.owner = THIS_MODULE,
.name = "bpck" ,
.max_mode = 5 ,
.epp_first = 2 ,
.default_delay = 4 ,
.max_units = 255 ,
.write_regr = bpck_write_regr,
.read_regr = bpck_read_regr,
.write_block = bpck_write_block,
.read_block = bpck_read_block,
.connect = bpck_connect,
.disconnect = bpck_disconnect,
.test_port = bpck_test_port,
.probe_unit = bpck_probe_unit,
.test_proto = bpck_test_proto,
.log_adapter = bpck_log_adapter,
};
MODULE_LICENSE("GPL" );
MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>" );
MODULE_DESCRIPTION("MicroSolutions BACKPACK parallel port IDE adapter protocol driver" );
module_pata_parport_driver(bpck);
Messung V0.5 in Prozent C=96 H=92 G=93
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland