1 /* 2 backpack.c (c) 2001 Micro Solutions Inc. 3 Released under the terms of the GNU General Public license 4 5 backpack.c is a low-level protocol driver for the Micro Solutions 6 "BACKPACK" parallel port IDE adapter 7 (Works on Series 6 drives) 8 9 Written by: Ken Hahn (linux-dev@micro-solutions.com) 10 Clive Turvey (linux-dev@micro-solutions.com) 11 12 */ 13 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/kernel.h> 17 #include <linux/types.h> 18 #include <linux/parport.h> 19 #include "pata_parport.h" 20 #include "ppc6lnx.c" 21 22 static void bpck6_send_cmd(struct pi_adapter *pi, u8 cmd) 23 { 24 switch (mode_map[pi->mode]) { 25 case PPCMODE_UNI_SW: 26 case PPCMODE_UNI_FW: 27 case PPCMODE_BI_SW: 28 case PPCMODE_BI_FW: 29 parport_write_data(pi->pardev->port, cmd); 30 parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_AUTOFD); 31 break; 32 case PPCMODE_EPP_BYTE: 33 case PPCMODE_EPP_WORD: 34 case PPCMODE_EPP_DWORD: 35 pi->pardev->port->ops->epp_write_addr(pi->pardev->port, &cmd, 1, 0); 36 break; 37 } 38 } 39 40 static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg) 41 { 42 u8 port = cont ? reg | 8 : reg; 43 44 bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ); 45 return ppc6_rd_data_byte(pi); 46 } 47 48 static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val) 49 { 50 u8 port = cont ? reg | 8 : reg; 51 52 bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE); 53 ppc6_wr_data_byte(pi, val); 54 } 55 56 static void bpck6_wait_for_fifo(struct pi_adapter *pi) 57 { 58 int i; 59 60 if (pi->private & fifo_wait) { 61 for (i = 0; i < 20; i++) 62 parport_read_status(pi->pardev->port); 63 } 64 } 65 66 static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len) 67 { 68 u8 this, last; 69 70 bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE); 71 ppc6_wr_data_byte(pi, (u8)len); 72 ppc6_wr_data_byte(pi, (u8)(len >> 8)); 73 ppc6_wr_data_byte(pi, 0); 74 75 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK); 76 bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE); 77 78 switch (mode_map[pi->mode]) { 79 case PPCMODE_UNI_SW: 80 case PPCMODE_BI_SW: 81 while (len--) { 82 parport_write_data(pi->pardev->port, *buf++); 83 parport_frob_control(pi->pardev->port, 0, 84 PARPORT_CONTROL_INIT); 85 } 86 break; 87 case PPCMODE_UNI_FW: 88 case PPCMODE_BI_FW: 89 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR); 90 91 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 92 PARPORT_CONTROL_STROBE); 93 94 last = *buf; 95 96 parport_write_data(pi->pardev->port, last); 97 98 while (len) { 99 this = *buf++; 100 len--; 101 102 if (this == last) { 103 parport_frob_control(pi->pardev->port, 0, 104 PARPORT_CONTROL_INIT); 105 } else { 106 parport_write_data(pi->pardev->port, this); 107 last = this; 108 } 109 } 110 111 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 112 0); 113 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR); 114 break; 115 case PPCMODE_EPP_BYTE: 116 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 117 len, PARPORT_EPP_FAST_8); 118 bpck6_wait_for_fifo(pi); 119 break; 120 case PPCMODE_EPP_WORD: 121 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 122 len, PARPORT_EPP_FAST_16); 123 bpck6_wait_for_fifo(pi); 124 break; 125 case PPCMODE_EPP_DWORD: 126 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 127 len, PARPORT_EPP_FAST_32); 128 bpck6_wait_for_fifo(pi); 129 break; 130 } 131 132 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK); 133 } 134 135 static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len) 136 { 137 bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE); 138 ppc6_wr_data_byte(pi, (u8)len); 139 ppc6_wr_data_byte(pi, (u8)(len >> 8)); 140 ppc6_wr_data_byte(pi, 0); 141 142 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK); 143 bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ); 144 145 switch (mode_map[pi->mode]) { 146 case PPCMODE_UNI_SW: 147 case PPCMODE_UNI_FW: 148 while (len) { 149 u8 d; 150 151 parport_frob_control(pi->pardev->port, 152 PARPORT_CONTROL_STROBE, 153 PARPORT_CONTROL_INIT); /* DATA STROBE */ 154 d = parport_read_status(pi->pardev->port); 155 d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3); 156 parport_frob_control(pi->pardev->port, 157 PARPORT_CONTROL_STROBE, 158 PARPORT_CONTROL_STROBE); 159 d |= parport_read_status(pi->pardev->port) & 0xB8; 160 *buf++ = d; 161 len--; 162 } 163 break; 164 case PPCMODE_BI_SW: 165 case PPCMODE_BI_FW: 166 parport_data_reverse(pi->pardev->port); 167 while (len) { 168 parport_frob_control(pi->pardev->port, 169 PARPORT_CONTROL_STROBE, 170 PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT); 171 *buf++ = parport_read_data(pi->pardev->port); 172 len--; 173 } 174 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 175 0); 176 parport_data_forward(pi->pardev->port); 177 break; 178 case PPCMODE_EPP_BYTE: 179 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 180 PARPORT_EPP_FAST_8); 181 break; 182 case PPCMODE_EPP_WORD: 183 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 184 PARPORT_EPP_FAST_16); 185 break; 186 case PPCMODE_EPP_DWORD: 187 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 188 PARPORT_EPP_FAST_32); 189 break; 190 } 191 192 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK); 193 } 194 195 static int bpck6_open(struct pi_adapter *pi) 196 { 197 u8 i, j, k; 198 199 pi->saved_r0 = parport_read_data(pi->pardev->port); 200 pi->saved_r2 = parport_read_control(pi->pardev->port) & 0x5F; 201 202 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 203 PARPORT_CONTROL_SELECT); 204 if (pi->saved_r0 == 'b') 205 parport_write_data(pi->pardev->port, 'x'); 206 parport_write_data(pi->pardev->port, 'b'); 207 parport_write_data(pi->pardev->port, 'p'); 208 parport_write_data(pi->pardev->port, pi->unit); 209 parport_write_data(pi->pardev->port, ~pi->unit); 210 211 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0); 212 parport_write_control(pi->pardev->port, PARPORT_CONTROL_INIT); 213 214 i = mode_map[pi->mode] & 0x0C; 215 if (i == 0) 216 i = (mode_map[pi->mode] & 2) | 1; 217 parport_write_data(pi->pardev->port, i); 218 219 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 220 PARPORT_CONTROL_SELECT); 221 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD, 222 PARPORT_CONTROL_AUTOFD); 223 224 j = ((i & 0x08) << 4) | ((i & 0x07) << 3); 225 k = parport_read_status(pi->pardev->port) & 0xB8; 226 if (j == k) { 227 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD, 0); 228 k = (parport_read_status(pi->pardev->port) & 0xB8) ^ 0xB8; 229 if (j == k) { 230 if (i & 4) // EPP 231 parport_frob_control(pi->pardev->port, 232 PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, 0); 233 else // PPC/ECP 234 parport_frob_control(pi->pardev->port, 235 PARPORT_CONTROL_SELECT, 0); 236 237 pi->private = 0; 238 239 bpck6_send_cmd(pi, ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE); 240 ppc6_wr_data_byte(pi, RAMSIZE_128K); 241 242 bpck6_send_cmd(pi, ACCESS_REG | ACCESS_READ | REG_VERSION); 243 if ((ppc6_rd_data_byte(pi) & 0x3F) == 0x0C) 244 pi->private |= fifo_wait; 245 246 return 1; 247 } 248 } 249 250 parport_write_control(pi->pardev->port, pi->saved_r2); 251 parport_write_data(pi->pardev->port, pi->saved_r0); 252 253 return 0; // FAIL 254 } 255 256 static void bpck6_deselect(struct pi_adapter *pi) 257 { 258 if (mode_map[pi->mode] & 4) // EPP 259 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_INIT, 260 PARPORT_CONTROL_INIT); 261 else // PPC/ECP 262 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 263 PARPORT_CONTROL_SELECT); 264 265 parport_write_data(pi->pardev->port, pi->saved_r0); 266 parport_write_control(pi->pardev->port, 267 pi->saved_r2 | PARPORT_CONTROL_SELECT); 268 parport_write_control(pi->pardev->port, pi->saved_r2); 269 } 270 271 static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata) 272 { 273 bpck6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE); 274 ppc6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6)); 275 } 276 277 static void bpck6_connect(struct pi_adapter *pi) 278 { 279 dev_dbg(&pi->dev, "connect\n"); 280 281 bpck6_open(pi); 282 bpck6_wr_extout(pi, 0x3); 283 } 284 285 static void bpck6_disconnect(struct pi_adapter *pi) 286 { 287 dev_dbg(&pi->dev, "disconnect\n"); 288 bpck6_wr_extout(pi, 0x0); 289 bpck6_deselect(pi); 290 } 291 292 static int bpck6_test_port(struct pi_adapter *pi) /* check for 8-bit port */ 293 { 294 dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n", 295 pi->pardev->port->modes, pi->pardev->port->base); 296 297 /* look at the parport device to see what modes we can use */ 298 if (pi->pardev->port->modes & PARPORT_MODE_EPP) 299 return 5; /* Can do EPP */ 300 if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE) 301 return 2; 302 return 1; /* Just flat SPP */ 303 } 304 305 static int bpck6_probe_unit(struct pi_adapter *pi) 306 { 307 int out, saved_mode; 308 309 dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port); 310 311 saved_mode = pi->mode; 312 /*LOWER DOWN TO UNIDIRECTIONAL*/ 313 pi->mode = 0; 314 315 out = bpck6_open(pi); 316 317 dev_dbg(&pi->dev, "ppc_open returned %2x\n", out); 318 319 if(out) 320 { 321 bpck6_deselect(pi); 322 dev_dbg(&pi->dev, "leaving probe\n"); 323 pi->mode = saved_mode; 324 return(1); 325 } 326 else 327 { 328 dev_dbg(&pi->dev, "Failed open\n"); 329 pi->mode = saved_mode; 330 return(0); 331 } 332 } 333 334 static void bpck6_log_adapter(struct pi_adapter *pi) 335 { 336 char *mode_string[5]= 337 {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; 338 339 dev_info(&pi->dev, "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n", 340 pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay); 341 } 342 343 static struct pi_protocol bpck6 = { 344 .owner = THIS_MODULE, 345 .name = "bpck6", 346 .max_mode = 5, 347 .epp_first = 2, /* 2-5 use epp (need 8 ports) */ 348 .max_units = 255, 349 .write_regr = bpck6_write_regr, 350 .read_regr = bpck6_read_regr, 351 .write_block = bpck6_write_block, 352 .read_block = bpck6_read_block, 353 .connect = bpck6_connect, 354 .disconnect = bpck6_disconnect, 355 .test_port = bpck6_test_port, 356 .probe_unit = bpck6_probe_unit, 357 .log_adapter = bpck6_log_adapter, 358 }; 359 360 MODULE_LICENSE("GPL"); 361 MODULE_AUTHOR("Micro Solutions Inc."); 362 MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); 363 module_pata_parport_driver(bpck6); 364