1 1.42 andvar /* $NetBSD: atppc.c,v 1.42 2025/07/29 19:07:53 andvar Exp $ */ 2 1.3 bjh21 3 1.1 jdolecek /* 4 1.1 jdolecek * Copyright (c) 2001 Alcove - Nicolas Souchu 5 1.13 jdolecek * Copyright (c) 2003, 2004 Gary Thorpe <gathorpe (at) users.sourceforge.net> 6 1.1 jdolecek * All rights reserved. 7 1.1 jdolecek * 8 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 9 1.1 jdolecek * modification, are permitted provided that the following conditions 10 1.1 jdolecek * are met: 11 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 12 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 13 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 15 1.1 jdolecek * documentation and/or other materials provided with the distribution. 16 1.1 jdolecek * 17 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 jdolecek * SUCH DAMAGE. 28 1.1 jdolecek * 29 1.7 bjh21 * FreeBSD: src/sys/isa/ppc.c,v 1.26.2.5 2001/10/02 05:21:45 nsouch Exp 30 1.1 jdolecek * 31 1.1 jdolecek */ 32 1.1 jdolecek 33 1.7 bjh21 #include <sys/cdefs.h> 34 1.42 andvar __KERNEL_RCSID(0, "$NetBSD: atppc.c,v 1.42 2025/07/29 19:07:53 andvar Exp $"); 35 1.7 bjh21 36 1.1 jdolecek #include "opt_atppc.h" 37 1.1 jdolecek 38 1.1 jdolecek #include <sys/types.h> 39 1.1 jdolecek #include <sys/param.h> 40 1.1 jdolecek #include <sys/kernel.h> 41 1.1 jdolecek #include <sys/device.h> 42 1.30 jakllsch #include <sys/kmem.h> 43 1.1 jdolecek #include <sys/proc.h> 44 1.1 jdolecek #include <sys/systm.h> 45 1.1 jdolecek #include <sys/vnode.h> 46 1.1 jdolecek #include <sys/syslog.h> 47 1.1 jdolecek 48 1.24 ad #include <sys/bus.h> 49 1.24 ad /*#include <sys/intr.h>*/ 50 1.1 jdolecek 51 1.1 jdolecek #include <dev/isa/isareg.h> 52 1.1 jdolecek 53 1.1 jdolecek #include <dev/ic/atppcreg.h> 54 1.1 jdolecek #include <dev/ic/atppcvar.h> 55 1.1 jdolecek 56 1.1 jdolecek #include <dev/ppbus/ppbus_conf.h> 57 1.1 jdolecek #include <dev/ppbus/ppbus_msq.h> 58 1.1 jdolecek #include <dev/ppbus/ppbus_io.h> 59 1.1 jdolecek #include <dev/ppbus/ppbus_var.h> 60 1.1 jdolecek 61 1.1 jdolecek #ifdef ATPPC_DEBUG 62 1.1 jdolecek int atppc_debug = 1; 63 1.1 jdolecek #endif 64 1.1 jdolecek 65 1.1 jdolecek #ifdef ATPPC_VERBOSE 66 1.1 jdolecek int atppc_verbose = 1; 67 1.1 jdolecek #endif 68 1.1 jdolecek 69 1.1 jdolecek /* List of supported chipsets detection routines */ 70 1.1 jdolecek static int (*chipset_detect[])(struct atppc_softc *) = { 71 1.22 wiz /* XXX Add these LATER: maybe as separate devices? 72 1.1 jdolecek atppc_pc873xx_detect, 73 1.1 jdolecek atppc_smc37c66xgt_detect, 74 1.1 jdolecek atppc_w83877f_detect, 75 1.1 jdolecek atppc_smc37c935_detect, 76 1.1 jdolecek */ 77 1.1 jdolecek NULL 78 1.1 jdolecek }; 79 1.1 jdolecek 80 1.9 drochner 81 1.1 jdolecek /* Prototypes for functions. */ 82 1.1 jdolecek 83 1.18 drochner /* Print function for config_found() */ 84 1.9 drochner static int atppc_print(void *, const char *); 85 1.15 drochner 86 1.1 jdolecek /* Detection routines */ 87 1.1 jdolecek static int atppc_detect_fifo(struct atppc_softc *); 88 1.1 jdolecek static int atppc_detect_chipset(struct atppc_softc *); 89 1.1 jdolecek static int atppc_detect_generic(struct atppc_softc *); 90 1.1 jdolecek 91 1.1 jdolecek /* Routines for ppbus interface (bus + device) */ 92 1.26 cegger static int atppc_read(device_t, char *, int, int, size_t *); 93 1.26 cegger static int atppc_write(device_t, char *, int, int, size_t *); 94 1.26 cegger static int atppc_setmode(device_t, int); 95 1.26 cegger static int atppc_getmode(device_t); 96 1.26 cegger static int atppc_check_epp_timeout(device_t); 97 1.26 cegger static void atppc_reset_epp_timeout(device_t); 98 1.26 cegger static void atppc_ecp_sync(device_t); 99 1.26 cegger static int atppc_exec_microseq(device_t, struct ppbus_microseq * *); 100 1.26 cegger static u_int8_t atppc_io(device_t, int, u_char *, int, u_char); 101 1.26 cegger static int atppc_read_ivar(device_t, int, unsigned int *); 102 1.26 cegger static int atppc_write_ivar(device_t, int, unsigned int *); 103 1.26 cegger static int atppc_add_handler(device_t, void (*)(void *), void *); 104 1.26 cegger static int atppc_remove_handler(device_t, void (*)(void *)); 105 1.1 jdolecek 106 1.1 jdolecek /* Utility functions */ 107 1.1 jdolecek 108 1.1 jdolecek /* Functions to read bytes into device's input buffer */ 109 1.1 jdolecek static void atppc_nibble_read(struct atppc_softc * const); 110 1.1 jdolecek static void atppc_byte_read(struct atppc_softc * const); 111 1.1 jdolecek static void atppc_epp_read(struct atppc_softc * const); 112 1.1 jdolecek static void atppc_ecp_read(struct atppc_softc * const); 113 1.9 drochner static void atppc_ecp_read_dma(struct atppc_softc *, unsigned int *, 114 1.1 jdolecek unsigned char); 115 1.9 drochner static void atppc_ecp_read_pio(struct atppc_softc *, unsigned int *, 116 1.1 jdolecek unsigned char); 117 1.21 drochner static void atppc_ecp_read_error(struct atppc_softc *); 118 1.1 jdolecek 119 1.1 jdolecek 120 1.1 jdolecek /* Functions to write bytes to device's output buffer */ 121 1.1 jdolecek static void atppc_std_write(struct atppc_softc * const); 122 1.1 jdolecek static void atppc_epp_write(struct atppc_softc * const); 123 1.1 jdolecek static void atppc_fifo_write(struct atppc_softc * const); 124 1.9 drochner static void atppc_fifo_write_dma(struct atppc_softc * const, unsigned char, 125 1.1 jdolecek unsigned char); 126 1.1 jdolecek static void atppc_fifo_write_pio(struct atppc_softc * const, unsigned char, 127 1.1 jdolecek unsigned char); 128 1.9 drochner static void atppc_fifo_write_error(struct atppc_softc * const, 129 1.1 jdolecek const unsigned int); 130 1.1 jdolecek 131 1.1 jdolecek /* Miscellaneous */ 132 1.9 drochner static int atppc_poll_str(const struct atppc_softc * const, const u_int8_t, 133 1.1 jdolecek const u_int8_t); 134 1.29 jakllsch static int atppc_wait_interrupt(struct atppc_softc * const, kcondvar_t *, 135 1.1 jdolecek const u_int8_t); 136 1.1 jdolecek 137 1.1 jdolecek 138 1.1 jdolecek /* 139 1.9 drochner * Generic attach and detach functions for atppc device. If sc_dev_ok in soft 140 1.1 jdolecek * configuration data is not ATPPC_ATTACHED, these should be skipped altogether. 141 1.1 jdolecek */ 142 1.1 jdolecek 143 1.1 jdolecek /* Soft configuration attach for atppc */ 144 1.1 jdolecek void 145 1.9 drochner atppc_sc_attach(struct atppc_softc *lsc) 146 1.1 jdolecek { 147 1.1 jdolecek /* Adapter used to configure ppbus device */ 148 1.1 jdolecek struct parport_adapter sc_parport_adapter; 149 1.1 jdolecek char buf[64]; 150 1.1 jdolecek 151 1.29 jakllsch mutex_init(&lsc->sc_lock, MUTEX_DEFAULT, IPL_TTY); 152 1.29 jakllsch cv_init(&lsc->sc_out_cv, "atppcout"); 153 1.29 jakllsch cv_init(&lsc->sc_in_cv, "atppcin"); 154 1.16 drochner 155 1.1 jdolecek /* Probe and set up chipset */ 156 1.9 drochner if (atppc_detect_chipset(lsc) != 0) { 157 1.9 drochner if (atppc_detect_generic(lsc) != 0) { 158 1.9 drochner ATPPC_DPRINTF(("%s: Error detecting chipset\n", 159 1.26 cegger device_xname(lsc->sc_dev))); 160 1.1 jdolecek } 161 1.1 jdolecek } 162 1.1 jdolecek 163 1.1 jdolecek /* Probe and setup FIFO queue */ 164 1.8 jdolecek if (atppc_detect_fifo(lsc) == 0) { 165 1.9 drochner printf("%s: FIFO <depth,wthr,rthr>=<%d,%d,%d>\n", 166 1.26 cegger device_xname(lsc->sc_dev), lsc->sc_fifo, lsc->sc_wthr, 167 1.8 jdolecek lsc->sc_rthr); 168 1.1 jdolecek } 169 1.1 jdolecek 170 1.1 jdolecek /* Print out chipset capabilities */ 171 1.28 christos snprintb(buf, sizeof(buf), "\20\1INTR\2DMA\3FIFO\4PS2\5ECP\6EPP", 172 1.28 christos lsc->sc_has); 173 1.26 cegger printf("%s: capabilities=%s\n", device_xname(lsc->sc_dev), buf); 174 1.1 jdolecek 175 1.1 jdolecek /* Initialize device's buffer pointers */ 176 1.9 drochner lsc->sc_outb = lsc->sc_outbstart = lsc->sc_inb = lsc->sc_inbstart 177 1.1 jdolecek = NULL; 178 1.1 jdolecek lsc->sc_inb_nbytes = lsc->sc_outb_nbytes = 0; 179 1.1 jdolecek 180 1.1 jdolecek /* Last configuration step: set mode to standard mode */ 181 1.26 cegger if (atppc_setmode(lsc->sc_dev, PPBUS_COMPATIBLE) != 0) { 182 1.9 drochner ATPPC_DPRINTF(("%s: unable to initialize mode.\n", 183 1.26 cegger device_xname(lsc->sc_dev))); 184 1.1 jdolecek } 185 1.1 jdolecek 186 1.1 jdolecek /* Set up parport_adapter structure */ 187 1.15 drochner 188 1.40 andvar /* Set capabilities */ 189 1.1 jdolecek sc_parport_adapter.capabilities = 0; 190 1.9 drochner if (lsc->sc_has & ATPPC_HAS_INTR) { 191 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_INTR; 192 1.1 jdolecek } 193 1.9 drochner if (lsc->sc_has & ATPPC_HAS_DMA) { 194 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_DMA; 195 1.1 jdolecek } 196 1.9 drochner if (lsc->sc_has & ATPPC_HAS_FIFO) { 197 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_FIFO; 198 1.1 jdolecek } 199 1.9 drochner if (lsc->sc_has & ATPPC_HAS_PS2) { 200 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_PS2; 201 1.1 jdolecek } 202 1.9 drochner if (lsc->sc_has & ATPPC_HAS_EPP) { 203 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_EPP; 204 1.1 jdolecek } 205 1.9 drochner if (lsc->sc_has & ATPPC_HAS_ECP) { 206 1.1 jdolecek sc_parport_adapter.capabilities |= PPBUS_HAS_ECP; 207 1.1 jdolecek } 208 1.1 jdolecek 209 1.1 jdolecek /* Set function pointers */ 210 1.1 jdolecek sc_parport_adapter.parport_io = atppc_io; 211 1.1 jdolecek sc_parport_adapter.parport_exec_microseq = atppc_exec_microseq; 212 1.9 drochner sc_parport_adapter.parport_reset_epp_timeout = 213 1.1 jdolecek atppc_reset_epp_timeout; 214 1.1 jdolecek sc_parport_adapter.parport_setmode = atppc_setmode; 215 1.1 jdolecek sc_parport_adapter.parport_getmode = atppc_getmode; 216 1.1 jdolecek sc_parport_adapter.parport_ecp_sync = atppc_ecp_sync; 217 1.1 jdolecek sc_parport_adapter.parport_read = atppc_read; 218 1.1 jdolecek sc_parport_adapter.parport_write = atppc_write; 219 1.1 jdolecek sc_parport_adapter.parport_read_ivar = atppc_read_ivar; 220 1.1 jdolecek sc_parport_adapter.parport_write_ivar = atppc_write_ivar; 221 1.1 jdolecek sc_parport_adapter.parport_dma_malloc = lsc->sc_dma_malloc; 222 1.1 jdolecek sc_parport_adapter.parport_dma_free = lsc->sc_dma_free; 223 1.1 jdolecek sc_parport_adapter.parport_add_handler = atppc_add_handler; 224 1.1 jdolecek sc_parport_adapter.parport_remove_handler = atppc_remove_handler; 225 1.1 jdolecek 226 1.1 jdolecek /* Initialize handler list, may be added to by grandchildren */ 227 1.1 jdolecek SLIST_INIT(&(lsc->sc_handler_listhead)); 228 1.15 drochner 229 1.1 jdolecek /* Initialize interrupt state */ 230 1.1 jdolecek lsc->sc_irqstat = ATPPC_IRQ_NONE; 231 1.1 jdolecek lsc->sc_ecr_intr = lsc->sc_ctr_intr = lsc->sc_str_intr = 0; 232 1.1 jdolecek 233 1.1 jdolecek /* Disable DMA/interrupts (each ppbus driver selects usage itself) */ 234 1.1 jdolecek lsc->sc_use = 0; 235 1.1 jdolecek 236 1.9 drochner /* Configure child of the device. */ 237 1.26 cegger lsc->child = config_found(lsc->sc_dev, &(sc_parport_adapter), 238 1.39 thorpej atppc_print, CFARGS_NONE); 239 1.1 jdolecek 240 1.1 jdolecek return; 241 1.1 jdolecek } 242 1.1 jdolecek 243 1.1 jdolecek /* Soft configuration detach */ 244 1.17 thorpej int 245 1.17 thorpej atppc_sc_detach(struct atppc_softc *lsc, int flag) 246 1.1 jdolecek { 247 1.26 cegger device_t dev = lsc->sc_dev; 248 1.1 jdolecek 249 1.1 jdolecek /* Detach children devices */ 250 1.9 drochner if (config_detach(lsc->child, flag) && !(flag & DETACH_QUIET)) { 251 1.25 cegger aprint_error_dev(dev, "not able to detach child device, "); 252 1.1 jdolecek 253 1.9 drochner if (!(flag & DETACH_FORCE)) { 254 1.2 jdolecek printf("cannot detach\n"); 255 1.1 jdolecek return 1; 256 1.9 drochner } else { 257 1.2 jdolecek printf("continuing (DETACH_FORCE)\n"); 258 1.1 jdolecek } 259 1.1 jdolecek } 260 1.1 jdolecek 261 1.9 drochner if (!(flag & DETACH_QUIET)) 262 1.25 cegger printf("%s detached", device_xname(dev)); 263 1.15 drochner 264 1.1 jdolecek return 0; 265 1.1 jdolecek } 266 1.1 jdolecek 267 1.18 drochner /* Used by config_found() to print out device information */ 268 1.9 drochner static int 269 1.9 drochner atppc_print(void *aux, const char *name) 270 1.1 jdolecek { 271 1.1 jdolecek /* Print out something on failure. */ 272 1.9 drochner if (name != NULL) { 273 1.1 jdolecek printf("%s: child devices", name); 274 1.1 jdolecek return UNCONF; 275 1.1 jdolecek } 276 1.1 jdolecek 277 1.1 jdolecek return QUIET; 278 1.1 jdolecek } 279 1.1 jdolecek 280 1.1 jdolecek /* 281 1.1 jdolecek * Machine independent detection routines for atppc driver. 282 1.1 jdolecek */ 283 1.1 jdolecek 284 1.1 jdolecek /* Detect parallel port I/O port: taken from FreeBSD code directly. */ 285 1.1 jdolecek int 286 1.1 jdolecek atppc_detect_port(bus_space_tag_t iot, bus_space_handle_t ioh) 287 1.1 jdolecek { 288 1.9 drochner /* 289 1.9 drochner * Much shorter than scheme used by lpt_isa_probe() and lpt_port_test() 290 1.9 drochner * in original lpt driver. 291 1.9 drochner * Write to data register common to all controllers and read back the 292 1.1 jdolecek * values. Also tests control and status registers. 293 1.1 jdolecek */ 294 1.1 jdolecek 295 1.1 jdolecek /* 296 1.9 drochner * Cannot use convenient macros because the device's config structure 297 1.1 jdolecek * may not have been created yet: major change from FreeBSD code. 298 1.1 jdolecek */ 299 1.1 jdolecek 300 1.1 jdolecek int rval; 301 1.1 jdolecek u_int8_t ctr_sav, dtr_sav, str_sav; 302 1.1 jdolecek 303 1.42 andvar /* Store writable registers' values and test if they can be read */ 304 1.1 jdolecek str_sav = bus_space_read_1(iot, ioh, ATPPC_SPP_STR); 305 1.1 jdolecek ctr_sav = bus_space_read_1(iot, ioh, ATPPC_SPP_CTR); 306 1.1 jdolecek dtr_sav = bus_space_read_1(iot, ioh, ATPPC_SPP_DTR); 307 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 308 1.9 drochner BUS_SPACE_BARRIER_READ); 309 1.1 jdolecek 310 1.9 drochner /* 311 1.9 drochner * Ensure PS2 ports in output mode, also read back value of control 312 1.9 drochner * register. 313 1.1 jdolecek */ 314 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_CTR, 0x0c); 315 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 316 1.9 drochner BUS_SPACE_BARRIER_WRITE); 317 1.15 drochner 318 1.9 drochner if (bus_space_read_1(iot, ioh, ATPPC_SPP_CTR) != 0x0c) { 319 1.1 jdolecek rval = 0; 320 1.9 drochner } else { 321 1.9 drochner /* 322 1.9 drochner * Test if two values can be written and read from the data 323 1.9 drochner * register. 324 1.1 jdolecek */ 325 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 326 1.9 drochner BUS_SPACE_BARRIER_READ); 327 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_DTR, 0xaa); 328 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 329 1.9 drochner BUS_SPACE_BARRIER_WRITE); 330 1.1 jdolecek if (bus_space_read_1(iot, ioh, ATPPC_SPP_DTR) != 0xaa) { 331 1.1 jdolecek rval = 1; 332 1.9 drochner } else { 333 1.1 jdolecek /* Second value to test */ 334 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 335 1.9 drochner BUS_SPACE_BARRIER_READ); 336 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_DTR, 0x55); 337 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 338 1.9 drochner BUS_SPACE_BARRIER_WRITE); 339 1.9 drochner if (bus_space_read_1(iot, ioh, ATPPC_SPP_DTR) != 0x55) { 340 1.1 jdolecek rval = 1; 341 1.9 drochner } else { 342 1.1 jdolecek rval = 0; 343 1.1 jdolecek } 344 1.1 jdolecek } 345 1.15 drochner 346 1.1 jdolecek } 347 1.15 drochner 348 1.1 jdolecek /* Restore registers */ 349 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 350 1.9 drochner BUS_SPACE_BARRIER_READ); 351 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_CTR, ctr_sav); 352 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_DTR, dtr_sav); 353 1.1 jdolecek bus_space_write_1(iot, ioh, ATPPC_SPP_STR, str_sav); 354 1.9 drochner bus_space_barrier(iot, ioh, 0, IO_LPTSIZE, 355 1.9 drochner BUS_SPACE_BARRIER_WRITE); 356 1.1 jdolecek 357 1.1 jdolecek return rval; 358 1.1 jdolecek } 359 1.1 jdolecek 360 1.1 jdolecek /* Detect parallel port chipset. */ 361 1.1 jdolecek static int 362 1.9 drochner atppc_detect_chipset(struct atppc_softc *atppc) 363 1.1 jdolecek { 364 1.1 jdolecek /* Try each detection routine. */ 365 1.1 jdolecek int i, mode; 366 1.1 jdolecek for (i = 0; chipset_detect[i] != NULL; i++) { 367 1.1 jdolecek if ((mode = chipset_detect[i](atppc)) != -1) { 368 1.1 jdolecek atppc->sc_mode = mode; 369 1.1 jdolecek return 0; 370 1.1 jdolecek } 371 1.1 jdolecek } 372 1.1 jdolecek 373 1.1 jdolecek return 1; 374 1.1 jdolecek } 375 1.1 jdolecek 376 1.1 jdolecek /* Detect generic capabilities. */ 377 1.9 drochner static int 378 1.9 drochner atppc_detect_generic(struct atppc_softc *atppc) 379 1.1 jdolecek { 380 1.1 jdolecek u_int8_t ecr_sav = atppc_r_ecr(atppc); 381 1.1 jdolecek u_int8_t ctr_sav = atppc_r_ctr(atppc); 382 1.1 jdolecek u_int8_t str_sav = atppc_r_str(atppc); 383 1.9 drochner u_int8_t tmp; 384 1.1 jdolecek atppc_barrier_r(atppc); 385 1.1 jdolecek 386 1.1 jdolecek /* Default to generic */ 387 1.1 jdolecek atppc->sc_type = ATPPC_TYPE_GENERIC; 388 1.1 jdolecek atppc->sc_model = GENERIC; 389 1.1 jdolecek 390 1.1 jdolecek /* Check for ECP */ 391 1.1 jdolecek tmp = atppc_r_ecr(atppc); 392 1.1 jdolecek atppc_barrier_r(atppc); 393 1.1 jdolecek if ((tmp & ATPPC_FIFO_EMPTY) && !(tmp & ATPPC_FIFO_FULL)) { 394 1.1 jdolecek atppc_w_ecr(atppc, 0x34); 395 1.1 jdolecek atppc_barrier_w(atppc); 396 1.1 jdolecek tmp = atppc_r_ecr(atppc); 397 1.1 jdolecek atppc_barrier_r(atppc); 398 1.9 drochner if (tmp == 0x35) { 399 1.1 jdolecek atppc->sc_has |= ATPPC_HAS_ECP; 400 1.1 jdolecek } 401 1.1 jdolecek } 402 1.1 jdolecek 403 1.1 jdolecek /* Allow search for SMC style ECP+EPP mode */ 404 1.9 drochner if (atppc->sc_has & ATPPC_HAS_ECP) { 405 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_EPP); 406 1.1 jdolecek atppc_barrier_w(atppc); 407 1.1 jdolecek } 408 1.1 jdolecek /* Check for EPP by checking for timeout bit */ 409 1.26 cegger if (atppc_check_epp_timeout(atppc->sc_dev) != 0) { 410 1.1 jdolecek atppc->sc_has |= ATPPC_HAS_EPP; 411 1.1 jdolecek atppc->sc_epp = ATPPC_EPP_1_9; 412 1.9 drochner if (atppc->sc_has & ATPPC_HAS_ECP) { 413 1.1 jdolecek /* SMC like chipset found */ 414 1.1 jdolecek atppc->sc_model = SMC_LIKE; 415 1.1 jdolecek atppc->sc_type = ATPPC_TYPE_SMCLIKE; 416 1.1 jdolecek } 417 1.1 jdolecek } 418 1.1 jdolecek 419 1.1 jdolecek /* Detect PS2 mode */ 420 1.9 drochner if (atppc->sc_has & ATPPC_HAS_ECP) { 421 1.1 jdolecek /* Put ECP port into PS2 mode */ 422 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 423 1.1 jdolecek atppc_barrier_w(atppc); 424 1.1 jdolecek } 425 1.1 jdolecek /* Put PS2 port in input mode: writes should not be readable */ 426 1.1 jdolecek atppc_w_ctr(atppc, 0x20); 427 1.1 jdolecek atppc_barrier_w(atppc); 428 1.9 drochner /* 429 1.9 drochner * Write two values to data port: if neither are read back, 430 1.1 jdolecek * bidirectional mode is functional. 431 1.1 jdolecek */ 432 1.1 jdolecek atppc_w_dtr(atppc, 0xaa); 433 1.1 jdolecek atppc_barrier_w(atppc); 434 1.1 jdolecek tmp = atppc_r_dtr(atppc); 435 1.1 jdolecek atppc_barrier_r(atppc); 436 1.15 drochner if (tmp != 0xaa) { 437 1.1 jdolecek atppc_w_dtr(atppc, 0x55); 438 1.1 jdolecek atppc_barrier_w(atppc); 439 1.1 jdolecek tmp = atppc_r_dtr(atppc); 440 1.1 jdolecek atppc_barrier_r(atppc); 441 1.9 drochner if (tmp != 0x55) { 442 1.1 jdolecek atppc->sc_has |= ATPPC_HAS_PS2; 443 1.1 jdolecek } 444 1.1 jdolecek } 445 1.15 drochner 446 1.1 jdolecek /* Restore to previous state */ 447 1.1 jdolecek atppc_w_ecr(atppc, ecr_sav); 448 1.1 jdolecek atppc_w_ctr(atppc, ctr_sav); 449 1.1 jdolecek atppc_w_str(atppc, str_sav); 450 1.1 jdolecek atppc_barrier_w(atppc); 451 1.1 jdolecek 452 1.1 jdolecek return 0; 453 1.1 jdolecek } 454 1.1 jdolecek 455 1.9 drochner /* 456 1.9 drochner * Detect parallel port FIFO: taken from FreeBSD code directly. 457 1.1 jdolecek */ 458 1.1 jdolecek static int 459 1.9 drochner atppc_detect_fifo(struct atppc_softc *atppc) 460 1.1 jdolecek { 461 1.1 jdolecek #ifdef ATPPC_DEBUG 462 1.26 cegger device_t dev = atppc->sc_dev; 463 1.1 jdolecek #endif 464 1.1 jdolecek u_int8_t ecr_sav; 465 1.1 jdolecek u_int8_t ctr_sav; 466 1.1 jdolecek u_int8_t str_sav; 467 1.1 jdolecek u_int8_t cc; 468 1.1 jdolecek short i; 469 1.1 jdolecek 470 1.1 jdolecek /* If there is no ECP mode, we cannot config a FIFO */ 471 1.9 drochner if (!(atppc->sc_has & ATPPC_HAS_ECP)) { 472 1.1 jdolecek return (EINVAL); 473 1.1 jdolecek } 474 1.1 jdolecek 475 1.1 jdolecek /* save registers */ 476 1.1 jdolecek ecr_sav = atppc_r_ecr(atppc); 477 1.1 jdolecek ctr_sav = atppc_r_ctr(atppc); 478 1.1 jdolecek str_sav = atppc_r_str(atppc); 479 1.1 jdolecek atppc_barrier_r(atppc); 480 1.15 drochner 481 1.1 jdolecek /* Enter ECP configuration mode, no interrupt, no DMA */ 482 1.9 drochner atppc_w_ecr(atppc, (ATPPC_ECR_CFG | ATPPC_SERVICE_INTR) & 483 1.1 jdolecek ~ATPPC_ENABLE_DMA); 484 1.1 jdolecek atppc_barrier_w(atppc); 485 1.1 jdolecek 486 1.1 jdolecek /* read PWord size - transfers in FIFO mode must be PWord aligned */ 487 1.1 jdolecek atppc->sc_pword = (atppc_r_cnfgA(atppc) & ATPPC_PWORD_MASK); 488 1.1 jdolecek atppc_barrier_r(atppc); 489 1.1 jdolecek 490 1.1 jdolecek /* XXX 16 and 32 bits implementations not supported */ 491 1.9 drochner if (atppc->sc_pword != ATPPC_PWORD_8) { 492 1.9 drochner ATPPC_DPRINTF(("%s(%s): FIFO PWord(%d) not supported.\n", 493 1.25 cegger __func__, device_xname(dev), atppc->sc_pword)); 494 1.1 jdolecek goto error; 495 1.1 jdolecek } 496 1.1 jdolecek 497 1.1 jdolecek /* Byte mode, reverse direction, no interrupt, no DMA */ 498 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2 | ATPPC_SERVICE_INTR); 499 1.1 jdolecek atppc_w_ctr(atppc, (ctr_sav & ~IRQENABLE) | PCD); 500 1.1 jdolecek /* enter ECP test mode, no interrupt, no DMA */ 501 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_TST | ATPPC_SERVICE_INTR); 502 1.1 jdolecek atppc_barrier_w(atppc); 503 1.1 jdolecek 504 1.1 jdolecek /* flush the FIFO */ 505 1.1 jdolecek for (i = 0; i < 1024; i++) { 506 1.1 jdolecek atppc_r_fifo(atppc); 507 1.1 jdolecek atppc_barrier_r(atppc); 508 1.1 jdolecek cc = atppc_r_ecr(atppc); 509 1.1 jdolecek atppc_barrier_r(atppc); 510 1.9 drochner if (cc & ATPPC_FIFO_EMPTY) 511 1.1 jdolecek break; 512 1.1 jdolecek } 513 1.1 jdolecek if (i >= 1024) { 514 1.9 drochner ATPPC_DPRINTF(("%s(%s): cannot flush FIFO.\n", __func__, 515 1.25 cegger device_xname(dev))); 516 1.1 jdolecek goto error; 517 1.1 jdolecek } 518 1.1 jdolecek 519 1.1 jdolecek /* Test mode, enable interrupts, no DMA */ 520 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_TST); 521 1.1 jdolecek atppc_barrier_w(atppc); 522 1.1 jdolecek 523 1.1 jdolecek /* Determine readIntrThreshold - fill FIFO until serviceIntr is set */ 524 1.1 jdolecek for (i = atppc->sc_rthr = atppc->sc_fifo = 0; i < 1024; i++) { 525 1.1 jdolecek atppc_w_fifo(atppc, (char)i); 526 1.1 jdolecek atppc_barrier_w(atppc); 527 1.9 drochner cc = atppc_r_ecr(atppc); 528 1.1 jdolecek atppc_barrier_r(atppc); 529 1.1 jdolecek if ((atppc->sc_rthr == 0) && (cc & ATPPC_SERVICE_INTR)) { 530 1.1 jdolecek /* readThreshold reached */ 531 1.1 jdolecek atppc->sc_rthr = i + 1; 532 1.1 jdolecek } 533 1.1 jdolecek if (cc & ATPPC_FIFO_FULL) { 534 1.1 jdolecek atppc->sc_fifo = i + 1; 535 1.1 jdolecek break; 536 1.1 jdolecek } 537 1.1 jdolecek } 538 1.1 jdolecek if (i >= 1024) { 539 1.9 drochner ATPPC_DPRINTF(("%s(%s): cannot fill FIFO.\n", __func__, 540 1.25 cegger device_xname(dev))); 541 1.1 jdolecek goto error; 542 1.1 jdolecek } 543 1.1 jdolecek 544 1.1 jdolecek /* Change direction */ 545 1.1 jdolecek atppc_w_ctr(atppc, (ctr_sav & ~IRQENABLE) & ~PCD); 546 1.1 jdolecek atppc_barrier_w(atppc); 547 1.9 drochner 548 1.5 jdolecek /* Clear the serviceIntr bit we've already set in the above loop */ 549 1.5 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_TST); 550 1.5 jdolecek atppc_barrier_w(atppc); 551 1.1 jdolecek 552 1.1 jdolecek /* Determine writeIntrThreshold - empty FIFO until serviceIntr is set */ 553 1.9 drochner for (atppc->sc_wthr = 0; i > -1; i--) { 554 1.9 drochner cc = atppc_r_fifo(atppc); 555 1.1 jdolecek atppc_barrier_r(atppc); 556 1.9 drochner if (cc != (char)(atppc->sc_fifo - i - 1)) { 557 1.9 drochner ATPPC_DPRINTF(("%s(%s): invalid data in FIFO.\n", 558 1.25 cegger __func__, device_xname(dev))); 559 1.1 jdolecek goto error; 560 1.1 jdolecek } 561 1.15 drochner 562 1.9 drochner cc = atppc_r_ecr(atppc); 563 1.1 jdolecek atppc_barrier_r(atppc); 564 1.9 drochner if ((atppc->sc_wthr == 0) && (cc & ATPPC_SERVICE_INTR)) { 565 1.1 jdolecek /* writeIntrThreshold reached */ 566 1.1 jdolecek atppc->sc_wthr = atppc->sc_fifo - i; 567 1.1 jdolecek } 568 1.15 drochner 569 1.1 jdolecek if (i > 0 && (cc & ATPPC_FIFO_EMPTY)) { 570 1.1 jdolecek /* If FIFO empty before the last byte, error */ 571 1.1 jdolecek ATPPC_DPRINTF(("%s(%s): data lost in FIFO.\n", __func__, 572 1.25 cegger device_xname(dev))); 573 1.1 jdolecek goto error; 574 1.1 jdolecek } 575 1.1 jdolecek } 576 1.1 jdolecek 577 1.1 jdolecek /* FIFO must be empty after the last byte */ 578 1.9 drochner cc = atppc_r_ecr(atppc); 579 1.1 jdolecek atppc_barrier_r(atppc); 580 1.1 jdolecek if (!(cc & ATPPC_FIFO_EMPTY)) { 581 1.9 drochner ATPPC_DPRINTF(("%s(%s): cannot empty the FIFO.\n", __func__, 582 1.25 cegger device_xname(dev))); 583 1.1 jdolecek goto error; 584 1.1 jdolecek } 585 1.1 jdolecek 586 1.1 jdolecek /* Restore original registers */ 587 1.1 jdolecek atppc_w_ctr(atppc, ctr_sav); 588 1.1 jdolecek atppc_w_str(atppc, str_sav); 589 1.1 jdolecek atppc_w_ecr(atppc, ecr_sav); 590 1.1 jdolecek atppc_barrier_w(atppc); 591 1.1 jdolecek 592 1.1 jdolecek /* Update capabilities */ 593 1.1 jdolecek atppc->sc_has |= ATPPC_HAS_FIFO; 594 1.1 jdolecek 595 1.1 jdolecek return 0; 596 1.1 jdolecek 597 1.1 jdolecek error: 598 1.1 jdolecek /* Restore original registers */ 599 1.1 jdolecek atppc_w_ctr(atppc, ctr_sav); 600 1.1 jdolecek atppc_w_str(atppc, str_sav); 601 1.1 jdolecek atppc_w_ecr(atppc, ecr_sav); 602 1.1 jdolecek atppc_barrier_w(atppc); 603 1.1 jdolecek 604 1.1 jdolecek return (EINVAL); 605 1.1 jdolecek } 606 1.1 jdolecek 607 1.1 jdolecek /* Interrupt handler for atppc device: wakes up read/write functions */ 608 1.9 drochner int 609 1.9 drochner atppcintr(void *arg) 610 1.1 jdolecek { 611 1.27 cegger device_t dev = arg; 612 1.27 cegger struct atppc_softc *atppc = device_private(dev); 613 1.12 jdolecek int claim = 1; 614 1.1 jdolecek enum { NONE, READER, WRITER } wake_up = NONE; 615 1.1 jdolecek 616 1.29 jakllsch mutex_enter(&atppc->sc_lock); 617 1.29 jakllsch 618 1.1 jdolecek /* Record registers' status */ 619 1.1 jdolecek atppc->sc_str_intr = atppc_r_str(atppc); 620 1.1 jdolecek atppc->sc_ctr_intr = atppc_r_ctr(atppc); 621 1.1 jdolecek atppc->sc_ecr_intr = atppc_r_ecr(atppc); 622 1.1 jdolecek atppc_barrier_r(atppc); 623 1.1 jdolecek 624 1.9 drochner /* Determine cause of interrupt and wake up top half */ 625 1.9 drochner switch (atppc->sc_mode) { 626 1.1 jdolecek case ATPPC_MODE_STD: 627 1.1 jdolecek /* nAck pulsed for 5 usec, too fast to check reliably, assume */ 628 1.1 jdolecek atppc->sc_irqstat = ATPPC_IRQ_nACK; 629 1.9 drochner if (atppc->sc_outb) 630 1.1 jdolecek wake_up = WRITER; 631 1.1 jdolecek else 632 1.12 jdolecek claim = 0; 633 1.1 jdolecek break; 634 1.15 drochner 635 1.1 jdolecek case ATPPC_MODE_NIBBLE: 636 1.1 jdolecek case ATPPC_MODE_PS2: 637 1.1 jdolecek /* nAck is set low by device and then high on ack */ 638 1.9 drochner if (!(atppc->sc_str_intr & nACK)) { 639 1.12 jdolecek claim = 0; 640 1.1 jdolecek break; 641 1.1 jdolecek } 642 1.1 jdolecek atppc->sc_irqstat = ATPPC_IRQ_nACK; 643 1.9 drochner if (atppc->sc_inb) 644 1.1 jdolecek wake_up = READER; 645 1.1 jdolecek break; 646 1.1 jdolecek 647 1.1 jdolecek case ATPPC_MODE_ECP: 648 1.1 jdolecek case ATPPC_MODE_FAST: 649 1.1 jdolecek /* Confirm interrupt cause: these are not pulsed as in nAck. */ 650 1.9 drochner if (atppc->sc_ecr_intr & ATPPC_SERVICE_INTR) { 651 1.9 drochner if (atppc->sc_ecr_intr & ATPPC_ENABLE_DMA) 652 1.1 jdolecek atppc->sc_irqstat |= ATPPC_IRQ_DMA; 653 1.9 drochner else 654 1.9 drochner atppc->sc_irqstat |= ATPPC_IRQ_FIFO; 655 1.15 drochner 656 1.1 jdolecek /* Decide where top half will be waiting */ 657 1.9 drochner if (atppc->sc_mode & ATPPC_MODE_ECP) { 658 1.9 drochner if (atppc->sc_ctr_intr & PCD) { 659 1.9 drochner if (atppc->sc_inb) 660 1.1 jdolecek wake_up = READER; 661 1.1 jdolecek else 662 1.12 jdolecek claim = 0; 663 1.9 drochner } else { 664 1.9 drochner if (atppc->sc_outb) 665 1.1 jdolecek wake_up = WRITER; 666 1.1 jdolecek else 667 1.12 jdolecek claim = 0; 668 1.1 jdolecek } 669 1.9 drochner } else { 670 1.9 drochner if (atppc->sc_outb) 671 1.1 jdolecek wake_up = WRITER; 672 1.1 jdolecek else 673 1.12 jdolecek claim = 0; 674 1.1 jdolecek } 675 1.1 jdolecek } 676 1.14 wiz /* Determine if nFault has occurred */ 677 1.9 drochner if ((atppc->sc_mode & ATPPC_MODE_ECP) && 678 1.9 drochner (atppc->sc_ecr_intr & ATPPC_nFAULT_INTR) && 679 1.1 jdolecek !(atppc->sc_str_intr & nFAULT)) { 680 1.1 jdolecek 681 1.1 jdolecek /* Device is requesting the channel */ 682 1.1 jdolecek atppc->sc_irqstat |= ATPPC_IRQ_nFAULT; 683 1.12 jdolecek claim = 1; 684 1.1 jdolecek } 685 1.1 jdolecek break; 686 1.1 jdolecek 687 1.1 jdolecek case ATPPC_MODE_EPP: 688 1.1 jdolecek /* nAck pulsed for 5 usec, too fast to check reliably */ 689 1.1 jdolecek atppc->sc_irqstat = ATPPC_IRQ_nACK; 690 1.9 drochner if (atppc->sc_inb) 691 1.1 jdolecek wake_up = WRITER; 692 1.9 drochner else if (atppc->sc_outb) 693 1.1 jdolecek wake_up = READER; 694 1.9 drochner else 695 1.12 jdolecek claim = 0; 696 1.1 jdolecek break; 697 1.1 jdolecek 698 1.1 jdolecek default: 699 1.25 cegger panic("%s: chipset is in invalid mode.", device_xname(dev)); 700 1.1 jdolecek } 701 1.1 jdolecek 702 1.12 jdolecek if (claim) { 703 1.12 jdolecek switch (wake_up) { 704 1.12 jdolecek case NONE: 705 1.12 jdolecek break; 706 1.1 jdolecek 707 1.12 jdolecek case READER: 708 1.29 jakllsch cv_broadcast(&atppc->sc_in_cv); 709 1.12 jdolecek break; 710 1.1 jdolecek 711 1.12 jdolecek case WRITER: 712 1.29 jakllsch cv_broadcast(&atppc->sc_out_cv); 713 1.12 jdolecek break; 714 1.12 jdolecek } 715 1.12 jdolecek } 716 1.1 jdolecek 717 1.1 jdolecek /* Call all of the installed handlers */ 718 1.12 jdolecek if (claim) { 719 1.1 jdolecek struct atppc_handler_node * callback; 720 1.9 drochner SLIST_FOREACH(callback, &(atppc->sc_handler_listhead), 721 1.1 jdolecek entries) { 722 1.1 jdolecek (*callback->func)(callback->arg); 723 1.1 jdolecek } 724 1.1 jdolecek } 725 1.12 jdolecek 726 1.29 jakllsch mutex_exit(&atppc->sc_lock); 727 1.29 jakllsch 728 1.12 jdolecek return claim; 729 1.1 jdolecek } 730 1.1 jdolecek 731 1.1 jdolecek 732 1.1 jdolecek /* Functions which support ppbus interface */ 733 1.1 jdolecek 734 1.1 jdolecek 735 1.1 jdolecek /* Check EPP mode timeout */ 736 1.1 jdolecek static int 737 1.26 cegger atppc_check_epp_timeout(device_t dev) 738 1.1 jdolecek { 739 1.26 cegger struct atppc_softc *atppc = device_private(dev); 740 1.1 jdolecek int error; 741 1.1 jdolecek 742 1.29 jakllsch mutex_enter(&atppc->sc_lock); 743 1.1 jdolecek 744 1.1 jdolecek atppc_reset_epp_timeout(dev); 745 1.1 jdolecek error = !(atppc_r_str(atppc) & TIMEOUT); 746 1.1 jdolecek atppc_barrier_r(atppc); 747 1.1 jdolecek 748 1.29 jakllsch mutex_exit(&atppc->sc_lock); 749 1.1 jdolecek 750 1.1 jdolecek return (error); 751 1.1 jdolecek } 752 1.1 jdolecek 753 1.1 jdolecek /* 754 1.1 jdolecek * EPP timeout, according to the PC87332 manual 755 1.1 jdolecek * Semantics of clearing EPP timeout bit. 756 1.1 jdolecek * PC87332 - reading SPP_STR does it... 757 1.1 jdolecek * SMC - write 1 to EPP timeout bit XXX 758 1.1 jdolecek * Others - (?) write 0 to EPP timeout bit 759 1.1 jdolecek */ 760 1.1 jdolecek static void 761 1.26 cegger atppc_reset_epp_timeout(device_t dev) 762 1.1 jdolecek { 763 1.26 cegger struct atppc_softc *atppc = device_private(dev); 764 1.1 jdolecek register unsigned char r; 765 1.1 jdolecek 766 1.1 jdolecek r = atppc_r_str(atppc); 767 1.1 jdolecek atppc_barrier_r(atppc); 768 1.1 jdolecek atppc_w_str(atppc, r | 0x1); 769 1.1 jdolecek atppc_barrier_w(atppc); 770 1.1 jdolecek atppc_w_str(atppc, r & 0xfe); 771 1.1 jdolecek atppc_barrier_w(atppc); 772 1.1 jdolecek 773 1.1 jdolecek return; 774 1.1 jdolecek } 775 1.1 jdolecek 776 1.1 jdolecek 777 1.1 jdolecek /* Read from atppc device: returns 0 on success. */ 778 1.1 jdolecek static int 779 1.26 cegger atppc_read(device_t dev, char *buf, int len, int ioflag, 780 1.9 drochner size_t *cnt) 781 1.1 jdolecek { 782 1.26 cegger struct atppc_softc *atppc = device_private(dev); 783 1.1 jdolecek int error = 0; 784 1.1 jdolecek 785 1.29 jakllsch mutex_enter(&atppc->sc_lock); 786 1.1 jdolecek 787 1.1 jdolecek *cnt = 0; 788 1.1 jdolecek 789 1.1 jdolecek /* Initialize buffer */ 790 1.1 jdolecek atppc->sc_inb = atppc->sc_inbstart = buf; 791 1.1 jdolecek atppc->sc_inb_nbytes = len; 792 1.1 jdolecek 793 1.1 jdolecek /* Initialize device input error state for new operation */ 794 1.1 jdolecek atppc->sc_inerr = 0; 795 1.1 jdolecek 796 1.1 jdolecek /* Call appropriate function to read bytes */ 797 1.1 jdolecek switch(atppc->sc_mode) { 798 1.1 jdolecek case ATPPC_MODE_STD: 799 1.1 jdolecek case ATPPC_MODE_FAST: 800 1.1 jdolecek error = ENODEV; 801 1.1 jdolecek break; 802 1.15 drochner 803 1.1 jdolecek case ATPPC_MODE_NIBBLE: 804 1.1 jdolecek atppc_nibble_read(atppc); 805 1.1 jdolecek break; 806 1.1 jdolecek 807 1.1 jdolecek case ATPPC_MODE_PS2: 808 1.1 jdolecek atppc_byte_read(atppc); 809 1.1 jdolecek break; 810 1.1 jdolecek 811 1.1 jdolecek case ATPPC_MODE_ECP: 812 1.1 jdolecek atppc_ecp_read(atppc); 813 1.1 jdolecek break; 814 1.1 jdolecek 815 1.1 jdolecek case ATPPC_MODE_EPP: 816 1.1 jdolecek atppc_epp_read(atppc); 817 1.1 jdolecek break; 818 1.1 jdolecek 819 1.1 jdolecek default: 820 1.9 drochner panic("%s(%s): chipset in invalid mode.\n", __func__, 821 1.25 cegger device_xname(dev)); 822 1.1 jdolecek } 823 1.1 jdolecek 824 1.1 jdolecek /* Update counter*/ 825 1.1 jdolecek *cnt = (atppc->sc_inbstart - atppc->sc_inb); 826 1.1 jdolecek 827 1.1 jdolecek /* Reset buffer */ 828 1.1 jdolecek atppc->sc_inb = atppc->sc_inbstart = NULL; 829 1.1 jdolecek atppc->sc_inb_nbytes = 0; 830 1.1 jdolecek 831 1.9 drochner if (!(error)) 832 1.1 jdolecek error = atppc->sc_inerr; 833 1.1 jdolecek 834 1.29 jakllsch mutex_exit(&atppc->sc_lock); 835 1.1 jdolecek 836 1.1 jdolecek return (error); 837 1.1 jdolecek } 838 1.1 jdolecek 839 1.1 jdolecek /* Write to atppc device: returns 0 on success. */ 840 1.1 jdolecek static int 841 1.26 cegger atppc_write(device_t dev, char *buf, int len, int ioflag, size_t *cnt) 842 1.1 jdolecek { 843 1.26 cegger struct atppc_softc * const atppc = device_private(dev); 844 1.1 jdolecek int error = 0; 845 1.1 jdolecek 846 1.1 jdolecek *cnt = 0; 847 1.15 drochner 848 1.29 jakllsch mutex_enter(&atppc->sc_lock); 849 1.1 jdolecek 850 1.1 jdolecek /* Set up line buffer */ 851 1.1 jdolecek atppc->sc_outb = atppc->sc_outbstart = buf; 852 1.1 jdolecek atppc->sc_outb_nbytes = len; 853 1.1 jdolecek 854 1.1 jdolecek /* Initialize device output error state for new operation */ 855 1.1 jdolecek atppc->sc_outerr = 0; 856 1.1 jdolecek 857 1.1 jdolecek /* Call appropriate function to write bytes */ 858 1.9 drochner switch (atppc->sc_mode) { 859 1.1 jdolecek case ATPPC_MODE_STD: 860 1.1 jdolecek atppc_std_write(atppc); 861 1.1 jdolecek break; 862 1.1 jdolecek 863 1.1 jdolecek case ATPPC_MODE_NIBBLE: 864 1.1 jdolecek case ATPPC_MODE_PS2: 865 1.1 jdolecek error = ENODEV; 866 1.1 jdolecek break; 867 1.1 jdolecek 868 1.1 jdolecek case ATPPC_MODE_FAST: 869 1.1 jdolecek case ATPPC_MODE_ECP: 870 1.1 jdolecek atppc_fifo_write(atppc); 871 1.1 jdolecek break; 872 1.1 jdolecek 873 1.1 jdolecek case ATPPC_MODE_EPP: 874 1.1 jdolecek atppc_epp_write(atppc); 875 1.1 jdolecek break; 876 1.1 jdolecek 877 1.1 jdolecek default: 878 1.9 drochner panic("%s(%s): chipset in invalid mode.\n", __func__, 879 1.25 cegger device_xname(dev)); 880 1.1 jdolecek } 881 1.1 jdolecek 882 1.1 jdolecek /* Update counter*/ 883 1.1 jdolecek *cnt = (atppc->sc_outbstart - atppc->sc_outb); 884 1.1 jdolecek 885 1.1 jdolecek /* Reset output buffer */ 886 1.1 jdolecek atppc->sc_outb = atppc->sc_outbstart = NULL; 887 1.1 jdolecek atppc->sc_outb_nbytes = 0; 888 1.1 jdolecek 889 1.9 drochner if (!(error)) 890 1.1 jdolecek error = atppc->sc_outerr; 891 1.1 jdolecek 892 1.29 jakllsch mutex_exit(&atppc->sc_lock); 893 1.1 jdolecek 894 1.1 jdolecek return (error); 895 1.1 jdolecek } 896 1.1 jdolecek 897 1.9 drochner /* 898 1.9 drochner * Set mode of chipset to mode argument. Modes not supported are ignored. If 899 1.9 drochner * multiple modes are flagged, the mode is not changed. Mode's are those 900 1.9 drochner * defined for ppbus_softc.sc_mode in ppbus_conf.h. Only ECP-capable chipsets 901 1.9 drochner * can change their mode of operation. However, ALL operation modes support 902 1.9 drochner * centronics mode and nibble mode. Modes determine both hardware AND software 903 1.1 jdolecek * behaviour. 904 1.9 drochner * NOTE: the mode for ECP should only be changed when the channel is in 905 1.9 drochner * forward idle mode. This function does not make sure FIFO's have flushed or 906 1.1 jdolecek * any consistency checks. 907 1.1 jdolecek */ 908 1.9 drochner static int 909 1.26 cegger atppc_setmode(device_t dev, int mode) 910 1.1 jdolecek { 911 1.26 cegger struct atppc_softc *atppc = device_private(dev); 912 1.9 drochner u_int8_t ecr; 913 1.1 jdolecek u_int8_t chipset_mode; 914 1.1 jdolecek int rval = 0; 915 1.1 jdolecek 916 1.29 jakllsch mutex_enter(&atppc->sc_lock); 917 1.1 jdolecek 918 1.1 jdolecek /* If ECP capable, configure ecr register */ 919 1.1 jdolecek if (atppc->sc_has & ATPPC_HAS_ECP) { 920 1.1 jdolecek /* Read ECR with mode masked out */ 921 1.11 jdolecek ecr = (atppc_r_ecr(atppc) & 0x1f); 922 1.1 jdolecek atppc_barrier_r(atppc); 923 1.1 jdolecek 924 1.9 drochner switch (mode) { 925 1.1 jdolecek case PPBUS_ECP: 926 1.1 jdolecek /* Set ECP mode */ 927 1.1 jdolecek ecr |= ATPPC_ECR_ECP; 928 1.1 jdolecek chipset_mode = ATPPC_MODE_ECP; 929 1.1 jdolecek break; 930 1.1 jdolecek 931 1.1 jdolecek case PPBUS_EPP: 932 1.1 jdolecek /* Set EPP mode */ 933 1.9 drochner if (atppc->sc_has & ATPPC_HAS_EPP) { 934 1.1 jdolecek ecr |= ATPPC_ECR_EPP; 935 1.1 jdolecek chipset_mode = ATPPC_MODE_EPP; 936 1.9 drochner } else { 937 1.1 jdolecek rval = ENODEV; 938 1.1 jdolecek goto end; 939 1.1 jdolecek } 940 1.1 jdolecek break; 941 1.1 jdolecek 942 1.1 jdolecek case PPBUS_FAST: 943 1.1 jdolecek /* Set fast centronics mode */ 944 1.1 jdolecek ecr |= ATPPC_ECR_FIFO; 945 1.1 jdolecek chipset_mode = ATPPC_MODE_FAST; 946 1.1 jdolecek break; 947 1.1 jdolecek 948 1.1 jdolecek case PPBUS_PS2: 949 1.1 jdolecek /* Set PS2 mode */ 950 1.1 jdolecek ecr |= ATPPC_ECR_PS2; 951 1.1 jdolecek chipset_mode = ATPPC_MODE_PS2; 952 1.1 jdolecek break; 953 1.1 jdolecek 954 1.1 jdolecek case PPBUS_COMPATIBLE: 955 1.1 jdolecek /* Set standard mode */ 956 1.1 jdolecek ecr |= ATPPC_ECR_STD; 957 1.15 drochner chipset_mode = ATPPC_MODE_STD; 958 1.1 jdolecek break; 959 1.1 jdolecek 960 1.1 jdolecek case PPBUS_NIBBLE: 961 1.1 jdolecek /* Set nibble mode: uses chipset standard mode */ 962 1.1 jdolecek ecr |= ATPPC_ECR_STD; 963 1.1 jdolecek chipset_mode = ATPPC_MODE_NIBBLE; 964 1.1 jdolecek break; 965 1.1 jdolecek 966 1.1 jdolecek default: 967 1.1 jdolecek /* Invalid mode specified for ECP chip */ 968 1.1 jdolecek ATPPC_DPRINTF(("%s(%s): invalid mode passed as " 969 1.25 cegger "argument.\n", __func__, device_xname(dev))); 970 1.1 jdolecek rval = ENODEV; 971 1.1 jdolecek goto end; 972 1.1 jdolecek } 973 1.1 jdolecek 974 1.1 jdolecek /* Switch to byte mode to be able to change modes. */ 975 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 976 1.1 jdolecek atppc_barrier_w(atppc); 977 1.1 jdolecek 978 1.1 jdolecek /* Update mode */ 979 1.1 jdolecek atppc_w_ecr(atppc, ecr); 980 1.1 jdolecek atppc_barrier_w(atppc); 981 1.9 drochner } else { 982 1.9 drochner switch (mode) { 983 1.1 jdolecek case PPBUS_EPP: 984 1.9 drochner if (atppc->sc_has & ATPPC_HAS_EPP) { 985 1.1 jdolecek chipset_mode = ATPPC_MODE_EPP; 986 1.9 drochner } else { 987 1.1 jdolecek rval = ENODEV; 988 1.1 jdolecek goto end; 989 1.1 jdolecek } 990 1.1 jdolecek break; 991 1.1 jdolecek 992 1.1 jdolecek case PPBUS_PS2: 993 1.9 drochner if (atppc->sc_has & ATPPC_HAS_PS2) { 994 1.1 jdolecek chipset_mode = ATPPC_MODE_PS2; 995 1.9 drochner } else { 996 1.1 jdolecek rval = ENODEV; 997 1.1 jdolecek goto end; 998 1.1 jdolecek } 999 1.1 jdolecek break; 1000 1.1 jdolecek 1001 1.1 jdolecek case PPBUS_NIBBLE: 1002 1.1 jdolecek /* Set nibble mode (virtual) */ 1003 1.1 jdolecek chipset_mode = ATPPC_MODE_NIBBLE; 1004 1.1 jdolecek break; 1005 1.1 jdolecek 1006 1.1 jdolecek case PPBUS_COMPATIBLE: 1007 1.1 jdolecek chipset_mode = ATPPC_MODE_STD; 1008 1.1 jdolecek break; 1009 1.1 jdolecek 1010 1.1 jdolecek case PPBUS_ECP: 1011 1.1 jdolecek rval = ENODEV; 1012 1.1 jdolecek goto end; 1013 1.1 jdolecek 1014 1.1 jdolecek default: 1015 1.1 jdolecek ATPPC_DPRINTF(("%s(%s): invalid mode passed as " 1016 1.25 cegger "argument.\n", __func__, device_xname(dev))); 1017 1.1 jdolecek rval = ENODEV; 1018 1.1 jdolecek goto end; 1019 1.1 jdolecek } 1020 1.1 jdolecek } 1021 1.1 jdolecek 1022 1.1 jdolecek atppc->sc_mode = chipset_mode; 1023 1.9 drochner if (chipset_mode == ATPPC_MODE_PS2) { 1024 1.1 jdolecek /* Set direction bit to reverse */ 1025 1.1 jdolecek ecr = atppc_r_ctr(atppc); 1026 1.1 jdolecek atppc_barrier_r(atppc); 1027 1.1 jdolecek ecr |= PCD; 1028 1.1 jdolecek atppc_w_ctr(atppc, ecr); 1029 1.1 jdolecek atppc_barrier_w(atppc); 1030 1.1 jdolecek } 1031 1.1 jdolecek 1032 1.1 jdolecek end: 1033 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1034 1.1 jdolecek 1035 1.1 jdolecek return rval; 1036 1.1 jdolecek } 1037 1.1 jdolecek 1038 1.1 jdolecek /* Get the current mode of chipset */ 1039 1.1 jdolecek static int 1040 1.26 cegger atppc_getmode(device_t dev) 1041 1.1 jdolecek { 1042 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1043 1.1 jdolecek int mode; 1044 1.1 jdolecek 1045 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1046 1.1 jdolecek 1047 1.1 jdolecek /* The chipset can only be in one mode at a time logically */ 1048 1.9 drochner switch (atppc->sc_mode) { 1049 1.1 jdolecek case ATPPC_MODE_ECP: 1050 1.1 jdolecek mode = PPBUS_ECP; 1051 1.1 jdolecek break; 1052 1.1 jdolecek 1053 1.1 jdolecek case ATPPC_MODE_EPP: 1054 1.1 jdolecek mode = PPBUS_EPP; 1055 1.1 jdolecek break; 1056 1.1 jdolecek 1057 1.1 jdolecek case ATPPC_MODE_PS2: 1058 1.1 jdolecek mode = PPBUS_PS2; 1059 1.1 jdolecek break; 1060 1.1 jdolecek 1061 1.1 jdolecek case ATPPC_MODE_STD: 1062 1.1 jdolecek mode = PPBUS_COMPATIBLE; 1063 1.1 jdolecek break; 1064 1.1 jdolecek 1065 1.1 jdolecek case ATPPC_MODE_NIBBLE: 1066 1.1 jdolecek mode = PPBUS_NIBBLE; 1067 1.1 jdolecek break; 1068 1.1 jdolecek 1069 1.1 jdolecek case ATPPC_MODE_FAST: 1070 1.1 jdolecek mode = PPBUS_FAST; 1071 1.1 jdolecek break; 1072 1.1 jdolecek 1073 1.1 jdolecek default: 1074 1.9 drochner panic("%s(%s): device is in invalid mode!", __func__, 1075 1.25 cegger device_xname(dev)); 1076 1.1 jdolecek break; 1077 1.1 jdolecek } 1078 1.1 jdolecek 1079 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1080 1.1 jdolecek 1081 1.1 jdolecek return mode; 1082 1.1 jdolecek } 1083 1.1 jdolecek 1084 1.1 jdolecek 1085 1.9 drochner /* Wait for FIFO buffer to empty for ECP-capable chipset */ 1086 1.1 jdolecek static void 1087 1.26 cegger atppc_ecp_sync(device_t dev) 1088 1.1 jdolecek { 1089 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1090 1.1 jdolecek int i; 1091 1.1 jdolecek u_int8_t r; 1092 1.1 jdolecek 1093 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1094 1.1 jdolecek 1095 1.9 drochner /* 1096 1.9 drochner * Only wait for FIFO to empty if mode is chipset is ECP-capable AND 1097 1.1 jdolecek * the mode is either ECP or Fast Centronics. 1098 1.1 jdolecek */ 1099 1.1 jdolecek r = atppc_r_ecr(atppc); 1100 1.1 jdolecek atppc_barrier_r(atppc); 1101 1.1 jdolecek r &= 0xe0; 1102 1.9 drochner if (!(atppc->sc_has & ATPPC_HAS_ECP) || ((r != ATPPC_ECR_ECP) 1103 1.1 jdolecek && (r != ATPPC_ECR_FIFO))) { 1104 1.1 jdolecek goto end; 1105 1.1 jdolecek } 1106 1.1 jdolecek 1107 1.1 jdolecek /* Wait for FIFO to empty */ 1108 1.1 jdolecek for (i = 0; i < ((MAXBUSYWAIT/hz) * 1000000); i += 100) { 1109 1.1 jdolecek r = atppc_r_ecr(atppc); 1110 1.1 jdolecek atppc_barrier_r(atppc); 1111 1.1 jdolecek if (r & ATPPC_FIFO_EMPTY) { 1112 1.1 jdolecek goto end; 1113 1.1 jdolecek } 1114 1.1 jdolecek delay(100); /* Supposed to be a 100 usec delay */ 1115 1.1 jdolecek } 1116 1.1 jdolecek 1117 1.9 drochner ATPPC_DPRINTF(("%s: ECP sync failed, data still in FIFO.\n", 1118 1.25 cegger device_xname(dev))); 1119 1.1 jdolecek 1120 1.1 jdolecek end: 1121 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1122 1.15 drochner 1123 1.1 jdolecek return; 1124 1.1 jdolecek } 1125 1.1 jdolecek 1126 1.1 jdolecek /* Execute a microsequence to handle fast I/O operations. */ 1127 1.1 jdolecek static int 1128 1.26 cegger atppc_exec_microseq(device_t dev, struct ppbus_microseq **p_msq) 1129 1.1 jdolecek { 1130 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1131 1.9 drochner struct ppbus_microseq *mi = *p_msq; 1132 1.9 drochner char cc, *p; 1133 1.1 jdolecek int i, iter, len; 1134 1.1 jdolecek int error; 1135 1.1 jdolecek register int reg; 1136 1.1 jdolecek register unsigned char mask; 1137 1.1 jdolecek register int accum = 0; 1138 1.9 drochner register char *ptr = NULL; 1139 1.9 drochner struct ppbus_microseq *stack = NULL; 1140 1.1 jdolecek 1141 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1142 1.1 jdolecek 1143 1.1 jdolecek /* microsequence registers are equivalent to PC-like port registers */ 1144 1.1 jdolecek 1145 1.1 jdolecek #define r_reg(register,atppc) bus_space_read_1((atppc)->sc_iot, \ 1146 1.1 jdolecek (atppc)->sc_ioh, (register)) 1147 1.1 jdolecek #define w_reg(register, atppc, byte) bus_space_write_1((atppc)->sc_iot, \ 1148 1.1 jdolecek (atppc)->sc_ioh, (register), (byte)) 1149 1.1 jdolecek 1150 1.1 jdolecek /* Loop until microsequence execution finishes (ending op code) */ 1151 1.1 jdolecek for (;;) { 1152 1.9 drochner switch (mi->opcode) { 1153 1.1 jdolecek case MS_OP_RSET: 1154 1.1 jdolecek cc = r_reg(mi->arg[0].i, atppc); 1155 1.1 jdolecek atppc_barrier_r(atppc); 1156 1.1 jdolecek cc &= (char)mi->arg[2].i; /* clear mask */ 1157 1.1 jdolecek cc |= (char)mi->arg[1].i; /* assert mask */ 1158 1.1 jdolecek w_reg(mi->arg[0].i, atppc, cc); 1159 1.1 jdolecek atppc_barrier_w(atppc); 1160 1.1 jdolecek mi++; 1161 1.1 jdolecek break; 1162 1.1 jdolecek 1163 1.1 jdolecek case MS_OP_RASSERT_P: 1164 1.1 jdolecek reg = mi->arg[1].i; 1165 1.1 jdolecek ptr = atppc->sc_ptr; 1166 1.1 jdolecek 1167 1.9 drochner if ((len = mi->arg[0].i) == MS_ACCUM) { 1168 1.1 jdolecek accum = atppc->sc_accum; 1169 1.1 jdolecek for (; accum; accum--) { 1170 1.1 jdolecek w_reg(reg, atppc, *ptr++); 1171 1.1 jdolecek atppc_barrier_w(atppc); 1172 1.1 jdolecek } 1173 1.1 jdolecek atppc->sc_accum = accum; 1174 1.9 drochner } else { 1175 1.9 drochner for (i = 0; i < len; i++) { 1176 1.1 jdolecek w_reg(reg, atppc, *ptr++); 1177 1.1 jdolecek atppc_barrier_w(atppc); 1178 1.1 jdolecek } 1179 1.1 jdolecek } 1180 1.1 jdolecek 1181 1.1 jdolecek atppc->sc_ptr = ptr; 1182 1.1 jdolecek mi++; 1183 1.1 jdolecek break; 1184 1.1 jdolecek 1185 1.1 jdolecek case MS_OP_RFETCH_P: 1186 1.1 jdolecek reg = mi->arg[1].i; 1187 1.1 jdolecek mask = (char)mi->arg[2].i; 1188 1.1 jdolecek ptr = atppc->sc_ptr; 1189 1.1 jdolecek 1190 1.9 drochner if ((len = mi->arg[0].i) == MS_ACCUM) { 1191 1.1 jdolecek accum = atppc->sc_accum; 1192 1.1 jdolecek for (; accum; accum--) { 1193 1.1 jdolecek *ptr++ = r_reg(reg, atppc) & mask; 1194 1.1 jdolecek atppc_barrier_r(atppc); 1195 1.1 jdolecek } 1196 1.1 jdolecek atppc->sc_accum = accum; 1197 1.9 drochner } else { 1198 1.9 drochner for (i = 0; i < len; i++) { 1199 1.1 jdolecek *ptr++ = r_reg(reg, atppc) & mask; 1200 1.1 jdolecek atppc_barrier_r(atppc); 1201 1.1 jdolecek } 1202 1.1 jdolecek } 1203 1.1 jdolecek 1204 1.1 jdolecek atppc->sc_ptr = ptr; 1205 1.1 jdolecek mi++; 1206 1.9 drochner break; 1207 1.1 jdolecek 1208 1.1 jdolecek case MS_OP_RFETCH: 1209 1.9 drochner *((char *)mi->arg[2].p) = r_reg(mi->arg[0].i, atppc) & 1210 1.1 jdolecek (char)mi->arg[1].i; 1211 1.1 jdolecek atppc_barrier_r(atppc); 1212 1.1 jdolecek mi++; 1213 1.9 drochner break; 1214 1.1 jdolecek 1215 1.1 jdolecek case MS_OP_RASSERT: 1216 1.1 jdolecek case MS_OP_DELAY: 1217 1.1 jdolecek /* let's suppose the next instr. is the same */ 1218 1.1 jdolecek do { 1219 1.9 drochner for (;mi->opcode == MS_OP_RASSERT; mi++) { 1220 1.9 drochner w_reg(mi->arg[0].i, atppc, 1221 1.1 jdolecek (char)mi->arg[1].i); 1222 1.1 jdolecek atppc_barrier_w(atppc); 1223 1.1 jdolecek } 1224 1.1 jdolecek 1225 1.9 drochner for (;mi->opcode == MS_OP_DELAY; mi++) { 1226 1.1 jdolecek delay(mi->arg[0].i); 1227 1.1 jdolecek } 1228 1.9 drochner } while (mi->opcode == MS_OP_RASSERT); 1229 1.1 jdolecek break; 1230 1.1 jdolecek 1231 1.1 jdolecek case MS_OP_ADELAY: 1232 1.9 drochner if (mi->arg[0].i) { 1233 1.1 jdolecek tsleep(atppc, PPBUSPRI, "atppcdelay", 1234 1.1 jdolecek mi->arg[0].i * (hz/1000)); 1235 1.1 jdolecek } 1236 1.1 jdolecek mi++; 1237 1.1 jdolecek break; 1238 1.1 jdolecek 1239 1.1 jdolecek case MS_OP_TRIG: 1240 1.1 jdolecek reg = mi->arg[0].i; 1241 1.1 jdolecek iter = mi->arg[1].i; 1242 1.1 jdolecek p = (char *)mi->arg[2].p; 1243 1.1 jdolecek 1244 1.1 jdolecek /* XXX delay limited to 255 us */ 1245 1.9 drochner for (i = 0; i < iter; i++) { 1246 1.1 jdolecek w_reg(reg, atppc, *p++); 1247 1.1 jdolecek atppc_barrier_w(atppc); 1248 1.1 jdolecek delay((unsigned char)*p++); 1249 1.1 jdolecek } 1250 1.1 jdolecek 1251 1.1 jdolecek mi++; 1252 1.1 jdolecek break; 1253 1.1 jdolecek 1254 1.1 jdolecek case MS_OP_SET: 1255 1.1 jdolecek atppc->sc_accum = mi->arg[0].i; 1256 1.1 jdolecek mi++; 1257 1.9 drochner break; 1258 1.1 jdolecek 1259 1.1 jdolecek case MS_OP_DBRA: 1260 1.9 drochner if (--atppc->sc_accum > 0) { 1261 1.1 jdolecek mi += mi->arg[0].i; 1262 1.1 jdolecek } 1263 1.15 drochner 1264 1.1 jdolecek mi++; 1265 1.9 drochner break; 1266 1.1 jdolecek 1267 1.1 jdolecek case MS_OP_BRSET: 1268 1.1 jdolecek cc = atppc_r_str(atppc); 1269 1.1 jdolecek atppc_barrier_r(atppc); 1270 1.9 drochner if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) { 1271 1.1 jdolecek mi += mi->arg[1].i; 1272 1.1 jdolecek } 1273 1.1 jdolecek mi++; 1274 1.1 jdolecek break; 1275 1.1 jdolecek 1276 1.1 jdolecek case MS_OP_BRCLEAR: 1277 1.1 jdolecek cc = atppc_r_str(atppc); 1278 1.1 jdolecek atppc_barrier_r(atppc); 1279 1.9 drochner if ((cc & (char)mi->arg[0].i) == 0) { 1280 1.9 drochner mi += mi->arg[1].i; 1281 1.1 jdolecek } 1282 1.1 jdolecek mi++; 1283 1.9 drochner break; 1284 1.1 jdolecek 1285 1.1 jdolecek case MS_OP_BRSTAT: 1286 1.1 jdolecek cc = atppc_r_str(atppc); 1287 1.1 jdolecek atppc_barrier_r(atppc); 1288 1.9 drochner if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == 1289 1.1 jdolecek (char)mi->arg[0].i) { 1290 1.1 jdolecek mi += mi->arg[2].i; 1291 1.1 jdolecek } 1292 1.1 jdolecek mi++; 1293 1.1 jdolecek break; 1294 1.1 jdolecek 1295 1.1 jdolecek case MS_OP_C_CALL: 1296 1.1 jdolecek /* 1297 1.1 jdolecek * If the C call returns !0 then end the microseq. 1298 1.1 jdolecek * The current state of ptr is passed to the C function 1299 1.1 jdolecek */ 1300 1.9 drochner if ((error = mi->arg[0].f(mi->arg[1].p, 1301 1.1 jdolecek atppc->sc_ptr))) { 1302 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1303 1.1 jdolecek return (error); 1304 1.1 jdolecek } 1305 1.1 jdolecek mi++; 1306 1.1 jdolecek break; 1307 1.1 jdolecek 1308 1.1 jdolecek case MS_OP_PTR: 1309 1.1 jdolecek atppc->sc_ptr = (char *)mi->arg[0].p; 1310 1.1 jdolecek mi++; 1311 1.1 jdolecek break; 1312 1.1 jdolecek 1313 1.1 jdolecek case MS_OP_CALL: 1314 1.1 jdolecek if (stack) { 1315 1.25 cegger panic("%s - %s: too much calls", device_xname(dev), 1316 1.1 jdolecek __func__); 1317 1.1 jdolecek } 1318 1.1 jdolecek 1319 1.1 jdolecek if (mi->arg[0].p) { 1320 1.1 jdolecek /* store state of the actual microsequence */ 1321 1.1 jdolecek stack = mi; 1322 1.1 jdolecek 1323 1.1 jdolecek /* jump to the new microsequence */ 1324 1.1 jdolecek mi = (struct ppbus_microseq *)mi->arg[0].p; 1325 1.9 drochner } else { 1326 1.1 jdolecek mi++; 1327 1.1 jdolecek } 1328 1.1 jdolecek break; 1329 1.1 jdolecek 1330 1.1 jdolecek case MS_OP_SUBRET: 1331 1.1 jdolecek /* retrieve microseq and pc state before the call */ 1332 1.1 jdolecek mi = stack; 1333 1.1 jdolecek 1334 1.1 jdolecek /* reset the stack */ 1335 1.1 jdolecek stack = 0; 1336 1.1 jdolecek 1337 1.1 jdolecek /* XXX return code */ 1338 1.1 jdolecek 1339 1.1 jdolecek mi++; 1340 1.1 jdolecek break; 1341 1.1 jdolecek 1342 1.1 jdolecek case MS_OP_PUT: 1343 1.1 jdolecek case MS_OP_GET: 1344 1.1 jdolecek case MS_OP_RET: 1345 1.9 drochner /* 1346 1.1 jdolecek * Can't return to atppc level during the execution 1347 1.1 jdolecek * of a submicrosequence. 1348 1.1 jdolecek */ 1349 1.1 jdolecek if (stack) { 1350 1.9 drochner panic("%s: cannot return to atppc level", 1351 1.1 jdolecek __func__); 1352 1.1 jdolecek } 1353 1.1 jdolecek /* update pc for atppc level of execution */ 1354 1.1 jdolecek *p_msq = mi; 1355 1.1 jdolecek 1356 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1357 1.1 jdolecek return (0); 1358 1.1 jdolecek break; 1359 1.1 jdolecek 1360 1.9 drochner default: 1361 1.1 jdolecek panic("%s: unknown microsequence " 1362 1.9 drochner "opcode 0x%x", __func__, mi->opcode); 1363 1.1 jdolecek break; 1364 1.1 jdolecek } 1365 1.1 jdolecek } 1366 1.1 jdolecek 1367 1.1 jdolecek /* Should not be reached! */ 1368 1.1 jdolecek #ifdef ATPPC_DEBUG 1369 1.1 jdolecek panic("%s: unexpected code reached!\n", __func__); 1370 1.1 jdolecek #endif 1371 1.1 jdolecek } 1372 1.1 jdolecek 1373 1.1 jdolecek /* General I/O routine */ 1374 1.1 jdolecek static u_int8_t 1375 1.26 cegger atppc_io(device_t dev, int iop, u_char *addr, int cnt, u_char byte) 1376 1.1 jdolecek { 1377 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1378 1.1 jdolecek u_int8_t val = 0; 1379 1.1 jdolecek 1380 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1381 1.15 drochner 1382 1.1 jdolecek switch (iop) { 1383 1.1 jdolecek case PPBUS_OUTSB_EPP: 1384 1.9 drochner bus_space_write_multi_1(atppc->sc_iot, atppc->sc_ioh, 1385 1.1 jdolecek ATPPC_EPP_DATA, addr, cnt); 1386 1.1 jdolecek break; 1387 1.1 jdolecek case PPBUS_OUTSW_EPP: 1388 1.9 drochner bus_space_write_multi_2(atppc->sc_iot, atppc->sc_ioh, 1389 1.1 jdolecek ATPPC_EPP_DATA, (u_int16_t *)addr, cnt); 1390 1.1 jdolecek break; 1391 1.1 jdolecek case PPBUS_OUTSL_EPP: 1392 1.9 drochner bus_space_write_multi_4(atppc->sc_iot, atppc->sc_ioh, 1393 1.1 jdolecek ATPPC_EPP_DATA, (u_int32_t *)addr, cnt); 1394 1.1 jdolecek break; 1395 1.1 jdolecek case PPBUS_INSB_EPP: 1396 1.9 drochner bus_space_read_multi_1(atppc->sc_iot, atppc->sc_ioh, 1397 1.1 jdolecek ATPPC_EPP_DATA, addr, cnt); 1398 1.1 jdolecek break; 1399 1.1 jdolecek case PPBUS_INSW_EPP: 1400 1.9 drochner bus_space_read_multi_2(atppc->sc_iot, atppc->sc_ioh, 1401 1.1 jdolecek ATPPC_EPP_DATA, (u_int16_t *)addr, cnt); 1402 1.1 jdolecek break; 1403 1.1 jdolecek case PPBUS_INSL_EPP: 1404 1.9 drochner bus_space_read_multi_4(atppc->sc_iot, atppc->sc_ioh, 1405 1.1 jdolecek ATPPC_EPP_DATA, (u_int32_t *)addr, cnt); 1406 1.1 jdolecek break; 1407 1.1 jdolecek case PPBUS_RDTR: 1408 1.1 jdolecek val = (atppc_r_dtr(atppc)); 1409 1.1 jdolecek break; 1410 1.1 jdolecek case PPBUS_RSTR: 1411 1.1 jdolecek val = (atppc_r_str(atppc)); 1412 1.1 jdolecek break; 1413 1.1 jdolecek case PPBUS_RCTR: 1414 1.1 jdolecek val = (atppc_r_ctr(atppc)); 1415 1.1 jdolecek break; 1416 1.1 jdolecek case PPBUS_REPP_A: 1417 1.1 jdolecek val = (atppc_r_eppA(atppc)); 1418 1.1 jdolecek break; 1419 1.1 jdolecek case PPBUS_REPP_D: 1420 1.1 jdolecek val = (atppc_r_eppD(atppc)); 1421 1.1 jdolecek break; 1422 1.1 jdolecek case PPBUS_RECR: 1423 1.1 jdolecek val = (atppc_r_ecr(atppc)); 1424 1.1 jdolecek break; 1425 1.1 jdolecek case PPBUS_RFIFO: 1426 1.1 jdolecek val = (atppc_r_fifo(atppc)); 1427 1.1 jdolecek break; 1428 1.1 jdolecek case PPBUS_WDTR: 1429 1.1 jdolecek atppc_w_dtr(atppc, byte); 1430 1.1 jdolecek break; 1431 1.1 jdolecek case PPBUS_WSTR: 1432 1.1 jdolecek atppc_w_str(atppc, byte); 1433 1.1 jdolecek break; 1434 1.1 jdolecek case PPBUS_WCTR: 1435 1.1 jdolecek atppc_w_ctr(atppc, byte); 1436 1.1 jdolecek break; 1437 1.1 jdolecek case PPBUS_WEPP_A: 1438 1.1 jdolecek atppc_w_eppA(atppc, byte); 1439 1.1 jdolecek break; 1440 1.1 jdolecek case PPBUS_WEPP_D: 1441 1.1 jdolecek atppc_w_eppD(atppc, byte); 1442 1.1 jdolecek break; 1443 1.1 jdolecek case PPBUS_WECR: 1444 1.1 jdolecek atppc_w_ecr(atppc, byte); 1445 1.1 jdolecek break; 1446 1.1 jdolecek case PPBUS_WFIFO: 1447 1.1 jdolecek atppc_w_fifo(atppc, byte); 1448 1.1 jdolecek break; 1449 1.1 jdolecek default: 1450 1.25 cegger panic("%s(%s): unknown I/O operation", device_xname(dev), 1451 1.1 jdolecek __func__); 1452 1.1 jdolecek break; 1453 1.1 jdolecek } 1454 1.1 jdolecek 1455 1.1 jdolecek atppc_barrier(atppc); 1456 1.1 jdolecek 1457 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1458 1.15 drochner 1459 1.1 jdolecek return val; 1460 1.1 jdolecek } 1461 1.1 jdolecek 1462 1.1 jdolecek /* Read "instance variables" of atppc device */ 1463 1.1 jdolecek static int 1464 1.26 cegger atppc_read_ivar(device_t dev, int index, unsigned int *val) 1465 1.1 jdolecek { 1466 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1467 1.1 jdolecek int rval = 0; 1468 1.1 jdolecek 1469 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1470 1.15 drochner 1471 1.1 jdolecek switch(index) { 1472 1.1 jdolecek case PPBUS_IVAR_EPP_PROTO: 1473 1.9 drochner if (atppc->sc_epp == ATPPC_EPP_1_9) 1474 1.1 jdolecek *val = PPBUS_EPP_1_9; 1475 1.9 drochner else if (atppc->sc_epp == ATPPC_EPP_1_7) 1476 1.1 jdolecek *val = PPBUS_EPP_1_7; 1477 1.11 jdolecek /* XXX what if not using EPP ? */ 1478 1.1 jdolecek break; 1479 1.1 jdolecek 1480 1.1 jdolecek case PPBUS_IVAR_INTR: 1481 1.11 jdolecek *val = ((atppc->sc_use & ATPPC_USE_INTR) != 0); 1482 1.1 jdolecek break; 1483 1.1 jdolecek 1484 1.1 jdolecek case PPBUS_IVAR_DMA: 1485 1.11 jdolecek *val = ((atppc->sc_use & ATPPC_USE_DMA) != 0); 1486 1.1 jdolecek break; 1487 1.1 jdolecek 1488 1.1 jdolecek default: 1489 1.1 jdolecek rval = ENODEV; 1490 1.1 jdolecek } 1491 1.1 jdolecek 1492 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1493 1.15 drochner 1494 1.1 jdolecek return rval; 1495 1.1 jdolecek } 1496 1.1 jdolecek 1497 1.41 andvar /* Write "instance variables" of atppc device */ 1498 1.1 jdolecek static int 1499 1.26 cegger atppc_write_ivar(device_t dev, int index, unsigned int *val) 1500 1.1 jdolecek { 1501 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1502 1.1 jdolecek int rval = 0; 1503 1.1 jdolecek 1504 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1505 1.15 drochner 1506 1.1 jdolecek switch(index) { 1507 1.1 jdolecek case PPBUS_IVAR_EPP_PROTO: 1508 1.9 drochner if (*val == PPBUS_EPP_1_9 || *val == PPBUS_EPP_1_7) 1509 1.1 jdolecek atppc->sc_epp = *val; 1510 1.1 jdolecek else 1511 1.1 jdolecek rval = EINVAL; 1512 1.1 jdolecek break; 1513 1.1 jdolecek 1514 1.1 jdolecek case PPBUS_IVAR_INTR: 1515 1.9 drochner if (*val == 0) 1516 1.1 jdolecek atppc->sc_use &= ~ATPPC_USE_INTR; 1517 1.9 drochner else if (atppc->sc_has & ATPPC_HAS_INTR) 1518 1.1 jdolecek atppc->sc_use |= ATPPC_USE_INTR; 1519 1.1 jdolecek else 1520 1.9 drochner rval = ENODEV; 1521 1.1 jdolecek break; 1522 1.1 jdolecek 1523 1.1 jdolecek case PPBUS_IVAR_DMA: 1524 1.9 drochner if (*val == 0) 1525 1.1 jdolecek atppc->sc_use &= ~ATPPC_USE_DMA; 1526 1.9 drochner else if (atppc->sc_has & ATPPC_HAS_DMA) 1527 1.1 jdolecek atppc->sc_use |= ATPPC_USE_DMA; 1528 1.1 jdolecek else 1529 1.9 drochner rval = ENODEV; 1530 1.1 jdolecek break; 1531 1.1 jdolecek 1532 1.1 jdolecek default: 1533 1.1 jdolecek rval = ENODEV; 1534 1.1 jdolecek } 1535 1.1 jdolecek 1536 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1537 1.15 drochner 1538 1.1 jdolecek return rval; 1539 1.1 jdolecek } 1540 1.1 jdolecek 1541 1.1 jdolecek /* Add a handler routine to be called by the interrupt handler */ 1542 1.9 drochner static int 1543 1.26 cegger atppc_add_handler(device_t dev, void (*handler)(void *), void *arg) 1544 1.1 jdolecek { 1545 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1546 1.9 drochner struct atppc_handler_node *callback; 1547 1.1 jdolecek 1548 1.9 drochner if (handler == NULL) { 1549 1.9 drochner ATPPC_DPRINTF(("%s(%s): attempt to register NULL handler.\n", 1550 1.25 cegger __func__, device_xname(dev))); 1551 1.33 chs return EINVAL; 1552 1.1 jdolecek } 1553 1.1 jdolecek 1554 1.33 chs callback = kmem_alloc(sizeof(*callback), KM_SLEEP); 1555 1.33 chs callback->func = handler; 1556 1.33 chs callback->arg = arg; 1557 1.33 chs mutex_enter(&atppc->sc_lock); 1558 1.33 chs SLIST_INSERT_HEAD(&(atppc->sc_handler_listhead), 1559 1.33 chs callback, entries); 1560 1.33 chs mutex_exit(&atppc->sc_lock); 1561 1.33 chs 1562 1.33 chs return 0; 1563 1.1 jdolecek } 1564 1.1 jdolecek 1565 1.1 jdolecek /* Remove a handler added by atppc_add_handler() */ 1566 1.9 drochner static int 1567 1.26 cegger atppc_remove_handler(device_t dev, void (*handler)(void *)) 1568 1.1 jdolecek { 1569 1.26 cegger struct atppc_softc *atppc = device_private(dev); 1570 1.9 drochner struct atppc_handler_node *callback; 1571 1.1 jdolecek int rval = EINVAL; 1572 1.1 jdolecek 1573 1.29 jakllsch mutex_enter(&atppc->sc_lock); 1574 1.15 drochner 1575 1.9 drochner if (SLIST_EMPTY(&(atppc->sc_handler_listhead))) 1576 1.1 jdolecek panic("%s(%s): attempt to remove handler from empty list.\n", 1577 1.25 cegger __func__, device_xname(dev)); 1578 1.1 jdolecek 1579 1.1 jdolecek /* Search list for handler */ 1580 1.1 jdolecek SLIST_FOREACH(callback, &(atppc->sc_handler_listhead), entries) { 1581 1.9 drochner if (callback->func == handler) { 1582 1.9 drochner SLIST_REMOVE(&(atppc->sc_handler_listhead), callback, 1583 1.1 jdolecek atppc_handler_node, entries); 1584 1.1 jdolecek rval = 0; 1585 1.1 jdolecek break; 1586 1.1 jdolecek } 1587 1.1 jdolecek } 1588 1.1 jdolecek 1589 1.29 jakllsch mutex_exit(&atppc->sc_lock); 1590 1.29 jakllsch 1591 1.29 jakllsch if (rval == 0) { 1592 1.30 jakllsch kmem_free(callback, sizeof(*callback)); 1593 1.29 jakllsch } 1594 1.15 drochner 1595 1.1 jdolecek return rval; 1596 1.1 jdolecek } 1597 1.1 jdolecek 1598 1.1 jdolecek /* Utility functions */ 1599 1.1 jdolecek 1600 1.1 jdolecek 1601 1.9 drochner /* 1602 1.9 drochner * Functions that read bytes from port into buffer: called from interrupt 1603 1.9 drochner * handler depending on current chipset mode and cause of interrupt. Return 1604 1.1 jdolecek * value: number of bytes moved. 1605 1.1 jdolecek */ 1606 1.1 jdolecek 1607 1.1 jdolecek /* Only the lower 4 bits of the final value are valid */ 1608 1.1 jdolecek #define nibble2char(s) ((((s) & ~nACK) >> 3) | (~(s) & nBUSY) >> 4) 1609 1.1 jdolecek 1610 1.9 drochner /* Read bytes in nibble mode */ 1611 1.9 drochner static void 1612 1.9 drochner atppc_nibble_read(struct atppc_softc *atppc) 1613 1.1 jdolecek { 1614 1.1 jdolecek int i; 1615 1.1 jdolecek u_int8_t nibble[2]; 1616 1.1 jdolecek u_int8_t ctr; 1617 1.1 jdolecek u_int8_t str; 1618 1.1 jdolecek 1619 1.1 jdolecek /* Enable interrupts if needed */ 1620 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 1621 1.1 jdolecek ctr = atppc_r_ctr(atppc); 1622 1.1 jdolecek atppc_barrier_r(atppc); 1623 1.9 drochner if (!(ctr & IRQENABLE)) { 1624 1.1 jdolecek ctr |= IRQENABLE; 1625 1.1 jdolecek atppc_w_ctr(atppc, ctr); 1626 1.1 jdolecek atppc_barrier_w(atppc); 1627 1.1 jdolecek } 1628 1.1 jdolecek } 1629 1.15 drochner 1630 1.9 drochner while (atppc->sc_inbstart < (atppc->sc_inb + atppc->sc_inb_nbytes)) { 1631 1.1 jdolecek /* Check if device has data to send in idle phase */ 1632 1.1 jdolecek str = atppc_r_str(atppc); 1633 1.1 jdolecek atppc_barrier_r(atppc); 1634 1.9 drochner if (str & nDATAVAIL) { 1635 1.1 jdolecek return; 1636 1.1 jdolecek } 1637 1.1 jdolecek 1638 1.1 jdolecek /* Nibble-mode handshake transfer */ 1639 1.9 drochner for (i = 0; i < 2; i++) { 1640 1.1 jdolecek /* Event 7 - ready to take data (HOSTBUSY low) */ 1641 1.1 jdolecek ctr = atppc_r_ctr(atppc); 1642 1.1 jdolecek atppc_barrier_r(atppc); 1643 1.1 jdolecek ctr |= HOSTBUSY; 1644 1.9 drochner atppc_w_ctr(atppc, ctr); 1645 1.1 jdolecek atppc_barrier_w(atppc); 1646 1.1 jdolecek 1647 1.1 jdolecek /* Event 8 - peripheral writes the first nibble */ 1648 1.1 jdolecek 1649 1.1 jdolecek /* Event 9 - peripheral set nAck low */ 1650 1.1 jdolecek atppc->sc_inerr = atppc_poll_str(atppc, 0, PTRCLK); 1651 1.9 drochner if (atppc->sc_inerr) 1652 1.1 jdolecek return; 1653 1.1 jdolecek 1654 1.1 jdolecek /* read nibble */ 1655 1.1 jdolecek nibble[i] = atppc_r_str(atppc); 1656 1.1 jdolecek 1657 1.1 jdolecek /* Event 10 - ack, nibble received */ 1658 1.1 jdolecek ctr &= ~HOSTBUSY; 1659 1.9 drochner atppc_w_ctr(atppc, ctr); 1660 1.1 jdolecek 1661 1.32 dholland /* Event 11 - wait ack from peripheral */ 1662 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) 1663 1.9 drochner atppc->sc_inerr = atppc_wait_interrupt(atppc, 1664 1.29 jakllsch &atppc->sc_in_cv, ATPPC_IRQ_nACK); 1665 1.1 jdolecek else 1666 1.9 drochner atppc->sc_inerr = atppc_poll_str(atppc, PTRCLK, 1667 1.1 jdolecek PTRCLK); 1668 1.9 drochner if (atppc->sc_inerr) 1669 1.1 jdolecek return; 1670 1.1 jdolecek } 1671 1.1 jdolecek 1672 1.35 msaitoh /* Store byte transferred */ 1673 1.1 jdolecek *(atppc->sc_inbstart) = ((nibble2char(nibble[1]) << 4) & 0xf0) | 1674 1.1 jdolecek (nibble2char(nibble[0]) & 0x0f); 1675 1.9 drochner atppc->sc_inbstart++; 1676 1.1 jdolecek } 1677 1.1 jdolecek } 1678 1.1 jdolecek 1679 1.1 jdolecek /* Read bytes in bidirectional mode */ 1680 1.9 drochner static void 1681 1.1 jdolecek atppc_byte_read(struct atppc_softc * const atppc) 1682 1.1 jdolecek { 1683 1.1 jdolecek u_int8_t ctr; 1684 1.1 jdolecek u_int8_t str; 1685 1.1 jdolecek 1686 1.1 jdolecek /* Check direction bit */ 1687 1.9 drochner ctr = atppc_r_ctr(atppc); 1688 1.1 jdolecek atppc_barrier_r(atppc); 1689 1.9 drochner if (!(ctr & PCD)) { 1690 1.1 jdolecek ATPPC_DPRINTF(("%s: byte-mode read attempted without direction " 1691 1.26 cegger "bit set.", device_xname(atppc->sc_dev))); 1692 1.1 jdolecek atppc->sc_inerr = ENODEV; 1693 1.1 jdolecek return; 1694 1.1 jdolecek } 1695 1.1 jdolecek /* Enable interrupts if needed */ 1696 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 1697 1.9 drochner if (!(ctr & IRQENABLE)) { 1698 1.1 jdolecek ctr |= IRQENABLE; 1699 1.1 jdolecek atppc_w_ctr(atppc, ctr); 1700 1.1 jdolecek atppc_barrier_w(atppc); 1701 1.1 jdolecek } 1702 1.1 jdolecek } 1703 1.15 drochner 1704 1.1 jdolecek /* Byte-mode handshake transfer */ 1705 1.9 drochner while (atppc->sc_inbstart < (atppc->sc_inb + atppc->sc_inb_nbytes)) { 1706 1.1 jdolecek /* Check if device has data to send */ 1707 1.1 jdolecek str = atppc_r_str(atppc); 1708 1.1 jdolecek atppc_barrier_r(atppc); 1709 1.9 drochner if (str & nDATAVAIL) { 1710 1.1 jdolecek return; 1711 1.1 jdolecek } 1712 1.1 jdolecek 1713 1.1 jdolecek /* Event 7 - ready to take data (nAUTO low) */ 1714 1.1 jdolecek ctr |= HOSTBUSY; 1715 1.9 drochner atppc_w_ctr(atppc, ctr); 1716 1.1 jdolecek atppc_barrier_w(atppc); 1717 1.1 jdolecek 1718 1.1 jdolecek /* Event 9 - peripheral set nAck low */ 1719 1.1 jdolecek atppc->sc_inerr = atppc_poll_str(atppc, 0, PTRCLK); 1720 1.9 drochner if (atppc->sc_inerr) 1721 1.1 jdolecek return; 1722 1.1 jdolecek 1723 1.35 msaitoh /* Store byte transferred */ 1724 1.1 jdolecek *(atppc->sc_inbstart) = atppc_r_dtr(atppc); 1725 1.1 jdolecek atppc_barrier_r(atppc); 1726 1.1 jdolecek 1727 1.1 jdolecek /* Event 10 - data received, can't accept more */ 1728 1.1 jdolecek ctr &= ~HOSTBUSY; 1729 1.9 drochner atppc_w_ctr(atppc, ctr); 1730 1.1 jdolecek atppc_barrier_w(atppc); 1731 1.1 jdolecek 1732 1.1 jdolecek /* Event 11 - peripheral ack */ 1733 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) 1734 1.9 drochner atppc->sc_inerr = atppc_wait_interrupt(atppc, 1735 1.29 jakllsch &atppc->sc_in_cv, ATPPC_IRQ_nACK); 1736 1.1 jdolecek else 1737 1.1 jdolecek atppc->sc_inerr = atppc_poll_str(atppc, PTRCLK, PTRCLK); 1738 1.9 drochner if (atppc->sc_inerr) 1739 1.1 jdolecek return; 1740 1.15 drochner 1741 1.1 jdolecek /* Event 16 - strobe */ 1742 1.1 jdolecek str |= HOSTCLK; 1743 1.9 drochner atppc_w_str(atppc, str); 1744 1.1 jdolecek atppc_barrier_w(atppc); 1745 1.1 jdolecek DELAY(1); 1746 1.1 jdolecek str &= ~HOSTCLK; 1747 1.9 drochner atppc_w_str(atppc, str); 1748 1.1 jdolecek atppc_barrier_w(atppc); 1749 1.1 jdolecek 1750 1.1 jdolecek /* Update counter */ 1751 1.1 jdolecek atppc->sc_inbstart++; 1752 1.1 jdolecek } 1753 1.1 jdolecek } 1754 1.1 jdolecek 1755 1.1 jdolecek /* Read bytes in EPP mode */ 1756 1.9 drochner static void 1757 1.1 jdolecek atppc_epp_read(struct atppc_softc * atppc) 1758 1.1 jdolecek { 1759 1.9 drochner if (atppc->sc_epp == ATPPC_EPP_1_9) { 1760 1.1 jdolecek { 1761 1.1 jdolecek uint8_t str; 1762 1.1 jdolecek int i; 1763 1.1 jdolecek 1764 1.26 cegger atppc_reset_epp_timeout(atppc->sc_dev); 1765 1.9 drochner for (i = 0; i < atppc->sc_inb_nbytes; i++) { 1766 1.1 jdolecek *(atppc->sc_inbstart) = atppc_r_eppD(atppc); 1767 1.1 jdolecek atppc_barrier_r(atppc); 1768 1.1 jdolecek str = atppc_r_str(atppc); 1769 1.1 jdolecek atppc_barrier_r(atppc); 1770 1.9 drochner if (str & TIMEOUT) { 1771 1.1 jdolecek atppc->sc_inerr = EIO; 1772 1.1 jdolecek break; 1773 1.1 jdolecek } 1774 1.1 jdolecek atppc->sc_inbstart++; 1775 1.1 jdolecek } 1776 1.1 jdolecek } 1777 1.9 drochner } else { 1778 1.1 jdolecek /* Read data block from EPP data register */ 1779 1.9 drochner atppc_r_eppD_multi(atppc, atppc->sc_inbstart, 1780 1.1 jdolecek atppc->sc_inb_nbytes); 1781 1.1 jdolecek atppc_barrier_r(atppc); 1782 1.1 jdolecek /* Update buffer position, byte count and counter */ 1783 1.1 jdolecek atppc->sc_inbstart += atppc->sc_inb_nbytes; 1784 1.1 jdolecek } 1785 1.1 jdolecek 1786 1.1 jdolecek return; 1787 1.1 jdolecek } 1788 1.1 jdolecek 1789 1.9 drochner /* Read bytes in ECP mode */ 1790 1.9 drochner static void 1791 1.9 drochner atppc_ecp_read(struct atppc_softc *atppc) 1792 1.1 jdolecek { 1793 1.1 jdolecek u_int8_t ecr; 1794 1.1 jdolecek u_int8_t ctr; 1795 1.1 jdolecek u_int8_t str; 1796 1.1 jdolecek const unsigned char ctr_sav = atppc_r_ctr(atppc); 1797 1.1 jdolecek const unsigned char ecr_sav = atppc_r_ecr(atppc); 1798 1.1 jdolecek unsigned int worklen; 1799 1.1 jdolecek 1800 1.1 jdolecek /* Check direction bit */ 1801 1.9 drochner ctr = ctr_sav; 1802 1.1 jdolecek atppc_barrier_r(atppc); 1803 1.9 drochner if (!(ctr & PCD)) { 1804 1.1 jdolecek ATPPC_DPRINTF(("%s: ecp-mode read attempted without direction " 1805 1.25 cegger "bit set.", device_xname(atppc->sc_dev))); 1806 1.1 jdolecek atppc->sc_inerr = ENODEV; 1807 1.1 jdolecek goto end; 1808 1.1 jdolecek } 1809 1.1 jdolecek 1810 1.1 jdolecek /* Clear device request if any */ 1811 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) 1812 1.9 drochner atppc->sc_irqstat &= ~ATPPC_IRQ_nFAULT; 1813 1.15 drochner 1814 1.9 drochner while (atppc->sc_inbstart < (atppc->sc_inb + atppc->sc_inb_nbytes)) { 1815 1.1 jdolecek ecr = atppc_r_ecr(atppc); 1816 1.1 jdolecek atppc_barrier_r(atppc); 1817 1.9 drochner if (ecr & ATPPC_FIFO_EMPTY) { 1818 1.9 drochner /* Check for invalid state */ 1819 1.9 drochner if (ecr & ATPPC_FIFO_FULL) { 1820 1.21 drochner atppc_ecp_read_error(atppc); 1821 1.1 jdolecek break; 1822 1.1 jdolecek } 1823 1.15 drochner 1824 1.1 jdolecek /* Check if device has data to send */ 1825 1.1 jdolecek str = atppc_r_str(atppc); 1826 1.1 jdolecek atppc_barrier_r(atppc); 1827 1.9 drochner if (str & nDATAVAIL) { 1828 1.1 jdolecek break; 1829 1.1 jdolecek } 1830 1.15 drochner 1831 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 1832 1.1 jdolecek /* Enable interrupts */ 1833 1.1 jdolecek ecr &= ~ATPPC_SERVICE_INTR; 1834 1.1 jdolecek atppc_w_ecr(atppc, ecr); 1835 1.1 jdolecek atppc_barrier_w(atppc); 1836 1.1 jdolecek /* Wait for FIFO to fill */ 1837 1.9 drochner atppc->sc_inerr = atppc_wait_interrupt(atppc, 1838 1.29 jakllsch &atppc->sc_in_cv, ATPPC_IRQ_FIFO); 1839 1.9 drochner if (atppc->sc_inerr) 1840 1.1 jdolecek break; 1841 1.9 drochner } else { 1842 1.1 jdolecek DELAY(1); 1843 1.1 jdolecek } 1844 1.1 jdolecek continue; 1845 1.1 jdolecek } 1846 1.9 drochner else if (ecr & ATPPC_FIFO_FULL) { 1847 1.1 jdolecek /* Transfer sc_fifo bytes */ 1848 1.1 jdolecek worklen = atppc->sc_fifo; 1849 1.1 jdolecek } 1850 1.9 drochner else if (ecr & ATPPC_SERVICE_INTR) { 1851 1.1 jdolecek /* Transfer sc_rthr bytes */ 1852 1.1 jdolecek worklen = atppc->sc_rthr; 1853 1.9 drochner } else { 1854 1.1 jdolecek /* At least one byte is in the FIFO */ 1855 1.1 jdolecek worklen = 1; 1856 1.1 jdolecek } 1857 1.1 jdolecek 1858 1.9 drochner if ((atppc->sc_use & ATPPC_USE_INTR) && 1859 1.1 jdolecek (atppc->sc_use & ATPPC_USE_DMA)) { 1860 1.1 jdolecek 1861 1.1 jdolecek atppc_ecp_read_dma(atppc, &worklen, ecr); 1862 1.9 drochner } else { 1863 1.1 jdolecek atppc_ecp_read_pio(atppc, &worklen, ecr); 1864 1.1 jdolecek } 1865 1.15 drochner 1866 1.9 drochner if (atppc->sc_inerr) { 1867 1.21 drochner atppc_ecp_read_error(atppc); 1868 1.1 jdolecek break; 1869 1.1 jdolecek } 1870 1.1 jdolecek 1871 1.1 jdolecek /* Update counter */ 1872 1.1 jdolecek atppc->sc_inbstart += worklen; 1873 1.1 jdolecek } 1874 1.1 jdolecek end: 1875 1.1 jdolecek atppc_w_ctr(atppc, ctr_sav); 1876 1.1 jdolecek atppc_w_ecr(atppc, ecr_sav); 1877 1.1 jdolecek atppc_barrier_w(atppc); 1878 1.1 jdolecek } 1879 1.1 jdolecek 1880 1.9 drochner /* Read bytes in ECP mode using DMA transfers */ 1881 1.9 drochner static void 1882 1.9 drochner atppc_ecp_read_dma(struct atppc_softc *atppc, unsigned int *length, 1883 1.1 jdolecek unsigned char ecr) 1884 1.1 jdolecek { 1885 1.1 jdolecek /* Limit transfer to maximum DMA size and start it */ 1886 1.34 riastrad *length = uimin(*length, atppc->sc_dma_maxsize); 1887 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_INIT; 1888 1.9 drochner atppc->sc_dma_start(atppc, atppc->sc_inbstart, *length, 1889 1.1 jdolecek ATPPC_DMA_MODE_READ); 1890 1.15 drochner 1891 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_STARTED; 1892 1.1 jdolecek 1893 1.1 jdolecek /* Enable interrupts, DMA */ 1894 1.1 jdolecek ecr &= ~ATPPC_SERVICE_INTR; 1895 1.1 jdolecek ecr |= ATPPC_ENABLE_DMA; 1896 1.1 jdolecek atppc_w_ecr(atppc, ecr); 1897 1.1 jdolecek atppc_barrier_w(atppc); 1898 1.1 jdolecek 1899 1.1 jdolecek /* Wait for DMA completion */ 1900 1.29 jakllsch atppc->sc_inerr = atppc_wait_interrupt(atppc, &atppc->sc_in_cv, 1901 1.1 jdolecek ATPPC_IRQ_DMA); 1902 1.9 drochner if (atppc->sc_inerr) 1903 1.1 jdolecek return; 1904 1.15 drochner 1905 1.1 jdolecek /* Get register value recorded by interrupt handler */ 1906 1.9 drochner ecr = atppc->sc_ecr_intr; 1907 1.1 jdolecek /* Clear DMA programming */ 1908 1.1 jdolecek atppc->sc_dma_finish(atppc); 1909 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_COMPLETE; 1910 1.1 jdolecek /* Disable DMA */ 1911 1.1 jdolecek ecr &= ~ATPPC_ENABLE_DMA; 1912 1.1 jdolecek atppc_w_ecr(atppc, ecr); 1913 1.1 jdolecek atppc_barrier_w(atppc); 1914 1.1 jdolecek } 1915 1.1 jdolecek 1916 1.9 drochner /* Read bytes in ECP mode using PIO transfers */ 1917 1.9 drochner static void 1918 1.9 drochner atppc_ecp_read_pio(struct atppc_softc *atppc, unsigned int *length, 1919 1.1 jdolecek unsigned char ecr) 1920 1.1 jdolecek { 1921 1.1 jdolecek /* Disable DMA */ 1922 1.1 jdolecek ecr &= ~ATPPC_ENABLE_DMA; 1923 1.1 jdolecek atppc_w_ecr(atppc, ecr); 1924 1.1 jdolecek atppc_barrier_w(atppc); 1925 1.15 drochner 1926 1.1 jdolecek /* Read from FIFO */ 1927 1.1 jdolecek atppc_r_fifo_multi(atppc, atppc->sc_inbstart, *length); 1928 1.1 jdolecek } 1929 1.1 jdolecek 1930 1.1 jdolecek /* Handle errors for ECP reads */ 1931 1.9 drochner static void 1932 1.21 drochner atppc_ecp_read_error(struct atppc_softc *atppc) 1933 1.1 jdolecek { 1934 1.1 jdolecek unsigned char ecr = atppc_r_ecr(atppc); 1935 1.1 jdolecek 1936 1.1 jdolecek /* Abort DMA if not finished */ 1937 1.9 drochner if (atppc->sc_dmastat == ATPPC_DMA_STARTED) { 1938 1.1 jdolecek atppc->sc_dma_abort(atppc); 1939 1.1 jdolecek ATPPC_DPRINTF(("%s: DMA interrupted.\n", __func__)); 1940 1.1 jdolecek } 1941 1.1 jdolecek 1942 1.1 jdolecek /* Check for invalid states */ 1943 1.9 drochner if ((ecr & ATPPC_FIFO_EMPTY) && (ecr & ATPPC_FIFO_FULL)) { 1944 1.9 drochner ATPPC_DPRINTF(("%s: FIFO full+empty bits set.\n", __func__)); 1945 1.36 msaitoh ATPPC_DPRINTF(("%s: resetting FIFO.\n", __func__)); 1946 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 1947 1.1 jdolecek atppc_barrier_w(atppc); 1948 1.1 jdolecek } 1949 1.1 jdolecek } 1950 1.1 jdolecek 1951 1.9 drochner /* 1952 1.9 drochner * Functions that write bytes to port from buffer: called from atppc_write() 1953 1.1 jdolecek * function depending on current chipset mode. Returns number of bytes moved. 1954 1.1 jdolecek */ 1955 1.1 jdolecek 1956 1.1 jdolecek /* Write bytes in std/bidirectional mode */ 1957 1.9 drochner static void 1958 1.1 jdolecek atppc_std_write(struct atppc_softc * const atppc) 1959 1.1 jdolecek { 1960 1.1 jdolecek unsigned char ctr; 1961 1.1 jdolecek 1962 1.9 drochner ctr = atppc_r_ctr(atppc); 1963 1.1 jdolecek atppc_barrier_r(atppc); 1964 1.1 jdolecek /* Enable interrupts if needed */ 1965 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 1966 1.9 drochner if (!(ctr & IRQENABLE)) { 1967 1.1 jdolecek ctr |= IRQENABLE; 1968 1.1 jdolecek atppc_w_ctr(atppc, ctr); 1969 1.1 jdolecek atppc_barrier_w(atppc); 1970 1.1 jdolecek } 1971 1.1 jdolecek } 1972 1.1 jdolecek 1973 1.9 drochner while (atppc->sc_outbstart < (atppc->sc_outb + atppc->sc_outb_nbytes)) { 1974 1.1 jdolecek /* Wait for peripheral to become ready for MAXBUSYWAIT */ 1975 1.1 jdolecek atppc->sc_outerr = atppc_poll_str(atppc, SPP_READY, SPP_MASK); 1976 1.9 drochner if (atppc->sc_outerr) 1977 1.1 jdolecek return; 1978 1.1 jdolecek 1979 1.1 jdolecek /* Put data in data register */ 1980 1.1 jdolecek atppc_w_dtr(atppc, *(atppc->sc_outbstart)); 1981 1.1 jdolecek atppc_barrier_w(atppc); 1982 1.1 jdolecek DELAY(1); 1983 1.1 jdolecek 1984 1.1 jdolecek /* Pulse strobe to indicate valid data on lines */ 1985 1.1 jdolecek ctr |= STROBE; 1986 1.1 jdolecek atppc_w_ctr(atppc, ctr); 1987 1.1 jdolecek atppc_barrier_w(atppc); 1988 1.1 jdolecek DELAY(1); 1989 1.1 jdolecek ctr &= ~STROBE; 1990 1.1 jdolecek atppc_w_ctr(atppc, ctr); 1991 1.1 jdolecek atppc_barrier_w(atppc); 1992 1.1 jdolecek 1993 1.1 jdolecek /* Wait for nACK for MAXBUSYWAIT */ 1994 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 1995 1.9 drochner atppc->sc_outerr = atppc_wait_interrupt(atppc, 1996 1.29 jakllsch &atppc->sc_out_cv, ATPPC_IRQ_nACK); 1997 1.9 drochner if (atppc->sc_outerr) 1998 1.1 jdolecek return; 1999 1.9 drochner } else { 2000 1.1 jdolecek /* Try to catch the pulsed acknowledgement */ 2001 1.1 jdolecek atppc->sc_outerr = atppc_poll_str(atppc, 0, nACK); 2002 1.9 drochner if (atppc->sc_outerr) 2003 1.1 jdolecek return; 2004 1.1 jdolecek atppc->sc_outerr = atppc_poll_str(atppc, nACK, nACK); 2005 1.9 drochner if (atppc->sc_outerr) 2006 1.1 jdolecek return; 2007 1.1 jdolecek } 2008 1.1 jdolecek 2009 1.1 jdolecek /* Update buffer position, byte count and counter */ 2010 1.1 jdolecek atppc->sc_outbstart++; 2011 1.1 jdolecek } 2012 1.1 jdolecek } 2013 1.1 jdolecek 2014 1.1 jdolecek 2015 1.1 jdolecek /* Write bytes in EPP mode */ 2016 1.9 drochner static void 2017 1.9 drochner atppc_epp_write(struct atppc_softc *atppc) 2018 1.1 jdolecek { 2019 1.9 drochner if (atppc->sc_epp == ATPPC_EPP_1_9) { 2020 1.1 jdolecek { 2021 1.1 jdolecek uint8_t str; 2022 1.1 jdolecek int i; 2023 1.1 jdolecek 2024 1.26 cegger atppc_reset_epp_timeout(atppc->sc_dev); 2025 1.9 drochner for (i = 0; i < atppc->sc_outb_nbytes; i++) { 2026 1.1 jdolecek atppc_w_eppD(atppc, *(atppc->sc_outbstart)); 2027 1.1 jdolecek atppc_barrier_w(atppc); 2028 1.1 jdolecek str = atppc_r_str(atppc); 2029 1.1 jdolecek atppc_barrier_r(atppc); 2030 1.9 drochner if (str & TIMEOUT) { 2031 1.1 jdolecek atppc->sc_outerr = EIO; 2032 1.1 jdolecek break; 2033 1.1 jdolecek } 2034 1.1 jdolecek atppc->sc_outbstart++; 2035 1.1 jdolecek } 2036 1.1 jdolecek } 2037 1.9 drochner } else { 2038 1.1 jdolecek /* Write data block to EPP data register */ 2039 1.9 drochner atppc_w_eppD_multi(atppc, atppc->sc_outbstart, 2040 1.1 jdolecek atppc->sc_outb_nbytes); 2041 1.1 jdolecek atppc_barrier_w(atppc); 2042 1.1 jdolecek /* Update buffer position, byte count and counter */ 2043 1.1 jdolecek atppc->sc_outbstart += atppc->sc_outb_nbytes; 2044 1.1 jdolecek } 2045 1.1 jdolecek 2046 1.1 jdolecek return; 2047 1.1 jdolecek } 2048 1.1 jdolecek 2049 1.1 jdolecek 2050 1.1 jdolecek /* Write bytes in ECP/Fast Centronics mode */ 2051 1.9 drochner static void 2052 1.1 jdolecek atppc_fifo_write(struct atppc_softc * const atppc) 2053 1.1 jdolecek { 2054 1.1 jdolecek unsigned char ctr; 2055 1.1 jdolecek unsigned char ecr; 2056 1.1 jdolecek const unsigned char ctr_sav = atppc_r_ctr(atppc); 2057 1.1 jdolecek const unsigned char ecr_sav = atppc_r_ecr(atppc); 2058 1.15 drochner 2059 1.1 jdolecek ctr = ctr_sav; 2060 1.1 jdolecek ecr = ecr_sav; 2061 1.1 jdolecek atppc_barrier_r(atppc); 2062 1.1 jdolecek 2063 1.1 jdolecek /* Reset and flush FIFO */ 2064 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 2065 1.1 jdolecek atppc_barrier_w(atppc); 2066 1.1 jdolecek /* Disable nAck interrupts and initialize port bits */ 2067 1.1 jdolecek ctr &= ~(IRQENABLE | STROBE | AUTOFEED); 2068 1.1 jdolecek atppc_w_ctr(atppc, ctr); 2069 1.1 jdolecek atppc_barrier_w(atppc); 2070 1.1 jdolecek /* Restore mode */ 2071 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2072 1.1 jdolecek atppc_barrier_w(atppc); 2073 1.1 jdolecek 2074 1.1 jdolecek /* DMA or Programmed IO */ 2075 1.9 drochner if ((atppc->sc_use & ATPPC_USE_DMA) && 2076 1.9 drochner (atppc->sc_use & ATPPC_USE_INTR)) { 2077 1.15 drochner 2078 1.1 jdolecek atppc_fifo_write_dma(atppc, ecr, ctr); 2079 1.9 drochner } else { 2080 1.1 jdolecek atppc_fifo_write_pio(atppc, ecr, ctr); 2081 1.1 jdolecek } 2082 1.15 drochner 2083 1.1 jdolecek /* Restore original register values */ 2084 1.1 jdolecek atppc_w_ctr(atppc, ctr_sav); 2085 1.1 jdolecek atppc_w_ecr(atppc, ecr_sav); 2086 1.1 jdolecek atppc_barrier_w(atppc); 2087 1.1 jdolecek } 2088 1.1 jdolecek 2089 1.9 drochner static void 2090 1.9 drochner atppc_fifo_write_dma(struct atppc_softc * const atppc, unsigned char ecr, 2091 1.1 jdolecek unsigned char ctr) 2092 1.1 jdolecek { 2093 1.1 jdolecek unsigned int len; 2094 1.1 jdolecek unsigned int worklen; 2095 1.1 jdolecek 2096 1.9 drochner for (len = (atppc->sc_outb + atppc->sc_outb_nbytes) - 2097 1.9 drochner atppc->sc_outbstart; len > 0; len = (atppc->sc_outb + 2098 1.1 jdolecek atppc->sc_outb_nbytes) - atppc->sc_outbstart) { 2099 1.15 drochner 2100 1.1 jdolecek /* Wait for device to become ready */ 2101 1.1 jdolecek atppc->sc_outerr = atppc_poll_str(atppc, SPP_READY, SPP_MASK); 2102 1.9 drochner if (atppc->sc_outerr) 2103 1.1 jdolecek return; 2104 1.15 drochner 2105 1.1 jdolecek /* Reset chipset for next DMA transfer */ 2106 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 2107 1.1 jdolecek atppc_barrier_w(atppc); 2108 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2109 1.1 jdolecek atppc_barrier_w(atppc); 2110 1.15 drochner 2111 1.1 jdolecek /* Limit transfer to maximum DMA size and start it */ 2112 1.34 riastrad worklen = uimin(len, atppc->sc_dma_maxsize); 2113 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_INIT; 2114 1.1 jdolecek atppc->sc_dma_start(atppc, atppc->sc_outbstart, 2115 1.1 jdolecek worklen, ATPPC_DMA_MODE_WRITE); 2116 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_STARTED; 2117 1.1 jdolecek 2118 1.1 jdolecek /* Enable interrupts, DMA */ 2119 1.1 jdolecek ecr &= ~ATPPC_SERVICE_INTR; 2120 1.1 jdolecek ecr |= ATPPC_ENABLE_DMA; 2121 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2122 1.1 jdolecek atppc_barrier_w(atppc); 2123 1.1 jdolecek 2124 1.1 jdolecek /* Wait for DMA completion */ 2125 1.29 jakllsch atppc->sc_outerr = atppc_wait_interrupt(atppc, 2126 1.29 jakllsch &atppc->sc_out_cv, ATPPC_IRQ_DMA); 2127 1.9 drochner if (atppc->sc_outerr) { 2128 1.9 drochner atppc_fifo_write_error(atppc, worklen); 2129 1.1 jdolecek return; 2130 1.1 jdolecek } 2131 1.1 jdolecek /* Get register value recorded by interrupt handler */ 2132 1.9 drochner ecr = atppc->sc_ecr_intr; 2133 1.1 jdolecek /* Clear DMA programming */ 2134 1.1 jdolecek atppc->sc_dma_finish(atppc); 2135 1.1 jdolecek atppc->sc_dmastat = ATPPC_DMA_COMPLETE; 2136 1.1 jdolecek /* Disable DMA */ 2137 1.1 jdolecek ecr &= ~ATPPC_ENABLE_DMA; 2138 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2139 1.1 jdolecek atppc_barrier_w(atppc); 2140 1.15 drochner 2141 1.1 jdolecek /* Wait for FIFO to empty */ 2142 1.9 drochner for (;;) { 2143 1.9 drochner if (ecr & ATPPC_FIFO_EMPTY) { 2144 1.9 drochner if (ecr & ATPPC_FIFO_FULL) { 2145 1.1 jdolecek atppc->sc_outerr = EIO; 2146 1.1 jdolecek atppc_fifo_write_error(atppc, worklen); 2147 1.1 jdolecek return; 2148 1.9 drochner } else { 2149 1.1 jdolecek break; 2150 1.1 jdolecek } 2151 1.1 jdolecek } 2152 1.15 drochner 2153 1.1 jdolecek /* Enable service interrupt */ 2154 1.1 jdolecek ecr &= ~ATPPC_SERVICE_INTR; 2155 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2156 1.1 jdolecek atppc_barrier_w(atppc); 2157 1.15 drochner 2158 1.9 drochner atppc->sc_outerr = atppc_wait_interrupt(atppc, 2159 1.29 jakllsch &atppc->sc_out_cv, ATPPC_IRQ_FIFO); 2160 1.9 drochner if (atppc->sc_outerr) { 2161 1.9 drochner atppc_fifo_write_error(atppc, worklen); 2162 1.1 jdolecek return; 2163 1.1 jdolecek } 2164 1.15 drochner 2165 1.1 jdolecek /* Get register value recorded by interrupt handler */ 2166 1.9 drochner ecr = atppc->sc_ecr_intr; 2167 1.1 jdolecek } 2168 1.1 jdolecek 2169 1.1 jdolecek /* Update pointer */ 2170 1.1 jdolecek atppc->sc_outbstart += worklen; 2171 1.1 jdolecek } 2172 1.1 jdolecek } 2173 1.1 jdolecek 2174 1.9 drochner static void 2175 1.9 drochner atppc_fifo_write_pio(struct atppc_softc * const atppc, unsigned char ecr, 2176 1.1 jdolecek unsigned char ctr) 2177 1.1 jdolecek { 2178 1.1 jdolecek unsigned int len; 2179 1.1 jdolecek unsigned int worklen; 2180 1.1 jdolecek unsigned int timecount; 2181 1.1 jdolecek 2182 1.1 jdolecek /* Disable DMA */ 2183 1.1 jdolecek ecr &= ~ATPPC_ENABLE_DMA; 2184 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2185 1.1 jdolecek atppc_barrier_w(atppc); 2186 1.15 drochner 2187 1.9 drochner for (len = (atppc->sc_outb + atppc->sc_outb_nbytes) - 2188 1.9 drochner atppc->sc_outbstart; len > 0; len = (atppc->sc_outb + 2189 1.1 jdolecek atppc->sc_outb_nbytes) - atppc->sc_outbstart) { 2190 1.15 drochner 2191 1.1 jdolecek /* Wait for device to become ready */ 2192 1.1 jdolecek atppc->sc_outerr = atppc_poll_str(atppc, SPP_READY, SPP_MASK); 2193 1.9 drochner if (atppc->sc_outerr) 2194 1.1 jdolecek return; 2195 1.15 drochner 2196 1.1 jdolecek /* Limit transfer to minimum of space in FIFO and buffer */ 2197 1.34 riastrad worklen = uimin(len, atppc->sc_fifo); 2198 1.1 jdolecek 2199 1.1 jdolecek /* Write to FIFO */ 2200 1.1 jdolecek atppc_w_fifo_multi(atppc, atppc->sc_outbstart, worklen); 2201 1.1 jdolecek 2202 1.1 jdolecek timecount = 0; 2203 1.9 drochner if (atppc->sc_use & ATPPC_USE_INTR) { 2204 1.1 jdolecek ecr = atppc_r_ecr(atppc); 2205 1.1 jdolecek atppc_barrier_w(atppc); 2206 1.15 drochner 2207 1.1 jdolecek /* Wait for interrupt */ 2208 1.9 drochner for (;;) { 2209 1.9 drochner if (ecr & ATPPC_FIFO_EMPTY) { 2210 1.9 drochner if (ecr & ATPPC_FIFO_FULL) { 2211 1.1 jdolecek atppc->sc_outerr = EIO; 2212 1.9 drochner atppc_fifo_write_error(atppc, 2213 1.1 jdolecek worklen); 2214 1.1 jdolecek return; 2215 1.9 drochner } else { 2216 1.1 jdolecek break; 2217 1.1 jdolecek } 2218 1.1 jdolecek } 2219 1.1 jdolecek 2220 1.1 jdolecek /* Enable service interrupt */ 2221 1.1 jdolecek ecr &= ~ATPPC_SERVICE_INTR; 2222 1.1 jdolecek atppc_w_ecr(atppc, ecr); 2223 1.1 jdolecek atppc_barrier_w(atppc); 2224 1.15 drochner 2225 1.9 drochner atppc->sc_outerr = atppc_wait_interrupt(atppc, 2226 1.29 jakllsch &atppc->sc_out_cv, ATPPC_IRQ_FIFO); 2227 1.9 drochner if (atppc->sc_outerr) { 2228 1.1 jdolecek atppc_fifo_write_error(atppc, worklen); 2229 1.1 jdolecek return; 2230 1.1 jdolecek } 2231 1.15 drochner 2232 1.1 jdolecek /* Get ECR value saved by interrupt handler */ 2233 1.9 drochner ecr = atppc->sc_ecr_intr; 2234 1.1 jdolecek } 2235 1.9 drochner } else { 2236 1.9 drochner for (; timecount < ((MAXBUSYWAIT/hz)*1000000); 2237 1.9 drochner timecount++) { 2238 1.15 drochner 2239 1.1 jdolecek ecr = atppc_r_ecr(atppc); 2240 1.1 jdolecek atppc_barrier_r(atppc); 2241 1.9 drochner if (ecr & ATPPC_FIFO_EMPTY) { 2242 1.9 drochner if (ecr & ATPPC_FIFO_FULL) { 2243 1.1 jdolecek atppc->sc_outerr = EIO; 2244 1.9 drochner atppc_fifo_write_error(atppc, 2245 1.1 jdolecek worklen); 2246 1.1 jdolecek return; 2247 1.9 drochner } else { 2248 1.1 jdolecek break; 2249 1.1 jdolecek } 2250 1.1 jdolecek } 2251 1.1 jdolecek DELAY(1); 2252 1.1 jdolecek } 2253 1.15 drochner 2254 1.9 drochner if (((timecount*hz)/1000000) >= MAXBUSYWAIT) { 2255 1.1 jdolecek atppc->sc_outerr = EIO; 2256 1.9 drochner atppc_fifo_write_error(atppc, worklen); 2257 1.1 jdolecek return; 2258 1.1 jdolecek } 2259 1.1 jdolecek } 2260 1.15 drochner 2261 1.1 jdolecek /* Update pointer */ 2262 1.1 jdolecek atppc->sc_outbstart += worklen; 2263 1.1 jdolecek } 2264 1.1 jdolecek } 2265 1.1 jdolecek 2266 1.9 drochner static void 2267 1.9 drochner atppc_fifo_write_error(struct atppc_softc * const atppc, 2268 1.1 jdolecek const unsigned int worklen) 2269 1.1 jdolecek { 2270 1.1 jdolecek unsigned char ecr = atppc_r_ecr(atppc); 2271 1.1 jdolecek 2272 1.1 jdolecek /* Abort DMA if not finished */ 2273 1.9 drochner if (atppc->sc_dmastat == ATPPC_DMA_STARTED) { 2274 1.1 jdolecek atppc->sc_dma_abort(atppc); 2275 1.1 jdolecek ATPPC_DPRINTF(("%s: DMA interrupted.\n", __func__)); 2276 1.1 jdolecek } 2277 1.1 jdolecek 2278 1.1 jdolecek /* Check for invalid states */ 2279 1.9 drochner if ((ecr & ATPPC_FIFO_EMPTY) && (ecr & ATPPC_FIFO_FULL)) { 2280 1.9 drochner ATPPC_DPRINTF(("%s: FIFO full+empty bits set.\n", __func__)); 2281 1.9 drochner } else if (!(ecr & ATPPC_FIFO_EMPTY)) { 2282 1.1 jdolecek unsigned char ctr = atppc_r_ctr(atppc); 2283 1.1 jdolecek int bytes_left; 2284 1.1 jdolecek int i; 2285 1.1 jdolecek 2286 1.9 drochner ATPPC_DPRINTF(("%s(%s): FIFO not empty.\n", __func__, 2287 1.26 cegger device_xname(atppc->sc_dev))); 2288 1.15 drochner 2289 1.1 jdolecek /* Drive strobe low to stop data transfer */ 2290 1.1 jdolecek ctr &= ~STROBE; 2291 1.1 jdolecek atppc_w_ctr(atppc, ctr); 2292 1.1 jdolecek atppc_barrier_w(atppc); 2293 1.1 jdolecek 2294 1.1 jdolecek /* Determine how many bytes remain in FIFO */ 2295 1.9 drochner for (i = 0; i < atppc->sc_fifo; i++) { 2296 1.1 jdolecek atppc_w_fifo(atppc, (unsigned char)i); 2297 1.1 jdolecek ecr = atppc_r_ecr(atppc); 2298 1.1 jdolecek atppc_barrier_r(atppc); 2299 1.9 drochner if (ecr & ATPPC_FIFO_FULL) 2300 1.1 jdolecek break; 2301 1.1 jdolecek } 2302 1.1 jdolecek bytes_left = (atppc->sc_fifo) - (i + 1); 2303 1.9 drochner ATPPC_DPRINTF(("%s: %d bytes left in FIFO.\n", __func__, 2304 1.1 jdolecek bytes_left)); 2305 1.15 drochner 2306 1.1 jdolecek /* Update counter */ 2307 1.1 jdolecek atppc->sc_outbstart += (worklen - bytes_left); 2308 1.9 drochner } else { 2309 1.1 jdolecek /* Update counter */ 2310 1.1 jdolecek atppc->sc_outbstart += worklen; 2311 1.1 jdolecek } 2312 1.1 jdolecek 2313 1.37 msaitoh ATPPC_DPRINTF(("%s: resetting FIFO.\n", __func__)); 2314 1.1 jdolecek atppc_w_ecr(atppc, ATPPC_ECR_PS2); 2315 1.1 jdolecek atppc_barrier_w(atppc); 2316 1.1 jdolecek } 2317 1.1 jdolecek 2318 1.9 drochner /* 2319 1.9 drochner * Poll status register using mask and status for MAXBUSYWAIT. 2320 1.1 jdolecek * Returns 0 if device ready, error value otherwise. 2321 1.1 jdolecek */ 2322 1.1 jdolecek static int 2323 1.9 drochner atppc_poll_str(const struct atppc_softc * const atppc, const u_int8_t status, 2324 1.1 jdolecek const u_int8_t mask) 2325 1.1 jdolecek { 2326 1.1 jdolecek unsigned int timecount; 2327 1.1 jdolecek u_int8_t str; 2328 1.1 jdolecek int error = EIO; 2329 1.1 jdolecek 2330 1.1 jdolecek /* Wait for str to have status for MAXBUSYWAIT */ 2331 1.9 drochner for (timecount = 0; timecount < ((MAXBUSYWAIT/hz)*1000000); 2332 1.1 jdolecek timecount++) { 2333 1.15 drochner 2334 1.1 jdolecek str = atppc_r_str(atppc); 2335 1.1 jdolecek atppc_barrier_r(atppc); 2336 1.9 drochner if ((str & mask) == status) { 2337 1.1 jdolecek error = 0; 2338 1.1 jdolecek break; 2339 1.1 jdolecek } 2340 1.1 jdolecek DELAY(1); 2341 1.1 jdolecek } 2342 1.1 jdolecek 2343 1.1 jdolecek return error; 2344 1.1 jdolecek } 2345 1.1 jdolecek 2346 1.1 jdolecek /* Wait for interrupt for MAXBUSYWAIT: returns 0 if acknowledge received. */ 2347 1.1 jdolecek static int 2348 1.29 jakllsch atppc_wait_interrupt(struct atppc_softc * const atppc, kcondvar_t *cv, 2349 1.1 jdolecek const u_int8_t irqstat) 2350 1.1 jdolecek { 2351 1.1 jdolecek int error = EIO; 2352 1.1 jdolecek 2353 1.1 jdolecek atppc->sc_irqstat &= ~irqstat; 2354 1.15 drochner 2355 1.1 jdolecek /* Wait for interrupt for MAXBUSYWAIT */ 2356 1.29 jakllsch error = cv_timedwait_sig(cv, &atppc->sc_lock, MAXBUSYWAIT); 2357 1.15 drochner 2358 1.9 drochner if (!(error) && (atppc->sc_irqstat & irqstat)) { 2359 1.1 jdolecek atppc->sc_irqstat &= ~irqstat; 2360 1.1 jdolecek error = 0; 2361 1.1 jdolecek } 2362 1.1 jdolecek 2363 1.1 jdolecek return error; 2364 1.1 jdolecek } 2365