1 /* $NetBSD: ppbus_conf.c,v 1.12 2007/12/05 07:58:31 ad 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.12 2007/12/05 07:58:31 ad 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 = device_private(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 mutex_init(&(ppbus->sc_lock), MUTEX_DEFAULT, IPL_NONE); 136 137 /* Set up bus mode and ieee state */ 138 ppbus->sc_mode = ppbus->ppbus_getmode(device_parent(self)); 139 ppbus->sc_use_ieee = 1; 140 ppbus->sc_1284_state = PPBUS_FORWARD_IDLE; 141 ppbus->sc_1284_error = PPBUS_NO_ERROR; 142 143 /* Record device's sucessful attachment */ 144 ppbus->sc_dev_ok = PPBUS_OK; 145 146 #ifndef DONTPROBE_1284 147 /* detect IEEE1284 compliant devices */ 148 if (ppbus_scan_bus(self)) { 149 printf("%s: No IEEE1284 device found.\n", self->dv_xname); 150 } else { 151 printf("%s: IEEE1284 device found.\n", self->dv_xname); 152 /* 153 * Detect device ID (interrupts must be disabled because we 154 * cannot do a ltsleep() to wait for it - no context) 155 */ 156 if (args.capabilities & PPBUS_HAS_INTR) { 157 int val = 0; 158 if(ppbus_write_ivar(self, PPBUS_IVAR_INTR, &val) != 0) { 159 printf(" <problem initializing interrupt " 160 "usage>"); 161 } 162 } 163 ppbus_pnp_detect(self); 164 } 165 #endif /* !DONTPROBE_1284 */ 166 167 /* Configure child devices */ 168 SLIST_INIT(&(ppbus->sc_childlist_head)); 169 config_search_ia(ppbus_search_children, self, "ppbus", &args); 170 171 return; 172 } 173 174 /* Detach function for ppbus. */ 175 static int 176 ppbus_detach(struct device *self, int flag) 177 { 178 struct ppbus_softc * ppbus = device_private(self); 179 struct ppbus_device_softc * child; 180 181 if (ppbus->sc_dev_ok != PPBUS_OK) { 182 if (!(flag & DETACH_QUIET)) 183 printf("%s: detach called on unattached device.\n", 184 ppbus->sc_dev.dv_xname); 185 if (!(flag & DETACH_FORCE)) 186 return 0; 187 if (!(flag & DETACH_QUIET)) 188 printf("%s: continuing detach (DETACH_FORCE).\n", 189 ppbus->sc_dev.dv_xname); 190 } 191 192 mutex_destroy(&(ppbus->sc_lock)); 193 194 /* Detach children devices */ 195 while (!SLIST_EMPTY(&(ppbus->sc_childlist_head))) { 196 child = SLIST_FIRST(&(ppbus->sc_childlist_head)); 197 config_deactivate((struct device *)child); 198 if (config_detach((struct device *)child, flag)) { 199 if(!(flag & DETACH_QUIET)) 200 printf("%s: error detaching %s.", 201 ppbus->sc_dev.dv_xname, 202 child->sc_dev.dv_xname); 203 if(!(flag & DETACH_FORCE)) 204 return 0; 205 if(!(flag & DETACH_QUIET)) 206 printf("%s: continuing (DETACH_FORCE).\n", 207 ppbus->sc_dev.dv_xname); 208 } 209 SLIST_REMOVE_HEAD(&(ppbus->sc_childlist_head), entries); 210 } 211 212 if (!(flag & DETACH_QUIET)) 213 printf("%s: detached.\n", ppbus->sc_dev.dv_xname); 214 215 return 1; 216 } 217 218 /* Search for children device and add to list */ 219 static int 220 ppbus_search_children(struct device *parent, struct cfdata *cf, 221 const int *ldesc, void *aux) 222 { 223 struct ppbus_softc *ppbus = (struct ppbus_softc *)parent; 224 struct ppbus_device_softc *child; 225 int rval = 0; 226 227 if (config_match(parent, cf, aux) > 0) { 228 child = (struct ppbus_device_softc *) config_attach(parent, 229 cf, aux, NULL); 230 if (child) { 231 SLIST_INSERT_HEAD(&(ppbus->sc_childlist_head), child, 232 entries); 233 rval = 1; 234 } 235 } 236 237 return rval; 238 } 239 240