ncr53c500_pccard.c revision 73280
1/* $FreeBSD: head/sys/dev/ncv/ncr53c500_pccard.c 73280 2001-03-01 17:09:09Z markm $ */ 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 <i386/isa/isa_device.h> 56 57#include <machine/dvcfg.h> 58 59#if defined(__FreeBSD__) && __FreeBSD_version < 400001 60static struct ncv_softc *ncv_get_softc(int); 61extern struct ncv_softc *ncvdata[]; 62#define DEVPORT_ALLOCSOFTCFUNC ncv_get_softc 63#define DEVPORT_SOFTCARRAY ncvdata 64#endif 65#include <sys/device_port.h> 66 67#include <cam/scsi/scsi_low.h> 68#include <cam/scsi/scsi_low_pisa.h> 69 70#include <dev/ncv/ncr53c500reg.h> 71#include <dev/ncv/ncr53c500hw.h> 72#include <dev/ncv/ncr53c500var.h> 73#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 400001) 74#include "ncv.h" 75#endif 76 77#define KME_KXLC004_01 0x100 78#define OFFSET_KME_KXLC004_01 0x10 79 80/* pccard support */ 81#include "card.h" 82#if NCARD > 0 83#include <sys/kernel.h> 84#include <sys/module.h> 85#if !defined(__FreeBSD__) || __FreeBSD_version < 500014 86#include <sys/select.h> 87#endif 88#include <pccard/cardinfo.h> 89#include <pccard/slot.h> 90 91static int ncvprobe(DEVPORT_PDEVICE devi); 92static int ncvattach(DEVPORT_PDEVICE devi); 93 94static void ncv_card_unload __P((DEVPORT_PDEVICE)); 95#if defined(__FreeBSD__) && __FreeBSD_version < 400001 96static int ncv_card_init __P((DEVPORT_PDEVICE)); 97static int ncv_card_intr __P((DEVPORT_PDEVICE)); 98#endif 99 100#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 101/* 102 * Additional code for FreeBSD new-bus PCCard frontend 103 */ 104 105static void 106ncv_pccard_intr(void * arg) 107{ 108 ncvintr(arg); 109} 110 111static void 112ncv_release_resource(DEVPORT_PDEVICE 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} 140 141static int 142ncv_alloc_resource(DEVPORT_PDEVICE dev) 143{ 144 struct ncv_softc *sc = device_get_softc(dev); 145 u_int32_t flags = DEVPORT_PDEVFLAGS(dev); 146 u_long ioaddr, iosize, maddr, msize; 147 int error; 148 bus_addr_t offset = 0; 149 150 if(flags & KME_KXLC004_01) 151 offset = OFFSET_KME_KXLC004_01; 152 153 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); 154 if (error || (iosize < (offset + NCVIOSZ))) { 155 return(ENOMEM); 156 } 157 158 sc->port_rid = 0; 159 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 160 ioaddr+offset, ioaddr+iosize-offset, 161 iosize-offset, RF_ACTIVE); 162 if (sc->port_res == NULL) { 163 ncv_release_resource(dev); 164 return(ENOMEM); 165 } 166 167 if (offset != 0) { 168 sc->port_rid_dmy = 0; 169 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 170 &sc->port_rid_dmy, 171 ioaddr, ioaddr+offset, offset, 172 RF_ACTIVE); 173 if (sc->port_res_dmy == NULL) { 174 printf("Warning: cannot allocate IOPORT partially.\n"); 175 } 176 } else { 177 sc->port_rid_dmy = 0; 178 sc->port_res_dmy = NULL; 179 } 180 181 sc->irq_rid = 0; 182 sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 183 0, ~0, 1, RF_ACTIVE); 184 if (sc->irq_res == NULL) { 185 ncv_release_resource(dev); 186 return(ENOMEM); 187 } 188 189 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); 190 if (error) { 191 return(0); /* XXX */ 192 } 193 194 /* no need to allocate memory if not configured */ 195 if (maddr == 0 || msize == 0) { 196 return(0); 197 } 198 199 sc->mem_rid = 0; 200 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 201 0, ~0, msize, RF_ACTIVE); 202 if (sc->mem_res == NULL) { 203 ncv_release_resource(dev); 204 return(ENOMEM); 205 } 206 207 return(0); 208} 209 210static int 211ncv_pccard_probe(DEVPORT_PDEVICE dev) 212{ 213 struct ncv_softc *sc = device_get_softc(dev); 214 int error; 215 216 bzero(sc, sizeof(struct ncv_softc)); 217 218 error = ncv_alloc_resource(dev); 219 if (error) { 220 return(error); 221 } 222 223 if (ncvprobe(dev) == 0) { 224 ncv_release_resource(dev); 225 return(ENXIO); 226 } 227 228 ncv_release_resource(dev); 229 230 return(0); 231} 232 233static int 234ncv_pccard_attach(DEVPORT_PDEVICE dev) 235{ 236 struct ncv_softc *sc = device_get_softc(dev); 237 int error; 238 239 error = ncv_alloc_resource(dev); 240 if (error) { 241 return(error); 242 } 243 244 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, 245 ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand); 246 if (error) { 247 ncv_release_resource(dev); 248 return(error); 249 } 250 251 if (ncvattach(dev) == 0) { 252 ncv_release_resource(dev); 253 return(ENXIO); 254 } 255 256 return(0); 257} 258 259static void 260ncv_pccard_detach(DEVPORT_PDEVICE dev) 261{ 262 ncv_card_unload(dev); 263 ncv_release_resource(dev); 264} 265 266static device_method_t ncv_pccard_methods[] = { 267 /* Device interface */ 268 DEVMETHOD(device_probe, ncv_pccard_probe), 269 DEVMETHOD(device_attach, ncv_pccard_attach), 270 DEVMETHOD(device_detach, ncv_pccard_detach), 271 272 { 0, 0 } 273}; 274 275static driver_t ncv_pccard_driver = { 276 "ncv", 277 ncv_pccard_methods, 278 sizeof(struct ncv_softc), 279}; 280 281static devclass_t ncv_devclass; 282 283DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); 284 285#else 286 287PCCARD_MODULE(ncv, ncv_card_init, ncv_card_unload, ncv_card_intr, 0, cam_imask); 288 289#endif 290 291#if defined(__FreeBSD__) && __FreeBSD_version < 400001 292static struct ncv_softc * 293ncv_get_softc(int unit) 294{ 295 struct ncv_softc *sc; 296 297 if (unit >= NNCV) { 298 return(NULL); 299 } 300 301 if (ncvdata[unit] == NULL) { 302 sc = malloc(sizeof(struct ncv_softc), M_TEMP,M_NOWAIT); 303 if (sc == NULL) { 304 printf("ncv_get_softc: cannot malloc!\n"); 305 return(NULL); 306 } 307 ncvdata[unit] = sc; 308 } else { 309 sc = ncvdata[unit]; 310 } 311 312 return(sc); 313} 314 315static int 316ncv_card_init(DEVPORT_PDEVICE devi) 317{ 318 int unit = DEVPORT_PDEVUNIT(devi); 319 320 if (NNCV <= unit) 321 return (ENODEV); 322 323 if (ncvprobe(devi) == 0) 324 return (ENXIO); 325 326 if (ncvattach(devi) == 0) 327 return (ENXIO); 328 return (0); 329} 330 331static int 332ncv_card_intr(DEVPORT_PDEVICE devi) 333{ 334 335 ncvintr(DEVPORT_PDEVGET_SOFTC(devi)); 336 return 1; 337} 338#endif 339 340static void 341ncv_card_unload(DEVPORT_PDEVICE devi) 342{ 343 struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); 344 345 printf("%s: unload\n", sc->sc_sclow.sl_xname); 346 scsi_low_deactivate((struct scsi_low_softc *)sc); 347 scsi_low_dettach(&sc->sc_sclow); 348} 349 350static int 351ncvprobe(DEVPORT_PDEVICE devi) 352{ 353 int rv; 354 struct ncv_softc *sc = device_get_softc(devi); 355 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 356 357#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 358 rv = ncvprobesubr(rman_get_bustag(sc->port_res), 359 rman_get_bushandle(sc->port_res), 360 flags, NCV_HOSTID); 361#else 362 bus_addr_t offset = 0; 363 u_int iobase = DEVPORT_PDEVIOBASE(devi); 364 365 if(flags & KME_KXLC004_01) 366 offset = OFFSET_KME_KXLC004_01; 367 368 rv = ncvprobesubr(I386_BUS_SPACE_IO, 369 iobase + offset, 370 flags, NCV_HOSTID); 371#endif 372 373 return rv; 374} 375 376static int 377ncvattach(DEVPORT_PDEVICE devi) 378{ 379 struct ncv_softc *sc; 380 struct scsi_low_softc *slp; 381 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 382#if defined(__FreeBSD__) && __FreeBSD_version < 400001 383 int unit = DEVPORT_PDEVUNIT(devi); 384 bus_addr_t offset = 0; 385 u_int iobase = DEVPORT_PDEVIOBASE(devi); 386#endif 387 char dvname[16]; /* SCSI_LOW_DVNAME_LEN */ 388 389 strcpy(dvname, "ncv"); 390 391#if defined(__FreeBSD__) && __FreeBSD_version < 400001 392 if (unit >= NNCV) 393 { 394 printf("%s: unit number too high\n", dvname); 395 return (0); 396 } 397 398 if (iobase == 0) 399 { 400 printf("%s: no ioaddr is given\n", dvname); 401 return (0); 402 } 403 404 if(flags & KME_KXLC004_01) 405 offset = OFFSET_KME_KXLC004_01; 406#endif 407 408 sc = DEVPORT_PDEVALLOC_SOFTC(devi); 409 if (sc == NULL) { 410 return(0); 411 } 412 413 slp = &sc->sc_sclow; 414#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 415 slp->sl_dev = devi; 416 sc->sc_iot = rman_get_bustag(sc->port_res); 417 sc->sc_ioh = rman_get_bushandle(sc->port_res); 418#else 419 bzero(sc, sizeof(struct ncv_softc)); 420 strcpy(slp->sl_dev.dv_xname, dvname); 421 slp->sl_dev.dv_unit = unit; 422 sc->sc_iot = I386_BUS_SPACE_IO; 423 sc->sc_ioh = iobase + offset; 424#endif 425 426 slp->sl_hostid = NCV_HOSTID; 427 slp->sl_cfgflags = flags; 428 429 ncvattachsubr(sc); 430 431 sc->sc_ih = ncvintr; 432 433 return(NCVIOSZ); 434} 435#endif /* NCARD */ 436