1 1.23 thorpej /* $NetBSD: ppbus_conf.c,v 1.23 2021/08/07 16:19:15 thorpej Exp $ */ 2 1.2 bjh21 3 1.1 jdolecek /*- 4 1.1 jdolecek * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 8 1.1 jdolecek * modification, are permitted provided that the following conditions 9 1.1 jdolecek * are met: 10 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 11 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 12 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 14 1.1 jdolecek * documentation and/or other materials provided with the distribution. 15 1.1 jdolecek * 16 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jdolecek * SUCH DAMAGE. 27 1.1 jdolecek * 28 1.3 bjh21 * FreeBSD: src/sys/dev/ppbus/ppbconf.c,v 1.17.2.1 2000/05/24 00:20:57 n_hibma Exp 29 1.1 jdolecek * 30 1.1 jdolecek */ 31 1.3 bjh21 32 1.3 bjh21 #include <sys/cdefs.h> 33 1.23 thorpej __KERNEL_RCSID(0, "$NetBSD: ppbus_conf.c,v 1.23 2021/08/07 16:19:15 thorpej Exp $"); 34 1.3 bjh21 35 1.1 jdolecek #include "opt_ppbus.h" 36 1.4 jdolecek #include "opt_ppbus_1284.h" 37 1.1 jdolecek 38 1.16 cegger #include "gpio.h" 39 1.16 cegger 40 1.1 jdolecek #include <sys/param.h> 41 1.1 jdolecek #include <sys/systm.h> 42 1.1 jdolecek #include <sys/kernel.h> 43 1.1 jdolecek #include <sys/device.h> 44 1.1 jdolecek #include <sys/proc.h> 45 1.1 jdolecek 46 1.1 jdolecek #include <dev/ppbus/ppbus_1284.h> 47 1.1 jdolecek #include <dev/ppbus/ppbus_base.h> 48 1.1 jdolecek #include <dev/ppbus/ppbus_conf.h> 49 1.1 jdolecek #include <dev/ppbus/ppbus_device.h> 50 1.1 jdolecek #include <dev/ppbus/ppbus_var.h> 51 1.1 jdolecek 52 1.1 jdolecek /* Probe, attach, and detach functions for ppbus. */ 53 1.14 cegger static int ppbus_probe(device_t, cfdata_t, void *); 54 1.14 cegger static void ppbus_attach(device_t, device_t, void *); 55 1.17 dyoung static void ppbus_childdet(device_t, device_t); 56 1.14 cegger static int ppbus_detach(device_t, int); 57 1.1 jdolecek 58 1.1 jdolecek /* Utility function prototypes */ 59 1.14 cegger static int ppbus_search_children(device_t, cfdata_t, 60 1.8 drochner const int *, void *); 61 1.1 jdolecek 62 1.1 jdolecek 63 1.17 dyoung CFATTACH_DECL2_NEW(ppbus, sizeof(struct ppbus_softc), ppbus_probe, ppbus_attach, 64 1.17 dyoung ppbus_detach, NULL, NULL, ppbus_childdet); 65 1.1 jdolecek 66 1.1 jdolecek /* Probe function for ppbus. */ 67 1.1 jdolecek static int 68 1.14 cegger ppbus_probe(device_t parent, cfdata_t cf, void *aux) 69 1.1 jdolecek { 70 1.5 drochner struct parport_adapter *sc_link = aux; 71 1.1 jdolecek 72 1.7 perry /* Check adapter for consistency */ 73 1.5 drochner if ( 74 1.1 jdolecek /* Required methods for all parports */ 75 1.7 perry sc_link->parport_io == NULL || 76 1.1 jdolecek sc_link->parport_exec_microseq == NULL || 77 1.1 jdolecek sc_link->parport_setmode == NULL || 78 1.1 jdolecek sc_link->parport_getmode == NULL || 79 1.1 jdolecek sc_link->parport_read == NULL || 80 1.1 jdolecek sc_link->parport_write == NULL || 81 1.1 jdolecek sc_link->parport_read_ivar == NULL || 82 1.1 jdolecek sc_link->parport_write_ivar == NULL || 83 1.1 jdolecek /* Methods which conditional exist based on capabilities */ 84 1.7 perry ((sc_link->capabilities & PPBUS_HAS_EPP) && 85 1.1 jdolecek (sc_link->parport_reset_epp_timeout == NULL)) || 86 1.7 perry ((sc_link->capabilities & PPBUS_HAS_ECP) && 87 1.1 jdolecek (sc_link->parport_ecp_sync == NULL)) || 88 1.7 perry ((sc_link->capabilities & PPBUS_HAS_DMA) && 89 1.1 jdolecek (sc_link->parport_dma_malloc == NULL || 90 1.7 perry sc_link->parport_dma_free == NULL)) || 91 1.7 perry ((sc_link->capabilities & PPBUS_HAS_INTR) && 92 1.1 jdolecek (sc_link->parport_add_handler == NULL || 93 1.1 jdolecek sc_link->parport_remove_handler == NULL)) 94 1.1 jdolecek ) { 95 1.7 perry 96 1.1 jdolecek #ifdef PPBUS_DEBUG 97 1.1 jdolecek printf("%s(%s): parport_adaptor is incomplete. Child device " 98 1.13 cegger "probe failed.\n", __func__, device_xname(parent)); 99 1.1 jdolecek #endif 100 1.1 jdolecek return 0; 101 1.5 drochner } else { 102 1.1 jdolecek return 1; 103 1.1 jdolecek } 104 1.1 jdolecek } 105 1.1 jdolecek 106 1.1 jdolecek /* Attach function for ppbus. */ 107 1.1 jdolecek static void 108 1.14 cegger ppbus_attach(device_t parent, device_t self, void *aux) 109 1.1 jdolecek { 110 1.11 thorpej struct ppbus_softc *ppbus = device_private(self); 111 1.5 drochner struct parport_adapter *sc_link = aux; 112 1.1 jdolecek struct ppbus_attach_args args; 113 1.1 jdolecek 114 1.1 jdolecek printf("\n"); 115 1.1 jdolecek 116 1.1 jdolecek /* Initialize config data from adapter (bus + device methods) */ 117 1.14 cegger ppbus->sc_dev = self; 118 1.7 perry args.capabilities = ppbus->sc_capabilities = sc_link->capabilities; 119 1.1 jdolecek ppbus->ppbus_io = sc_link->parport_io; 120 1.1 jdolecek ppbus->ppbus_exec_microseq = sc_link->parport_exec_microseq; 121 1.1 jdolecek ppbus->ppbus_reset_epp_timeout = sc_link-> 122 1.1 jdolecek parport_reset_epp_timeout; 123 1.1 jdolecek ppbus->ppbus_setmode = sc_link->parport_setmode; 124 1.1 jdolecek ppbus->ppbus_getmode = sc_link->parport_getmode; 125 1.1 jdolecek ppbus->ppbus_ecp_sync = sc_link->parport_ecp_sync; 126 1.1 jdolecek ppbus->ppbus_read = sc_link->parport_read; 127 1.1 jdolecek ppbus->ppbus_write = sc_link->parport_write; 128 1.1 jdolecek ppbus->ppbus_read_ivar = sc_link->parport_read_ivar; 129 1.1 jdolecek ppbus->ppbus_write_ivar = sc_link->parport_write_ivar; 130 1.1 jdolecek ppbus->ppbus_dma_malloc = sc_link->parport_dma_malloc; 131 1.1 jdolecek ppbus->ppbus_dma_free = sc_link->parport_dma_free; 132 1.1 jdolecek ppbus->ppbus_add_handler = sc_link->parport_add_handler; 133 1.1 jdolecek ppbus->ppbus_remove_handler = sc_link->parport_remove_handler; 134 1.1 jdolecek 135 1.1 jdolecek /* Initially there is no device owning the bus */ 136 1.1 jdolecek ppbus->ppbus_owner = NULL; 137 1.1 jdolecek 138 1.1 jdolecek /* Initialize locking structures */ 139 1.12 ad mutex_init(&(ppbus->sc_lock), MUTEX_DEFAULT, IPL_NONE); 140 1.1 jdolecek 141 1.1 jdolecek /* Set up bus mode and ieee state */ 142 1.10 thorpej ppbus->sc_mode = ppbus->ppbus_getmode(device_parent(self)); 143 1.1 jdolecek ppbus->sc_use_ieee = 1; 144 1.1 jdolecek ppbus->sc_1284_state = PPBUS_FORWARD_IDLE; 145 1.1 jdolecek ppbus->sc_1284_error = PPBUS_NO_ERROR; 146 1.1 jdolecek 147 1.21 msaitoh /* Record device's successful attachment */ 148 1.1 jdolecek ppbus->sc_dev_ok = PPBUS_OK; 149 1.1 jdolecek 150 1.1 jdolecek #ifndef DONTPROBE_1284 151 1.1 jdolecek /* detect IEEE1284 compliant devices */ 152 1.5 drochner if (ppbus_scan_bus(self)) { 153 1.13 cegger printf("%s: No IEEE1284 device found.\n", device_xname(self)); 154 1.5 drochner } else { 155 1.13 cegger printf("%s: IEEE1284 device found.\n", device_xname(self)); 156 1.7 perry /* 157 1.7 perry * Detect device ID (interrupts must be disabled because we 158 1.19 rmind * cannot do a block to wait for it - no context) 159 1.1 jdolecek */ 160 1.5 drochner if (args.capabilities & PPBUS_HAS_INTR) { 161 1.1 jdolecek int val = 0; 162 1.1 jdolecek if(ppbus_write_ivar(self, PPBUS_IVAR_INTR, &val) != 0) { 163 1.1 jdolecek printf(" <problem initializing interrupt " 164 1.1 jdolecek "usage>"); 165 1.1 jdolecek } 166 1.1 jdolecek } 167 1.1 jdolecek ppbus_pnp_detect(self); 168 1.1 jdolecek } 169 1.1 jdolecek #endif /* !DONTPROBE_1284 */ 170 1.1 jdolecek 171 1.1 jdolecek /* Configure child devices */ 172 1.1 jdolecek SLIST_INIT(&(ppbus->sc_childlist_head)); 173 1.22 thorpej config_search(self, &args, 174 1.23 thorpej CFARGS(.search = ppbus_search_children, 175 1.23 thorpej .iattr = "ppbus")); 176 1.1 jdolecek 177 1.16 cegger #if NGPIO > 0 178 1.16 cegger gpio_ppbus_attach(ppbus); 179 1.16 cegger #endif 180 1.1 jdolecek return; 181 1.1 jdolecek } 182 1.1 jdolecek 183 1.17 dyoung static void 184 1.17 dyoung ppbus_childdet(device_t self, device_t target) 185 1.17 dyoung { 186 1.18 he struct ppbus_softc * ppbus = device_private(self); 187 1.18 he struct ppbus_device_softc * child; 188 1.18 he 189 1.17 dyoung SLIST_FOREACH(child, &ppbus->sc_childlist_head, entries) { 190 1.17 dyoung if (child->sc_dev == target) 191 1.17 dyoung break; 192 1.17 dyoung } 193 1.17 dyoung if (child != NULL) 194 1.17 dyoung SLIST_REMOVE(&ppbus->sc_childlist_head, child, 195 1.18 he ppbus_device_softc, entries); 196 1.17 dyoung } 197 1.17 dyoung 198 1.1 jdolecek /* Detach function for ppbus. */ 199 1.1 jdolecek static int 200 1.14 cegger ppbus_detach(device_t self, int flag) 201 1.1 jdolecek { 202 1.11 thorpej struct ppbus_softc * ppbus = device_private(self); 203 1.1 jdolecek struct ppbus_device_softc * child; 204 1.1 jdolecek 205 1.5 drochner if (ppbus->sc_dev_ok != PPBUS_OK) { 206 1.5 drochner if (!(flag & DETACH_QUIET)) 207 1.7 perry printf("%s: detach called on unattached device.\n", 208 1.14 cegger device_xname(ppbus->sc_dev)); 209 1.5 drochner if (!(flag & DETACH_FORCE)) 210 1.1 jdolecek return 0; 211 1.5 drochner if (!(flag & DETACH_QUIET)) 212 1.1 jdolecek printf("%s: continuing detach (DETACH_FORCE).\n", 213 1.14 cegger device_xname(ppbus->sc_dev)); 214 1.1 jdolecek } 215 1.1 jdolecek 216 1.12 ad mutex_destroy(&(ppbus->sc_lock)); 217 1.1 jdolecek 218 1.1 jdolecek /* Detach children devices */ 219 1.17 dyoung while ((child = SLIST_FIRST(&ppbus->sc_childlist_head)) != NULL) { 220 1.15 cegger if (config_detach(child->sc_dev, flag)) { 221 1.1 jdolecek if(!(flag & DETACH_QUIET)) 222 1.14 cegger aprint_error_dev(ppbus->sc_dev, "error detaching %s.", 223 1.14 cegger device_xname(child->sc_dev)); 224 1.1 jdolecek if(!(flag & DETACH_FORCE)) 225 1.1 jdolecek return 0; 226 1.1 jdolecek if(!(flag & DETACH_QUIET)) 227 1.1 jdolecek printf("%s: continuing (DETACH_FORCE).\n", 228 1.14 cegger device_xname(ppbus->sc_dev)); 229 1.1 jdolecek } 230 1.1 jdolecek } 231 1.1 jdolecek 232 1.5 drochner if (!(flag & DETACH_QUIET)) 233 1.14 cegger printf("%s: detached.\n", device_xname(ppbus->sc_dev)); 234 1.7 perry 235 1.1 jdolecek return 1; 236 1.1 jdolecek } 237 1.1 jdolecek 238 1.1 jdolecek /* Search for children device and add to list */ 239 1.1 jdolecek static int 240 1.20 chs ppbus_search_children(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 241 1.1 jdolecek { 242 1.14 cegger struct ppbus_softc *ppbus = device_private(parent); 243 1.5 drochner struct ppbus_device_softc *child; 244 1.20 chs device_t dev; 245 1.1 jdolecek int rval = 0; 246 1.1 jdolecek 247 1.22 thorpej if (config_probe(parent, cf, aux)) { 248 1.23 thorpej dev = config_attach(parent, cf, aux, NULL, CFARGS_NONE); 249 1.20 chs if (dev) { 250 1.20 chs child = device_private(dev); 251 1.20 chs SLIST_INSERT_HEAD(&(ppbus->sc_childlist_head), 252 1.20 chs child, entries); 253 1.1 jdolecek rval = 1; 254 1.1 jdolecek } 255 1.1 jdolecek } 256 1.1 jdolecek 257 1.1 jdolecek return rval; 258 1.1 jdolecek } 259 1.1 jdolecek 260