1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * (c) 1997-8 Grant R. Guenther <grant@torque.net> |
4 | * |
5 | * aten.c is a low-level protocol driver for the ATEN EH-100 |
6 | * parallel port adapter. The EH-100 supports 4-bit and 8-bit |
7 | * modes only. There is also an EH-132 which supports EPP mode |
8 | * transfers. The EH-132 is not yet supported. |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/wait.h> |
16 | #include <linux/types.h> |
17 | #include <asm/io.h> |
18 | #include "pata_parport.h" |
19 | |
20 | #define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88) |
21 | |
22 | /* |
23 | * cont = 0 - access the IDE register file |
24 | * cont = 1 - access the IDE command set |
25 | */ |
26 | static int cont_map[2] = { 0x08, 0x20 }; |
27 | |
28 | static void aten_write_regr(struct pi_adapter *pi, int cont, int regr, int val) |
29 | { |
30 | int r = regr + cont_map[cont] + 0x80; |
31 | |
32 | w0(r); w2(0xe); w2(6); w0(val); w2(7); w2(6); w2(0xc); |
33 | } |
34 | |
35 | static int aten_read_regr(struct pi_adapter *pi, int cont, int regr) |
36 | { |
37 | int a, b, r; |
38 | |
39 | r = regr + cont_map[cont] + 0x40; |
40 | |
41 | switch (pi->mode) { |
42 | |
43 | case 0: |
44 | w0(r); w2(0xe); w2(6); |
45 | w2(7); w2(6); w2(0); |
46 | a = r1(); w0(0x10); b = r1(); w2(0xc); |
47 | return j44(a,b); |
48 | |
49 | case 1: |
50 | r |= 0x10; |
51 | w0(r); w2(0xe); w2(6); w0(0xff); |
52 | w2(0x27); w2(0x26); w2(0x20); |
53 | a = r0(); |
54 | w2(0x26); w2(0xc); |
55 | return a; |
56 | } |
57 | return -1; |
58 | } |
59 | |
60 | static void aten_read_block(struct pi_adapter *pi, char *buf, int count) |
61 | { |
62 | int k, a, b, c, d; |
63 | |
64 | switch (pi->mode) { |
65 | |
66 | case 0: |
67 | w0(0x48); w2(0xe); w2(6); |
68 | for (k = 0; k < count / 2; k++) { |
69 | w2(7); w2(6); w2(2); |
70 | a = r1(); w0(0x58); b = r1(); |
71 | w2(0); d = r1(); w0(0x48); c = r1(); |
72 | buf[2 * k] = j44(c, d); |
73 | buf[2 * k + 1] = j44(a, b); |
74 | } |
75 | w2(0xc); |
76 | break; |
77 | |
78 | case 1: |
79 | w0(0x58); w2(0xe); w2(6); |
80 | for (k = 0; k < count / 2; k++) { |
81 | w2(0x27); w2(0x26); w2(0x22); |
82 | a = r0(); w2(0x20); b = r0(); |
83 | buf[2 * k] = b; |
84 | buf[2 * k + 1] = a; |
85 | } |
86 | w2(0x26); w2(0xc); |
87 | break; |
88 | } |
89 | } |
90 | |
91 | static void aten_write_block(struct pi_adapter *pi, char *buf, int count) |
92 | { |
93 | int k; |
94 | |
95 | w0(0x88); w2(0xe); w2(6); |
96 | for (k = 0; k < count / 2; k++) { |
97 | w0(buf[2 * k + 1]); w2(0xe); w2(6); |
98 | w0(buf[2 * k]); w2(7); w2(6); |
99 | } |
100 | w2(0xc); |
101 | } |
102 | |
103 | static void aten_connect(struct pi_adapter *pi) |
104 | { |
105 | pi->saved_r0 = r0(); |
106 | pi->saved_r2 = r2(); |
107 | w2(0xc); |
108 | } |
109 | |
110 | static void aten_disconnect(struct pi_adapter *pi) |
111 | { |
112 | w0(pi->saved_r0); |
113 | w2(pi->saved_r2); |
114 | } |
115 | |
116 | static void aten_log_adapter(struct pi_adapter *pi) |
117 | { |
118 | char *mode_string[2] = { "4-bit" , "8-bit" }; |
119 | |
120 | dev_info(&pi->dev, |
121 | "ATEN EH-100 at 0x%x, mode %d (%s), delay %d\n" , |
122 | pi->port, pi->mode, mode_string[pi->mode], pi->delay); |
123 | } |
124 | |
125 | static struct pi_protocol aten = { |
126 | .owner = THIS_MODULE, |
127 | .name = "aten" , |
128 | .max_mode = 2, |
129 | .epp_first = 2, |
130 | .default_delay = 1, |
131 | .max_units = 1, |
132 | .write_regr = aten_write_regr, |
133 | .read_regr = aten_read_regr, |
134 | .write_block = aten_write_block, |
135 | .read_block = aten_read_block, |
136 | .connect = aten_connect, |
137 | .disconnect = aten_disconnect, |
138 | .log_adapter = aten_log_adapter, |
139 | }; |
140 | |
141 | MODULE_LICENSE("GPL" ); |
142 | MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>" ); |
143 | MODULE_DESCRIPTION("ATEN EH-100 parallel port IDE adapter protocol driver" ); |
144 | module_pata_parport_driver(aten); |
145 | |