1 /* 2 frpw.c (c) 1996-8 Grant R. Guenther <grant@torque.net> 3 Under the terms of the GNU General Public License 4 5 frpw.c is a low-level protocol driver for the Freecom "Power" 6 parallel port IDE adapter. 7 8 Some applications of this adapter may require a "printer" reset 9 prior to loading the driver. This can be done by loading and 10 unloading the "lp" driver, or it can be done by this driver 11 if you define FRPW_HARD_RESET. The latter is not recommended 12 as it may upset devices on other ports. 13 14 */ 15 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/delay.h> 19 #include <linux/kernel.h> 20 #include <linux/types.h> 21 #include <linux/wait.h> 22 #include <asm/io.h> 23 #include "pata_parport.h" 24 25 #define cec4 w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4); 26 #define j44(l,h) (((l>>4)&0x0f)|(h&0xf0)) 27 28 /* cont = 0 - access the IDE register file 29 cont = 1 - access the IDE command set 30 */ 31 32 static int cont_map[2] = { 0x08, 0x10 }; 33 34 static int frpw_read_regr(struct pi_adapter *pi, int cont, int regr) 35 36 { int h,l,r; 37 38 r = regr + cont_map[cont]; 39 40 w2(4); 41 w0(r); cec4; 42 w2(6); l = r1(); 43 w2(4); h = r1(); 44 w2(4); 45 46 return j44(l,h); 47 48 } 49 50 static void frpw_write_regr(struct pi_adapter *pi, int cont, int regr, int val) 51 52 { int r; 53 54 r = regr + cont_map[cont]; 55 56 w2(4); w0(r); cec4; 57 w0(val); 58 w2(5);w2(7);w2(5);w2(4); 59 } 60 61 static void frpw_read_block_int(struct pi_adapter *pi, char *buf, int count, int regr) 62 63 { int h, l, k, ph; 64 65 switch(pi->mode) { 66 67 case 0: w2(4); w0(regr); cec4; 68 for (k=0;k<count;k++) { 69 w2(6); l = r1(); 70 w2(4); h = r1(); 71 buf[k] = j44(l,h); 72 } 73 w2(4); 74 break; 75 76 case 1: ph = 2; 77 w2(4); w0(regr + 0xc0); cec4; 78 w0(0xff); 79 for (k=0;k<count;k++) { 80 w2(0xa4 + ph); 81 buf[k] = r0(); 82 ph = 2 - ph; 83 } 84 w2(0xac); w2(0xa4); w2(4); 85 break; 86 87 case 2: w2(4); w0(regr + 0x80); cec4; 88 for (k=0;k<count;k++) buf[k] = r4(); 89 w2(0xac); w2(0xa4); 90 w2(4); 91 break; 92 93 case 3: w2(4); w0(regr + 0x80); cec4; 94 for (k=0;k<count-2;k++) buf[k] = r4(); 95 w2(0xac); w2(0xa4); 96 buf[count-2] = r4(); 97 buf[count-1] = r4(); 98 w2(4); 99 break; 100 101 case 4: w2(4); w0(regr + 0x80); cec4; 102 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w(); 103 w2(0xac); w2(0xa4); 104 buf[count-2] = r4(); 105 buf[count-1] = r4(); 106 w2(4); 107 break; 108 109 case 5: w2(4); w0(regr + 0x80); cec4; 110 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l(); 111 buf[count-4] = r4(); 112 buf[count-3] = r4(); 113 w2(0xac); w2(0xa4); 114 buf[count-2] = r4(); 115 buf[count-1] = r4(); 116 w2(4); 117 break; 118 119 } 120 } 121 122 static void frpw_read_block(struct pi_adapter *pi, char *buf, int count) 123 124 { frpw_read_block_int(pi,buf,count,0x08); 125 } 126 127 static void frpw_write_block(struct pi_adapter *pi, char *buf, int count) 128 129 { int k; 130 131 switch(pi->mode) { 132 133 case 0: 134 case 1: 135 case 2: w2(4); w0(8); cec4; w2(5); 136 for (k=0;k<count;k++) { 137 w0(buf[k]); 138 w2(7);w2(5); 139 } 140 w2(4); 141 break; 142 143 case 3: w2(4); w0(0xc8); cec4; w2(5); 144 for (k=0;k<count;k++) w4(buf[k]); 145 w2(4); 146 break; 147 148 case 4: w2(4); w0(0xc8); cec4; w2(5); 149 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]); 150 w2(4); 151 break; 152 153 case 5: w2(4); w0(0xc8); cec4; w2(5); 154 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]); 155 w2(4); 156 break; 157 } 158 } 159 160 static void frpw_connect(struct pi_adapter *pi) 161 162 { pi->saved_r0 = r0(); 163 pi->saved_r2 = r2(); 164 w2(4); 165 } 166 167 static void frpw_disconnect(struct pi_adapter *pi) 168 169 { w2(4); w0(0x20); cec4; 170 w0(pi->saved_r0); 171 w2(pi->saved_r2); 172 } 173 174 /* Stub logic to see if PNP string is available - used to distinguish 175 between the Xilinx and ASIC implementations of the Freecom adapter. 176 */ 177 178 static int frpw_test_pnp(struct pi_adapter *pi) 179 180 /* returns chip_type: 0 = Xilinx, 1 = ASIC */ 181 182 { int olddelay, a, b; 183 184 #ifdef FRPW_HARD_RESET 185 w0(0); w2(8); udelay(50); w2(0xc); /* parallel bus reset */ 186 mdelay(1500); 187 #endif 188 189 olddelay = pi->delay; 190 pi->delay = 10; 191 192 pi->saved_r0 = r0(); 193 pi->saved_r2 = r2(); 194 195 w2(4); w0(4); w2(6); w2(7); 196 a = r1() & 0xff; w2(4); b = r1() & 0xff; 197 w2(0xc); w2(0xe); w2(4); 198 199 pi->delay = olddelay; 200 w0(pi->saved_r0); 201 w2(pi->saved_r2); 202 203 return ((~a&0x40) && (b&0x40)); 204 } 205 206 /* We use the pi->private to remember the result of the PNP test. 207 To make this work, private = port*2 + chip. Yes, I know it's 208 a hack :-( 209 */ 210 211 static int frpw_test_proto(struct pi_adapter *pi) 212 213 { int j, k, r; 214 int e[2] = {0,0}; 215 char scratch[512]; 216 217 if ((pi->private>>1) != pi->port) 218 pi->private = frpw_test_pnp(pi) + 2*pi->port; 219 220 if (((pi->private%2) == 0) && (pi->mode > 2)) { 221 dev_dbg(&pi->dev, "frpw: Xilinx does not support mode %d\n", pi->mode); 222 return 1; 223 } 224 225 if (((pi->private%2) == 1) && (pi->mode == 2)) { 226 dev_dbg(&pi->dev, "frpw: ASIC does not support mode 2\n"); 227 return 1; 228 } 229 230 frpw_connect(pi); 231 for (j=0;j<2;j++) { 232 frpw_write_regr(pi,0,6,0xa0+j*0x10); 233 for (k=0;k<256;k++) { 234 frpw_write_regr(pi,0,2,k^0xaa); 235 frpw_write_regr(pi,0,3,k^0x55); 236 if (frpw_read_regr(pi,0,2) != (k^0xaa)) e[j]++; 237 } 238 } 239 frpw_disconnect(pi); 240 241 frpw_connect(pi); 242 frpw_read_block_int(pi,scratch,512,0x10); 243 r = 0; 244 for (k=0;k<128;k++) if (scratch[k] != k) r++; 245 frpw_disconnect(pi); 246 247 dev_dbg(&pi->dev, "frpw: port 0x%x, chip %ld, mode %d, test=(%d,%d,%d)\n", 248 pi->port, (pi->private%2), pi->mode, e[0], e[1], r); 249 250 return (r || (e[0] && e[1])); 251 } 252 253 254 static void frpw_log_adapter(struct pi_adapter *pi) 255 256 { char *mode_string[6] = {"4-bit","8-bit","EPP", 257 "EPP-8","EPP-16","EPP-32"}; 258 259 dev_info(&pi->dev, "Freecom (%s) adapter at 0x%x, mode %d (%s), delay %d\n", 260 ((pi->private % 2) == 0) ? "Xilinx" : "ASIC", 261 pi->port, pi->mode, mode_string[pi->mode], pi->delay); 262 } 263 264 static struct pi_protocol frpw = { 265 .owner = THIS_MODULE, 266 .name = "frpw", 267 .max_mode = 6, 268 .epp_first = 2, 269 .default_delay = 2, 270 .max_units = 1, 271 .write_regr = frpw_write_regr, 272 .read_regr = frpw_read_regr, 273 .write_block = frpw_write_block, 274 .read_block = frpw_read_block, 275 .connect = frpw_connect, 276 .disconnect = frpw_disconnect, 277 .test_proto = frpw_test_proto, 278 .log_adapter = frpw_log_adapter, 279 }; 280 281 MODULE_LICENSE("GPL"); 282 module_pata_parport_driver(frpw); 283