1/* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda 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) 1995, 1996, 1997, 1998 13 * NetBSD/pc98 porting staff. All rights reserved. 14 * Copyright (c) 1995, 1996, 1997, 1998 15 * Naofumi HONDA. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. The name of the author may not be used to endorse or promote products 26 * derived from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD$"); 43 44#include <sys/param.h> 45#include <sys/errno.h> 46#include <sys/kernel.h> 47#include <sys/malloc.h> 48#include <sys/module.h> 49#include <sys/systm.h> 50 51#include <machine/bus.h> 52#include <machine/resource.h> 53#include <sys/rman.h> 54#include <compat/netbsd/dvcfg.h> 55 56#include <sys/bus.h> 57 58#include <dev/pccard/pccardvar.h> 59 60#include <cam/scsi/scsi_low.h> 61 62#include <dev/ncv/ncr53c500reg.h> 63#include <dev/ncv/ncr53c500hw.h> 64#include <dev/ncv/ncr53c500var.h> 65 66#define KME_KXLC004_01 0x100 67#define OFFSET_KME_KXLC004_01 0x10 68 69 70#include "pccarddevs.h" 71 72static int ncvprobe(device_t devi); 73static int ncvattach(device_t devi); 74 75static void ncv_card_unload(device_t); 76 77static const struct ncv_product { 78 struct pccard_product prod; 79 int flags; 80} ncv_products[] = { 81 { PCMCIA_CARD(EPSON, SC200), 0}, 82 { PCMCIA_CARD(PANASONIC, KXLC002), 0xb4d00000 }, 83 { PCMCIA_CARD(PANASONIC, KXLC003), 0xb4d00000 }, /* untested */ 84 { PCMCIA_CARD(PANASONIC, KXLC004), 0xb4d00100 }, 85 { PCMCIA_CARD(MACNICA, MPS100), 0xb6250000 }, 86 { PCMCIA_CARD(MACNICA, MPS110), 0 }, 87 { PCMCIA_CARD(NEC, PC9801N_J03R), 0 }, 88 { PCMCIA_CARD(NEWMEDIA, BASICS_SCSI), 0 }, 89 { PCMCIA_CARD(QLOGIC, PC05), 0x84d00000 }, 90#define FLAGS_REX5572 0x84d00000 91 { PCMCIA_CARD(RATOC, REX5572), FLAGS_REX5572 }, 92 { PCMCIA_CARD(RATOC, REX9530), 0x84d00000 }, 93 { { NULL }, 0 } 94}; 95 96/* 97 * Additional code for FreeBSD new-bus PCCard frontend 98 */ 99 100static void 101ncv_pccard_intr(void * arg) 102{ 103 struct ncv_softc *sc; 104 105 sc = arg; 106 SCSI_LOW_LOCK(&sc->sc_sclow); 107 ncvintr(arg); 108 SCSI_LOW_UNLOCK(&sc->sc_sclow); 109} 110 111static void 112ncv_release_resource(device_t dev) 113{ 114 struct ncv_softc *sc = device_get_softc(dev); 115 116 if (sc->ncv_intrhand) { 117 bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); 118 } 119 120 if (sc->port_res) { 121 bus_release_resource(dev, SYS_RES_IOPORT, 122 sc->port_rid, sc->port_res); 123 } 124 125 if (sc->port_res_dmy) { 126 bus_release_resource(dev, SYS_RES_IOPORT, 127 sc->port_rid_dmy, sc->port_res_dmy); 128 } 129 130 if (sc->irq_res) { 131 bus_release_resource(dev, SYS_RES_IRQ, 132 sc->irq_rid, sc->irq_res); 133 } 134 135 if (sc->mem_res) { 136 bus_release_resource(dev, SYS_RES_MEMORY, 137 sc->mem_rid, sc->mem_res); 138 } 139 mtx_destroy(&sc->sc_sclow.sl_lock); 140} 141 142static int 143ncv_alloc_resource(device_t dev) 144{ 145 struct ncv_softc *sc = device_get_softc(dev); 146 u_int32_t flags = device_get_flags(dev); 147 rman_res_t ioaddr, iosize, maddr, msize; 148 int error; 149 bus_addr_t offset = 0; 150 151 if(flags & KME_KXLC004_01) 152 offset = OFFSET_KME_KXLC004_01; 153 154 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); 155 if (error || (iosize < (offset + NCVIOSZ))) { 156 return(ENOMEM); 157 } 158 159 mtx_init(&sc->sc_sclow.sl_lock, "ncv", NULL, MTX_DEF); 160 sc->port_rid = 0; 161 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 162 ioaddr+offset, ioaddr+iosize-offset, 163 iosize-offset, RF_ACTIVE); 164 if (sc->port_res == NULL) { 165 ncv_release_resource(dev); 166 return(ENOMEM); 167 } 168 169 if (offset != 0) { 170 sc->port_rid_dmy = 0; 171 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 172 &sc->port_rid_dmy, 173 ioaddr, ioaddr+offset, offset, 174 RF_ACTIVE); 175 if (sc->port_res_dmy == NULL) { 176 printf("Warning: cannot allocate IOPORT partially.\n"); 177 } 178 } else { 179 sc->port_rid_dmy = 0; 180 sc->port_res_dmy = NULL; 181 } 182 183 sc->irq_rid = 0; 184 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 185 RF_ACTIVE); 186 if (sc->irq_res == NULL) { 187 ncv_release_resource(dev); 188 return(ENOMEM); 189 } 190 191 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); 192 if (error) { 193 return(0); /* XXX */ 194 } 195 196 /* no need to allocate memory if not configured */ 197 if (maddr == 0 || msize == 0) { 198 return(0); 199 } 200 201 sc->mem_rid = 0; 202 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, 203 RF_ACTIVE); 204 if (sc->mem_res == NULL) { 205 ncv_release_resource(dev); 206 return(ENOMEM); 207 } 208 209 return(0); 210} 211 212static int 213ncv_pccard_probe(device_t dev) 214{ 215 const struct ncv_product *pp; 216 const char *vendorstr; 217 const char *prodstr; 218 219 if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, 220 (const struct pccard_product *) ncv_products, 221 sizeof(ncv_products[0]), NULL)) != NULL) { 222 if (pp->prod.pp_name != NULL) 223 device_set_desc(dev, pp->prod.pp_name); 224 device_set_flags(dev, pp->flags); 225 return(0); 226 } 227 if (pccard_get_vendor_str(dev, &vendorstr)) 228 return(EIO); 229 if (pccard_get_product_str(dev, &prodstr)) 230 return(EIO); 231 if (strcmp(vendorstr, "RATOC System Inc.") == 0 && 232 strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) { 233 device_set_desc(dev, "RATOC REX-5572"); 234 device_set_flags(dev, FLAGS_REX5572); 235 return (BUS_PROBE_DEFAULT); 236 } 237 return(EIO); 238} 239 240static int 241ncv_pccard_attach(device_t dev) 242{ 243 struct ncv_softc *sc = device_get_softc(dev); 244 int error; 245 246 error = ncv_alloc_resource(dev); 247 if (error) { 248 return(error); 249 } 250 251 if (ncvprobe(dev) == 0) { 252 ncv_release_resource(dev); 253 return(ENXIO); 254 } 255 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | 256 INTR_MPSAFE, NULL, ncv_pccard_intr, sc, &sc->ncv_intrhand); 257 if (error) { 258 ncv_release_resource(dev); 259 return(error); 260 } 261 262 if (ncvattach(dev) == 0) { 263 ncv_release_resource(dev); 264 return(ENXIO); 265 } 266 gone_in_dev(dev, 12, "ncv(4) driver"); 267 268 return(0); 269} 270 271static int 272ncv_pccard_detach(device_t dev) 273{ 274 ncv_card_unload(dev); 275 ncv_release_resource(dev); 276 277 return (0); 278} 279 280static device_method_t ncv_pccard_methods[] = { 281 /* Device interface */ 282 DEVMETHOD(device_probe, ncv_pccard_probe), 283 DEVMETHOD(device_attach, ncv_pccard_attach), 284 DEVMETHOD(device_detach, ncv_pccard_detach), 285 286 { 0, 0 } 287}; 288 289static driver_t ncv_pccard_driver = { 290 "ncv", 291 ncv_pccard_methods, 292 sizeof(struct ncv_softc), 293}; 294 295static devclass_t ncv_devclass; 296 297MODULE_DEPEND(ncv, scsi_low, 1, 1, 1); 298DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); 299PCCARD_PNP_INFO(ncv_products); 300 301static void 302ncv_card_unload(device_t devi) 303{ 304 struct ncv_softc *sc = device_get_softc(devi); 305 306 scsi_low_deactivate(&sc->sc_sclow); 307 scsi_low_detach(&sc->sc_sclow); 308} 309 310static int 311ncvprobe(device_t devi) 312{ 313 int rv; 314 struct ncv_softc *sc = device_get_softc(devi); 315 u_int32_t flags = device_get_flags(devi); 316 317 rv = ncvprobesubr(sc->port_res, 318 flags, NCV_HOSTID); 319 320 return rv; 321} 322 323static int 324ncvattach(device_t devi) 325{ 326 struct ncv_softc *sc; 327 struct scsi_low_softc *slp; 328 u_int32_t flags = device_get_flags(devi); 329 330 sc = device_get_softc(devi); 331 332 slp = &sc->sc_sclow; 333 slp->sl_dev = devi; 334 slp->sl_hostid = NCV_HOSTID; 335 slp->sl_cfgflags = flags; 336 337 ncvattachsubr(sc); 338 339 return(NCVIOSZ); 340} 341