[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

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