162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (c) 1996-1998  Grant R. Guenther <grant@torque.net>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * bpck.c is a low-level protocol driver for the MicroSolutions
662306a36Sopenharmony_ci * "backpack" parallel port IDE adapter.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <linux/wait.h>
1562306a36Sopenharmony_ci#include <asm/io.h>
1662306a36Sopenharmony_ci#include "pata_parport.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#undef r2
1962306a36Sopenharmony_ci#undef w2
2062306a36Sopenharmony_ci#undef PC
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define PC			pi->private
2362306a36Sopenharmony_ci#define r2()			(PC=(in_p(2) & 0xff))
2462306a36Sopenharmony_ci#define w2(byte)  		{out_p(2,byte); PC = byte;}
2562306a36Sopenharmony_ci#define t2(pat)   		{PC ^= pat; out_p(2,PC);}
2662306a36Sopenharmony_ci#define e2()			{PC &= 0xfe; out_p(2,PC);}
2762306a36Sopenharmony_ci#define o2()			{PC |= 1; out_p(2,PC);}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define j44(l,h)     (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80))
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * cont = 0 - access the IDE register file
3362306a36Sopenharmony_ci * cont = 1 - access the IDE command set
3462306a36Sopenharmony_ci * cont = 2 - use internal bpck register addressing
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistatic int  cont_map[3] = { 0x40, 0x48, 0 };
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int bpck_read_regr(struct pi_adapter *pi, int cont, int regr)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	int r, l, h;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	r = regr + cont_map[cont];
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	switch (pi->mode) {
4562306a36Sopenharmony_ci	case 0:
4662306a36Sopenharmony_ci		w0(r & 0xf); w0(r); t2(2); t2(4);
4762306a36Sopenharmony_ci	        l = r1();
4862306a36Sopenharmony_ci		t2(4);
4962306a36Sopenharmony_ci		h = r1();
5062306a36Sopenharmony_ci		return j44(l, h);
5162306a36Sopenharmony_ci	case 1:
5262306a36Sopenharmony_ci		w0(r & 0xf); w0(r); t2(2);
5362306a36Sopenharmony_ci		e2(); t2(0x20);
5462306a36Sopenharmony_ci		t2(4); h = r0();
5562306a36Sopenharmony_ci		t2(1); t2(0x20);
5662306a36Sopenharmony_ci		return h;
5762306a36Sopenharmony_ci	case 2:
5862306a36Sopenharmony_ci	case 3:
5962306a36Sopenharmony_ci	case 4:
6062306a36Sopenharmony_ci		w0(r); w2(9); w2(0); w2(0x20);
6162306a36Sopenharmony_ci		h = r4();
6262306a36Sopenharmony_ci		w2(0);
6362306a36Sopenharmony_ci		return h;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci	return -1;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void bpck_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int r;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci        r = regr + cont_map[cont];
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	switch (pi->mode) {
7662306a36Sopenharmony_ci	case 0:
7762306a36Sopenharmony_ci	case 1: w0(r);
7862306a36Sopenharmony_ci		t2(2);
7962306a36Sopenharmony_ci		w0(val);
8062306a36Sopenharmony_ci		o2(); t2(4); t2(1);
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	case 2:
8362306a36Sopenharmony_ci	case 3:
8462306a36Sopenharmony_ci	case 4: w0(r); w2(9); w2(0);
8562306a36Sopenharmony_ci		w0(val); w2(1); w2(3); w2(0);
8662306a36Sopenharmony_ci		break;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* These macros access the bpck registers in native addressing */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#define WR(r,v)		bpck_write_regr(pi,2,r,v)
9462306a36Sopenharmony_ci#define RR(r)		(bpck_read_regr(pi,2,r))
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void bpck_write_block(struct pi_adapter *pi, char *buf, int count)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int i;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	switch (pi->mode) {
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	case 0:
10362306a36Sopenharmony_ci		WR(4, 0x40);
10462306a36Sopenharmony_ci		w0(0x40); t2(2); t2(1);
10562306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
10662306a36Sopenharmony_ci			w0(buf[i]);
10762306a36Sopenharmony_ci			t2(4);
10862306a36Sopenharmony_ci		}
10962306a36Sopenharmony_ci		WR(4, 0);
11062306a36Sopenharmony_ci		break;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	case 1:
11362306a36Sopenharmony_ci		WR(4, 0x50);
11462306a36Sopenharmony_ci		w0(0x40); t2(2); t2(1);
11562306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
11662306a36Sopenharmony_ci			w0(buf[i]);
11762306a36Sopenharmony_ci			t2(4);
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci		WR(4, 0x10);
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	case 2:
12362306a36Sopenharmony_ci		WR(4, 0x48);
12462306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(1);
12562306a36Sopenharmony_ci		for (i = 0; i < count; i++)
12662306a36Sopenharmony_ci			w4(buf[i]);
12762306a36Sopenharmony_ci		w2(0);
12862306a36Sopenharmony_ci		WR(4, 8);
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	case 3:
13262306a36Sopenharmony_ci		WR(4, 0x48);
13362306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(1);
13462306a36Sopenharmony_ci		for (i = 0; i < count / 2; i++)
13562306a36Sopenharmony_ci			w4w(((u16 *)buf)[i]);
13662306a36Sopenharmony_ci		w2(0);
13762306a36Sopenharmony_ci		WR(4, 8);
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	case 4:
14162306a36Sopenharmony_ci		WR(4, 0x48);
14262306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(1);
14362306a36Sopenharmony_ci		for (i = 0; i < count / 4; i++)
14462306a36Sopenharmony_ci			w4l(((u32 *)buf)[i]);
14562306a36Sopenharmony_ci		w2(0);
14662306a36Sopenharmony_ci		WR(4, 8);
14762306a36Sopenharmony_ci		break;
14862306a36Sopenharmony_ci 	}
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void bpck_read_block(struct pi_adapter *pi, char *buf, int count)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	int i, l, h;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	switch (pi->mode) {
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	case 0:
15862306a36Sopenharmony_ci		WR(4, 0x40);
15962306a36Sopenharmony_ci		w0(0x40); t2(2);
16062306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
16162306a36Sopenharmony_ci			t2(4); l = r1();
16262306a36Sopenharmony_ci			t2(4); h = r1();
16362306a36Sopenharmony_ci			buf[i] = j44(l, h);
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci		WR(4, 0);
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	case 1:
16962306a36Sopenharmony_ci		WR(4, 0x50);
17062306a36Sopenharmony_ci		w0(0x40); t2(2); t2(0x20);
17162306a36Sopenharmony_ci		for (i = 0; i < count; i++) {
17262306a36Sopenharmony_ci			t2(4);
17362306a36Sopenharmony_ci			buf[i] = r0();
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci		t2(1); t2(0x20);
17662306a36Sopenharmony_ci		WR(4, 0x10);
17762306a36Sopenharmony_ci		break;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	case 2:
18062306a36Sopenharmony_ci		WR(4, 0x48);
18162306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(0x20);
18262306a36Sopenharmony_ci		for (i = 0; i < count; i++)
18362306a36Sopenharmony_ci			buf[i] = r4();
18462306a36Sopenharmony_ci		w2(0);
18562306a36Sopenharmony_ci		WR(4, 8);
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	case 3:
18962306a36Sopenharmony_ci		WR(4, 0x48);
19062306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(0x20);
19162306a36Sopenharmony_ci		for (i = 0; i < count / 2; i++)
19262306a36Sopenharmony_ci			((u16 *)buf)[i] = r4w();
19362306a36Sopenharmony_ci		w2(0);
19462306a36Sopenharmony_ci		WR(4, 8);
19562306a36Sopenharmony_ci		break;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	case 4:
19862306a36Sopenharmony_ci		WR(4, 0x48);
19962306a36Sopenharmony_ci		w0(0x40); w2(9); w2(0); w2(0x20);
20062306a36Sopenharmony_ci		for (i = 0; i < count / 4; i++)
20162306a36Sopenharmony_ci			((u32 *)buf)[i] = r4l();
20262306a36Sopenharmony_ci		w2(0);
20362306a36Sopenharmony_ci		WR(4, 8);
20462306a36Sopenharmony_ci		break;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int bpck_probe_unit(struct pi_adapter *pi)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int o1, o0, f7, id;
21262306a36Sopenharmony_ci	int t, s;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	id = pi->unit;
21562306a36Sopenharmony_ci	s = 0;
21662306a36Sopenharmony_ci	w2(4); w2(0xe); r2(); t2(2);
21762306a36Sopenharmony_ci	o1 = r1()&0xf8;
21862306a36Sopenharmony_ci	o0 = r0();
21962306a36Sopenharmony_ci	w0(255-id); w2(4); w0(id);
22062306a36Sopenharmony_ci	t2(8); t2(8); t2(8);
22162306a36Sopenharmony_ci	t2(2); t = r1()&0xf8;
22262306a36Sopenharmony_ci	f7 = ((id % 8) == 7);
22362306a36Sopenharmony_ci	if ((f7) || (t != o1)) {
22462306a36Sopenharmony_ci		t2(2);
22562306a36Sopenharmony_ci		s = r1() & 0xf8;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci	if ((t == o1) && ((!f7) || (s == o1)))  {
22862306a36Sopenharmony_ci		w2(0x4c); w0(o0);
22962306a36Sopenharmony_ci		return 0;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	t2(8); w0(0); t2(2); w2(0x4c); w0(o0);
23262306a36Sopenharmony_ci	return 1;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void bpck_connect(struct pi_adapter *pi)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	pi->saved_r0 = r0();
23862306a36Sopenharmony_ci	w0(0xff-pi->unit); w2(4); w0(pi->unit);
23962306a36Sopenharmony_ci	t2(8); t2(8); t2(8);
24062306a36Sopenharmony_ci	t2(2); t2(2);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	switch (pi->mode) {
24362306a36Sopenharmony_ci	case 0:
24462306a36Sopenharmony_ci		t2(8); WR(4, 0);
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	case 1:
24762306a36Sopenharmony_ci		t2(8); WR(4, 0x10);
24862306a36Sopenharmony_ci		break;
24962306a36Sopenharmony_ci	case 2:
25062306a36Sopenharmony_ci	case 3:
25162306a36Sopenharmony_ci	case 4:
25262306a36Sopenharmony_ci		w2(0); WR(4, 8);
25362306a36Sopenharmony_ci		break;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	WR(5,8);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/*
25962306a36Sopenharmony_ci	 * Possibly wrong, purpose unknown (fiddle with ESS logic ???)
26062306a36Sopenharmony_ci	 * if (pi->devtype == PI_PCD) {
26162306a36Sopenharmony_ci	 */
26262306a36Sopenharmony_ci	WR(0x46, 0x10);
26362306a36Sopenharmony_ci	WR(0x4c, 0x38);
26462306a36Sopenharmony_ci	WR(0x4d, 0x88);
26562306a36Sopenharmony_ci	WR(0x46, 0xa0);
26662306a36Sopenharmony_ci	WR(0x41, 0);
26762306a36Sopenharmony_ci	WR(0x4e, 8);
26862306a36Sopenharmony_ci	/* } */
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void bpck_disconnect(struct pi_adapter *pi)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	w0(0);
27462306a36Sopenharmony_ci	if (pi->mode >= 2) {
27562306a36Sopenharmony_ci		w2(9); w2(0);
27662306a36Sopenharmony_ci	} else {
27762306a36Sopenharmony_ci		t2(2);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	w2(0x4c); w0(pi->saved_r0);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic void bpck_force_spp(struct pi_adapter *pi)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	/* This fakes the EPP protocol to turn off EPP ... */
28562306a36Sopenharmony_ci	pi->saved_r0 = r0();
28662306a36Sopenharmony_ci	w0(0xff-pi->unit); w2(4); w0(pi->unit);
28762306a36Sopenharmony_ci	t2(8); t2(8); t2(8);
28862306a36Sopenharmony_ci	t2(2); t2(2);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	w2(0);
29162306a36Sopenharmony_ci	w0(4); w2(9); w2(0);
29262306a36Sopenharmony_ci	w0(0); w2(1); w2(3); w2(0);
29362306a36Sopenharmony_ci	w0(0); w2(9); w2(0);
29462306a36Sopenharmony_ci	w2(0x4c); w0(pi->saved_r0);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define TEST_LEN  16
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int bpck_test_proto(struct pi_adapter *pi)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	int i, e, l, h, om;
30262306a36Sopenharmony_ci	char buf[TEST_LEN];
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	bpck_force_spp(pi);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	switch (pi->mode) {
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	case 0:
30962306a36Sopenharmony_ci		bpck_connect(pi);
31062306a36Sopenharmony_ci		WR(0x13, 0x7f);
31162306a36Sopenharmony_ci		w0(0x13); t2(2);
31262306a36Sopenharmony_ci		for (i = 0; i < TEST_LEN; i++) {
31362306a36Sopenharmony_ci			t2(4); l = r1();
31462306a36Sopenharmony_ci			t2(4); h = r1();
31562306a36Sopenharmony_ci			buf[i] = j44(l, h);
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci		bpck_disconnect(pi);
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	case 1:
32162306a36Sopenharmony_ci		bpck_connect(pi);
32262306a36Sopenharmony_ci		WR(0x13, 0x7f);
32362306a36Sopenharmony_ci		w0(0x13); t2(2); t2(0x20);
32462306a36Sopenharmony_ci		for (i = 0; i < TEST_LEN; i++) {
32562306a36Sopenharmony_ci			t2(4);
32662306a36Sopenharmony_ci			buf[i] = r0();
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci		t2(1); t2(0x20);
32962306a36Sopenharmony_ci		bpck_disconnect(pi);
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	case 2:
33362306a36Sopenharmony_ci	case 3:
33462306a36Sopenharmony_ci	case 4:
33562306a36Sopenharmony_ci		om = pi->mode;
33662306a36Sopenharmony_ci		pi->mode = 0;
33762306a36Sopenharmony_ci		bpck_connect(pi);
33862306a36Sopenharmony_ci		WR(7, 3);
33962306a36Sopenharmony_ci		WR(4, 8);
34062306a36Sopenharmony_ci		bpck_disconnect(pi);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		pi->mode = om;
34362306a36Sopenharmony_ci		bpck_connect(pi);
34462306a36Sopenharmony_ci		w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		switch (pi->mode) {
34762306a36Sopenharmony_ci		case 2:
34862306a36Sopenharmony_ci			for (i = 0; i < TEST_LEN; i++)
34962306a36Sopenharmony_ci				buf[i] = r4();
35062306a36Sopenharmony_ci			break;
35162306a36Sopenharmony_ci		case 3:
35262306a36Sopenharmony_ci			for (i = 0; i < TEST_LEN / 2; i++)
35362306a36Sopenharmony_ci				((u16 *)buf)[i] = r4w();
35462306a36Sopenharmony_ci			break;
35562306a36Sopenharmony_ci		case 4:
35662306a36Sopenharmony_ci			for (i = 0; i < TEST_LEN / 4; i++)
35762306a36Sopenharmony_ci				((u32 *)buf)[i] = r4l();
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		w2(0);
36262306a36Sopenharmony_ci		WR(7, 0);
36362306a36Sopenharmony_ci		bpck_disconnect(pi);
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	dev_dbg(&pi->dev, "bpck: 0x%x unit %d mode %d: ",
36962306a36Sopenharmony_ci		pi->port, pi->unit, pi->mode);
37062306a36Sopenharmony_ci	print_hex_dump_debug("bpck: ", DUMP_PREFIX_NONE, TEST_LEN, 1, buf,
37162306a36Sopenharmony_ci			     TEST_LEN, false);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	e = 0;
37462306a36Sopenharmony_ci	for (i = 0; i < TEST_LEN; i++) {
37562306a36Sopenharmony_ci		if (buf[i] != i + 1)
37662306a36Sopenharmony_ci			e++;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return e;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void bpck_read_eeprom(struct pi_adapter *pi, char *buf)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	int i, j, k, p, v, f, om, od;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	bpck_force_spp(pi);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	om = pi->mode;  od = pi->delay;
38962306a36Sopenharmony_ci	pi->mode = 0; pi->delay = 6;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	bpck_connect(pi);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	WR(4, 0);
39462306a36Sopenharmony_ci	for (i = 0; i < 64; i++) {
39562306a36Sopenharmony_ci		WR(6, 8);
39662306a36Sopenharmony_ci		WR(6, 0xc);
39762306a36Sopenharmony_ci		p = 0x100;
39862306a36Sopenharmony_ci		for (k = 0; k < 9; k++) {
39962306a36Sopenharmony_ci			f = (((i + 0x180) & p) != 0) * 2;
40062306a36Sopenharmony_ci			WR(6, f + 0xc);
40162306a36Sopenharmony_ci			WR(6, f + 0xd);
40262306a36Sopenharmony_ci			WR(6, f + 0xc);
40362306a36Sopenharmony_ci			p = (p >> 1);
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci		for (j = 0; j < 2; j++) {
40662306a36Sopenharmony_ci			v = 0;
40762306a36Sopenharmony_ci			for (k = 0; k < 8; k++) {
40862306a36Sopenharmony_ci				WR(6, 0xc);
40962306a36Sopenharmony_ci				WR(6, 0xd);
41062306a36Sopenharmony_ci				WR(6, 0xc);
41162306a36Sopenharmony_ci				f = RR(0);
41262306a36Sopenharmony_ci				v = 2 * v + (f == 0x84);
41362306a36Sopenharmony_ci			}
41462306a36Sopenharmony_ci			buf[2 * i + 1 - j] = v;
41562306a36Sopenharmony_ci		}
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	WR(6, 8);
41862306a36Sopenharmony_ci	WR(6, 0);
41962306a36Sopenharmony_ci	WR(5, 8);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	bpck_disconnect(pi);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci        if (om >= 2) {
42462306a36Sopenharmony_ci		bpck_connect(pi);
42562306a36Sopenharmony_ci		WR(7, 3);
42662306a36Sopenharmony_ci		WR(4, 8);
42762306a36Sopenharmony_ci		bpck_disconnect(pi);
42862306a36Sopenharmony_ci        }
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	pi->mode = om; pi->delay = od;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int bpck_test_port(struct pi_adapter *pi)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int i, r, m;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/* Check for 8-bit port */
43862306a36Sopenharmony_ci	w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i);
43962306a36Sopenharmony_ci	m = -1;
44062306a36Sopenharmony_ci	if (r == i)
44162306a36Sopenharmony_ci		m = 2;
44262306a36Sopenharmony_ci	if (r == (255-i))
44362306a36Sopenharmony_ci		m = 0;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	w2(0xc);
44662306a36Sopenharmony_ci	i = r0();
44762306a36Sopenharmony_ci	w0(255-i);
44862306a36Sopenharmony_ci	r = r0();
44962306a36Sopenharmony_ci	w0(i);
45062306a36Sopenharmony_ci	if (r != (255-i))
45162306a36Sopenharmony_ci		m = -1;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (m == 0) {
45462306a36Sopenharmony_ci		w2(6);
45562306a36Sopenharmony_ci		w2(0xc);
45662306a36Sopenharmony_ci		r = r0();
45762306a36Sopenharmony_ci		w0(0xaa);
45862306a36Sopenharmony_ci		w0(r);
45962306a36Sopenharmony_ci		w0(0xaa);
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	if (m == 2) {
46262306a36Sopenharmony_ci		w2(0x26);
46362306a36Sopenharmony_ci		w2(0xc);
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (m == -1)
46762306a36Sopenharmony_ci		return 0;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return 5;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic void bpck_log_adapter(struct pi_adapter *pi)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	char *mode_str[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" };
47562306a36Sopenharmony_ci	char scratch[128];
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	bpck_read_eeprom(pi,scratch);
47862306a36Sopenharmony_ci	print_hex_dump_bytes("bpck EEPROM: ", DUMP_PREFIX_NONE, scratch, 128);
47962306a36Sopenharmony_ci	dev_info(&pi->dev,
48062306a36Sopenharmony_ci		 "backpack %8.8s unit %d at 0x%x, mode %d (%s), delay %d\n",
48162306a36Sopenharmony_ci		 &scratch[110], pi->unit, pi->port, pi->mode,
48262306a36Sopenharmony_ci		 mode_str[pi->mode], pi->delay);
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic struct pi_protocol bpck = {
48662306a36Sopenharmony_ci	.owner		= THIS_MODULE,
48762306a36Sopenharmony_ci	.name		= "bpck",
48862306a36Sopenharmony_ci	.max_mode	= 5,
48962306a36Sopenharmony_ci	.epp_first	= 2,
49062306a36Sopenharmony_ci	.default_delay	= 4,
49162306a36Sopenharmony_ci	.max_units	= 255,
49262306a36Sopenharmony_ci	.write_regr	= bpck_write_regr,
49362306a36Sopenharmony_ci	.read_regr	= bpck_read_regr,
49462306a36Sopenharmony_ci	.write_block	= bpck_write_block,
49562306a36Sopenharmony_ci	.read_block	= bpck_read_block,
49662306a36Sopenharmony_ci	.connect	= bpck_connect,
49762306a36Sopenharmony_ci	.disconnect	= bpck_disconnect,
49862306a36Sopenharmony_ci	.test_port	= bpck_test_port,
49962306a36Sopenharmony_ci	.probe_unit	= bpck_probe_unit,
50062306a36Sopenharmony_ci	.test_proto	= bpck_test_proto,
50162306a36Sopenharmony_ci	.log_adapter	= bpck_log_adapter,
50262306a36Sopenharmony_ci};
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
50562306a36Sopenharmony_ciMODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
50662306a36Sopenharmony_ciMODULE_DESCRIPTION("MicroSolutions BACKPACK parallel port IDE adapter protocol driver");
50762306a36Sopenharmony_cimodule_pata_parport_driver(bpck);
508