1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * (c) 1998 Grant R. Guenther <grant@torque.net> |
4 | * |
5 | * fit2.c is a low-level protocol driver for the older version |
6 | * of the Fidelity International Technology parallel port adapter. |
7 | * This adapter is used in their TransDisk 2000 and older TransDisk |
8 | * 3000 portable hard-drives. As far as I can tell, this device |
9 | * supports 4-bit mode _only_. |
10 | * |
11 | * Newer models of the FIT products use an enhanced protocol. |
12 | * The "fit3" protocol module should support current drives. |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/init.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/types.h> |
20 | #include <linux/wait.h> |
21 | #include <asm/io.h> |
22 | #include "pata_parport.h" |
23 | |
24 | #define j44(a, b) (((a >> 4) & 0x0f) | (b & 0xf0)) |
25 | |
26 | /* |
27 | * cont = 0 - access the IDE register file |
28 | * cont = 1 - access the IDE command set |
29 | * |
30 | * NB: The FIT adapter does not appear to use the control registers. |
31 | * So, we map ALT_STATUS to STATUS and NO-OP writes to the device |
32 | * control register - this means that IDE reset will not work on these |
33 | * devices. |
34 | */ |
35 | |
36 | static void fit2_write_regr(struct pi_adapter *pi, int cont, int regr, int val) |
37 | { |
38 | if (cont == 1) |
39 | return; |
40 | w2(0xc); w0(regr); w2(4); w0(val); w2(5); w0(0); w2(4); |
41 | } |
42 | |
43 | static int fit2_read_regr(struct pi_adapter *pi, int cont, int regr) |
44 | { |
45 | int a, b, r; |
46 | |
47 | if (cont) { |
48 | if (regr != 6) |
49 | return 0xff; |
50 | r = 7; |
51 | } else { |
52 | r = regr + 0x10; |
53 | } |
54 | |
55 | w2(0xc); w0(r); w2(4); w2(5); |
56 | w0(0); a = r1(); |
57 | w0(1); b = r1(); |
58 | w2(4); |
59 | |
60 | return j44(a, b); |
61 | } |
62 | |
63 | static void fit2_read_block(struct pi_adapter *pi, char *buf, int count) |
64 | { |
65 | int k, a, b, c, d; |
66 | |
67 | w2(0xc); w0(0x10); |
68 | |
69 | for (k = 0; k < count / 4; k++) { |
70 | w2(4); w2(5); |
71 | w0(0); a = r1(); w0(1); b = r1(); |
72 | w0(3); c = r1(); w0(2); d = r1(); |
73 | buf[4 * k + 0] = j44(a, b); |
74 | buf[4 * k + 1] = j44(d, c); |
75 | |
76 | w2(4); w2(5); |
77 | a = r1(); w0(3); b = r1(); |
78 | w0(1); c = r1(); w0(0); d = r1(); |
79 | buf[4 * k + 2] = j44(d, c); |
80 | buf[4 * k + 3] = j44(a, b); |
81 | } |
82 | |
83 | w2(4); |
84 | } |
85 | |
86 | static void fit2_write_block(struct pi_adapter *pi, char *buf, int count) |
87 | { |
88 | int k; |
89 | |
90 | w2(0xc); w0(0); |
91 | for (k = 0; k < count / 2; k++) { |
92 | w2(4); w0(buf[2 * k]); |
93 | w2(5); w0(buf[2 * k + 1]); |
94 | } |
95 | w2(4); |
96 | } |
97 | |
98 | static void fit2_connect(struct pi_adapter *pi) |
99 | { |
100 | pi->saved_r0 = r0(); |
101 | pi->saved_r2 = r2(); |
102 | w2(0xcc); |
103 | } |
104 | |
105 | static void fit2_disconnect(struct pi_adapter *pi) |
106 | { |
107 | w0(pi->saved_r0); |
108 | w2(pi->saved_r2); |
109 | } |
110 | |
111 | static void fit2_log_adapter(struct pi_adapter *pi) |
112 | { |
113 | dev_info(&pi->dev, "FIT 2000 adapter at 0x%x, delay %d\n" , |
114 | pi->port, pi->delay); |
115 | |
116 | } |
117 | |
118 | static struct pi_protocol fit2 = { |
119 | .owner = THIS_MODULE, |
120 | .name = "fit2" , |
121 | .max_mode = 1, |
122 | .epp_first = 2, |
123 | .default_delay = 1, |
124 | .max_units = 1, |
125 | .write_regr = fit2_write_regr, |
126 | .read_regr = fit2_read_regr, |
127 | .write_block = fit2_write_block, |
128 | .read_block = fit2_read_block, |
129 | .connect = fit2_connect, |
130 | .disconnect = fit2_disconnect, |
131 | .log_adapter = fit2_log_adapter, |
132 | }; |
133 | |
134 | MODULE_LICENSE("GPL" ); |
135 | MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>" ); |
136 | MODULE_DESCRIPTION("Fidelity International Technology parallel port IDE adapter" |
137 | "(older models) protocol driver" ); |
138 | module_pata_parport_driver(fit2); |
139 | |