1 1.13 andvar /* $NetBSD: aupcmcia.c,v 1.13 2022/09/25 12:41:46 andvar Exp $ */ 2 1.1 gdamore 3 1.1 gdamore /*- 4 1.1 gdamore * Copyright (c) 2006 Itronix Inc. 5 1.1 gdamore * All rights reserved. 6 1.1 gdamore * 7 1.1 gdamore * Written by Garrett D'Amore for Itronix Inc. 8 1.1 gdamore * 9 1.1 gdamore * Redistribution and use in source and binary forms, with or without 10 1.1 gdamore * modification, are permitted provided that the following conditions 11 1.1 gdamore * are met: 12 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 13 1.1 gdamore * notice, this list of conditions and the following disclaimer. 14 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 16 1.1 gdamore * documentation and/or other materials provided with the distribution. 17 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse 18 1.1 gdamore * or promote products derived from this software without specific 19 1.1 gdamore * prior written permission. 20 1.1 gdamore * 21 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE. 32 1.1 gdamore */ 33 1.1 gdamore 34 1.1 gdamore /* #include "opt_pci.h" */ 35 1.1 gdamore /* #include "pci.h" */ 36 1.1 gdamore 37 1.1 gdamore #include <sys/cdefs.h> 38 1.13 andvar __KERNEL_RCSID(0, "$NetBSD: aupcmcia.c,v 1.13 2022/09/25 12:41:46 andvar Exp $"); 39 1.1 gdamore 40 1.1 gdamore #include <sys/types.h> 41 1.1 gdamore #include <sys/param.h> 42 1.1 gdamore #include <sys/systm.h> 43 1.1 gdamore #include <sys/errno.h> 44 1.1 gdamore #include <sys/kernel.h> 45 1.1 gdamore #include <sys/kthread.h> 46 1.5 ad #include <sys/intr.h> 47 1.6 dogcow #include <sys/device.h> 48 1.1 gdamore 49 1.1 gdamore #include <dev/pcmcia/pcmciareg.h> 50 1.1 gdamore #include <dev/pcmcia/pcmciavar.h> 51 1.1 gdamore #include <dev/pcmcia/pcmciachip.h> 52 1.1 gdamore 53 1.1 gdamore #include <mips/alchemy/include/au_himem_space.h> 54 1.1 gdamore #include <mips/alchemy/include/aubusvar.h> 55 1.1 gdamore #include <mips/alchemy/include/aureg.h> 56 1.1 gdamore #include <mips/alchemy/include/auvar.h> 57 1.1 gdamore 58 1.1 gdamore #include <mips/alchemy/dev/aupcmciareg.h> 59 1.1 gdamore #include <mips/alchemy/dev/aupcmciavar.h> 60 1.1 gdamore 61 1.1 gdamore /* 62 1.1 gdamore * Borrow PCMCIADEBUG for now. Generally aupcmcia is the only PCMCIA 63 1.1 gdamore * host on these machines anyway. 64 1.1 gdamore */ 65 1.1 gdamore #ifdef PCMCIADEBUG 66 1.1 gdamore int aupcm_debug = 1; 67 1.1 gdamore #define DPRINTF(arg) if (aupcm_debug) printf arg 68 1.1 gdamore #else 69 1.1 gdamore #define DPRINTF(arg) 70 1.1 gdamore #endif 71 1.1 gdamore 72 1.1 gdamore /* 73 1.1 gdamore * And for information about mappings, etc. use this one. 74 1.1 gdamore */ 75 1.1 gdamore #ifdef AUPCMCIANOISY 76 1.1 gdamore #define NOISY(arg) printf arg 77 1.1 gdamore #else 78 1.1 gdamore #define NOISY(arg) 79 1.1 gdamore #endif 80 1.1 gdamore 81 1.1 gdamore /* 82 1.1 gdamore * Note, we use prefix "aupcm" instead of "aupcmcia", even though our 83 1.1 gdamore * driver is the latter, mostly because my fingers have trouble typing 84 1.1 gdamore * the former. "aupcm" should be sufficiently unique to avoid 85 1.1 gdamore * confusion. 86 1.1 gdamore */ 87 1.1 gdamore 88 1.1 gdamore static int aupcm_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 89 1.1 gdamore struct pcmcia_mem_handle *); 90 1.1 gdamore static void aupcm_mem_free(pcmcia_chipset_handle_t, 91 1.1 gdamore struct pcmcia_mem_handle *); 92 1.1 gdamore static int aupcm_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 93 1.1 gdamore bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 94 1.1 gdamore static void aupcm_mem_unmap(pcmcia_chipset_handle_t, int); 95 1.1 gdamore 96 1.1 gdamore static int aupcm_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t, 97 1.1 gdamore bus_size_t, struct pcmcia_io_handle *); 98 1.1 gdamore static void aupcm_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *); 99 1.1 gdamore static int aupcm_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 100 1.1 gdamore bus_size_t, struct pcmcia_io_handle *, int *); 101 1.1 gdamore static void aupcm_io_unmap(pcmcia_chipset_handle_t, int); 102 1.1 gdamore static void *aupcm_intr_establish(pcmcia_chipset_handle_t, 103 1.1 gdamore struct pcmcia_function *, int, int (*)(void *), void *); 104 1.1 gdamore static void aupcm_intr_disestablish(pcmcia_chipset_handle_t, void *); 105 1.1 gdamore 106 1.1 gdamore static void aupcm_slot_enable(pcmcia_chipset_handle_t); 107 1.1 gdamore static void aupcm_slot_disable(pcmcia_chipset_handle_t); 108 1.1 gdamore static void aupcm_slot_settype(pcmcia_chipset_handle_t, int); 109 1.1 gdamore 110 1.8 kiyohara static int aupcm_match(device_t, struct cfdata *, void *); 111 1.8 kiyohara static void aupcm_attach(device_t, device_t, void *); 112 1.1 gdamore 113 1.1 gdamore static void aupcm_event_thread(void *); 114 1.1 gdamore static int aupcm_card_intr(void *); 115 1.1 gdamore static void aupcm_softintr(void *); 116 1.1 gdamore static int aupcm_print(void *, const char *); 117 1.1 gdamore 118 1.1 gdamore struct aupcm_slot { 119 1.1 gdamore struct aupcm_softc *as_softc; 120 1.1 gdamore int as_slot; 121 1.1 gdamore int as_status; 122 1.1 gdamore int as_enabled; 123 1.1 gdamore int (*as_intr)(void *); 124 1.1 gdamore int as_card_irq; 125 1.1 gdamore int as_status_irq; 126 1.1 gdamore void *as_intrarg; 127 1.1 gdamore void *as_softint; 128 1.1 gdamore void *as_hardint; 129 1.1 gdamore const char *as_name; 130 1.1 gdamore bus_addr_t as_offset; 131 1.1 gdamore struct mips_bus_space as_iot; 132 1.1 gdamore struct mips_bus_space as_attrt; 133 1.1 gdamore struct mips_bus_space as_memt; 134 1.1 gdamore void *as_wins[AUPCMCIA_NWINS]; 135 1.1 gdamore 136 1.8 kiyohara device_t as_pcmcia; 137 1.1 gdamore }; 138 1.1 gdamore 139 1.1 gdamore /* this structure needs to be exposed... */ 140 1.1 gdamore struct aupcm_softc { 141 1.8 kiyohara device_t sc_dev; 142 1.1 gdamore pcmcia_chipset_tag_t sc_pct; 143 1.1 gdamore 144 1.1 gdamore void (*sc_slot_enable)(int); 145 1.1 gdamore void (*sc_slot_disable)(int); 146 1.1 gdamore int (*sc_slot_status)(int); 147 1.1 gdamore 148 1.1 gdamore paddr_t sc_base; 149 1.1 gdamore 150 1.1 gdamore int sc_wake; 151 1.3 ad lwp_t *sc_thread; 152 1.1 gdamore 153 1.1 gdamore int sc_nslots; 154 1.1 gdamore struct aupcm_slot sc_slots[AUPCMCIA_NSLOTS]; 155 1.1 gdamore }; 156 1.1 gdamore 157 1.1 gdamore static struct pcmcia_chip_functions aupcm_functions = { 158 1.1 gdamore aupcm_mem_alloc, 159 1.1 gdamore aupcm_mem_free, 160 1.1 gdamore aupcm_mem_map, 161 1.1 gdamore aupcm_mem_unmap, 162 1.1 gdamore 163 1.1 gdamore aupcm_io_alloc, 164 1.1 gdamore aupcm_io_free, 165 1.1 gdamore aupcm_io_map, 166 1.1 gdamore aupcm_io_unmap, 167 1.1 gdamore 168 1.1 gdamore aupcm_intr_establish, 169 1.1 gdamore aupcm_intr_disestablish, 170 1.1 gdamore 171 1.1 gdamore aupcm_slot_enable, 172 1.1 gdamore aupcm_slot_disable, 173 1.1 gdamore aupcm_slot_settype, 174 1.1 gdamore }; 175 1.1 gdamore 176 1.1 gdamore static struct mips_bus_space aupcm_memt; 177 1.1 gdamore 178 1.8 kiyohara CFATTACH_DECL_NEW(aupcmcia, sizeof (struct aupcm_softc), 179 1.1 gdamore aupcm_match, aupcm_attach, NULL, NULL); 180 1.1 gdamore 181 1.1 gdamore int 182 1.8 kiyohara aupcm_match(device_t parent, struct cfdata *cf, void *aux) 183 1.1 gdamore { 184 1.1 gdamore struct aubus_attach_args *aa = aux; 185 1.1 gdamore static int found = 0; 186 1.1 gdamore 187 1.1 gdamore if (found) 188 1.1 gdamore return 0; 189 1.1 gdamore 190 1.1 gdamore if (strcmp(aa->aa_name, "aupcmcia") != 0) 191 1.1 gdamore return 0; 192 1.1 gdamore 193 1.1 gdamore found = 1; 194 1.1 gdamore 195 1.1 gdamore return 1; 196 1.1 gdamore } 197 1.1 gdamore 198 1.1 gdamore void 199 1.8 kiyohara aupcm_attach(device_t parent, device_t self, void *aux) 200 1.1 gdamore { 201 1.1 gdamore /* struct aubus_attach_args *aa = aux; */ 202 1.8 kiyohara struct aupcm_softc *sc = device_private(self); 203 1.1 gdamore static int done = 0; 204 1.1 gdamore int slot; 205 1.1 gdamore struct aupcmcia_machdep *md; 206 1.1 gdamore 207 1.8 kiyohara sc->sc_dev = self; 208 1.8 kiyohara 209 1.1 gdamore /* initialize bus space */ 210 1.1 gdamore if (done) { 211 1.1 gdamore /* there can be only one. */ 212 1.1 gdamore return; 213 1.1 gdamore } 214 1.1 gdamore 215 1.1 gdamore done = 1; 216 1.1 gdamore /* 217 1.1 gdamore * PCMCIA memory can live within pretty much the entire 32-bit 218 1.1 gdamore * space, modulo 64 MB wraps. We don't have to support coexisting 219 1.1 gdamore * DMA. 220 1.1 gdamore */ 221 1.1 gdamore au_himem_space_init(&aupcm_memt, "pcmciamem", 222 1.1 gdamore PCMCIA_BASE, AUPCMCIA_ATTR_OFFSET, 0xffffffff, 223 1.1 gdamore AU_HIMEM_SPACE_LITTLE_ENDIAN); 224 1.1 gdamore 225 1.1 gdamore if ((md = aupcmcia_machdep()) == NULL) { 226 1.8 kiyohara aprint_error(": unable to get machdep structure\n"); 227 1.1 gdamore return; 228 1.1 gdamore } 229 1.1 gdamore 230 1.1 gdamore sc->sc_nslots = md->am_nslots; 231 1.1 gdamore sc->sc_slot_enable = md->am_slot_enable; 232 1.1 gdamore sc->sc_slot_disable = md->am_slot_disable; 233 1.1 gdamore sc->sc_slot_status = md->am_slot_status; 234 1.1 gdamore 235 1.8 kiyohara aprint_normal(": Alchemy PCMCIA, %d slots\n", sc->sc_nslots); 236 1.8 kiyohara aprint_naive("\n"); 237 1.1 gdamore 238 1.1 gdamore sc->sc_pct = (pcmcia_chipset_tag_t)&aupcm_functions; 239 1.1 gdamore 240 1.1 gdamore for (slot = 0; slot < sc->sc_nslots; slot++) { 241 1.1 gdamore struct aupcm_slot *sp; 242 1.1 gdamore struct pcmciabus_attach_args paa; 243 1.1 gdamore 244 1.1 gdamore sp = &sc->sc_slots[slot]; 245 1.1 gdamore sp->as_softc = sc; 246 1.1 gdamore 247 1.1 gdamore sp->as_slot = slot; 248 1.1 gdamore sp->as_name = md->am_slot_name(slot); 249 1.1 gdamore sp->as_offset = md->am_slot_offset(slot); 250 1.1 gdamore sp->as_card_irq = md->am_slot_irq(slot, AUPCMCIA_IRQ_CARD); 251 1.1 gdamore sp->as_status_irq = md->am_slot_irq(slot, 252 1.1 gdamore AUPCMCIA_IRQ_INSERT); 253 1.1 gdamore 254 1.1 gdamore au_himem_space_init(&sp->as_attrt, "pcmciaattr", 255 1.1 gdamore PCMCIA_BASE + sp->as_offset + AUPCMCIA_ATTR_OFFSET, 256 1.1 gdamore 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 257 1.1 gdamore 258 1.1 gdamore au_himem_space_init(&sp->as_memt, "pcmciamem", 259 1.1 gdamore PCMCIA_BASE + sp->as_offset + AUPCMCIA_MEM_OFFSET, 260 1.1 gdamore 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN); 261 1.1 gdamore 262 1.1 gdamore au_himem_space_init(&sp->as_iot, "pcmciaio", 263 1.1 gdamore PCMCIA_BASE + sp->as_offset + AUPCMCIA_IO_OFFSET, 264 1.1 gdamore 0, AUPCMCIA_MAP_SIZE, 265 1.1 gdamore AU_HIMEM_SPACE_LITTLE_ENDIAN | AU_HIMEM_SPACE_IO); 266 1.1 gdamore 267 1.1 gdamore sp->as_status = 0; 268 1.1 gdamore 269 1.1 gdamore paa.paa_busname = "pcmcia"; 270 1.1 gdamore paa.pct = sc->sc_pct; 271 1.1 gdamore paa.pch = (pcmcia_chipset_handle_t)sp; 272 1.1 gdamore 273 1.11 thorpej sp->as_pcmcia = config_found(self, &paa, aupcm_print, 274 1.12 thorpej CFARGS_NONE); 275 1.1 gdamore 276 1.1 gdamore /* if no pcmcia, make sure slot is powered down */ 277 1.1 gdamore if (sp->as_pcmcia == NULL) { 278 1.1 gdamore aupcm_slot_disable(sp); 279 1.1 gdamore continue; 280 1.1 gdamore } 281 1.1 gdamore 282 1.1 gdamore /* this makes sure we probe the slot */ 283 1.1 gdamore sc->sc_wake |= (1 << slot); 284 1.1 gdamore } 285 1.1 gdamore 286 1.1 gdamore /* 287 1.1 gdamore * XXX: this would be an excellent time time to establish a handler 288 1.1 gdamore * for the card insertion interrupt, but that's edge triggered, and 289 1.1 gdamore * au_icu.c won't support it right now. We poll in the event thread 290 1.1 gdamore * for now. Start by initializing it now. 291 1.1 gdamore */ 292 1.3 ad if (kthread_create(PRI_NONE, 0, NULL, aupcm_event_thread, sc, 293 1.8 kiyohara &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) 294 1.3 ad panic("%s: unable to create event kthread", 295 1.8 kiyohara device_xname(sc->sc_dev)); 296 1.1 gdamore } 297 1.1 gdamore 298 1.1 gdamore int 299 1.1 gdamore aupcm_print(void *aux, const char *pnp) 300 1.1 gdamore { 301 1.1 gdamore struct pcmciabus_attach_args *paa = aux; 302 1.1 gdamore struct aupcm_slot *sp = paa->pch; 303 1.1 gdamore 304 1.1 gdamore printf(" socket %d irq %d, %s", sp->as_slot, sp->as_card_irq, 305 1.1 gdamore sp->as_name); 306 1.1 gdamore 307 1.1 gdamore return (UNCONF); 308 1.1 gdamore } 309 1.1 gdamore 310 1.1 gdamore void * 311 1.1 gdamore aupcm_intr_establish(pcmcia_chipset_handle_t pch, 312 1.1 gdamore struct pcmcia_function *pf, int level, int (*handler)(void *), void *arg) 313 1.1 gdamore { 314 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 315 1.1 gdamore int s; 316 1.1 gdamore 317 1.1 gdamore /* 318 1.1 gdamore * Hmm. perhaps this intr should be a list. well, PCMCIA 319 1.1 gdamore * devices generally only have one interrupt, and so should 320 1.1 gdamore * generally have only one handler. So we leave it for now. 321 1.1 gdamore * (Other PCMCIA bus drivers do it this way.) 322 1.1 gdamore */ 323 1.1 gdamore sp->as_intr = handler; 324 1.1 gdamore sp->as_intrarg = arg; 325 1.5 ad sp->as_softint = softint_establish(IPL_SOFTNET, aupcm_softintr, sp); 326 1.1 gdamore 327 1.1 gdamore /* set up hard interrupt handler for the card IRQs */ 328 1.1 gdamore s = splhigh(); 329 1.1 gdamore sp->as_hardint = au_intr_establish(sp->as_card_irq, 0, 330 1.2 gdamore IPL_TTY, IST_LEVEL_LOW, aupcm_card_intr, sp); 331 1.1 gdamore /* if card is not powered up, then leave the IRQ masked */ 332 1.1 gdamore if (!sp->as_enabled) { 333 1.1 gdamore au_intr_disable(sp->as_card_irq); 334 1.1 gdamore } 335 1.1 gdamore splx(s); 336 1.1 gdamore 337 1.1 gdamore return (sp->as_softint); 338 1.1 gdamore } 339 1.1 gdamore 340 1.1 gdamore void 341 1.1 gdamore aupcm_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih) 342 1.1 gdamore { 343 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 344 1.1 gdamore 345 1.1 gdamore KASSERT(sp->as_softint == ih); 346 1.1 gdamore /* KASSERT(sp->as_hardint); */ 347 1.1 gdamore /* set up hard interrupt handler for the card IRQs */ 348 1.1 gdamore 349 1.1 gdamore au_intr_disestablish(sp->as_hardint); 350 1.1 gdamore sp->as_hardint = 0; 351 1.1 gdamore 352 1.5 ad softint_disestablish(ih); 353 1.1 gdamore sp->as_softint = 0; 354 1.1 gdamore sp->as_intr = NULL; 355 1.1 gdamore sp->as_intrarg = NULL; 356 1.1 gdamore } 357 1.1 gdamore 358 1.1 gdamore /* 359 1.1 gdamore * FYI: Hot detach of PCMCIA is supposedly safe because H/W doesn't 360 1.1 gdamore * fault on accesses to missing hardware. 361 1.1 gdamore */ 362 1.1 gdamore void 363 1.1 gdamore aupcm_event_thread(void *arg) 364 1.1 gdamore { 365 1.1 gdamore struct aupcm_softc *sc = arg; 366 1.1 gdamore struct aupcm_slot *sp; 367 1.1 gdamore int s, i, attach, detach; 368 1.1 gdamore 369 1.1 gdamore for (;;) { 370 1.1 gdamore s = splhigh(); 371 1.1 gdamore if (sc->sc_wake == 0) { 372 1.1 gdamore splx(s); 373 1.1 gdamore /* 374 1.1 gdamore * XXX: Currently, the au_icu.c lacks support 375 1.1 gdamore * for edge-triggered interrupts. So we 376 1.1 gdamore * cannot really use the status change 377 1.13 andvar * interrupts. For now we poll (once per sec). 378 1.1 gdamore * FYI, Linux does it this way, and they *do* 379 1.1 gdamore * have support for edge triggered interrupts. 380 1.1 gdamore * Go figure. 381 1.1 gdamore */ 382 1.1 gdamore tsleep(&sc->sc_wake, PWAIT, "aupcm_event", hz); 383 1.10 dholland s = splhigh(); 384 1.1 gdamore } 385 1.1 gdamore sc->sc_wake = 0; 386 1.1 gdamore 387 1.1 gdamore attach = detach = 0; 388 1.1 gdamore for (i = 0; i < sc->sc_nslots; i++) { 389 1.1 gdamore sp = &sc->sc_slots[i]; 390 1.1 gdamore 391 1.1 gdamore if (sc->sc_slot_status(sp->as_slot) != 0) { 392 1.1 gdamore if (!sp->as_status) { 393 1.1 gdamore DPRINTF(("%s: card %d insertion\n", 394 1.9 kiyohara device_xname(sc->sc_dev), i)); 395 1.1 gdamore attach |= (1 << i); 396 1.1 gdamore sp->as_status = 1; 397 1.1 gdamore } 398 1.1 gdamore } else { 399 1.1 gdamore if (sp->as_status) { 400 1.1 gdamore DPRINTF(("%s: card %d removal\n", 401 1.9 kiyohara device_xname(sc->sc_dev), i)); 402 1.1 gdamore detach |= (1 << i); 403 1.1 gdamore sp->as_status = 0; 404 1.1 gdamore } 405 1.1 gdamore } 406 1.1 gdamore } 407 1.1 gdamore splx(s); 408 1.1 gdamore 409 1.1 gdamore for (i = 0; i < sc->sc_nslots; i++) { 410 1.1 gdamore sp = &sc->sc_slots[i]; 411 1.1 gdamore 412 1.1 gdamore if (detach & (1 << i)) { 413 1.1 gdamore aupcm_slot_disable(sp); 414 1.9 kiyohara pcmcia_card_detach(sp->as_pcmcia, DETACH_FORCE); 415 1.1 gdamore } else if (attach & (1 << i)) { 416 1.1 gdamore /* 417 1.1 gdamore * until the function is enabled, don't 418 1.1 gdamore * honor interrupts 419 1.1 gdamore */ 420 1.1 gdamore sp->as_enabled = 0; 421 1.1 gdamore au_intr_disable(sp->as_card_irq); 422 1.1 gdamore pcmcia_card_attach(sp->as_pcmcia); 423 1.1 gdamore } 424 1.1 gdamore } 425 1.1 gdamore } 426 1.1 gdamore } 427 1.1 gdamore 428 1.1 gdamore #if 0 429 1.1 gdamore void 430 1.1 gdamore aupcm_status_intr(void *arg) 431 1.1 gdamore { 432 1.1 gdamore int s; 433 1.1 gdamore struct aupcm_softc *sc = arg; 434 1.1 gdamore 435 1.1 gdamore s = splhigh(); 436 1.1 gdamore 437 1.1 gdamore /* kick the status thread so it does its bit */ 438 1.1 gdamore sc->sc_wake = 1; 439 1.1 gdamore wakeup(&sc->sc_wake); 440 1.1 gdamore 441 1.1 gdamore splx(s); 442 1.1 gdamore } 443 1.1 gdamore #endif 444 1.1 gdamore 445 1.1 gdamore int 446 1.1 gdamore aupcm_card_intr(void *arg) 447 1.1 gdamore { 448 1.1 gdamore struct aupcm_slot *sp = arg; 449 1.1 gdamore 450 1.1 gdamore /* disable the hard interrupt for now */ 451 1.1 gdamore au_intr_disable(sp->as_card_irq); 452 1.1 gdamore 453 1.1 gdamore if (sp->as_intr != NULL) { 454 1.5 ad softint_schedule(sp->as_softint); 455 1.1 gdamore } 456 1.1 gdamore 457 1.1 gdamore return 1; 458 1.1 gdamore } 459 1.1 gdamore 460 1.1 gdamore void 461 1.1 gdamore aupcm_softintr(void *arg) 462 1.1 gdamore { 463 1.1 gdamore struct aupcm_slot *sp = arg; 464 1.1 gdamore int s; 465 1.1 gdamore 466 1.1 gdamore sp->as_intr(sp->as_intrarg); 467 1.1 gdamore 468 1.1 gdamore s = splhigh(); 469 1.1 gdamore 470 1.1 gdamore if (sp->as_intr && sp->as_enabled) { 471 1.1 gdamore au_intr_enable(sp->as_card_irq); 472 1.1 gdamore } 473 1.1 gdamore 474 1.1 gdamore splx(s); 475 1.1 gdamore } 476 1.1 gdamore 477 1.1 gdamore void 478 1.1 gdamore aupcm_slot_enable(pcmcia_chipset_handle_t pch) 479 1.1 gdamore { 480 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 481 1.1 gdamore int s; 482 1.1 gdamore 483 1.1 gdamore /* no interrupts while we reset the card, please */ 484 1.1 gdamore if (sp->as_intr) 485 1.1 gdamore au_intr_disable(sp->as_card_irq); 486 1.1 gdamore 487 1.1 gdamore /* 488 1.1 gdamore * XXX: should probably lock to make sure slot_disable and 489 1.1 gdamore * enable not called together. However, i believe that the 490 1.1 gdamore * event thread basically serializes them anyway. 491 1.1 gdamore */ 492 1.1 gdamore 493 1.1 gdamore sp->as_softc->sc_slot_enable(sp->as_slot); 494 1.1 gdamore /* card is powered up now, honor device interrupts */ 495 1.1 gdamore 496 1.1 gdamore s = splhigh(); 497 1.1 gdamore sp->as_enabled = 1; 498 1.1 gdamore if (sp->as_intr) 499 1.1 gdamore au_intr_enable(sp->as_card_irq); 500 1.1 gdamore splx(s); 501 1.1 gdamore } 502 1.1 gdamore 503 1.1 gdamore void 504 1.1 gdamore aupcm_slot_disable(pcmcia_chipset_handle_t pch) 505 1.1 gdamore { 506 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 507 1.1 gdamore int s; 508 1.1 gdamore 509 1.1 gdamore s = splhigh(); 510 1.1 gdamore au_intr_disable(sp->as_card_irq); 511 1.1 gdamore sp->as_enabled = 0; 512 1.1 gdamore splx(s); 513 1.1 gdamore 514 1.1 gdamore sp->as_softc->sc_slot_disable(sp->as_slot); 515 1.1 gdamore } 516 1.1 gdamore 517 1.1 gdamore void 518 1.1 gdamore aupcm_slot_settype(pcmcia_chipset_handle_t pch, int type) 519 1.1 gdamore { 520 1.1 gdamore /* we do nothing now : type == PCMCIA_IFTYPE_IO */ 521 1.1 gdamore } 522 1.1 gdamore 523 1.1 gdamore int 524 1.1 gdamore aupcm_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size, 525 1.1 gdamore struct pcmcia_mem_handle *pcmh) 526 1.1 gdamore { 527 1.1 gdamore pcmh->memt = NULL; 528 1.1 gdamore pcmh->size = pcmh->realsize = size; 529 1.1 gdamore pcmh->addr = 0; 530 1.1 gdamore pcmh->mhandle = 0; 531 1.1 gdamore 532 1.1 gdamore return 0; 533 1.1 gdamore } 534 1.1 gdamore 535 1.1 gdamore void 536 1.1 gdamore aupcm_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmh) 537 1.1 gdamore { 538 1.1 gdamore /* nothing to do */ 539 1.1 gdamore } 540 1.1 gdamore 541 1.1 gdamore int 542 1.1 gdamore aupcm_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr, 543 1.1 gdamore bus_size_t size, struct pcmcia_mem_handle *pcmh, bus_size_t *offsetp, 544 1.1 gdamore int *windowp) 545 1.1 gdamore { 546 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 547 1.1 gdamore int win, err; 548 1.1 gdamore int s; 549 1.1 gdamore 550 1.1 gdamore s = splhigh(); 551 1.1 gdamore for (win = 0; win < AUPCMCIA_NWINS; win++) { 552 1.1 gdamore if (sp->as_wins[win] == NULL) { 553 1.1 gdamore sp->as_wins[win] = pcmh; 554 1.1 gdamore break; 555 1.1 gdamore } 556 1.1 gdamore } 557 1.1 gdamore splx(s); 558 1.1 gdamore 559 1.1 gdamore if (win >= AUPCMCIA_NWINS) { 560 1.1 gdamore return ENOMEM; 561 1.1 gdamore } 562 1.1 gdamore 563 1.1 gdamore if (kind & PCMCIA_MEM_ATTR) { 564 1.1 gdamore pcmh->memt = &sp->as_attrt; 565 1.1 gdamore NOISY(("mapping ATTR addr %x size %x\n", (uint32_t)addr, 566 1.1 gdamore (uint32_t)size)); 567 1.1 gdamore } else { 568 1.1 gdamore pcmh->memt = &sp->as_memt; 569 1.1 gdamore NOISY(("mapping MEMORY addr %x size %x\n", (uint32_t)addr, 570 1.1 gdamore (uint32_t)size)); 571 1.1 gdamore } 572 1.1 gdamore 573 1.1 gdamore if ((size + addr) > (64 * 1024 * 1024)) 574 1.1 gdamore return EINVAL; 575 1.1 gdamore 576 1.1 gdamore pcmh->size = size; 577 1.1 gdamore 578 1.1 gdamore err = bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh); 579 1.1 gdamore if (err != 0) { 580 1.1 gdamore sp->as_wins[win] = NULL; 581 1.1 gdamore return err; 582 1.1 gdamore } 583 1.1 gdamore *offsetp = 0; 584 1.1 gdamore *windowp = win; 585 1.1 gdamore 586 1.1 gdamore return 0; 587 1.1 gdamore } 588 1.1 gdamore 589 1.1 gdamore void 590 1.1 gdamore aupcm_mem_unmap(pcmcia_chipset_handle_t pch, int win) 591 1.1 gdamore { 592 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 593 1.1 gdamore struct pcmcia_mem_handle *pcmh; 594 1.1 gdamore 595 1.1 gdamore pcmh = (struct pcmcia_mem_handle *)sp->as_wins[win]; 596 1.1 gdamore sp->as_wins[win] = NULL; 597 1.1 gdamore 598 1.1 gdamore NOISY(("memory umap virtual %x\n", (uint32_t)pcmh->memh)); 599 1.1 gdamore bus_space_unmap(pcmh->memt, pcmh->memh, pcmh->size); 600 1.1 gdamore pcmh->memt = NULL; 601 1.1 gdamore } 602 1.1 gdamore 603 1.1 gdamore int 604 1.1 gdamore aupcm_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, 605 1.1 gdamore bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih) 606 1.1 gdamore { 607 1.1 gdamore struct aupcm_slot *sp = (struct aupcm_slot *)pch; 608 1.1 gdamore bus_space_handle_t bush; 609 1.1 gdamore int err; 610 1.1 gdamore 611 1.1 gdamore pih->iot = &sp->as_iot; 612 1.1 gdamore pih->size = size; 613 1.1 gdamore pih->flags = 0; 614 1.1 gdamore 615 1.1 gdamore /* 616 1.1 gdamore * start from the initial offset - this gets us a slot 617 1.1 gdamore * specific address, while still leaving the addresses more or 618 1.1 gdamore * less zero-based which is required for x86-style device 619 1.1 gdamore * drivers. 620 1.1 gdamore */ 621 1.1 gdamore err = bus_space_alloc(pih->iot, start, 0x100000, 622 1.1 gdamore size, align, 0, 0, &pih->addr, &bush); 623 1.1 gdamore NOISY(("start = %x, addr = %x, size = %x, bush = %x\n", 624 1.1 gdamore (uint32_t)start, (uint32_t)pih->addr, (uint32_t)size, 625 1.1 gdamore (uint32_t)bush)); 626 1.1 gdamore 627 1.1 gdamore /* and we convert it back */ 628 1.1 gdamore if (err == 0) { 629 1.1 gdamore pih->ihandle = (void *)bush; 630 1.1 gdamore } 631 1.1 gdamore 632 1.1 gdamore return (err); 633 1.1 gdamore } 634 1.1 gdamore 635 1.1 gdamore void 636 1.1 gdamore aupcm_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih) 637 1.1 gdamore { 638 1.1 gdamore bus_space_free(pih->iot, (bus_space_handle_t)pih->ihandle, 639 1.1 gdamore pih->size); 640 1.1 gdamore } 641 1.1 gdamore 642 1.1 gdamore int 643 1.1 gdamore aupcm_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset, 644 1.1 gdamore bus_size_t size, struct pcmcia_io_handle *pih, int *windowp) 645 1.1 gdamore { 646 1.1 gdamore int err; 647 1.1 gdamore 648 1.1 gdamore err = bus_space_subregion(pih->iot, (bus_space_handle_t)pih->ihandle, 649 1.1 gdamore offset, size, &pih->ioh); 650 1.1 gdamore NOISY(("io map offset = %x, size = %x, ih = %x, hdl=%x\n", 651 1.1 gdamore (uint32_t)offset, (uint32_t)size, 652 1.1 gdamore (uint32_t)pih->ihandle, (uint32_t)pih->ioh)); 653 1.1 gdamore 654 1.1 gdamore return err; 655 1.1 gdamore } 656 1.1 gdamore 657 1.1 gdamore void 658 1.1 gdamore aupcm_io_unmap(pcmcia_chipset_handle_t pch, int win) 659 1.1 gdamore { 660 1.1 gdamore /* We mustn't unmap/free subregion bus space! */ 661 1.1 gdamore NOISY(("io unmap\n")); 662 1.1 gdamore } 663