1 /* $NetBSD: ppbus_conf.c,v 1.16 2008/04/29 14:07:37 cegger 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.16 2008/04/29 14:07:37 cegger Exp $"); 34 35 #include "opt_ppbus.h" 36 #include "opt_ppbus_1284.h" 37 38 #include "gpio.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/device.h> 44 #include <sys/proc.h> 45 46 #include <dev/ppbus/ppbus_1284.h> 47 #include <dev/ppbus/ppbus_base.h> 48 #include <dev/ppbus/ppbus_conf.h> 49 #include <dev/ppbus/ppbus_device.h> 50 #include <dev/ppbus/ppbus_var.h> 51 52 /* Probe, attach, and detach functions for ppbus. */ 53 static int ppbus_probe(device_t, cfdata_t, void *); 54 static void ppbus_attach(device_t, device_t, void *); 55 static int ppbus_detach(device_t, int); 56 57 /* Utility function prototypes */ 58 static int ppbus_search_children(device_t, cfdata_t, 59 const int *, void *); 60 61 62 CFATTACH_DECL_NEW(ppbus, sizeof(struct ppbus_softc), ppbus_probe, ppbus_attach, 63 ppbus_detach, NULL); 64 65 /* Probe function for ppbus. */ 66 static int 67 ppbus_probe(device_t parent, cfdata_t cf, void *aux) 68 { 69 struct parport_adapter *sc_link = aux; 70 71 /* Check adapter for consistency */ 72 if ( 73 /* Required methods for all parports */ 74 sc_link->parport_io == NULL || 75 sc_link->parport_exec_microseq == NULL || 76 sc_link->parport_setmode == NULL || 77 sc_link->parport_getmode == NULL || 78 sc_link->parport_read == NULL || 79 sc_link->parport_write == NULL || 80 sc_link->parport_read_ivar == NULL || 81 sc_link->parport_write_ivar == NULL || 82 /* Methods which conditional exist based on capabilities */ 83 ((sc_link->capabilities & PPBUS_HAS_EPP) && 84 (sc_link->parport_reset_epp_timeout == NULL)) || 85 ((sc_link->capabilities & PPBUS_HAS_ECP) && 86 (sc_link->parport_ecp_sync == NULL)) || 87 ((sc_link->capabilities & PPBUS_HAS_DMA) && 88 (sc_link->parport_dma_malloc == NULL || 89 sc_link->parport_dma_free == NULL)) || 90 ((sc_link->capabilities & PPBUS_HAS_INTR) && 91 (sc_link->parport_add_handler == NULL || 92 sc_link->parport_remove_handler == NULL)) 93 ) { 94 95 #ifdef PPBUS_DEBUG 96 printf("%s(%s): parport_adaptor is incomplete. Child device " 97 "probe failed.\n", __func__, device_xname(parent)); 98 #endif 99 return 0; 100 } else { 101 return 1; 102 } 103 } 104 105 /* Attach function for ppbus. */ 106 static void 107 ppbus_attach(device_t parent, device_t self, void *aux) 108 { 109 struct ppbus_softc *ppbus = device_private(self); 110 struct parport_adapter *sc_link = aux; 111 struct ppbus_attach_args args; 112 113 printf("\n"); 114 115 /* Initialize config data from adapter (bus + device methods) */ 116 ppbus->sc_dev = self; 117 args.capabilities = ppbus->sc_capabilities = sc_link->capabilities; 118 ppbus->ppbus_io = sc_link->parport_io; 119 ppbus->ppbus_exec_microseq = sc_link->parport_exec_microseq; 120 ppbus->ppbus_reset_epp_timeout = sc_link-> 121 parport_reset_epp_timeout; 122 ppbus->ppbus_setmode = sc_link->parport_setmode; 123 ppbus->ppbus_getmode = sc_link->parport_getmode; 124 ppbus->ppbus_ecp_sync = sc_link->parport_ecp_sync; 125 ppbus->ppbus_read = sc_link->parport_read; 126 ppbus->ppbus_write = sc_link->parport_write; 127 ppbus->ppbus_read_ivar = sc_link->parport_read_ivar; 128 ppbus->ppbus_write_ivar = sc_link->parport_write_ivar; 129 ppbus->ppbus_dma_malloc = sc_link->parport_dma_malloc; 130 ppbus->ppbus_dma_free = sc_link->parport_dma_free; 131 ppbus->ppbus_add_handler = sc_link->parport_add_handler; 132 ppbus->ppbus_remove_handler = sc_link->parport_remove_handler; 133 134 /* Initially there is no device owning the bus */ 135 ppbus->ppbus_owner = NULL; 136 137 /* Initialize locking structures */ 138 mutex_init(&(ppbus->sc_lock), MUTEX_DEFAULT, IPL_NONE); 139 140 /* Set up bus mode and ieee state */ 141 ppbus->sc_mode = ppbus->ppbus_getmode(device_parent(self)); 142 ppbus->sc_use_ieee = 1; 143 ppbus->sc_1284_state = PPBUS_FORWARD_IDLE; 144 ppbus->sc_1284_error = PPBUS_NO_ERROR; 145 146 /* Record device's sucessful attachment */ 147 ppbus->sc_dev_ok = PPBUS_OK; 148 149 #ifndef DONTPROBE_1284 150 /* detect IEEE1284 compliant devices */ 151 if (ppbus_scan_bus(self)) { 152 printf("%s: No IEEE1284 device found.\n", device_xname(self)); 153 } else { 154 printf("%s: IEEE1284 device found.\n", device_xname(self)); 155 /* 156 * Detect device ID (interrupts must be disabled because we 157 * cannot do a ltsleep() to wait for it - no context) 158 */ 159 if (args.capabilities & PPBUS_HAS_INTR) { 160 int val = 0; 161 if(ppbus_write_ivar(self, PPBUS_IVAR_INTR, &val) != 0) { 162 printf(" <problem initializing interrupt " 163 "usage>"); 164 } 165 } 166 ppbus_pnp_detect(self); 167 } 168 #endif /* !DONTPROBE_1284 */ 169 170 /* Configure child devices */ 171 SLIST_INIT(&(ppbus->sc_childlist_head)); 172 config_search_ia(ppbus_search_children, self, "ppbus", &args); 173 174 #if NGPIO > 0 175 gpio_ppbus_attach(ppbus); 176 #endif 177 return; 178 } 179 180 /* Detach function for ppbus. */ 181 static int 182 ppbus_detach(device_t self, int flag) 183 { 184 struct ppbus_softc * ppbus = device_private(self); 185 struct ppbus_device_softc * child; 186 187 if (ppbus->sc_dev_ok != PPBUS_OK) { 188 if (!(flag & DETACH_QUIET)) 189 printf("%s: detach called on unattached device.\n", 190 device_xname(ppbus->sc_dev)); 191 if (!(flag & DETACH_FORCE)) 192 return 0; 193 if (!(flag & DETACH_QUIET)) 194 printf("%s: continuing detach (DETACH_FORCE).\n", 195 device_xname(ppbus->sc_dev)); 196 } 197 198 mutex_destroy(&(ppbus->sc_lock)); 199 200 /* Detach children devices */ 201 while (!SLIST_EMPTY(&(ppbus->sc_childlist_head))) { 202 child = SLIST_FIRST(&(ppbus->sc_childlist_head)); 203 config_deactivate(child->sc_dev); 204 if (config_detach(child->sc_dev, flag)) { 205 if(!(flag & DETACH_QUIET)) 206 aprint_error_dev(ppbus->sc_dev, "error detaching %s.", 207 device_xname(child->sc_dev)); 208 if(!(flag & DETACH_FORCE)) 209 return 0; 210 if(!(flag & DETACH_QUIET)) 211 printf("%s: continuing (DETACH_FORCE).\n", 212 device_xname(ppbus->sc_dev)); 213 } 214 SLIST_REMOVE_HEAD(&(ppbus->sc_childlist_head), entries); 215 } 216 217 if (!(flag & DETACH_QUIET)) 218 printf("%s: detached.\n", device_xname(ppbus->sc_dev)); 219 220 return 1; 221 } 222 223 /* Search for children device and add to list */ 224 static int 225 ppbus_search_children(device_t parent, cfdata_t cf, 226 const int *ldesc, void *aux) 227 { 228 struct ppbus_softc *ppbus = device_private(parent); 229 struct ppbus_device_softc *child; 230 int rval = 0; 231 232 if (config_match(parent, cf, aux) > 0) { 233 child = (struct ppbus_device_softc *) config_attach(parent, 234 cf, aux, NULL); 235 if (child) { 236 SLIST_INSERT_HEAD(&(ppbus->sc_childlist_head), child, 237 entries); 238 rval = 1; 239 } 240 } 241 242 return rval; 243 } 244 245