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