ncr53c500_pccard.c revision 119418
1/* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $ */ 2/* $NetBSD$ */ 3 4/* 5 * [Ported for FreeBSD] 6 * Copyright (c) 2000 7 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. 8 * All rights reserved. 9 * [NetBSD for NEC PC-98 series] 10 * Copyright (c) 1995, 1996, 1997, 1998 11 * NetBSD/pc98 porting staff. All rights reserved. 12 * Copyright (c) 1995, 1996, 1997, 1998 13 * Naofumi HONDA. 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: head/sys/dev/ncv/ncr53c500_pccard.c 119418 2003-08-24 17:55:58Z obrien $"); 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/errno.h> 46 47#include <machine/bus.h> 48#include <machine/bus_pio.h> 49#include <machine/dvcfg.h> 50 51#include <sys/device_port.h> 52 53#include <dev/pccard/pccarddevs.h> 54#include <dev/pccard/pccardvar.h> 55 56#include <cam/scsi/scsi_low.h> 57#include <cam/scsi/scsi_low_pisa.h> 58 59#include <dev/ncv/ncr53c500reg.h> 60#include <dev/ncv/ncr53c500hw.h> 61#include <dev/ncv/ncr53c500var.h> 62 63#define KME_KXLC004_01 0x100 64#define OFFSET_KME_KXLC004_01 0x10 65 66#include <sys/kernel.h> 67#include <sys/module.h> 68#if !defined(__FreeBSD__) || __FreeBSD_version < 500014 69#include <sys/select.h> 70#endif 71#include <pccard/cardinfo.h> 72#include <pccard/slot.h> 73 74static int ncvprobe(DEVPORT_PDEVICE devi); 75static int ncvattach(DEVPORT_PDEVICE devi); 76 77static void ncv_card_unload(DEVPORT_PDEVICE); 78 79static const struct ncv_product { 80 struct pccard_product prod; 81 int flags; 82} ncv_products[] = { 83 { PCMCIA_CARD(EPSON, SC200, 0), 0}, 84 { PCMCIA_CARD(PANASONIC, KXLC002, 0), 0xb4d00000 }, 85 { PCMCIA_CARD(PANASONIC, KXLC004, 0), 0xb4d00100 }, 86 { PCMCIA_CARD(MACNICA, MPS100, 0), 0xb6250000 }, 87 { PCMCIA_CARD(MACNICA, MPS110, 0), 0 }, 88 { PCMCIA_CARD(NEC, PC9801N_J03R, 0), 0 }, 89 { PCMCIA_CARD(NEWMEDIA, BASICS_SCSI, 0), 0 }, 90 { PCMCIA_CARD(QLOGIC, PC05, 0), 0x84d00000 }, 91#define FLAGS_REX5572 0x84d00000 92 { PCMCIA_CARD(RATOC, REX5572, 0), FLAGS_REX5572 }, 93 { PCMCIA_CARD(RATOC, REX9530, 0), 0x84d00000 }, 94 { { NULL }, 0 } 95}; 96 97/* 98 * Additional code for FreeBSD new-bus PCCard frontend 99 */ 100 101static void 102ncv_pccard_intr(void * arg) 103{ 104 ncvintr(arg); 105} 106 107static void 108ncv_release_resource(DEVPORT_PDEVICE dev) 109{ 110 struct ncv_softc *sc = device_get_softc(dev); 111 112 if (sc->ncv_intrhand) { 113 bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); 114 } 115 116 if (sc->port_res) { 117 bus_release_resource(dev, SYS_RES_IOPORT, 118 sc->port_rid, sc->port_res); 119 } 120 121 if (sc->port_res_dmy) { 122 bus_release_resource(dev, SYS_RES_IOPORT, 123 sc->port_rid_dmy, sc->port_res_dmy); 124 } 125 126 if (sc->irq_res) { 127 bus_release_resource(dev, SYS_RES_IRQ, 128 sc->irq_rid, sc->irq_res); 129 } 130 131 if (sc->mem_res) { 132 bus_release_resource(dev, SYS_RES_MEMORY, 133 sc->mem_rid, sc->mem_res); 134 } 135} 136 137static int 138ncv_alloc_resource(DEVPORT_PDEVICE dev) 139{ 140 struct ncv_softc *sc = device_get_softc(dev); 141 u_int32_t flags = DEVPORT_PDEVFLAGS(dev); 142 u_long ioaddr, iosize, maddr, msize; 143 int error; 144 bus_addr_t offset = 0; 145 146 if(flags & KME_KXLC004_01) 147 offset = OFFSET_KME_KXLC004_01; 148 149 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); 150 if (error || (iosize < (offset + NCVIOSZ))) { 151 return(ENOMEM); 152 } 153 154 sc->port_rid = 0; 155 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 156 ioaddr+offset, ioaddr+iosize-offset, 157 iosize-offset, RF_ACTIVE); 158 if (sc->port_res == NULL) { 159 ncv_release_resource(dev); 160 return(ENOMEM); 161 } 162 163 if (offset != 0) { 164 sc->port_rid_dmy = 0; 165 sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, 166 &sc->port_rid_dmy, 167 ioaddr, ioaddr+offset, offset, 168 RF_ACTIVE); 169 if (sc->port_res_dmy == NULL) { 170 printf("Warning: cannot allocate IOPORT partially.\n"); 171 } 172 } else { 173 sc->port_rid_dmy = 0; 174 sc->port_res_dmy = NULL; 175 } 176 177 sc->irq_rid = 0; 178 sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, 179 0, ~0, 1, RF_ACTIVE); 180 if (sc->irq_res == NULL) { 181 ncv_release_resource(dev); 182 return(ENOMEM); 183 } 184 185 error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); 186 if (error) { 187 return(0); /* XXX */ 188 } 189 190 /* no need to allocate memory if not configured */ 191 if (maddr == 0 || msize == 0) { 192 return(0); 193 } 194 195 sc->mem_rid = 0; 196 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, 197 0, ~0, 1, RF_ACTIVE); 198 if (sc->mem_res == NULL) { 199 ncv_release_resource(dev); 200 return(ENOMEM); 201 } 202 203 return(0); 204} 205 206static int ncv_pccard_match(device_t dev) 207{ 208 const struct ncv_product *pp; 209 char *vendorstr; 210 char *prodstr; 211 212 if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, 213 (const struct pccard_product *) ncv_products, 214 sizeof(ncv_products[0]), NULL)) != NULL) { 215 if (pp->prod.pp_name != NULL) 216 device_set_desc(dev, pp->prod.pp_name); 217 device_set_flags(dev, pp->flags); 218 return(0); 219 } 220 if (pccard_get_vendor_str(dev, &vendorstr)) 221 return(EIO); 222 if (pccard_get_product_str(dev, &prodstr)) 223 return(EIO); 224 if (strcmp(vendorstr, "RATOC System Inc.") == 0 && 225 strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) { 226 device_set_desc(dev, "RATOC REX-5572"); 227 device_set_flags(dev, FLAGS_REX5572); 228 return (0); 229 } 230 return(EIO); 231} 232 233static int 234ncv_pccard_probe(DEVPORT_PDEVICE dev) 235{ 236 struct ncv_softc *sc = device_get_softc(dev); 237 int error; 238 239 bzero(sc, sizeof(struct ncv_softc)); 240 241 error = ncv_alloc_resource(dev); 242 if (error) { 243 return(error); 244 } 245 246 if (ncvprobe(dev) == 0) { 247 ncv_release_resource(dev); 248 return(ENXIO); 249 } 250 251 ncv_release_resource(dev); 252 253 return(0); 254} 255 256static int 257ncv_pccard_attach(DEVPORT_PDEVICE dev) 258{ 259 struct ncv_softc *sc = device_get_softc(dev); 260 int error; 261 262 error = ncv_alloc_resource(dev); 263 if (error) { 264 return(error); 265 } 266 267 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY, 268 ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand); 269 if (error) { 270 ncv_release_resource(dev); 271 return(error); 272 } 273 274 if (ncvattach(dev) == 0) { 275 ncv_release_resource(dev); 276 return(ENXIO); 277 } 278 279 return(0); 280} 281 282static void 283ncv_pccard_detach(DEVPORT_PDEVICE dev) 284{ 285 ncv_card_unload(dev); 286 ncv_release_resource(dev); 287} 288 289static device_method_t ncv_pccard_methods[] = { 290 /* Device interface */ 291 DEVMETHOD(device_probe, pccard_compat_probe), 292 DEVMETHOD(device_attach, pccard_compat_attach), 293 DEVMETHOD(device_detach, ncv_pccard_detach), 294 295 /* Card interface */ 296 DEVMETHOD(card_compat_match, ncv_pccard_match), 297 DEVMETHOD(card_compat_probe, ncv_pccard_probe), 298 DEVMETHOD(card_compat_attach, ncv_pccard_attach), 299 300 { 0, 0 } 301}; 302 303static driver_t ncv_pccard_driver = { 304 "ncv", 305 ncv_pccard_methods, 306 sizeof(struct ncv_softc), 307}; 308 309static devclass_t ncv_devclass; 310 311MODULE_DEPEND(ncv, scsi_low, 1, 1, 1); 312DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); 313 314static void 315ncv_card_unload(DEVPORT_PDEVICE devi) 316{ 317 struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); 318 intrmask_t s; 319 320 printf("%s: unload\n", sc->sc_sclow.sl_xname); 321 s = splcam(); 322 scsi_low_deactivate((struct scsi_low_softc *)sc); 323 scsi_low_dettach(&sc->sc_sclow); 324 splx(s); 325} 326 327static int 328ncvprobe(DEVPORT_PDEVICE devi) 329{ 330 int rv; 331 struct ncv_softc *sc = device_get_softc(devi); 332 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 333 334 rv = ncvprobesubr(rman_get_bustag(sc->port_res), 335 rman_get_bushandle(sc->port_res), 336 flags, NCV_HOSTID); 337 338 return rv; 339} 340 341static int 342ncvattach(DEVPORT_PDEVICE devi) 343{ 344 struct ncv_softc *sc; 345 struct scsi_low_softc *slp; 346 u_int32_t flags = DEVPORT_PDEVFLAGS(devi); 347 intrmask_t s; 348 char dvname[16]; /* SCSI_LOW_DVNAME_LEN */ 349 350 strcpy(dvname, "ncv"); 351 352 sc = DEVPORT_PDEVALLOC_SOFTC(devi); 353 if (sc == NULL) { 354 return(0); 355 } 356 357 slp = &sc->sc_sclow; 358 slp->sl_dev = devi; 359 sc->sc_iot = rman_get_bustag(sc->port_res); 360 sc->sc_ioh = rman_get_bushandle(sc->port_res); 361 362 slp->sl_hostid = NCV_HOSTID; 363 slp->sl_cfgflags = flags; 364 365 s = splcam(); 366 ncvattachsubr(sc); 367 splx(s); 368 369 return(NCVIOSZ); 370} 371