[BACK]Return to i82365_isasubr.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/i82365_isasubr.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: i82365_isasubr.c,v 1.21 2006/03/12 01:38:34 brad Exp $        */
        !             2: /*     $NetBSD: i82365_isasubr.c,v 1.1 1998/06/07 18:28:31 sommerfe Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1998 Bill Sommerfeld.  All rights reserved.
        !             6:  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by Marc Horowitz.
        !            19:  * 4. The name of the author may not be used to endorse or promote products
        !            20:  *    derived from this software without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34:
        !            35: #include <sys/types.h>
        !            36: #include <sys/param.h>
        !            37: #include <sys/systm.h>
        !            38: #include <sys/device.h>
        !            39: #include <sys/extent.h>
        !            40: #include <sys/malloc.h>
        !            41:
        !            42: #include <machine/bus.h>
        !            43: #include <machine/intr.h>
        !            44:
        !            45: #include <dev/isa/isareg.h>
        !            46: #include <dev/isa/isavar.h>
        !            47:
        !            48: #include <dev/pcmcia/pcmciareg.h>
        !            49: #include <dev/pcmcia/pcmciavar.h>
        !            50: #include <dev/pcmcia/pcmciachip.h>
        !            51:
        !            52: #include <dev/ic/i82365reg.h>
        !            53: #include <dev/ic/i82365var.h>
        !            54: #include <dev/isa/i82365_isavar.h>
        !            55:
        !            56: /*****************************************************************************
        !            57:  * Configurable parameters.
        !            58:  *****************************************************************************/
        !            59:
        !            60: /*
        !            61:  * Default I/O allocation range.  If both are set to non-zero, these
        !            62:  * values will be used instead.  Otherwise, the code attempts to probe
        !            63:  * the bus width.
        !            64:  */
        !            65:
        !            66: #ifndef PCIC_ISA_ALLOC_IOBASE
        !            67: #define        PCIC_ISA_ALLOC_IOBASE           0
        !            68: #endif
        !            69:
        !            70: #ifndef PCIC_ISA_ALLOC_IOSIZE
        !            71: #define        PCIC_ISA_ALLOC_IOSIZE           0
        !            72: #endif
        !            73:
        !            74: int    pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
        !            75: int    pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
        !            76:
        !            77: /*
        !            78:  * I am well aware that some of later irqs below are not for real, but there
        !            79:  * is a way to deal with that in the search loop.  For beauty's sake I want
        !            80:  * this list to be a permutation of 0..15.
        !            81:  */
        !            82: char   pcic_isa_intr_list[] = {
        !            83:        3, 4, 14, 9, 5, 12, 10, 11, 15, 13, 7, 1, 6, 2, 0, 8
        !            84: };
        !            85:
        !            86: struct pcic_ranges pcic_isa_addr[] = {
        !            87:        { 0x340, 0x030 },
        !            88:        { 0x300, 0x030 },
        !            89:        { 0x390, 0x020 },
        !            90:        { 0x400, 0xbff },
        !            91:        { 0, 0 },               /* terminator */
        !            92: };
        !            93:
        !            94:
        !            95: /*****************************************************************************
        !            96:  * End of configurable parameters.
        !            97:  *****************************************************************************/
        !            98:
        !            99: #ifdef PCICISADEBUG
        !           100: int    pcicsubr_debug = 1 /* XXX */ ;
        !           101: #define        DPRINTF(arg) if (pcicsubr_debug) printf arg;
        !           102: #else
        !           103: #define        DPRINTF(arg)
        !           104: #endif
        !           105:
        !           106: static int pcic_intr_seen;
        !           107:
        !           108: void
        !           109: pcic_isa_bus_width_probe(sc, iot, ioh, base, length)
        !           110:        struct pcic_softc *sc;
        !           111:        bus_space_tag_t iot;
        !           112:        bus_space_handle_t ioh;
        !           113:        bus_addr_t base;
        !           114:        u_int32_t length;
        !           115: {
        !           116:        bus_space_handle_t ioh_high;
        !           117:        int i, iobuswidth, tmp1, tmp2;
        !           118:
        !           119:        /*
        !           120:         * figure out how wide the isa bus is.  Do this by checking if the
        !           121:         * pcic controller is mirrored 0x400 above where we expect it to be.
        !           122:         *
        !           123:         * XXX some hardware doesn't seem to grok addresses in 0x400
        !           124:         * range-- apparently missing a bit or more of address lines.
        !           125:         * (e.g. CIRRUS_PD672X with Linksys EthernetCard ne2000 clone
        !           126:         * in TI TravelMate 5000 -- not clear which is at fault)
        !           127:         *
        !           128:         * Add a kludge to detect 10 bit wide buses and deal with them,
        !           129:         * and also a config file option to override the probe.
        !           130:         */
        !           131:        iobuswidth = 12;
        !           132:
        !           133:        /* Map i/o space. */
        !           134:        if (bus_space_map(iot, base + 0x400, length, 0, &ioh_high)) {
        !           135:                printf("%s: can't map high i/o space\n", sc->dev.dv_xname);
        !           136:                return;
        !           137:        }
        !           138:
        !           139:        for (i = 0; i < PCIC_NSLOTS; i++) {
        !           140:                if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
        !           141:                        /*
        !           142:                         * read the ident flags from the normal space and
        !           143:                         * from the mirror, and compare them
        !           144:                         */
        !           145:                        bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
        !           146:                            sc->handle[i].sock + PCIC_IDENT);
        !           147:                        tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
        !           148:
        !           149:                        bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
        !           150:                            sc->handle[i].sock + PCIC_IDENT);
        !           151:                        tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
        !           152:
        !           153:                        if (tmp1 == tmp2)
        !           154:                                iobuswidth = 10;
        !           155:                }
        !           156:        }
        !           157:
        !           158:        bus_space_free(iot, ioh_high, length);
        !           159:
        !           160:        sc->ranges = pcic_isa_addr;
        !           161:        if (iobuswidth == 10) {
        !           162:                sc->iobase = 0x000;
        !           163:                sc->iosize = 0x400;
        !           164:        } else {
        !           165:                sc->iobase = 0x0000;
        !           166:                sc->iosize = 0x1000;
        !           167:        }
        !           168:
        !           169:        DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
        !           170:            sc->dev.dv_xname, (long) sc->iobase,
        !           171:            (long) sc->iobase + sc->iosize));
        !           172:
        !           173:        if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
        !           174:                sc->iobase = pcic_isa_alloc_iobase;
        !           175:                sc->iosize = pcic_isa_alloc_iosize;
        !           176:
        !           177:                DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx "
        !           178:                    "(config override)\n", sc->dev.dv_xname, (long) sc->iobase,
        !           179:                    (long) sc->iobase + sc->iosize));
        !           180:        }
        !           181: }
        !           182:
        !           183:
        !           184: void *
        !           185: pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg, xname)
        !           186:        pcmcia_chipset_handle_t pch;
        !           187:        struct pcmcia_function *pf;
        !           188:        int ipl;
        !           189:        int (*fct)(void *);
        !           190:        void *arg;
        !           191:        char *xname;
        !           192: {
        !           193:        struct pcic_handle *h = (struct pcic_handle *)pch;
        !           194:        struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
        !           195:        isa_chipset_tag_t ic = sc->intr_est;
        !           196:        int irq, ist, reg;
        !           197:
        !           198:        if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
        !           199:                ist = IST_LEVEL;
        !           200:        else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
        !           201:                ist = IST_PULSE;
        !           202:        else
        !           203:                ist = IST_EDGE;
        !           204:
        !           205:        irq = pcic_intr_find(sc, ist);
        !           206:        if (!irq)
        !           207:                return (NULL);
        !           208:
        !           209:        h->ih_irq = irq;
        !           210:        reg = pcic_read(h, PCIC_INTR);
        !           211:        reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
        !           212:        pcic_write(h, PCIC_INTR, reg | irq);
        !           213:
        !           214:        return isa_intr_establish(ic, irq, ist, ipl, fct, arg,
        !           215:            h->pcmcia->dv_xname);
        !           216: }
        !           217:
        !           218: void
        !           219: pcic_isa_chip_intr_disestablish(pch, ih)
        !           220:        pcmcia_chipset_handle_t pch;
        !           221:        void *ih;
        !           222: {
        !           223:        struct pcic_handle *h = (struct pcic_handle *) pch;
        !           224:        struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
        !           225:        isa_chipset_tag_t ic = sc->intr_est;
        !           226:        int reg;
        !           227:
        !           228:        h->ih_irq = 0;
        !           229:
        !           230:        isa_intr_disestablish(ic, ih);
        !           231:
        !           232:        reg = pcic_read(h, PCIC_INTR);
        !           233:        reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
        !           234:        pcic_write(h, PCIC_INTR, reg);
        !           235: }
        !           236:
        !           237: const char *
        !           238: pcic_isa_chip_intr_string(pch, ih)
        !           239:        pcmcia_chipset_handle_t pch;
        !           240:        void *ih;
        !           241: {
        !           242:        struct pcic_handle *h = (struct pcic_handle *)pch;
        !           243:        static char irqstr[64];
        !           244:
        !           245:        if (ih == NULL)
        !           246:                snprintf(irqstr, sizeof(irqstr), "couldn't establish interrupt");
        !           247:        else
        !           248:                snprintf(irqstr, sizeof(irqstr), "irq %d", h->ih_irq);
        !           249:        return (irqstr);
        !           250: }
        !           251:
        !           252: int
        !           253: pcic_intr_probe(v)
        !           254:        void *v;
        !           255: {
        !           256:        pcic_intr_seen = 1;
        !           257:        return (1);
        !           258: }
        !           259:
        !           260: /*
        !           261:  * Try to find a working interrupt, first by searching for a unique
        !           262:  * irq that is known to work, verified by tickling the pcic, then
        !           263:  * by searching for a shareable irq known to work.  If the pcic does
        !           264:  * not allow tickling we then fallback to the same strategy but without
        !           265:  * tickling just assuming the first usable irq found works.
        !           266:  */
        !           267: int
        !           268: pcic_intr_find(sc, ist)
        !           269:        struct pcic_softc *sc;
        !           270:        int ist;
        !           271: {
        !           272:        struct pcic_handle *ph = &sc->handle[0];
        !           273:        isa_chipset_tag_t ic = sc->intr_est;
        !           274:        int i, tickle, check, irq, chosen_irq = 0, csc_touched = 0;
        !           275:        void *ih;
        !           276:        u_int8_t saved_csc_intr;
        !           277:
        !           278:        /*
        !           279:         * First time, look for entirely free interrupts, last
        !           280:         * time accept shareable ones.
        !           281:         */
        !           282:        for (tickle = 1; tickle >= 0; tickle--) {
        !           283:                if (tickle)
        !           284:                        /*
        !           285:                         * Remember card status change interrupt
        !           286:                         * configuration.
        !           287:                         */
        !           288:                        saved_csc_intr = pcic_read(ph, PCIC_CSC_INTR);
        !           289:
        !           290:                for (check = 2; check; check--) {
        !           291:
        !           292:                        /* Walk over all possible interrupts. */
        !           293:                        for (i = 0; i < 16; i++) {
        !           294:                                irq = pcic_isa_intr_list[i];
        !           295:
        !           296:                                if (((1 << irq) &
        !           297:                                     PCIC_CSC_INTR_IRQ_VALIDMASK) == 0)
        !           298:                                        continue;
        !           299:
        !           300:                                if (isa_intr_check(ic, irq, ist) < check)
        !           301:                                        continue;
        !           302:
        !           303:                                if (!tickle) {
        !           304:                                        chosen_irq = irq;
        !           305:                                        goto out;
        !           306:                                }
        !           307:
        !           308:                                /*
        !           309:                                 * Prepare for an interrupt tickle.
        !           310:                                 * As this can be called from an
        !           311:                                 * IPL_TTY context (the card status
        !           312:                                 * change interrupt) we need to do
        !           313:                                 * higher.
        !           314:                                 */
        !           315:                                ih = isa_intr_establish(ic, irq, ist, IPL_VM,
        !           316:                                    pcic_intr_probe, 0, NULL);
        !           317:                                if (ih == NULL)
        !           318:                                        continue;
        !           319:                                pcic_intr_seen = 0;
        !           320:                                pcic_write(ph, PCIC_CSC_INTR,
        !           321:                                    (saved_csc_intr & ~PCIC_CSC_INTR_IRQ_MASK)
        !           322:                                    | PCIC_CSC_INTR_CD_ENABLE
        !           323:                                    | (irq << PCIC_CSC_INTR_IRQ_SHIFT));
        !           324:                                csc_touched = 1;
        !           325:
        !           326:                                /* Teehee, you tickle me! ;-) */
        !           327:                                pcic_write(ph, PCIC_CARD_DETECT,
        !           328:                                    pcic_read(ph, PCIC_CARD_DETECT) |
        !           329:                                    PCIC_CARD_DETECT_SW_INTR);
        !           330:
        !           331:                                /*
        !           332:                                 * Delay for 10 ms and then shut the
        !           333:                                 * probe off.  That should be plenty
        !           334:                                 * of time for the interrupt to be
        !           335:                                 * handled.
        !           336:                                 */
        !           337:                                delay(10000);
        !           338:
        !           339:                                /* Acknowledge the interrupt. */
        !           340:                                pcic_read(ph, PCIC_CSC);
        !           341:
        !           342:                                isa_intr_disestablish(ic, ih);
        !           343:
        !           344:                                if (pcic_intr_seen) {
        !           345:                                        chosen_irq = irq;
        !           346:                                        goto out;
        !           347:                                }
        !           348:                        }
        !           349:                }
        !           350:        }
        !           351:
        !           352: out:
        !           353:        if (csc_touched)
        !           354:                /* Restore card detection bit. */
        !           355:                pcic_write(ph, PCIC_CSC_INTR, saved_csc_intr);
        !           356:        return (chosen_irq);
        !           357: }

CVSweb