1/* $NetBSD: ppbus_conf.c,v 1.23 2021/08/07 16:19:15 thorpej 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.23 2021/08/07 16:19:15 thorpej 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 successful 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(self, &args, 174 CFARGS(.search = ppbus_search_children, 175 .iattr = "ppbus")); 176 177#if NGPIO > 0 178 gpio_ppbus_attach(ppbus); 179#endif 180 return; 181} 182 183static void 184ppbus_childdet(device_t self, device_t target) 185{ 186 struct ppbus_softc * ppbus = device_private(self); 187 struct ppbus_device_softc * child; 188 189 SLIST_FOREACH(child, &ppbus->sc_childlist_head, entries) { 190 if (child->sc_dev == target) 191 break; 192 } 193 if (child != NULL) 194 SLIST_REMOVE(&ppbus->sc_childlist_head, child, 195 ppbus_device_softc, entries); 196} 197 198/* Detach function for ppbus. */ 199static int 200ppbus_detach(device_t self, int flag) 201{ 202 struct ppbus_softc * ppbus = device_private(self); 203 struct ppbus_device_softc * child; 204 205 if (ppbus->sc_dev_ok != PPBUS_OK) { 206 if (!(flag & DETACH_QUIET)) 207 printf("%s: detach called on unattached device.\n", 208 device_xname(ppbus->sc_dev)); 209 if (!(flag & DETACH_FORCE)) 210 return 0; 211 if (!(flag & DETACH_QUIET)) 212 printf("%s: continuing detach (DETACH_FORCE).\n", 213 device_xname(ppbus->sc_dev)); 214 } 215 216 mutex_destroy(&(ppbus->sc_lock)); 217 218 /* Detach children devices */ 219 while ((child = SLIST_FIRST(&ppbus->sc_childlist_head)) != NULL) { 220 if (config_detach(child->sc_dev, flag)) { 221 if(!(flag & DETACH_QUIET)) 222 aprint_error_dev(ppbus->sc_dev, "error detaching %s.", 223 device_xname(child->sc_dev)); 224 if(!(flag & DETACH_FORCE)) 225 return 0; 226 if(!(flag & DETACH_QUIET)) 227 printf("%s: continuing (DETACH_FORCE).\n", 228 device_xname(ppbus->sc_dev)); 229 } 230 } 231 232 if (!(flag & DETACH_QUIET)) 233 printf("%s: detached.\n", device_xname(ppbus->sc_dev)); 234 235 return 1; 236} 237 238/* Search for children device and add to list */ 239static int 240ppbus_search_children(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 241{ 242 struct ppbus_softc *ppbus = device_private(parent); 243 struct ppbus_device_softc *child; 244 device_t dev; 245 int rval = 0; 246 247 if (config_probe(parent, cf, aux)) { 248 dev = config_attach(parent, cf, aux, NULL, CFARGS_NONE); 249 if (dev) { 250 child = device_private(dev); 251 SLIST_INSERT_HEAD(&(ppbus->sc_childlist_head), 252 child, entries); 253 rval = 1; 254 } 255 } 256 257 return rval; 258} 259 260