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_pata_parport_driver(fit2); 136