Home | History | Annotate | Line # | Download | only in dev
aupcmcia.c revision 1.10.32.1
      1  1.10.32.1   thorpej /* $NetBSD: aupcmcia.c,v 1.10.32.1 2021/03/21 21:09:03 thorpej 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.10.32.1   thorpej __KERNEL_RCSID(0, "$NetBSD: aupcmcia.c,v 1.10.32.1 2021/03/21 21:09:03 thorpej 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.10.32.1   thorpej 		sp->as_pcmcia = config_found(self, &paa, aupcm_print,
    274  1.10.32.1   thorpej 		    CFARG_EOL);
    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.1   gdamore 			 * inerrupts.  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