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 int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg) 23 { 24 u8 port = cont ? reg | 8 : reg; 25 26 ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ); 27 return ppc6_rd_data_byte(pi); 28 } 29 30 static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val) 31 { 32 u8 port = cont ? reg | 8 : reg; 33 34 ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE); 35 ppc6_wr_data_byte(pi, val); 36 } 37 38 static void bpck6_wait_for_fifo(struct pi_adapter *pi) 39 { 40 int i; 41 42 if (pi->private & fifo_wait) { 43 for (i = 0; i < 20; i++) 44 parport_read_status(pi->pardev->port); 45 } 46 } 47 48 static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len) 49 { 50 u8 this, last; 51 52 ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE); 53 ppc6_wr_data_byte(pi, (u8)len); 54 ppc6_wr_data_byte(pi, (u8)(len >> 8)); 55 ppc6_wr_data_byte(pi, 0); 56 57 ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK); 58 ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE); 59 60 switch (mode_map[pi->mode]) { 61 case PPCMODE_UNI_SW: 62 case PPCMODE_BI_SW: 63 while (len--) { 64 parport_write_data(pi->pardev->port, *buf++); 65 parport_frob_control(pi->pardev->port, 0, 66 PARPORT_CONTROL_INIT); 67 } 68 break; 69 case PPCMODE_UNI_FW: 70 case PPCMODE_BI_FW: 71 ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR); 72 73 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 74 PARPORT_CONTROL_STROBE); 75 76 last = *buf; 77 78 parport_write_data(pi->pardev->port, last); 79 80 while (len) { 81 this = *buf++; 82 len--; 83 84 if (this == last) { 85 parport_frob_control(pi->pardev->port, 0, 86 PARPORT_CONTROL_INIT); 87 } else { 88 parport_write_data(pi->pardev->port, this); 89 last = this; 90 } 91 } 92 93 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 94 0); 95 ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR); 96 break; 97 case PPCMODE_EPP_BYTE: 98 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 99 len, PARPORT_EPP_FAST_8); 100 bpck6_wait_for_fifo(pi); 101 break; 102 case PPCMODE_EPP_WORD: 103 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 104 len, PARPORT_EPP_FAST_16); 105 bpck6_wait_for_fifo(pi); 106 break; 107 case PPCMODE_EPP_DWORD: 108 pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf, 109 len, PARPORT_EPP_FAST_32); 110 bpck6_wait_for_fifo(pi); 111 break; 112 } 113 114 ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK); 115 } 116 117 static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len) 118 { 119 ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE); 120 ppc6_wr_data_byte(pi, (u8)len); 121 ppc6_wr_data_byte(pi, (u8)(len >> 8)); 122 ppc6_wr_data_byte(pi, 0); 123 124 ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK); 125 ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ); 126 127 switch (mode_map[pi->mode]) { 128 case PPCMODE_UNI_SW: 129 case PPCMODE_UNI_FW: 130 while (len) { 131 u8 d; 132 133 parport_frob_control(pi->pardev->port, 134 PARPORT_CONTROL_STROBE, 135 PARPORT_CONTROL_INIT); /* DATA STROBE */ 136 d = parport_read_status(pi->pardev->port); 137 d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3); 138 parport_frob_control(pi->pardev->port, 139 PARPORT_CONTROL_STROBE, 140 PARPORT_CONTROL_STROBE); 141 d |= parport_read_status(pi->pardev->port) & 0xB8; 142 *buf++ = d; 143 len--; 144 } 145 break; 146 case PPCMODE_BI_SW: 147 case PPCMODE_BI_FW: 148 parport_data_reverse(pi->pardev->port); 149 while (len) { 150 parport_frob_control(pi->pardev->port, 151 PARPORT_CONTROL_STROBE, 152 PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT); 153 *buf++ = parport_read_data(pi->pardev->port); 154 len--; 155 } 156 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 157 0); 158 parport_data_forward(pi->pardev->port); 159 break; 160 case PPCMODE_EPP_BYTE: 161 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 162 PARPORT_EPP_FAST_8); 163 break; 164 case PPCMODE_EPP_WORD: 165 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 166 PARPORT_EPP_FAST_16); 167 break; 168 case PPCMODE_EPP_DWORD: 169 pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len, 170 PARPORT_EPP_FAST_32); 171 break; 172 } 173 174 ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK); 175 } 176 177 static void bpck6_connect(struct pi_adapter *pi) 178 { 179 dev_dbg(&pi->dev, "connect\n"); 180 181 ppc6_open(pi); 182 ppc6_wr_extout(pi, 0x3); 183 } 184 185 static void bpck6_disconnect(struct pi_adapter *pi) 186 { 187 dev_dbg(&pi->dev, "disconnect\n"); 188 ppc6_wr_extout(pi, 0x0); 189 ppc6_deselect(pi); 190 } 191 192 static int bpck6_test_port(struct pi_adapter *pi) /* check for 8-bit port */ 193 { 194 dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n", 195 pi->pardev->port->modes, pi->pardev->port->base); 196 197 /* look at the parport device to see what modes we can use */ 198 if (pi->pardev->port->modes & PARPORT_MODE_EPP) 199 return 5; /* Can do EPP */ 200 if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE) 201 return 2; 202 return 1; /* Just flat SPP */ 203 } 204 205 static int bpck6_probe_unit(struct pi_adapter *pi) 206 { 207 int out, saved_mode; 208 209 dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port); 210 211 saved_mode = pi->mode; 212 /*LOWER DOWN TO UNIDIRECTIONAL*/ 213 pi->mode = 0; 214 215 out = ppc6_open(pi); 216 217 dev_dbg(&pi->dev, "ppc_open returned %2x\n", out); 218 219 if(out) 220 { 221 ppc6_deselect(pi); 222 dev_dbg(&pi->dev, "leaving probe\n"); 223 pi->mode = saved_mode; 224 return(1); 225 } 226 else 227 { 228 dev_dbg(&pi->dev, "Failed open\n"); 229 pi->mode = saved_mode; 230 return(0); 231 } 232 } 233 234 static void bpck6_log_adapter(struct pi_adapter *pi) 235 { 236 char *mode_string[5]= 237 {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"}; 238 239 dev_info(&pi->dev, "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n", 240 pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay); 241 } 242 243 static struct pi_protocol bpck6 = { 244 .owner = THIS_MODULE, 245 .name = "bpck6", 246 .max_mode = 5, 247 .epp_first = 2, /* 2-5 use epp (need 8 ports) */ 248 .max_units = 255, 249 .write_regr = bpck6_write_regr, 250 .read_regr = bpck6_read_regr, 251 .write_block = bpck6_write_block, 252 .read_block = bpck6_read_block, 253 .connect = bpck6_connect, 254 .disconnect = bpck6_disconnect, 255 .test_port = bpck6_test_port, 256 .probe_unit = bpck6_probe_unit, 257 .log_adapter = bpck6_log_adapter, 258 }; 259 260 MODULE_LICENSE("GPL"); 261 MODULE_AUTHOR("Micro Solutions Inc."); 262 MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); 263 module_pata_parport_driver(bpck6); 264