1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (c) 1998 Grant R. Guenther <grant@torque.net> 4 * 5 * fit3.c is a low-level protocol driver for newer models 6 * of the Fidelity International Technology parallel port adapter. 7 * This adapter is used in their TransDisk 3000 portable 8 * hard-drives, as well as CD-ROM, PD-CD and other devices. 9 * 10 * The TD-2000 and certain older devices use a different protocol. 11 * Try the fit2 protocol module with them. 12 * 13 * NB: The FIT adapters do not appear to support the control 14 * registers. So, we map ALT_STATUS to STATUS and NO-OP writes 15 * to the device control register - this means that IDE reset 16 * will not work on these devices. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/init.h> 21 #include <linux/delay.h> 22 #include <linux/kernel.h> 23 #include <linux/types.h> 24 #include <linux/wait.h> 25 #include <asm/io.h> 26 #include "pata_parport.h" 27 28 #define j44(a, b) (((a >> 3) & 0x0f) | ((b << 1) & 0xf0)) 29 30 #define w7(byte) out_p(7, byte) 31 #define r7() (in_p(7) & 0xff) 32 33 /* 34 * cont = 0 - access the IDE register file 35 * cont = 1 - access the IDE command set 36 */ 37 38 static void fit3_write_regr(struct pi_adapter *pi, int cont, int regr, int val) 39 { 40 if (cont == 1) 41 return; 42 43 switch (pi->mode) { 44 case 0: 45 case 1: 46 w2(0xc); w0(regr); w2(0x8); w2(0xc); 47 w0(val); w2(0xd); 48 w0(0); w2(0xc); 49 break; 50 case 2: 51 w2(0xc); w0(regr); w2(0x8); w2(0xc); 52 w4(val); w4(0); 53 w2(0xc); 54 break; 55 } 56 } 57 58 static int fit3_read_regr(struct pi_adapter *pi, int cont, int regr) 59 { 60 int a, b; 61 62 if (cont) { 63 if (regr != 6) 64 return 0xff; 65 regr = 7; 66 } 67 68 switch (pi->mode) { 69 case 0: 70 w2(0xc); w0(regr + 0x10); w2(0x8); w2(0xc); 71 w2(0xd); a = r1(); 72 w2(0xf); b = r1(); 73 w2(0xc); 74 return j44(a, b); 75 case 1: 76 w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 77 w2(0xec); w2(0xee); w2(0xef); a = r0(); 78 w2(0xc); 79 return a; 80 case 2: 81 w2(0xc); w0(regr + 0x90); w2(0x8); w2(0xc); 82 w2(0xec); 83 a = r4(); b = r4(); 84 w2(0xc); 85 return a; 86 } 87 88 return -1; 89 } 90 91 static void fit3_read_block(struct pi_adapter *pi, char *buf, int count) 92 { 93 int k, a, b, c, d; 94 95 switch (pi->mode) { 96 case 0: 97 w2(0xc); w0(0x10); w2(0x8); w2(0xc); 98 for (k = 0; k < count / 2; k++) { 99 w2(0xd); a = r1(); 100 w2(0xf); b = r1(); 101 w2(0xc); c = r1(); 102 w2(0xe); d = r1(); 103 buf[2 * k] = j44(a, b); 104 buf[2 * k + 1] = j44(c, d); 105 } 106 w2(0xc); 107 break; 108 case 1: 109 w2(0xc); w0(0x90); w2(0x8); w2(0xc); 110 w2(0xec); w2(0xee); 111 for (k = 0; k < count / 2; k++) { 112 w2(0xef); a = r0(); 113 w2(0xee); b = r0(); 114 buf[2 * k] = a; 115 buf[2 * k + 1] = b; 116 } 117 w2(0xec); 118 w2(0xc); 119 break; 120 case 2: 121 w2(0xc); w0(0x90); w2(0x8); w2(0xc); 122 w2(0xec); 123 for (k = 0; k < count; k++) 124 buf[k] = r4(); 125 w2(0xc); 126 break; 127 } 128 } 129 130 static void fit3_write_block(struct pi_adapter *pi, char *buf, int count) 131 { 132 int k; 133 134 switch (pi->mode) { 135 case 0: 136 case 1: 137 w2(0xc); w0(0); w2(0x8); w2(0xc); 138 for (k = 0; k < count / 2; k++) { 139 w0(buf[2 * k]); w2(0xd); 140 w0(buf[2 * k + 1]); w2(0xc); 141 } 142 break; 143 case 2: 144 w2(0xc); w0(0); w2(0x8); w2(0xc); 145 for (k = 0; k < count; k++) 146 w4(buf[k]); 147 w2(0xc); 148 break; 149 } 150 } 151 152 static void fit3_connect(struct pi_adapter *pi) 153 { 154 pi->saved_r0 = r0(); 155 pi->saved_r2 = r2(); 156 w2(0xc); w0(0); w2(0xa); 157 if (pi->mode == 2) { 158 w2(0xc); w0(0x9); 159 w2(0x8); w2(0xc); 160 } 161 } 162 163 static void fit3_disconnect(struct pi_adapter *pi) 164 { 165 w2(0xc); w0(0xa); w2(0x8); w2(0xc); 166 w0(pi->saved_r0); 167 w2(pi->saved_r2); 168 } 169 170 static void fit3_log_adapter(struct pi_adapter *pi) 171 { 172 char *mode_string[3] = { "4-bit", "8-bit", "EPP"}; 173 174 dev_info(&pi->dev, 175 "FIT 3000 adapter at 0x%x, mode %d (%s), delay %d\n", 176 pi->port, pi->mode, mode_string[pi->mode], pi->delay); 177 } 178 179 static struct pi_protocol fit3 = { 180 .owner = THIS_MODULE, 181 .name = "fit3", 182 .max_mode = 3, 183 .epp_first = 2, 184 .default_delay = 1, 185 .max_units = 1, 186 .write_regr = fit3_write_regr, 187 .read_regr = fit3_read_regr, 188 .write_block = fit3_write_block, 189 .read_block = fit3_read_block, 190 .connect = fit3_connect, 191 .disconnect = fit3_disconnect, 192 .log_adapter = fit3_log_adapter, 193 }; 194 195 MODULE_LICENSE("GPL"); 196 module_pata_parport_driver(fit3); 197