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