summaryrefslogtreecommitdiffstats
path: root/drivers/ata/pata_parport/on20.c
blob: 7c70e5b13a2adb565c08df8a19a7360b8488ec88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * (c) 1996-1998  Grant R. Guenther <grant@torque.net>
 *
 * on20.c is a low-level protocol driver for the
 * Onspec 90c20 parallel to 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"

#define op(f)					\
	do {					\
		w2(4); w0(f); w2(5); w2(0xd);	\
		w2(5); w2(0xd); w2(5); w2(4);	\
	} while (0)

#define vl(v)					\
	do {					\
		w2(4); w0(v); w2(5);		\
		w2(7); w2(5); w2(4);		\
	} while (0)

#define j44(a, b)	(((a >> 4) & 0x0f) | (b & 0xf0))

/*
 * cont = 0 - access the IDE register file
 * cont = 1 - access the IDE command set
 */

static int on20_read_regr(struct pi_adapter *pi, int cont, int regr)
{
	int h, l, r;

	r = (regr << 2) + 1 + cont;

	op(1); vl(r); op(0);

	switch (pi->mode) {
	case 0:
		w2(4); w2(6); l = r1();
		w2(4); w2(6); h = r1();
		w2(4); w2(6); w2(4); w2(6); w2(4);
		return j44(l, h);
	case 1:
		w2(4); w2(0x26); r = r0();
		w2(4); w2(0x26); w2(4);
		return r;
	}

	return -1;
}

static void on20_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
{
	int r = (regr << 2) + 1 + cont;

	op(1); vl(r);
	op(0); vl(val);
	op(0); vl(val);
}

static void on20_connect(struct pi_adapter *pi)
{
	pi->saved_r0 = r0();
	pi->saved_r2 = r2();

	w2(4); w0(0); w2(0xc); w2(4); w2(6); w2(4); w2(6); w2(4);
	if (pi->mode) {
		op(2); vl(8); op(2); vl(9);
	} else {
		op(2); vl(0); op(2); vl(8);
	}
}

static void on20_disconnect(struct pi_adapter *pi)
{
	w2(4); w0(7); w2(4); w2(0xc); w2(4);
	w0(pi->saved_r0);
	w2(pi->saved_r2);
}

static void on20_read_block(struct pi_adapter *pi, char *buf, int count)
{
	int k, l, h;

	op(1); vl(1); op(0);

	for (k = 0; k < count; k++) {
		if (pi->mode) {
			w2(4); w2(0x26); buf[k] = r0();
		} else {
			w2(6); l = r1(); w2(4);
			w2(6); h = r1(); w2(4);
			buf[k] = j44(l, h);
		}
	}
	w2(4);
}

static void on20_write_block(struct pi_adapter *pi, char *buf, int count)
{
	int k;

	op(1); vl(1); op(0);

	for (k = 0; k < count; k++) {
		w2(5); w0(buf[k]); w2(7);
	}
	w2(4);
}

static void on20_log_adapter(struct pi_adapter *pi)
{
	char *mode_string[2] = { "4-bit", "8-bit" };

	dev_info(&pi->dev,
		 "OnSpec 90c20 at 0x%x, mode %d (%s), delay %d\n",
		 pi->port, pi->mode, mode_string[pi->mode], pi->delay);
}

static struct pi_protocol on20 = {
	.owner		= THIS_MODULE,
	.name		= "on20",
	.max_mode	= 2,
	.epp_first	= 2,
	.default_delay	= 1,
	.max_units	= 1,
	.write_regr	= on20_write_regr,
	.read_regr	= on20_read_regr,
	.write_block	= on20_write_block,
	.read_block	= on20_read_block,
	.connect	= on20_connect,
	.disconnect	= on20_disconnect,
	.log_adapter	= on20_log_adapter,
};

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
MODULE_DESCRIPTION("Onspec 90c20 parallel port IDE adapter protocol driver");
module_pata_parport_driver(on20);