1227825Stheraven/* $NetBSD: aupcmcia.c,v 1.13 2022/09/25 12:41:46 andvar Exp $ */ 2227825Stheraven 3227825Stheraven/*- 4227825Stheraven * Copyright (c) 2006 Itronix Inc. 5227825Stheraven * All rights reserved. 6227825Stheraven * 7227825Stheraven * Written by Garrett D'Amore for Itronix Inc. 8227825Stheraven * 9227825Stheraven * Redistribution and use in source and binary forms, with or without 10227825Stheraven * modification, are permitted provided that the following conditions 11227825Stheraven * are met: 12227825Stheraven * 1. Redistributions of source code must retain the above copyright 13227825Stheraven * notice, this list of conditions and the following disclaimer. 14278724Sdim * 2. Redistributions in binary form must reproduce the above copyright 15278724Sdim * notice, this list of conditions and the following disclaimer in the 16262801Sdim * documentation and/or other materials provided with the distribution. 17262801Sdim * 3. The name of Itronix Inc. may not be used to endorse 18262801Sdim * or promote products derived from this software without specific 19262801Sdim * prior written permission. 20227825Stheraven * 21227825Stheraven * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22227825Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23227825Stheraven * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24249998Sdim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25249998Sdim * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26249998Sdim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27278724Sdim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28227825Stheraven * ON ANY THEORY OF LIABILITY, WHETHER IN 29278724Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30278724Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31227825Stheraven * POSSIBILITY OF SUCH DAMAGE. 32227825Stheraven */ 33227825Stheraven 34227825Stheraven/* #include "opt_pci.h" */ 35227825Stheraven/* #include "pci.h" */ 36227825Stheraven 37249998Sdim#include <sys/cdefs.h> 38227825Stheraven__KERNEL_RCSID(0, "$NetBSD: aupcmcia.c,v 1.13 2022/09/25 12:41:46 andvar Exp $"); 39249998Sdim 40227825Stheraven#include <sys/types.h> 41227825Stheraven#include <sys/param.h> 42227825Stheraven#include <sys/systm.h> 43227825Stheraven#include <sys/errno.h> 44227825Stheraven#include <sys/kernel.h> 45262801Sdim#include <sys/kthread.h> 46227825Stheraven#include <sys/intr.h> 47227825Stheraven#include <sys/device.h> 48262801Sdim 49262801Sdim#include <dev/pcmcia/pcmciareg.h> 50262801Sdim#include <dev/pcmcia/pcmciavar.h> 51262801Sdim#include <dev/pcmcia/pcmciachip.h> 52262801Sdim 53262801Sdim#include <mips/alchemy/include/au_himem_space.h> 54227825Stheraven#include <mips/alchemy/include/aubusvar.h> 55227825Stheraven#include <mips/alchemy/include/aureg.h> 56227825Stheraven#include <mips/alchemy/include/auvar.h> 57227825Stheraven 58227825Stheraven#include <mips/alchemy/dev/aupcmciareg.h> 59227825Stheraven#include <mips/alchemy/dev/aupcmciavar.h> 60249998Sdim 61227825Stheraven/* 62227825Stheraven * Borrow PCMCIADEBUG for now. Generally aupcmcia is the only PCMCIA 63227825Stheraven * host on these machines anyway. 64227825Stheraven */ 65227825Stheraven#ifdef PCMCIADEBUG 66227825Stheravenint aupcm_debug = 1; 67227825Stheraven#define DPRINTF(arg) if (aupcm_debug) printf arg 68262801Sdim#else 69227825Stheraven#define DPRINTF(arg) 70227825Stheraven#endif 71262801Sdim 72262801Sdim/* 73262801Sdim * And for information about mappings, etc. use this one. 74262801Sdim */ 75262801Sdim#ifdef AUPCMCIANOISY 76262801Sdim#define NOISY(arg) printf arg 77227825Stheraven#else 78227825Stheraven#define NOISY(arg) 79227825Stheraven#endif 80227825Stheraven 81227825Stheraven/* 82227825Stheraven * Note, we use prefix "aupcm" instead of "aupcmcia", even though our 83227825Stheraven * driver is the latter, mostly because my fingers have trouble typing 84227825Stheraven * the former. "aupcm" should be sufficiently unique to avoid 85227825Stheraven * confusion. 86227825Stheraven */ 87227825Stheraven 88227825Stheravenstatic int aupcm_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 89227825Stheraven struct pcmcia_mem_handle *); 90227825Stheravenstatic void aupcm_mem_free(pcmcia_chipset_handle_t, 91227825Stheraven struct pcmcia_mem_handle *); 92227825Stheravenstatic int aupcm_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 93227825Stheraven bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 94227825Stheravenstatic void aupcm_mem_unmap(pcmcia_chipset_handle_t, int); 95227825Stheraven 96227825Stheravenstatic int aupcm_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, 97227825Stheraven bus_size_t, struct pcmcia_io_handle *); 98227825Stheravenstatic void aupcm_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *); 99227825Stheravenstatic int aupcm_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 100227825Stheraven bus_size_t, struct pcmcia_io_handle *, int *); 101227825Stheravenstatic void aupcm_io_unmap(pcmcia_chipset_handle_t, int); 102227825Stheravenstatic void *aupcm_intr_establish(pcmcia_chipset_handle_t, 103227825Stheraven struct pcmcia_function *, int, int (*)(void *), void *); 104227825Stheravenstatic void aupcm_intr_disestablish(pcmcia_chipset_handle_t, void *); 105227825Stheraven 106227825Stheravenstatic void aupcm_slot_enable(pcmcia_chipset_handle_t); 107227825Stheravenstatic void aupcm_slot_disable(pcmcia_chipset_handle_t); 108227825Stheravenstatic void aupcm_slot_settype(pcmcia_chipset_handle_t, int); 109227825Stheraven 110232950Stheravenstatic int aupcm_match(device_t, struct cfdata *, void *); 111232950Stheravenstatic void aupcm_attach(device_t, device_t, void *); 112227825Stheraven 113227825Stheravenstatic void aupcm_event_thread(void *); 114227825Stheravenstatic int aupcm_card_intr(void *); 115227825Stheravenstatic void aupcm_softintr(void *); 116227825Stheravenstatic int aupcm_print(void *, const char *); 117227825Stheraven 118227825Stheravenstruct aupcm_slot { 119227825Stheraven struct aupcm_softc *as_softc; 120232950Stheraven int as_slot; 121232950Stheraven int as_status; 122227825Stheraven int as_enabled; 123227825Stheraven int (*as_intr)(void *); 124227825Stheraven int as_card_irq; 125227825Stheraven int as_status_irq; 126227825Stheraven void *as_intrarg; 127227825Stheraven void *as_softint; 128227825Stheraven void *as_hardint; 129227825Stheraven const char *as_name; 130232950Stheraven bus_addr_t as_offset; 131232950Stheraven struct mips_bus_space as_iot; 132227825Stheraven struct mips_bus_space as_attrt; 133227825Stheraven struct mips_bus_space as_memt; 134227825Stheraven void *as_wins[AUPCMCIA_NWINS]; 135227825Stheraven 136227825Stheraven device_t as_pcmcia; 137227825Stheraven}; 138227825Stheraven 139227825Stheraven/* this structure needs to be exposed... */ 140232950Stheravenstruct aupcm_softc { 141232950Stheraven device_t sc_dev; 142227825Stheraven pcmcia_chipset_tag_t sc_pct; 143227825Stheraven 144249998Sdim void (*sc_slot_enable)(int); 145227825Stheraven void (*sc_slot_disable)(int); 146227825Stheraven int (*sc_slot_status)(int); 147227825Stheraven 148227825Stheraven paddr_t sc_base; 149227825Stheraven 150227825Stheraven int sc_wake; 151227825Stheraven lwp_t *sc_thread; 152227825Stheraven 153227825Stheraven int sc_nslots; 154227825Stheraven struct aupcm_slot sc_slots[AUPCMCIA_NSLOTS]; 155262801Sdim}; 156227825Stheraven 157227825Stheravenstatic struct pcmcia_chip_functions aupcm_functions = { 158262801Sdim aupcm_mem_alloc, 159262801Sdim aupcm_mem_free, 160262801Sdim aupcm_mem_map, 161262801Sdim aupcm_mem_unmap, 162262801Sdim 163262801Sdim aupcm_io_alloc, 164227825Stheraven aupcm_io_free, 165227825Stheraven aupcm_io_map, 166227825Stheraven aupcm_io_unmap, 167227825Stheraven 168227825Stheraven aupcm_intr_establish, 169227825Stheraven aupcm_intr_disestablish, 170227825Stheraven 171227825Stheraven aupcm_slot_enable, 172227825Stheraven aupcm_slot_disable, 173227825Stheraven aupcm_slot_settype, 174227825Stheraven}; 175227825Stheraven 176227825Stheravenstatic struct mips_bus_space aupcm_memt; 177227825Stheraven 178227825StheravenCFATTACH_DECL_NEW(aupcmcia, sizeof (struct aupcm_softc), 179227825Stheraven aupcm_match, aupcm_attach, NULL, NULL); 180227825Stheraven 181227825Stheravenint 182227825Stheravenaupcm_match(device_t parent, struct cfdata *cf, void *aux) 183227825Stheraven{ 184227825Stheraven struct aubus_attach_args *aa = aux; 185227825Stheraven static int found = 0; 186227825Stheraven 187227825Stheraven if (found) 188227825Stheraven return 0; 189227825Stheraven 190227825Stheraven if (strcmp(aa->aa_name, "aupcmcia") != 0) 191227825Stheraven return 0; 192227825Stheraven 193227825Stheraven found = 1; 194227825Stheraven 195227825Stheraven return 1; 196227825Stheraven} 197227825Stheraven 198227825Stheravenvoid 199227825Stheravenaupcm_attach(device_t parent, device_t self, void *aux) 200227825Stheraven{ 201227825Stheraven /* struct aubus_attach_args *aa = aux; */ 202227825Stheraven struct aupcm_softc *sc = device_private(self); 203262801Sdim static int done = 0; 204227825Stheraven int slot; 205227825Stheraven struct aupcmcia_machdep *md; 206227825Stheraven 207227825Stheraven sc->sc_dev = self; 208227825Stheraven 209227825Stheraven /* initialize bus space */ 210249998Sdim if (done) { 211227825Stheraven /* there can be only one. */ 212227825Stheraven return; 213249998Sdim } 214249998Sdim 215227825Stheraven done = 1; 216227825Stheraven /* 217227825Stheraven * PCMCIA memory can live within pretty much the entire 32-bit 218227825Stheraven * space, modulo 64 MB wraps. We don't have to support coexisting 219227825Stheraven * DMA. 220227825Stheraven */ 221227825Stheraven au_himem_space_init(&aupcm_memt, "pcmciamem", 222227825Stheraven PCMCIA_BASE, AUPCMCIA_ATTR_OFFSET, 0xffffffff, 223 AU_HIMEM_SPACE_LITTLE_ENDIAN); 224 225 if ((md = aupcmcia_machdep()) == NULL) { 226 aprint_error(": unable to get machdep structure\n"); 227 return; 228 } 229 230 sc->sc_nslots = md->am_nslots; 231 sc->sc_slot_enable = md->am_slot_enable; 232 sc->sc_slot_disable = md->am_slot_disable; 233 sc->sc_slot_status = md->am_slot_status; 234 235 aprint_normal(": Alchemy PCMCIA, %d slots\n", sc->sc_nslots); 236 aprint_naive("\n"); 237 238 sc->sc_pct = (pcmcia_chipset_tag_t)&aupcm_functions; 239 240 for (slot = 0; slot < sc->sc_nslots; slot++) { 241 struct aupcm_slot *sp; 242 struct pcmciabus_attach_args paa; 243 244 sp = &sc->sc_slots[slot]; 245 sp->as_softc = sc; 246 247 sp->as_slot = slot; 248 sp->as_name = md->am_slot_name(slot); 249 sp->as_offset = md->am_slot_offset(slot); 250 sp->as_card_irq = md->am_slot_irq(slot, AUPCMCIA_IRQ_CARD); 251 sp->as_status_irq = md->am_slot_irq(slot, 252 AUPCMCIA_IRQ_INSERT); 253 254 au_himem_space_init(&sp->as_attrt, "pcmciaattr", 255 PCMCIA_BASE + sp->as_offset + AUPCMCIA_ATTR_OFFSET, 256 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 257 258 au_himem_space_init(&sp->as_memt, "pcmciamem", 259 PCMCIA_BASE + sp->as_offset + AUPCMCIA_MEM_OFFSET, 260 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 261 262 au_himem_space_init(&sp->as_iot, "pcmciaio", 263 PCMCIA_BASE + sp->as_offset + AUPCMCIA_IO_OFFSET, 264 0, AUPCMCIA_MAP_SIZE, 265 AU_HIMEM_SPACE_LITTLE_ENDIAN | AU_HIMEM_SPACE_IO); 266 267 sp->as_status = 0; 268 269 paa.paa_busname = "pcmcia"; 270 paa.pct = sc->sc_pct; 271 paa.pch = (pcmcia_chipset_handle_t)sp; 272 273 sp->as_pcmcia = config_found(self, &paa, aupcm_print, 274 CFARGS_NONE); 275 276 /* if no pcmcia, make sure slot is powered down */ 277 if (sp->as_pcmcia == NULL) { 278 aupcm_slot_disable(sp); 279 continue; 280 } 281 282 /* this makes sure we probe the slot */ 283 sc->sc_wake |= (1 << slot); 284 } 285 286 /* 287 * XXX: this would be an excellent time time to establish a handler 288 * for the card insertion interrupt, but that's edge triggered, and 289 * au_icu.c won't support it right now. We poll in the event thread 290 * for now. Start by initializing it now. 291 */ 292 if (kthread_create(PRI_NONE, 0, NULL, aupcm_event_thread, sc, 293 &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) 294 panic("%s: unable to create event kthread", 295 device_xname(sc->sc_dev)); 296} 297 298int 299aupcm_print(void *aux, const char *pnp) 300{ 301 struct pcmciabus_attach_args *paa = aux; 302 struct aupcm_slot *sp = paa->pch; 303 304 printf(" socket %d irq %d, %s", sp->as_slot, sp->as_card_irq, 305 sp->as_name); 306 307 return (UNCONF); 308} 309 310void * 311aupcm_intr_establish(pcmcia_chipset_handle_t pch, 312 struct pcmcia_function *pf, int level, int (*handler)(void *), void *arg) 313{ 314 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 315 int s; 316 317 /* 318 * Hmm. perhaps this intr should be a list. well, PCMCIA 319 * devices generally only have one interrupt, and so should 320 * generally have only one handler. So we leave it for now. 321 * (Other PCMCIA bus drivers do it this way.) 322 */ 323 sp->as_intr = handler; 324 sp->as_intrarg = arg; 325 sp->as_softint = softint_establish(IPL_SOFTNET, aupcm_softintr, sp); 326 327 /* set up hard interrupt handler for the card IRQs */ 328 s = splhigh(); 329 sp->as_hardint = au_intr_establish(sp->as_card_irq, 0, 330 IPL_TTY, IST_LEVEL_LOW, aupcm_card_intr, sp); 331 /* if card is not powered up, then leave the IRQ masked */ 332 if (!sp->as_enabled) { 333 au_intr_disable(sp->as_card_irq); 334 } 335 splx(s); 336 337 return (sp->as_softint); 338} 339 340void 341aupcm_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 342{ 343 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 344 345 KASSERT(sp->as_softint == ih); 346 /* KASSERT(sp->as_hardint); */ 347 /* set up hard interrupt handler for the card IRQs */ 348 349 au_intr_disestablish(sp->as_hardint); 350 sp->as_hardint = 0; 351 352 softint_disestablish(ih); 353 sp->as_softint = 0; 354 sp->as_intr = NULL; 355 sp->as_intrarg = NULL; 356} 357 358/* 359 * FYI: Hot detach of PCMCIA is supposedly safe because H/W doesn't 360 * fault on accesses to missing hardware. 361 */ 362void 363aupcm_event_thread(void *arg) 364{ 365 struct aupcm_softc *sc = arg; 366 struct aupcm_slot *sp; 367 int s, i, attach, detach; 368 369 for (;;) { 370 s = splhigh(); 371 if (sc->sc_wake == 0) { 372 splx(s); 373 /* 374 * XXX: Currently, the au_icu.c lacks support 375 * for edge-triggered interrupts. So we 376 * cannot really use the status change 377 * interrupts. For now we poll (once per sec). 378 * FYI, Linux does it this way, and they *do* 379 * have support for edge triggered interrupts. 380 * Go figure. 381 */ 382 tsleep(&sc->sc_wake, PWAIT, "aupcm_event", hz); 383 s = splhigh(); 384 } 385 sc->sc_wake = 0; 386 387 attach = detach = 0; 388 for (i = 0; i < sc->sc_nslots; i++) { 389 sp = &sc->sc_slots[i]; 390 391 if (sc->sc_slot_status(sp->as_slot) != 0) { 392 if (!sp->as_status) { 393 DPRINTF(("%s: card %d insertion\n", 394 device_xname(sc->sc_dev), i)); 395 attach |= (1 << i); 396 sp->as_status = 1; 397 } 398 } else { 399 if (sp->as_status) { 400 DPRINTF(("%s: card %d removal\n", 401 device_xname(sc->sc_dev), i)); 402 detach |= (1 << i); 403 sp->as_status = 0; 404 } 405 } 406 } 407 splx(s); 408 409 for (i = 0; i < sc->sc_nslots; i++) { 410 sp = &sc->sc_slots[i]; 411 412 if (detach & (1 << i)) { 413 aupcm_slot_disable(sp); 414 pcmcia_card_detach(sp->as_pcmcia, DETACH_FORCE); 415 } else if (attach & (1 << i)) { 416 /* 417 * until the function is enabled, don't 418 * honor interrupts 419 */ 420 sp->as_enabled = 0; 421 au_intr_disable(sp->as_card_irq); 422 pcmcia_card_attach(sp->as_pcmcia); 423 } 424 } 425 } 426} 427 428#if 0 429void 430aupcm_status_intr(void *arg) 431{ 432 int s; 433 struct aupcm_softc *sc = arg; 434 435 s = splhigh(); 436 437 /* kick the status thread so it does its bit */ 438 sc->sc_wake = 1; 439 wakeup(&sc->sc_wake); 440 441 splx(s); 442} 443#endif 444 445int 446aupcm_card_intr(void *arg) 447{ 448 struct aupcm_slot *sp = arg; 449 450 /* disable the hard interrupt for now */ 451 au_intr_disable(sp->as_card_irq); 452 453 if (sp->as_intr != NULL) { 454 softint_schedule(sp->as_softint); 455 } 456 457 return 1; 458} 459 460void 461aupcm_softintr(void *arg) 462{ 463 struct aupcm_slot *sp = arg; 464 int s; 465 466 sp->as_intr(sp->as_intrarg); 467 468 s = splhigh(); 469 470 if (sp->as_intr && sp->as_enabled) { 471 au_intr_enable(sp->as_card_irq); 472 } 473 474 splx(s); 475} 476 477void 478aupcm_slot_enable(pcmcia_chipset_handle_t pch) 479{ 480 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 481 int s; 482 483 /* no interrupts while we reset the card, please */ 484 if (sp->as_intr) 485 au_intr_disable(sp->as_card_irq); 486 487 /* 488 * XXX: should probably lock to make sure slot_disable and 489 * enable not called together. However, i believe that the 490 * event thread basically serializes them anyway. 491 */ 492 493 sp->as_softc->sc_slot_enable(sp->as_slot); 494 /* card is powered up now, honor device interrupts */ 495 496 s = splhigh(); 497 sp->as_enabled = 1; 498 if (sp->as_intr) 499 au_intr_enable(sp->as_card_irq); 500 splx(s); 501} 502 503void 504aupcm_slot_disable(pcmcia_chipset_handle_t pch) 505{ 506 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 507 int s; 508 509 s = splhigh(); 510 au_intr_disable(sp->as_card_irq); 511 sp->as_enabled = 0; 512 splx(s); 513 514 sp->as_softc->sc_slot_disable(sp->as_slot); 515} 516 517void 518aupcm_slot_settype(pcmcia_chipset_handle_t pch, int type) 519{ 520 /* we do nothing now : type == PCMCIA_IFTYPE_IO */ 521} 522 523int 524aupcm_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 525 struct pcmcia_mem_handle *pcmh) 526{ 527 pcmh->memt = NULL; 528 pcmh->size = pcmh->realsize = size; 529 pcmh->addr = 0; 530 pcmh->mhandle = 0; 531 532 return 0; 533} 534 535void 536aupcm_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmh) 537{ 538 /* nothing to do */ 539} 540 541int 542aupcm_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr, 543 bus_size_t size, struct pcmcia_mem_handle *pcmh, bus_size_t *offsetp, 544 int *windowp) 545{ 546 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 547 int win, err; 548 int s; 549 550 s = splhigh(); 551 for (win = 0; win < AUPCMCIA_NWINS; win++) { 552 if (sp->as_wins[win] == NULL) { 553 sp->as_wins[win] = pcmh; 554 break; 555 } 556 } 557 splx(s); 558 559 if (win >= AUPCMCIA_NWINS) { 560 return ENOMEM; 561 } 562 563 if (kind & PCMCIA_MEM_ATTR) { 564 pcmh->memt = &sp->as_attrt; 565 NOISY(("mapping ATTR addr %x size %x\n", (uint32_t)addr, 566 (uint32_t)size)); 567 } else { 568 pcmh->memt = &sp->as_memt; 569 NOISY(("mapping MEMORY addr %x size %x\n", (uint32_t)addr, 570 (uint32_t)size)); 571 } 572 573 if ((size + addr) > (64 * 1024 * 1024)) 574 return EINVAL; 575 576 pcmh->size = size; 577 578 err = bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh); 579 if (err != 0) { 580 sp->as_wins[win] = NULL; 581 return err; 582 } 583 *offsetp = 0; 584 *windowp = win; 585 586 return 0; 587} 588 589void 590aupcm_mem_unmap(pcmcia_chipset_handle_t pch, int win) 591{ 592 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 593 struct pcmcia_mem_handle *pcmh; 594 595 pcmh = (struct pcmcia_mem_handle *)sp->as_wins[win]; 596 sp->as_wins[win] = NULL; 597 598 NOISY(("memory umap virtual %x\n", (uint32_t)pcmh->memh)); 599 bus_space_unmap(pcmh->memt, pcmh->memh, pcmh->size); 600 pcmh->memt = NULL; 601} 602 603int 604aupcm_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 605 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih) 606{ 607 struct aupcm_slot *sp = (struct aupcm_slot *)pch; 608 bus_space_handle_t bush; 609 int err; 610 611 pih->iot = &sp->as_iot; 612 pih->size = size; 613 pih->flags = 0; 614 615 /* 616 * start from the initial offset - this gets us a slot 617 * specific address, while still leaving the addresses more or 618 * less zero-based which is required for x86-style device 619 * drivers. 620 */ 621 err = bus_space_alloc(pih->iot, start, 0x100000, 622 size, align, 0, 0, &pih->addr, &bush); 623 NOISY(("start = %x, addr = %x, size = %x, bush = %x\n", 624 (uint32_t)start, (uint32_t)pih->addr, (uint32_t)size, 625 (uint32_t)bush)); 626 627 /* and we convert it back */ 628 if (err == 0) { 629 pih->ihandle = (void *)bush; 630 } 631 632 return (err); 633} 634 635void 636aupcm_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih) 637{ 638 bus_space_free(pih->iot, (bus_space_handle_t)pih->ihandle, 639 pih->size); 640} 641 642int 643aupcm_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 644 bus_size_t size, struct pcmcia_io_handle *pih, int *windowp) 645{ 646 int err; 647 648 err = bus_space_subregion(pih->iot, (bus_space_handle_t)pih->ihandle, 649 offset, size, &pih->ioh); 650 NOISY(("io map offset = %x, size = %x, ih = %x, hdl=%x\n", 651 (uint32_t)offset, (uint32_t)size, 652 (uint32_t)pih->ihandle, (uint32_t)pih->ioh)); 653 654 return err; 655} 656 657void 658aupcm_io_unmap(pcmcia_chipset_handle_t pch, int win) 659{ 660 /* We mustn't unmap/free subregion bus space! */ 661 NOISY(("io unmap\n")); 662} 663