1/* $NecBSD: nsp_pisa.c,v 1.4 1999/04/15 01:35:54 kmatsuda Exp $ */ 2/* $NetBSD$ */ 3 4/*- 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * [Ported for FreeBSD] 8 * Copyright (c) 2000 9 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. 10 * All rights reserved. 11 * [NetBSD for NEC PC-98 series] 12 * Copyright (c) 1998 13 * NetBSD/pc98 porting staff. All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 3. The name of the author may not be used to endorse or promote products 24 * derived from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD$"); 41 42#include <sys/param.h> 43#include <sys/bus.h> 44#include <sys/errno.h> 45#include <sys/kernel.h> 46#include <sys/malloc.h> 47#include <sys/module.h> 48#include <sys/systm.h> 49 50#include <machine/bus.h> 51#include <machine/resource.h> 52#include <sys/rman.h> 53 54#include <sys/bus.h> 55 56#include <dev/pccard/pccardvar.h> 57 58#include <cam/scsi/scsi_low.h> 59 60#include <dev/nsp/nspreg.h> 61#include <dev/nsp/nspvar.h> 62 63#define NSP_HOSTID 7 64 65#include "pccarddevs.h" 66 67#define PIO_MODE 0x100 /* pd_flags */ 68 69static int nspprobe(device_t devi); 70static int nspattach(device_t devi); 71 72static void nsp_card_unload (device_t); 73 74const struct pccard_product nsp_products[] = { 75 PCMCIA_CARD(IODATA3, CBSC16), 76 PCMCIA_CARD(PANASONIC, KME), 77 PCMCIA_CARD(WORKBIT2, NINJA_SCSI3), 78 PCMCIA_CARD(WORKBIT, ULTRA_NINJA_16), 79 { NULL } 80}; 81 82/* 83 * Additional code for FreeBSD new-bus PC Card frontend 84 */ 85 86static void 87nsp_pccard_intr(void * arg) 88{ 89 struct nsp_softc *sc; 90 91 sc = arg; 92 SCSI_LOW_LOCK(&sc->sc_sclow); 93 nspintr(sc); 94 SCSI_LOW_UNLOCK(&sc->sc_sclow); 95} 96 97static void 98nsp_release_resource(device_t dev) 99{ 100 struct nsp_softc *sc = device_get_softc(dev); 101 102 if (sc->nsp_intrhand) 103 bus_teardown_intr(dev, sc->irq_res, sc->nsp_intrhand); 104 if (sc->port_res) 105 bus_release_resource(dev, SYS_RES_IOPORT, 106 sc->port_rid, sc->port_res); 107 if (sc->irq_res) 108 bus_release_resource(dev, SYS_RES_IRQ, 109 sc->irq_rid, sc->irq_res); 110 if (sc->mem_res) 111 bus_release_resource(dev, SYS_RES_MEMORY, 112 sc->mem_rid, sc->mem_res); 113 mtx_destroy(&sc->sc_sclow.sl_lock); 114} 115 116static int 117nsp_alloc_resource(device_t dev) 118{ 119 struct nsp_softc *sc = device_get_softc(dev); 120 rman_res_t ioaddr, iosize, maddr, msize; 121 int error; 122 123 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); 124 if (error || iosize < NSP_IOSIZE) 125 return(ENOMEM); 126 127 mtx_init(&sc->sc_sclow.sl_lock, "nsp", NULL, MTX_DEF); 128 sc->port_rid = 0; 129 sc->port_res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, 130 &sc->port_rid, NSP_IOSIZE, 131 RF_ACTIVE); 132 if (sc->port_res == NULL) { 133 nsp_release_resource(dev); 134 return(ENOMEM); 135 } 136 137 sc->irq_rid = 0; 138 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 139 RF_ACTIVE); 140 if (sc->irq_res == NULL) { 141 nsp_release_resource(dev); 142 return(ENOMEM); 143 } 144 145 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); 146 if (error) 147 return(0); /* XXX */ 148 149 /* No need to allocate memory if not configured and it's in PIO mode */ 150 if (maddr == 0 || msize == 0) { 151 if ((device_get_flags(dev) & PIO_MODE) == 0) { 152 printf("Memory window was not configured. Configure or use in PIO mode."); 153 nsp_release_resource(dev); 154 return(ENOMEM); 155 } 156 /* no need to allocate memory if PIO mode */ 157 return(0); 158 } 159 160 sc->mem_rid = 0; 161 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 162 RF_ACTIVE); 163 if (sc->mem_res == NULL) { 164 nsp_release_resource(dev); 165 return(ENOMEM); 166 } 167 168 return(0); 169} 170 171static int 172nsp_pccard_probe(device_t dev) 173{ 174 const struct pccard_product *pp; 175 176 if ((pp = pccard_product_lookup(dev, nsp_products, 177 sizeof(nsp_products[0]), NULL)) != NULL) { 178 if (pp->pp_name) 179 device_set_desc(dev, pp->pp_name); 180 return (BUS_PROBE_DEFAULT); 181 } 182 return(EIO); 183} 184 185static int 186nsp_pccard_attach(device_t dev) 187{ 188 struct nsp_softc *sc = device_get_softc(dev); 189 int error; 190 191 error = nsp_alloc_resource(dev); 192 if (error) 193 return(error); 194 if (nspprobe(dev) == 0) { 195 nsp_release_resource(dev); 196 return(ENXIO); 197 } 198 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | 199 INTR_MPSAFE, NULL, nsp_pccard_intr, sc, &sc->nsp_intrhand); 200 if (error) { 201 nsp_release_resource(dev); 202 return(error); 203 } 204 if (nspattach(dev) == 0) { 205 nsp_release_resource(dev); 206 return(ENXIO); 207 } 208 gone_in_dev(dev, 12, "nsp(4) driver"); 209 210 return(0); 211} 212 213static int 214nsp_pccard_detach(device_t dev) 215{ 216 nsp_card_unload(dev); 217 nsp_release_resource(dev); 218 219 return (0); 220} 221 222static device_method_t nsp_pccard_methods[] = { 223 /* Device interface */ 224 DEVMETHOD(device_probe, nsp_pccard_probe), 225 DEVMETHOD(device_attach, nsp_pccard_attach), 226 DEVMETHOD(device_detach, nsp_pccard_detach), 227 { 0, 0 } 228}; 229 230static driver_t nsp_pccard_driver = { 231 "nsp", 232 nsp_pccard_methods, 233 sizeof(struct nsp_softc), 234}; 235 236static devclass_t nsp_devclass; 237 238MODULE_DEPEND(nsp, scsi_low, 1, 1, 1); 239DRIVER_MODULE(nsp, pccard, nsp_pccard_driver, nsp_devclass, 0, 0); 240PCCARD_PNP_INFO(nsp_products); 241 242static void 243nsp_card_unload(device_t devi) 244{ 245 struct nsp_softc *sc = device_get_softc(devi); 246 247 scsi_low_deactivate(&sc->sc_sclow); 248 scsi_low_detach(&sc->sc_sclow); 249} 250 251static int 252nspprobe(device_t devi) 253{ 254 int rv; 255 struct nsp_softc *sc = device_get_softc(devi); 256 257 rv = nspprobesubr(sc->port_res, 258 device_get_flags(devi)); 259 260 return rv; 261} 262 263static int 264nspattach(device_t devi) 265{ 266 struct nsp_softc *sc; 267 struct scsi_low_softc *slp; 268 u_int32_t flags = device_get_flags(devi); 269 u_int iobase = bus_get_resource_start(devi, SYS_RES_IOPORT, 0); 270 271 if (iobase == 0) { 272 device_printf(devi, "no ioaddr is given\n"); 273 return (ENXIO); 274 } 275 276 sc = device_get_softc(devi); 277 slp = &sc->sc_sclow; 278 slp->sl_dev = devi; 279 280 if (sc->mem_res == NULL) { 281 device_printf(devi, 282 "WARNING: CANNOT GET Memory RESOURCE going PIO mode\n"); 283 flags |= PIO_MODE; 284 } 285 286 /* slp->sl_irq = devi->pd_irq; */ 287 sc->sc_iclkdiv = CLKDIVR_20M; 288 sc->sc_clkdiv = CLKDIVR_40M; 289 290 slp->sl_hostid = NSP_HOSTID; 291 slp->sl_cfgflags = flags; 292 293 nspattachsubr(sc); 294 295 return(NSP_IOSIZE); 296} 297