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