ncr53c500_pccard.c revision 87983
1/* $FreeBSD: head/sys/dev/ncv/ncr53c500_pccard.c 87983 2001-12-15 12:32:23Z non $ */ 2/* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $ */ 3/* $NetBSD$ */ 4 5/* 6 * [Ported for FreeBSD] 7 * Copyright (c) 2000 8 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. 9 * All rights reserved. 10 * [NetBSD for NEC PC-98 series] 11 * Copyright (c) 1995, 1996, 1997, 1998 12 * NetBSD/pc98 porting staff. All rights reserved. 13 * Copyright (c) 1995, 1996, 1997, 1998 14 * Naofumi HONDA. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. The name of the author may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/disklabel.h> 43#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 44#include <sys/bio.h> 45#endif 46#include <sys/buf.h> 47#include <sys/queue.h> 48#include <sys/malloc.h> 49#include <sys/errno.h> 50 51#include <vm/vm.h> 52 53#include <machine/bus.h> 54#include <machine/bus_pio.h> 55#include <machine/dvcfg.h> 56 57#include <sys/device_port.h> 58 59#include <cam/scsi/scsi_low.h> 60#include <cam/scsi/scsi_low_pisa.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#include <sys/kernel.h> 70#include <sys/module.h> 71#if !defined(__FreeBSD__) || __FreeBSD_version < 500014 72#include <sys/select.h> 73#endif 74#include <pccard/cardinfo.h> 75#include <pccard/slot.h> 76 77static int ncvprobe(DEVPORT_PDEVICE devi); 78static int ncvattach(DEVPORT_PDEVICE devi); 79 80static void ncv_card_unload __P((DEVPORT_PDEVICE)); 81 82/* 83 * Additional code for FreeBSD new-bus PCCard frontend 84 */ 85 86static void 87ncv_pccard_intr(void * arg) 88{ 89 ncvintr(arg); 90} 91 92static void 93ncv_release_resource(DEVPORT_PDEVICE dev) 94{ 95 struct ncv_softc *sc = device_get_softc(dev); 96 97 if (sc->ncv_intrhand) { 98 bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); 99 } 100 101 if (sc->port_res) { 102 bus_release_resource(dev, SYS_RES_IOPORT, 103 sc->port_rid, sc->port_res); 104 } 105 106 if (sc->port_res_dmy) { 107 bus_release_resource(dev, SYS_RES_IOPORT, 108 sc->port_rid_dmy, sc->port_res_dmy); 109 } 110 111 if (sc->irq_res) { 112 bus_release_resource(dev, SYS_RES_IRQ, 113 sc->irq_rid, sc->irq_res); 114 } 115 116 if (sc->mem_res) { 117 bus_release_resource(dev, SYS_RES_MEMORY, 118 sc->mem_rid, sc->mem_res); 119 } 120} 121 122static int 123ncv_alloc_resource(DEVPORT_PDEVICE dev) 124{ 125 struct ncv_softc *sc = device_get_softc(dev); 126 u_int32_t flags = DEVPORT_PDEVFLAGS(dev); 127 u_long ioaddr, iosize, maddr, msize; 128 int error; 129 bus_addr_t offset = 0; 130 131 if(flags & KME_KXLC004_01) 132 offset = OFFSET_KME_KXLC004_01; 133 134 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); 135 if (error || (iosize < (offset + NCVIOSZ))) { 136 return(ENOMEM); 137 } 138 139 sc->port_rid = 0; 140 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 141 ioaddr+offset, ioaddr+iosize-offset, 142 iosize-offset, RF_ACTIVE); 143 if (sc->port_res == NULL) { 144 ncv_release_resource(dev); 145 return(ENOMEM); 146 } 147 148 if (offset != 0) { 149 sc->port_rid_dmy = 0; 150 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 151 &sc->port_rid_dmy, 152 ioaddr, ioaddr+offset, offset, 153 RF_ACTIVE); 154 if (sc->port_res_dmy == NULL) { 155 printf("Warning: cannot allocate IOPORT partially.\n"); 156 } 157 } else { 158 sc->port_rid_dmy = 0; 159 sc->port_res_dmy = NULL; 160 } 161 162 sc->irq_rid = 0; 163 sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 164 0, ~0, 1, RF_ACTIVE); 165 if (sc->irq_res == NULL) { 166 ncv_release_resource(dev); 167 return(ENOMEM); 168 } 169 170 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); 171 if (error) { 172 return(0); /* XXX */ 173 } 174 175 /* no need to allocate memory if not configured */ 176 if (maddr == 0 || msize == 0) { 177 return(0); 178 } 179 180 sc->mem_rid = 0; 181 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 182 0, ~0, 1, RF_ACTIVE); 183 if (sc->mem_res == NULL) { 184 ncv_release_resource(dev); 185 return(ENOMEM); 186 } 187 188 return(0); 189} 190 191static int 192ncv_pccard_probe(DEVPORT_PDEVICE dev) 193{ 194 struct ncv_softc *sc = device_get_softc(dev); 195 int error; 196 197 bzero(sc, sizeof(struct ncv_softc)); 198 199 error = ncv_alloc_resource(dev); 200 if (error) { 201 return(error); 202 } 203 204 if (ncvprobe(dev) == 0) { 205 ncv_release_resource(dev); 206 return(ENXIO); 207 } 208 209 ncv_release_resource(dev); 210 211 return(0); 212} 213 214static int 215ncv_pccard_attach(DEVPORT_PDEVICE dev) 216{ 217 struct ncv_softc *sc = device_get_softc(dev); 218 int error; 219 220 error = ncv_alloc_resource(dev); 221 if (error) { 222 return(error); 223 } 224 225 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, 226 ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand); 227 if (error) { 228 ncv_release_resource(dev); 229 return(error); 230 } 231 232 if (ncvattach(dev) == 0) { 233 ncv_release_resource(dev); 234 return(ENXIO); 235 } 236 237 return(0); 238} 239 240static void 241ncv_pccard_detach(DEVPORT_PDEVICE dev) 242{ 243 ncv_card_unload(dev); 244 ncv_release_resource(dev); 245} 246 247static device_method_t ncv_pccard_methods[] = { 248 /* Device interface */ 249 DEVMETHOD(device_probe, ncv_pccard_probe), 250 DEVMETHOD(device_attach, ncv_pccard_attach), 251 DEVMETHOD(device_detach, ncv_pccard_detach), 252 253 { 0, 0 } 254}; 255 256static driver_t ncv_pccard_driver = { 257 "ncv", 258 ncv_pccard_methods, 259 sizeof(struct ncv_softc), 260}; 261 262static devclass_t ncv_devclass; 263 264MODULE_DEPEND(ncv, scsi_low, 1, 1, 1); 265DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); 266 267static void 268ncv_card_unload(DEVPORT_PDEVICE devi) 269{ 270 struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); 271 intrmask_t s; 272 273 printf("%s: unload\n", sc->sc_sclow.sl_xname); 274 s = splcam(); 275 scsi_low_deactivate((struct scsi_low_softc *)sc); 276 scsi_low_dettach(&sc->sc_sclow); 277 splx(s); 278} 279 280static int 281ncvprobe(DEVPORT_PDEVICE devi) 282{ 283 int rv; 284 struct ncv_softc *sc = device_get_softc(devi); 285 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 286 287 rv = ncvprobesubr(rman_get_bustag(sc->port_res), 288 rman_get_bushandle(sc->port_res), 289 flags, NCV_HOSTID); 290 291 return rv; 292} 293 294static int 295ncvattach(DEVPORT_PDEVICE devi) 296{ 297 struct ncv_softc *sc; 298 struct scsi_low_softc *slp; 299 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 300 intrmask_t s; 301 char dvname[16]; /* SCSI_LOW_DVNAME_LEN */ 302 303 strcpy(dvname, "ncv"); 304 305 sc = DEVPORT_PDEVALLOC_SOFTC(devi); 306 if (sc == NULL) { 307 return(0); 308 } 309 310 slp = &sc->sc_sclow; 311 slp->sl_dev = devi; 312 sc->sc_iot = rman_get_bustag(sc->port_res); 313 sc->sc_ioh = rman_get_bushandle(sc->port_res); 314 315 slp->sl_hostid = NCV_HOSTID; 316 slp->sl_cfgflags = flags; 317 318 s = splcam(); 319 ncvattachsubr(sc); 320 splx(s); 321 322 return(NCVIOSZ); 323} 324