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