1 1.14 andvar /* $NetBSD: ppbus_1284.c,v 1.14 2021/11/14 20:51:57 andvar Exp $ */ 2 1.2 bjh21 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 1997 Nicolas Souchu 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 8 1.1 jdolecek * modification, are permitted provided that the following conditions 9 1.1 jdolecek * are met: 10 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 11 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 12 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 14 1.1 jdolecek * documentation and/or other materials provided with the distribution. 15 1.1 jdolecek * 16 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jdolecek * SUCH DAMAGE. 27 1.1 jdolecek * 28 1.4 bjh21 * FreeBSD: src/sys/dev/ppbus/ppb_1284.c,v 1.11 2000/01/14 08:03:14 nsouch Exp 29 1.1 jdolecek * 30 1.1 jdolecek */ 31 1.1 jdolecek 32 1.1 jdolecek /* General purpose routines for the IEEE1284-1994 Standard */ 33 1.1 jdolecek 34 1.4 bjh21 #include <sys/cdefs.h> 35 1.14 andvar __KERNEL_RCSID(0, "$NetBSD: ppbus_1284.c,v 1.14 2021/11/14 20:51:57 andvar Exp $"); 36 1.4 bjh21 37 1.1 jdolecek #include "opt_ppbus_1284.h" 38 1.1 jdolecek 39 1.3 bjh21 #include <sys/param.h> 40 1.1 jdolecek #include <sys/malloc.h> 41 1.1 jdolecek #include <sys/systm.h> 42 1.1 jdolecek 43 1.1 jdolecek #include <dev/ppbus/ppbus_conf.h> 44 1.1 jdolecek #include <dev/ppbus/ppbus_base.h> 45 1.1 jdolecek #include <dev/ppbus/ppbus_1284.h> 46 1.1 jdolecek #include <dev/ppbus/ppbus_io.h> 47 1.1 jdolecek #include <dev/ppbus/ppbus_var.h> 48 1.1 jdolecek 49 1.1 jdolecek 50 1.13 dholland /* Wait for the peripheral up to 40ms */ 51 1.1 jdolecek static int 52 1.1 jdolecek do_1284_wait(struct ppbus_softc * bus, char mask, char status) 53 1.1 jdolecek { 54 1.11 cegger return (ppbus_poll_bus(bus->sc_dev, 4, mask, status, 55 1.1 jdolecek PPBUS_NOINTR | PPBUS_POLL)); 56 1.1 jdolecek } 57 1.1 jdolecek 58 1.1 jdolecek /* Wait for the host up to 1 second (peripheral side) */ 59 1.1 jdolecek static int 60 1.1 jdolecek do_peripheral_wait(struct ppbus_softc * bus, char mask, char status) 61 1.1 jdolecek { 62 1.11 cegger return (ppbus_poll_bus(bus->sc_dev, 100, mask, status, 63 1.1 jdolecek PPBUS_NOINTR | PPBUS_POLL)); 64 1.1 jdolecek } 65 1.1 jdolecek 66 1.1 jdolecek 67 1.14 andvar /* Unconditionally reset the error field */ 68 1.1 jdolecek static int 69 1.1 jdolecek ppbus_1284_reset_error(struct ppbus_softc * bus, int state) 70 1.1 jdolecek { 71 1.1 jdolecek bus->sc_1284_error = PPBUS_NO_ERROR; 72 1.1 jdolecek bus->sc_1284_state = state; 73 1.1 jdolecek return 0; 74 1.1 jdolecek } 75 1.1 jdolecek 76 1.1 jdolecek 77 1.1 jdolecek /* Get IEEE1284 state */ 78 1.1 jdolecek int 79 1.11 cegger ppbus_1284_get_state(device_t dev) 80 1.1 jdolecek { 81 1.11 cegger struct ppbus_softc *sc = device_private(dev); 82 1.11 cegger 83 1.11 cegger return sc->sc_1284_state; 84 1.1 jdolecek } 85 1.1 jdolecek 86 1.1 jdolecek 87 1.6 wiz /* Set IEEE1284 state if no error occurred */ 88 1.1 jdolecek int 89 1.11 cegger ppbus_1284_set_state(device_t dev, int state) 90 1.1 jdolecek { 91 1.11 cegger struct ppbus_softc * bus = device_private(dev); 92 1.1 jdolecek 93 1.1 jdolecek /* call ppbus_1284_reset_error() if you absolutly want to change 94 1.1 jdolecek * the state from PPBUS_ERROR to another */ 95 1.1 jdolecek if ((bus->sc_1284_state != PPBUS_ERROR) && 96 1.1 jdolecek (bus->sc_1284_error == PPBUS_NO_ERROR)) { 97 1.1 jdolecek bus->sc_1284_state = state; 98 1.1 jdolecek bus->sc_1284_error = PPBUS_NO_ERROR; 99 1.1 jdolecek } 100 1.1 jdolecek 101 1.1 jdolecek return 0; 102 1.1 jdolecek } 103 1.1 jdolecek 104 1.1 jdolecek 105 1.1 jdolecek /* Set the IEEE1284 error field */ 106 1.1 jdolecek static int 107 1.1 jdolecek ppbus_1284_set_error(struct ppbus_softc * bus, int error, int event) 108 1.1 jdolecek { 109 1.1 jdolecek /* do not accumulate errors */ 110 1.1 jdolecek if ((bus->sc_1284_error == PPBUS_NO_ERROR) && 111 1.1 jdolecek (bus->sc_1284_state != PPBUS_ERROR)) { 112 1.1 jdolecek bus->sc_1284_error = error; 113 1.1 jdolecek bus->sc_1284_state = PPBUS_ERROR; 114 1.1 jdolecek } 115 1.1 jdolecek 116 1.1 jdolecek #ifdef DEBUG_1284 117 1.7 perry printf("%s<1284>: error=%d status=0x%x event=%d\n", 118 1.12 cegger device_xname(bus->sc_dev), error, ppbus_rstr(bus->sc_dev), 119 1.1 jdolecek event); 120 1.7 perry 121 1.1 jdolecek #endif 122 1.1 jdolecek 123 1.1 jdolecek return 0; 124 1.1 jdolecek } 125 1.1 jdolecek 126 1.1 jdolecek 127 1.1 jdolecek /* Converts mode+options into ext. value */ 128 1.1 jdolecek static int 129 1.1 jdolecek ppbus_request_mode(int mode, int options) 130 1.1 jdolecek { 131 1.1 jdolecek int request_mode = 0; 132 1.1 jdolecek 133 1.1 jdolecek if (options & PPBUS_EXTENSIBILITY_LINK) { 134 1.1 jdolecek request_mode = EXT_LINK_1284_NORMAL; 135 1.1 jdolecek 136 1.7 perry } 137 1.1 jdolecek else { 138 1.1 jdolecek switch (mode) { 139 1.1 jdolecek case PPBUS_NIBBLE: 140 1.1 jdolecek request_mode = (options & PPBUS_REQUEST_ID) ? 141 1.1 jdolecek NIBBLE_1284_REQUEST_ID : 142 1.1 jdolecek NIBBLE_1284_NORMAL; 143 1.1 jdolecek break; 144 1.1 jdolecek case PPBUS_PS2: 145 1.1 jdolecek request_mode = (options & PPBUS_REQUEST_ID) ? 146 1.1 jdolecek BYTE_1284_REQUEST_ID : 147 1.1 jdolecek BYTE_1284_NORMAL; 148 1.1 jdolecek break; 149 1.1 jdolecek case PPBUS_ECP: 150 1.1 jdolecek if (options & PPBUS_USE_RLE) 151 1.1 jdolecek request_mode = (options & PPBUS_REQUEST_ID) ? 152 1.1 jdolecek ECP_1284_RLE_REQUEST_ID : 153 1.1 jdolecek ECP_1284_RLE; 154 1.1 jdolecek else 155 1.1 jdolecek request_mode = (options & PPBUS_REQUEST_ID) ? 156 1.1 jdolecek ECP_1284_REQUEST_ID : 157 1.1 jdolecek ECP_1284_NORMAL; 158 1.1 jdolecek break; 159 1.1 jdolecek case PPBUS_EPP: 160 1.1 jdolecek request_mode = EPP_1284_NORMAL; 161 1.1 jdolecek break; 162 1.1 jdolecek default: 163 1.9 perry panic("%s: unsupported mode %d\n", __func__, mode); 164 1.1 jdolecek } 165 1.1 jdolecek } 166 1.1 jdolecek 167 1.1 jdolecek return (request_mode); 168 1.1 jdolecek } 169 1.1 jdolecek 170 1.1 jdolecek 171 1.5 bjh21 /* Negotiate the peripheral side */ 172 1.1 jdolecek int 173 1.11 cegger ppbus_peripheral_negotiate(device_t dev, int mode, int options) 174 1.1 jdolecek { 175 1.11 cegger struct ppbus_softc * bus = device_private(dev); 176 1.1 jdolecek int spin, request_mode, error = 0; 177 1.1 jdolecek char r; 178 1.1 jdolecek 179 1.1 jdolecek ppbus_1284_terminate(dev); 180 1.5 bjh21 ppbus_1284_set_state(dev, PPBUS_PERIPHERAL_NEGOTIATION); 181 1.1 jdolecek 182 1.1 jdolecek /* compute ext. value */ 183 1.1 jdolecek request_mode = ppbus_request_mode(mode, options); 184 1.1 jdolecek 185 1.1 jdolecek /* wait host */ 186 1.1 jdolecek spin = 10; 187 1.1 jdolecek while (spin-- && (ppbus_rstr(dev) & nBUSY)) 188 1.1 jdolecek DELAY(1); 189 1.1 jdolecek 190 1.1 jdolecek /* check termination */ 191 1.1 jdolecek if (!(ppbus_rstr(dev) & SELECT) || !spin) { 192 1.1 jdolecek error = ENODEV; 193 1.1 jdolecek goto error; 194 1.1 jdolecek } 195 1.1 jdolecek 196 1.1 jdolecek /* Event 4 - read ext. value */ 197 1.1 jdolecek r = ppbus_rdtr(dev); 198 1.1 jdolecek 199 1.1 jdolecek /* nibble mode is not supported */ 200 1.1 jdolecek if ((r == (char)request_mode) || 201 1.1 jdolecek (r == NIBBLE_1284_NORMAL)) { 202 1.1 jdolecek 203 1.1 jdolecek /* Event 5 - restore direction bit, no data avail */ 204 1.1 jdolecek ppbus_wctr(dev, (STROBE | nINIT) & ~(SELECTIN)); 205 1.1 jdolecek DELAY(1); 206 1.1 jdolecek 207 1.1 jdolecek /* Event 6 */ 208 1.1 jdolecek ppbus_wctr(dev, (nINIT) & ~(SELECTIN | STROBE)); 209 1.1 jdolecek 210 1.1 jdolecek if (r == NIBBLE_1284_NORMAL) { 211 1.1 jdolecek #ifdef DEBUG_1284 212 1.1 jdolecek printf("R"); 213 1.1 jdolecek #endif 214 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_MODE_UNSUPPORTED, 4); 215 1.1 jdolecek error = EINVAL; 216 1.1 jdolecek goto error; 217 1.7 perry } 218 1.1 jdolecek else { 219 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_PERIPHERAL_IDLE); 220 1.1 jdolecek #ifdef DEBUG_1284 221 1.1 jdolecek printf("A"); 222 1.1 jdolecek #endif 223 1.5 bjh21 /* negotiation succeeds */ 224 1.1 jdolecek } 225 1.7 perry } 226 1.1 jdolecek else { 227 1.1 jdolecek /* Event 5 - mode not supported */ 228 1.1 jdolecek ppbus_wctr(dev, SELECTIN); 229 1.1 jdolecek DELAY(1); 230 1.1 jdolecek 231 1.1 jdolecek /* Event 6 */ 232 1.1 jdolecek ppbus_wctr(dev, (SELECTIN) & ~(STROBE | nINIT)); 233 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_MODE_UNSUPPORTED, 4); 234 1.1 jdolecek 235 1.1 jdolecek #ifdef DEBUG_1284 236 1.1 jdolecek printf("r"); 237 1.1 jdolecek #endif 238 1.1 jdolecek error = EINVAL; 239 1.1 jdolecek goto error; 240 1.1 jdolecek } 241 1.1 jdolecek 242 1.1 jdolecek return (0); 243 1.1 jdolecek 244 1.1 jdolecek error: 245 1.1 jdolecek ppbus_peripheral_terminate(dev, PPBUS_WAIT); 246 1.1 jdolecek return (error); 247 1.1 jdolecek } 248 1.1 jdolecek 249 1.1 jdolecek 250 1.1 jdolecek /* Terminate peripheral transfer side. Always return 0 in compatible mode */ 251 1.1 jdolecek int 252 1.11 cegger ppbus_peripheral_terminate(device_t dev, int how) 253 1.1 jdolecek { 254 1.11 cegger struct ppbus_softc * bus = device_private(dev); 255 1.1 jdolecek int error = 0; 256 1.1 jdolecek 257 1.1 jdolecek #ifdef DEBUG_1284 258 1.1 jdolecek printf("t"); 259 1.1 jdolecek #endif 260 1.1 jdolecek 261 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_PERIPHERAL_TERMINATION); 262 1.1 jdolecek 263 1.1 jdolecek /* Event 22 - wait up to host response time (1s) */ 264 1.1 jdolecek if ((error = do_peripheral_wait(bus, SELECT | nBUSY, 0))) { 265 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 22); 266 1.1 jdolecek goto error; 267 1.1 jdolecek } 268 1.1 jdolecek 269 1.1 jdolecek /* Event 24 */ 270 1.1 jdolecek ppbus_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); 271 1.1 jdolecek 272 1.1 jdolecek /* Event 25 - wait up to host response time (1s) */ 273 1.1 jdolecek if ((error = do_peripheral_wait(bus, nBUSY, nBUSY))) { 274 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 25); 275 1.1 jdolecek goto error; 276 1.1 jdolecek } 277 1.1 jdolecek 278 1.1 jdolecek /* Event 26 */ 279 1.1 jdolecek ppbus_wctr(dev, (SELECTIN | nINIT | STROBE) & ~(AUTOFEED)); 280 1.1 jdolecek DELAY(1); 281 1.1 jdolecek /* Event 27 */ 282 1.1 jdolecek ppbus_wctr(dev, (SELECTIN | nINIT) & ~(STROBE | AUTOFEED)); 283 1.1 jdolecek 284 1.1 jdolecek /* Event 28 - wait up to host response time (1s) */ 285 1.1 jdolecek if ((error = do_peripheral_wait(bus, nBUSY, 0))) { 286 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 28); 287 1.1 jdolecek goto error; 288 1.1 jdolecek } 289 1.7 perry 290 1.1 jdolecek error: 291 1.1 jdolecek ppbus_1284_terminate(dev); 292 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_FORWARD_IDLE); 293 1.1 jdolecek 294 1.1 jdolecek return (0); 295 1.1 jdolecek } 296 1.1 jdolecek 297 1.1 jdolecek 298 1.1 jdolecek /* Write 1 byte to host in BYTE mode (peripheral side) */ 299 1.1 jdolecek static int 300 1.11 cegger byte_peripheral_outbyte(device_t dev, char *buffer, int last) 301 1.1 jdolecek { 302 1.11 cegger struct ppbus_softc * bus = device_private(dev); 303 1.1 jdolecek int error = 0; 304 1.1 jdolecek 305 1.1 jdolecek /* Event 7 */ 306 1.1 jdolecek if ((error = do_1284_wait(bus, nBUSY, nBUSY))) { 307 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 7); 308 1.1 jdolecek goto error; 309 1.1 jdolecek } 310 1.1 jdolecek 311 1.1 jdolecek /* check termination */ 312 1.1 jdolecek if (!(ppbus_rstr(dev) & SELECT)) { 313 1.1 jdolecek ppbus_peripheral_terminate(dev, PPBUS_WAIT); 314 1.1 jdolecek goto error; 315 1.1 jdolecek } 316 1.1 jdolecek 317 1.1 jdolecek /* Event 15 - put byte on data lines */ 318 1.1 jdolecek #ifdef DEBUG_1284 319 1.1 jdolecek printf("B"); 320 1.1 jdolecek #endif 321 1.1 jdolecek ppbus_wdtr(dev, *buffer); 322 1.1 jdolecek 323 1.1 jdolecek /* Event 9 */ 324 1.1 jdolecek ppbus_wctr(dev, (AUTOFEED | STROBE) & ~(nINIT | SELECTIN)); 325 1.1 jdolecek 326 1.1 jdolecek /* Event 10 - wait data read */ 327 1.1 jdolecek if ((error = do_peripheral_wait(bus, nBUSY, 0))) { 328 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 16); 329 1.1 jdolecek goto error; 330 1.1 jdolecek } 331 1.1 jdolecek 332 1.1 jdolecek /* Event 11 */ 333 1.1 jdolecek if (!last) { 334 1.1 jdolecek ppbus_wctr(dev, (AUTOFEED) & ~(nINIT | STROBE | SELECTIN)); 335 1.1 jdolecek } else { 336 1.1 jdolecek ppbus_wctr(dev, (nINIT) & ~(STROBE | SELECTIN | AUTOFEED)); 337 1.1 jdolecek } 338 1.1 jdolecek 339 1.1 jdolecek #if 0 340 1.1 jdolecek /* Event 16 - wait strobe */ 341 1.1 jdolecek if ((error = do_peripheral_wait(bus, nACK | nBUSY, 0))) { 342 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 16); 343 1.1 jdolecek goto error; 344 1.1 jdolecek } 345 1.1 jdolecek #endif 346 1.1 jdolecek 347 1.1 jdolecek /* check termination */ 348 1.1 jdolecek if (!(ppbus_rstr(dev) & SELECT)) { 349 1.1 jdolecek ppbus_peripheral_terminate(dev, PPBUS_WAIT); 350 1.1 jdolecek goto error; 351 1.1 jdolecek } 352 1.1 jdolecek 353 1.1 jdolecek error: 354 1.1 jdolecek return (error); 355 1.1 jdolecek } 356 1.1 jdolecek 357 1.1 jdolecek 358 1.1 jdolecek /* Write n bytes to host in BYTE mode (peripheral side) */ 359 1.1 jdolecek int 360 1.11 cegger byte_peripheral_write(device_t dev, char *buffer, int len, 361 1.1 jdolecek int *sent) 362 1.1 jdolecek { 363 1.1 jdolecek int error = 0, i; 364 1.1 jdolecek char r; 365 1.1 jdolecek 366 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_PERIPHERAL_TRANSFER); 367 1.1 jdolecek 368 1.1 jdolecek /* wait forever, the remote host is master and should initiate 369 1.1 jdolecek * termination 370 1.1 jdolecek */ 371 1.1 jdolecek for(i = 0; i < len; i++) { 372 1.1 jdolecek /* force remote nFAULT low to release the remote waiting 373 1.1 jdolecek * process, if any 374 1.1 jdolecek */ 375 1.1 jdolecek r = ppbus_rctr(dev); 376 1.1 jdolecek ppbus_wctr(dev, r & ~nINIT); 377 1.1 jdolecek 378 1.1 jdolecek #ifdef DEBUG_1284 379 1.1 jdolecek printf("y"); 380 1.1 jdolecek #endif 381 1.1 jdolecek /* Event 7 */ 382 1.1 jdolecek error = ppbus_poll_bus(dev, PPBUS_FOREVER, nBUSY, nBUSY, 383 1.1 jdolecek PPBUS_INTR); 384 1.1 jdolecek 385 1.1 jdolecek if (error && error != EWOULDBLOCK) 386 1.1 jdolecek goto error; 387 1.1 jdolecek 388 1.1 jdolecek #ifdef DEBUG_1284 389 1.1 jdolecek printf("b"); 390 1.1 jdolecek #endif 391 1.1 jdolecek if ((error = byte_peripheral_outbyte(dev, buffer+i, (i == len-1)))) 392 1.1 jdolecek goto error; 393 1.1 jdolecek } 394 1.1 jdolecek error: 395 1.1 jdolecek if (!error) 396 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_PERIPHERAL_IDLE); 397 1.1 jdolecek 398 1.1 jdolecek *sent = i; 399 1.1 jdolecek return (error); 400 1.1 jdolecek } 401 1.1 jdolecek 402 1.1 jdolecek 403 1.1 jdolecek /* Read the device ID using the specified mode */ 404 1.1 jdolecek int 405 1.11 cegger ppbus_1284_read_id(device_t dev, int mode, char ** buffer, 406 1.1 jdolecek size_t * size, size_t * read) 407 1.1 jdolecek { 408 1.1 jdolecek u_int16_t msg_sz; 409 1.1 jdolecek u_int8_t length_field; 410 1.1 jdolecek u_int8_t old_mode; 411 1.1 jdolecek int error; 412 1.1 jdolecek int old_ivar; 413 1.1 jdolecek int new_ivar = 1; 414 1.7 perry 415 1.1 jdolecek error = ppbus_read_ivar(dev, PPBUS_IVAR_IEEE, &old_ivar); 416 1.1 jdolecek if(error) { 417 1.1 jdolecek printf("%s(%s): error reading PPBUS_IVAR_IEEE.\n", __func__, 418 1.10 cegger device_xname(dev)); 419 1.1 jdolecek return error; 420 1.1 jdolecek } 421 1.1 jdolecek if(old_ivar == 0) { 422 1.1 jdolecek error = ppbus_write_ivar(dev, PPBUS_IVAR_IEEE, &new_ivar); 423 1.1 jdolecek if(error) { 424 1.1 jdolecek printf("%s(%s): error enabling IEEE usage.\n", __func__, 425 1.10 cegger device_xname(dev)); 426 1.1 jdolecek return error; 427 1.1 jdolecek } 428 1.1 jdolecek } 429 1.1 jdolecek 430 1.1 jdolecek old_mode = ppbus_get_mode(dev); 431 1.1 jdolecek switch (mode) { 432 1.1 jdolecek case PPBUS_NIBBLE: 433 1.1 jdolecek case PPBUS_ECP: 434 1.1 jdolecek case PPBUS_BYTE: 435 1.1 jdolecek error = ppbus_set_mode(dev, mode, PPBUS_REQUEST_ID); 436 1.1 jdolecek if(error) { 437 1.10 cegger printf("%s(%s): error setting bus mode.\n", __func__, 438 1.10 cegger device_xname(dev)); 439 1.1 jdolecek goto end_read_id; 440 1.1 jdolecek } 441 1.1 jdolecek break; 442 1.1 jdolecek default: 443 1.1 jdolecek printf("%s(%s): mode does not support returning device ID.\n", 444 1.10 cegger __func__, device_xname(dev)); 445 1.7 perry error = ENODEV; 446 1.1 jdolecek goto end_read_id; 447 1.1 jdolecek } 448 1.7 perry 449 1.7 perry error = ppbus_read(dev, &length_field, 1, 0, read); 450 1.1 jdolecek if(error) { 451 1.7 perry printf("%s(%s): error reading first byte.\n", __func__, 452 1.10 cegger device_xname(dev)); 453 1.1 jdolecek goto end_read_id; 454 1.1 jdolecek } 455 1.1 jdolecek msg_sz = length_field; 456 1.7 perry error = ppbus_read(dev, &length_field, 1, 0, read); 457 1.7 perry if(error) { 458 1.7 perry printf("%s(%s): error reading second byte.\n", 459 1.10 cegger __func__, device_xname(dev)); 460 1.1 jdolecek goto end_read_id; 461 1.1 jdolecek } 462 1.1 jdolecek msg_sz <<= 8; 463 1.1 jdolecek msg_sz |= length_field; 464 1.1 jdolecek msg_sz -= 2; 465 1.1 jdolecek if(msg_sz <= 0) { 466 1.1 jdolecek printf("%s(%s): device ID length <= 0.\n", __func__, 467 1.10 cegger device_xname(dev)); 468 1.1 jdolecek goto end_read_id; 469 1.1 jdolecek } 470 1.1 jdolecek *buffer = malloc(msg_sz, M_DEVBUF, M_WAITOK); 471 1.1 jdolecek *size = msg_sz; 472 1.7 perry error = ppbus_read(dev, *buffer, msg_sz, 0, read); 473 1.1 jdolecek 474 1.1 jdolecek end_read_id: 475 1.1 jdolecek ppbus_set_mode(dev, old_mode, 0); 476 1.1 jdolecek if(old_ivar == 0) { 477 1.1 jdolecek if(ppbus_write_ivar(dev, PPBUS_IVAR_IEEE, &old_ivar)) { 478 1.7 perry printf("%s(%s): error restoring PPBUS_IVAR_IEEE.\n", 479 1.10 cegger __func__, device_xname(dev)); 480 1.1 jdolecek } 481 1.1 jdolecek } 482 1.1 jdolecek return (error); 483 1.1 jdolecek } 484 1.1 jdolecek 485 1.1 jdolecek /* 486 1.7 perry * IEEE1284 negotiation phase: after negotiation, nFAULT is low if data is 487 1.1 jdolecek * available for reverse modes. 488 1.1 jdolecek */ 489 1.1 jdolecek int 490 1.11 cegger ppbus_1284_negotiate(device_t dev, int mode, int options) 491 1.1 jdolecek { 492 1.11 cegger struct ppbus_softc * bus = device_private(dev); 493 1.1 jdolecek int error; 494 1.1 jdolecek int request_mode; 495 1.1 jdolecek 496 1.1 jdolecek #ifdef DEBUG_1284 497 1.1 jdolecek printf("n"); 498 1.1 jdolecek #endif 499 1.1 jdolecek 500 1.5 bjh21 if (ppbus_1284_get_state(dev) >= PPBUS_PERIPHERAL_NEGOTIATION) 501 1.1 jdolecek ppbus_peripheral_terminate(dev, PPBUS_WAIT); 502 1.1 jdolecek 503 1.1 jdolecek #ifdef DEBUG_1284 504 1.1 jdolecek printf("%d", mode); 505 1.1 jdolecek #endif 506 1.1 jdolecek 507 1.1 jdolecek /* ensure the host is in compatible mode */ 508 1.1 jdolecek ppbus_1284_terminate(dev); 509 1.1 jdolecek 510 1.5 bjh21 /* reset error to catch the actual negotiation error */ 511 1.1 jdolecek ppbus_1284_reset_error(bus, PPBUS_FORWARD_IDLE); 512 1.1 jdolecek 513 1.1 jdolecek /* calculate ext. value */ 514 1.1 jdolecek request_mode = ppbus_request_mode(mode, options); 515 1.1 jdolecek 516 1.1 jdolecek /* default state */ 517 1.1 jdolecek ppbus_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); 518 1.1 jdolecek DELAY(1); 519 1.1 jdolecek 520 1.5 bjh21 /* enter negotiation phase */ 521 1.5 bjh21 ppbus_1284_set_state(dev, PPBUS_NEGOTIATION); 522 1.1 jdolecek 523 1.1 jdolecek /* Event 0 - put the exten. value on the data lines */ 524 1.1 jdolecek ppbus_wdtr(dev, request_mode); 525 1.1 jdolecek 526 1.1 jdolecek #ifdef PERIPH_1284 527 1.1 jdolecek /* request remote host attention */ 528 1.1 jdolecek ppbus_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); 529 1.1 jdolecek DELAY(1); 530 1.1 jdolecek ppbus_wctr(dev, (nINIT) & ~(STROBE | AUTOFEED | SELECTIN)); 531 1.1 jdolecek #else 532 1.1 jdolecek DELAY(1); 533 1.1 jdolecek 534 1.1 jdolecek #endif /* !PERIPH_1284 */ 535 1.1 jdolecek 536 1.1 jdolecek /* Event 1 - enter IEEE1284 mode */ 537 1.1 jdolecek ppbus_wctr(dev, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); 538 1.1 jdolecek 539 1.1 jdolecek #ifdef PERIPH_1284 540 1.7 perry /* ignore the PError line, wait a bit more, remote host's 541 1.1 jdolecek * interrupts don't respond fast enough */ 542 1.1 jdolecek if (ppbus_poll_bus(bus, 40, nACK | SELECT | nFAULT, 543 1.1 jdolecek SELECT | nFAULT, PPBUS_NOINTR | PPBUS_POLL)) { 544 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_NOT_IEEE1284, 2); 545 1.1 jdolecek error = ENODEV; 546 1.1 jdolecek goto error; 547 1.1 jdolecek } 548 1.1 jdolecek #else 549 1.1 jdolecek /* Event 2 - trying IEEE1284 dialog */ 550 1.1 jdolecek if (do_1284_wait(bus, nACK | PERROR | SELECT | nFAULT, 551 1.1 jdolecek PERROR | SELECT | nFAULT)) { 552 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_NOT_IEEE1284, 2); 553 1.1 jdolecek error = ENODEV; 554 1.1 jdolecek goto error; 555 1.1 jdolecek } 556 1.1 jdolecek #endif /* !PERIPH_1284 */ 557 1.1 jdolecek 558 1.1 jdolecek /* Event 3 - latch the ext. value to the peripheral */ 559 1.1 jdolecek ppbus_wctr(dev, (nINIT | STROBE | AUTOFEED) & ~SELECTIN); 560 1.1 jdolecek DELAY(1); 561 1.1 jdolecek 562 1.1 jdolecek /* Event 4 - IEEE1284 device recognized */ 563 1.1 jdolecek ppbus_wctr(dev, nINIT & ~(SELECTIN | AUTOFEED | STROBE)); 564 1.1 jdolecek 565 1.1 jdolecek /* Event 6 - waiting for status lines */ 566 1.1 jdolecek if (do_1284_wait(bus, nACK, nACK)) { 567 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 6); 568 1.1 jdolecek error = EBUSY; 569 1.1 jdolecek goto error; 570 1.1 jdolecek } 571 1.1 jdolecek 572 1.14 andvar /* Event 7 - querying result consider nACK not to misunderstand 573 1.1 jdolecek * a remote computer terminate sequence */ 574 1.1 jdolecek if (options & PPBUS_EXTENSIBILITY_LINK) { 575 1.1 jdolecek /* XXX not fully supported yet */ 576 1.1 jdolecek ppbus_1284_terminate(dev); 577 1.1 jdolecek error = ENODEV; 578 1.1 jdolecek goto error; 579 1.1 jdolecek /* return (0); */ 580 1.1 jdolecek } 581 1.1 jdolecek if (request_mode == NIBBLE_1284_NORMAL) { 582 1.1 jdolecek if (do_1284_wait(bus, nACK | SELECT, nACK)) { 583 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_MODE_UNSUPPORTED, 7); 584 1.1 jdolecek error = ENODEV; 585 1.1 jdolecek goto error; 586 1.1 jdolecek } 587 1.1 jdolecek } else { 588 1.1 jdolecek if (do_1284_wait(bus, nACK | SELECT, SELECT | nACK)) { 589 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_MODE_UNSUPPORTED, 7); 590 1.1 jdolecek error = ENODEV; 591 1.1 jdolecek goto error; 592 1.1 jdolecek } 593 1.1 jdolecek } 594 1.1 jdolecek 595 1.1 jdolecek switch (mode) { 596 1.1 jdolecek case PPBUS_NIBBLE: 597 1.1 jdolecek case PPBUS_PS2: 598 1.1 jdolecek /* enter reverse idle phase */ 599 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_REVERSE_IDLE); 600 1.1 jdolecek break; 601 1.1 jdolecek case PPBUS_ECP: 602 1.5 bjh21 /* negotiation ok, now setup the communication */ 603 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_SETUP); 604 1.1 jdolecek ppbus_wctr(dev, (nINIT | AUTOFEED) & ~(SELECTIN | STROBE)); 605 1.1 jdolecek 606 1.1 jdolecek #ifdef PERIPH_1284 607 1.1 jdolecek /* ignore PError line */ 608 1.1 jdolecek if (do_1284_wait(bus, nACK | SELECT | nBUSY, 609 1.1 jdolecek nACK | SELECT | nBUSY)) { 610 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 30); 611 1.1 jdolecek error = ENODEV; 612 1.1 jdolecek goto error; 613 1.1 jdolecek } 614 1.1 jdolecek #else 615 1.1 jdolecek if (do_1284_wait(bus, nACK | SELECT | PERROR | nBUSY, 616 1.1 jdolecek nACK | SELECT | PERROR | nBUSY)) { 617 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 30); 618 1.1 jdolecek error = ENODEV; 619 1.1 jdolecek goto error; 620 1.1 jdolecek } 621 1.1 jdolecek #endif /* !PERIPH_1284 */ 622 1.1 jdolecek 623 1.1 jdolecek /* ok, the host enters the ForwardIdle state */ 624 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_ECP_FORWARD_IDLE); 625 1.1 jdolecek break; 626 1.1 jdolecek case PPBUS_EPP: 627 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_EPP_IDLE); 628 1.1 jdolecek break; 629 1.1 jdolecek default: 630 1.1 jdolecek panic("%s: unknown mode (%d)!", __func__, mode); 631 1.1 jdolecek } 632 1.7 perry 633 1.1 jdolecek return 0; 634 1.1 jdolecek 635 1.1 jdolecek error: 636 1.1 jdolecek ppbus_1284_terminate(dev); 637 1.1 jdolecek return error; 638 1.1 jdolecek } 639 1.1 jdolecek 640 1.1 jdolecek /* 641 1.1 jdolecek * IEEE1284 termination phase, return code should ignored since the host 642 1.7 perry * is _always_ in compatible mode after ppbus_1284_terminate() 643 1.1 jdolecek */ 644 1.1 jdolecek int 645 1.11 cegger ppbus_1284_terminate(device_t dev) 646 1.1 jdolecek { 647 1.11 cegger struct ppbus_softc * bus = device_private(dev); 648 1.1 jdolecek 649 1.1 jdolecek #ifdef DEBUG_1284 650 1.1 jdolecek printf("T"); 651 1.1 jdolecek #endif 652 1.1 jdolecek 653 1.1 jdolecek /* do not reset error here to keep the error that 654 1.6 wiz * may occurred before the ppbus_1284_terminate() call */ 655 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_TERMINATION); 656 1.1 jdolecek 657 1.1 jdolecek #ifdef PERIPH_1284 658 1.1 jdolecek /* request remote host attention */ 659 1.1 jdolecek ppbus_wctr(dev, (nINIT | STROBE | SELECTIN) & ~(AUTOFEED)); 660 1.1 jdolecek DELAY(1); 661 1.1 jdolecek #endif /* PERIPH_1284 */ 662 1.1 jdolecek 663 1.1 jdolecek /* Event 22 - set nSelectin low and nAutoFeed high */ 664 1.1 jdolecek ppbus_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); 665 1.1 jdolecek 666 1.1 jdolecek /* Event 24 - waiting for peripheral, Xflag ignored */ 667 1.1 jdolecek if (do_1284_wait(bus, nACK | nBUSY | nFAULT, nFAULT)) { 668 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 24); 669 1.1 jdolecek goto error; 670 1.1 jdolecek } 671 1.1 jdolecek 672 1.1 jdolecek /* Event 25 - set nAutoFd low */ 673 1.1 jdolecek ppbus_wctr(dev, (nINIT | SELECTIN | AUTOFEED) & ~STROBE); 674 1.1 jdolecek 675 1.1 jdolecek /* Event 26 - compatible mode status is set */ 676 1.1 jdolecek 677 1.1 jdolecek /* Event 27 - peripheral set nAck high */ 678 1.1 jdolecek if (do_1284_wait(bus, nACK, nACK)) { 679 1.1 jdolecek ppbus_1284_set_error(bus, PPBUS_TIMEOUT, 27); 680 1.1 jdolecek } 681 1.1 jdolecek 682 1.1 jdolecek /* Event 28 - end termination, return to idle phase */ 683 1.1 jdolecek ppbus_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); 684 1.1 jdolecek 685 1.1 jdolecek error: 686 1.1 jdolecek ppbus_1284_set_state(dev, PPBUS_FORWARD_IDLE); 687 1.1 jdolecek 688 1.1 jdolecek return (0); 689 1.1 jdolecek } 690