[BACK]Return to ts102.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / dev

Annotation of sys/arch/sparc/dev/ts102.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ts102.c,v 1.18 2006/08/11 18:57:35 miod Exp $ */
                      2: /*
                      3:  * Copyright (c) 2003, 2004, Miodrag Vallat.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     15:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     16:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     17:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     18:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     19:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     20:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     22:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     23:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     24:  * POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
                     27: /*
                     28:  * Driver for the PCMCIA controller found in Tadpole SPARCbook 3 series
                     29:  * notebooks.
                     30:  *
                     31:  * Based on the information provided in the SPARCbook 3 Technical Reference
                     32:  * Manual (s3gxtrmb.pdf), chapter 7.  A few ramblings against this document
                     33:  * and/or the chip itself are scattered across this file.
                     34:  *
                     35:  * Implementation notes:
                     36:  *
                     37:  * - The TS102 exports its PCMCIA windows as SBus memory ranges: 64MB for
                     38:  *   the common memory window, and 16MB for the attribute and I/O windows.
                     39:  *
                     40:  *   Mapping the whole windows would consume 192MB of address space, which
                     41:  *   is much more that what the iospace can offer.
                     42:  *
                     43:  *   A best-effort solution would be to map the windows on demand. However,
                     44:  *   due to the way mapdev() works, the va used for the mappings would be
                     45:  *   lost after unmapping (although using an extent to register iospace memory
                     46:  *   usage would fix this). So, instead, we will do a fixed mapping of a subset
                     47:  *   of each window upon attach - this is similar to what the stp4020 driver
                     48:  *   does.
                     49:  *
                     50:  * - IPL for the cards interrupt handlers are not respected. See the stp4020
                     51:  *   driver source for comments about this.
                     52:  *
                     53:  * Endianness farce:
                     54:  *
                     55:  * - The documentation pretends that the endianness settings only affect the
                     56:  *   common memory window. Gee, thanks a lot. What about other windows, then?
                     57:  *   As a result, this driver runs with endianness conversions turned off.
                     58:  *
                     59:  * - One of the little-endian SBus and big-endian PCMCIA flags has the reverse
                     60:  *   meaning, actually. To achieve a ``no endianness conversion'' status,
                     61:  *   one has to be set and the other unset. It does not matter which one,
                     62:  *   though.
                     63:  */
                     64:
                     65: #include <sys/param.h>
                     66: #include <sys/systm.h>
                     67: #include <sys/conf.h>
                     68: #include <sys/device.h>
                     69: #include <sys/kthread.h>
                     70: #include <sys/proc.h>
                     71: #include <sys/queue.h>
                     72:
                     73: #include <machine/bus.h>
                     74:
                     75: #include <uvm/uvm_extern.h>
                     76:
                     77: #include <dev/pcmcia/pcmciareg.h>
                     78: #include <dev/pcmcia/pcmciavar.h>
                     79: #include <dev/pcmcia/pcmciachip.h>
                     80:
                     81: #include <sparc/dev/sbusvar.h>
                     82: #include <sparc/dev/tctrlvar.h>
                     83: #include <sparc/dev/ts102reg.h>
                     84:
                     85: #define        TS102_NUM_SLOTS         2
                     86:
                     87: /*
                     88:  * Memory ranges
                     89:  */
                     90: #define        TS102_RANGE_COMMON      0
                     91: #define        TS102_RANGE_ATTR        1
                     92: #define        TS102_RANGE_IO          2
                     93:
                     94: #define        TS102_RANGE_CNT         3
                     95: #define        TS102_NUM_RANGES        (TS102_RANGE_CNT * TS102_NUM_SLOTS)
                     96:
                     97: #define        TS102_ARBITRARY_MAP_SIZE        (1 * 1024 * 1024)
                     98:
                     99: struct tslot_softc;
                    100:
                    101: /*
                    102:  * Per-slot data
                    103:  */
                    104: struct tslot_data {
                    105:        struct tslot_softc      *td_parent;
                    106:        struct device           *td_pcmcia;
                    107:
                    108:        volatile u_int8_t       *td_regs;
                    109:        struct rom_reg          td_rr;
                    110:        vaddr_t                 td_space[TS102_RANGE_CNT];
                    111:
                    112:        /* Interrupt handler */
                    113:        int                     (*td_intr)(void *);
                    114:        void                    *td_intrarg;
                    115:
                    116:        /* Socket status */
                    117:        int                     td_slot;
                    118:        int                     td_status;
                    119: #define        TS_CARD                 0x0001
                    120: };
                    121:
                    122: struct tslot_softc {
                    123:        struct device   sc_dev;
                    124:
                    125:        struct intrhand sc_ih;
                    126:
                    127:        pcmcia_chipset_tag_t sc_pct;
                    128:
                    129:        struct proc     *sc_thread;                     /* event thread */
                    130:        unsigned int    sc_events;      /* sockets with pending events */
                    131:
                    132:        struct tslot_data sc_slot[TS102_NUM_SLOTS];
                    133: };
                    134:
                    135: void   tslot_attach(struct device *, struct device *, void *);
                    136: void   tslot_create_event_thread(void *);
                    137: void   tslot_event_thread(void *);
                    138: int    tslot_intr(void *);
                    139: void   tslot_intr_disestablish(pcmcia_chipset_handle_t, void *);
                    140: void   *tslot_intr_establish(pcmcia_chipset_handle_t, struct pcmcia_function *,
                    141:            int, int (*)(void *), void *, char *);
                    142: const char *tslot_intr_string(pcmcia_chipset_handle_t, void *);
                    143: int    tslot_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
                    144:            bus_size_t, struct pcmcia_io_handle *);
                    145: void   tslot_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
                    146: int    tslot_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
                    147:            struct pcmcia_io_handle *, int *);
                    148: void   tslot_io_unmap(pcmcia_chipset_handle_t, int);
                    149: int    tslot_match(struct device *, void *, void *);
                    150: int    tslot_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
                    151:            struct pcmcia_mem_handle *);
                    152: void   tslot_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *);
                    153: int    tslot_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
                    154:            struct pcmcia_mem_handle *, bus_size_t *, int *);
                    155: void   tslot_mem_unmap(pcmcia_chipset_handle_t, int);
                    156: int    tslot_print(void *, const char *);
                    157: void   tslot_queue_event(struct tslot_softc *, int);
                    158: void   tslot_reset(struct tslot_data *, u_int32_t);
                    159: void   tslot_slot_disable(pcmcia_chipset_handle_t);
                    160: void   tslot_slot_enable(pcmcia_chipset_handle_t);
                    161: void   tslot_slot_intr(struct tslot_data *, int);
                    162:
                    163: struct cfattach tslot_ca = {
                    164:        sizeof(struct tslot_softc), tslot_match, tslot_attach
                    165: };
                    166:
                    167: struct cfdriver tslot_cd = {
                    168:        NULL, "tslot", DV_DULL
                    169: };
                    170:
                    171: /*
                    172:  * PCMCIA chipset methods
                    173:  */
                    174: struct pcmcia_chip_functions tslot_functions = {
                    175:        tslot_mem_alloc,
                    176:        tslot_mem_free,
                    177:        tslot_mem_map,
                    178:        tslot_mem_unmap,
                    179:
                    180:        tslot_io_alloc,
                    181:        tslot_io_free,
                    182:        tslot_io_map,
                    183:        tslot_io_unmap,
                    184:
                    185:        tslot_intr_establish,
                    186:        tslot_intr_disestablish,
                    187:        tslot_intr_string,
                    188:
                    189:        tslot_slot_enable,
                    190:        tslot_slot_disable
                    191: };
                    192:
                    193: #define        TSLOT_READ(slot, offset) \
                    194:        *(volatile u_int16_t *)((slot)->td_regs + (offset))
                    195: #define        TSLOT_WRITE(slot, offset, value) \
                    196:        *(volatile u_int16_t *)((slot)->td_regs + (offset)) = (value)
                    197:
                    198: /*
                    199:  * Attachment and initialization
                    200:  */
                    201:
                    202: int
                    203: tslot_match(struct device *parent, void *vcf, void *aux)
                    204: {
                    205:        struct confargs *ca = aux;
                    206:
                    207:        return (strcmp("ts102", ca->ca_ra.ra_name) == 0);
                    208: }
                    209:
                    210: void
                    211: tslot_attach(struct device *parent, struct device *self, void *args)
                    212: {
                    213:        struct confargs *ca = args;
                    214:        struct tslot_softc *sc = (struct tslot_softc *)self;
                    215:        struct romaux *ra;
                    216:        struct rom_range ranges[TS102_NUM_RANGES], *range;
                    217:        struct tslot_data *td;
                    218:        volatile u_int8_t *regs;
                    219:        int node, nranges, slot, rnum;
                    220:
                    221:        ra = &ca->ca_ra;
                    222:        node = ra->ra_node;
                    223:        regs = mapiodev(&ra->ra_reg[0], 0, ra->ra_len);
                    224:
                    225:        /*
                    226:         * Find memory ranges
                    227:         */
                    228:        nranges = getproplen(node, "ranges") / sizeof(struct rom_range);
                    229:        if (nranges < TS102_NUM_RANGES) {
                    230:                printf(": expected %d memory ranges, got %d\n",
                    231:                    TS102_NUM_RANGES, nranges);
                    232:                return;
                    233:        }
                    234:        getprop(node, "ranges", ranges, sizeof ranges);
                    235:
                    236:        /*
                    237:         * Ranges being relative to this sbus slot, turn them into absolute
                    238:         * addresses.
                    239:         */
                    240:        for (rnum = 0; rnum < TS102_NUM_RANGES; rnum++) {
                    241:                ranges[rnum].poffset -= TS102_OFFSET_REGISTERS;
                    242:        }
                    243:
                    244:        sc->sc_ih.ih_fun = tslot_intr;
                    245:        sc->sc_ih.ih_arg = sc;
                    246:        intr_establish(ra->ra_intr[0].int_pri, &sc->sc_ih, -1, self->dv_xname);
                    247:        printf(" pri %d", ra->ra_intr[0].int_pri);
                    248:
                    249:        printf(": %d slots\n", TS102_NUM_SLOTS);
                    250:
                    251:        /*
                    252:         * Setup asynchronous event handler
                    253:         */
                    254:        sc->sc_events = 0;
                    255:        kthread_create_deferred(tslot_create_event_thread, sc);
                    256:
                    257:        sc->sc_pct = (pcmcia_chipset_tag_t)&tslot_functions;
                    258:
                    259:        /*
                    260:         * Setup slots
                    261:         */
                    262:        for (slot = 0; slot < TS102_NUM_SLOTS; slot++) {
                    263:                td = &sc->sc_slot[slot];
                    264:                for (rnum = 0; rnum < TS102_RANGE_CNT; rnum++) {
                    265:                        range = ranges + (slot * TS102_RANGE_CNT + rnum);
                    266:                        td->td_rr = ra->ra_reg[0];
                    267:                        td->td_rr.rr_iospace = range->pspace;
                    268:                        td->td_rr.rr_paddr = (void *)
                    269:                           ((u_int32_t)td->td_rr.rr_paddr + range->poffset);
                    270:                        td->td_space[rnum] = (vaddr_t)mapiodev(&td->td_rr, 0,
                    271:                            TS102_ARBITRARY_MAP_SIZE);
                    272:                }
                    273:                td->td_parent = sc;
                    274:                td->td_regs = regs +
                    275:                    slot * (TS102_REG_CARD_B_INT - TS102_REG_CARD_A_INT);
                    276:                td->td_slot = slot;
                    277:                SET_TAG_LITTLE_ENDIAN(&td->td_rr);
                    278:                tslot_reset(td, TS102_ARBITRARY_MAP_SIZE);
                    279:        }
                    280: }
                    281:
                    282: void
                    283: tslot_reset(struct tslot_data *td, u_int32_t iosize)
                    284: {
                    285:        struct pcmciabus_attach_args paa;
                    286:        int ctl, status;
                    287:
                    288:        paa.paa_busname = "pcmcia";
                    289:        paa.pct = (pcmcia_chipset_tag_t)td->td_parent->sc_pct;
                    290:        paa.pch = (pcmcia_chipset_handle_t)td;
                    291:        paa.iobase = 0;
                    292:        paa.iosize = iosize;
                    293:
                    294:        td->td_pcmcia = config_found(&td->td_parent->sc_dev, &paa, tslot_print);
                    295:
                    296:        if (td->td_pcmcia == NULL) {
                    297:                /*
                    298:                 * If no pcmcia attachment, power down the slot.
                    299:                 */
                    300:                tslot_slot_disable((pcmcia_chipset_handle_t)td);
                    301:                return;
                    302:        }
                    303:
                    304:        /*
                    305:         * Initialize the slot
                    306:         */
                    307:
                    308:        ctl = TSLOT_READ(td, TS102_REG_CARD_A_CTL);
                    309:        /* force low addresses */
                    310:        ctl &= ~(TS102_CARD_CTL_AA_MASK | TS102_CARD_CTL_IA_MASK);
                    311:        /* Put SBus and PCMCIA in their respective endian mode */
                    312:        ctl |= TS102_CARD_CTL_SBLE;     /* this is not what it looks like! */
                    313:        ctl &= ~TS102_CARD_CTL_PCMBE;
                    314:        /* disable read ahead and address increment */
                    315:        ctl &= ~TS102_CARD_CTL_RAHD;
                    316:        ctl |= TS102_CARD_CTL_INCDIS;
                    317:        /* power on */
                    318:        ctl &= ~TS102_CARD_CTL_PWRD;
                    319:        TSLOT_WRITE(td, TS102_REG_CARD_A_CTL, ctl);
                    320:
                    321:        /*
                    322:         * Enable interrupt upon insertion/removal
                    323:         */
                    324:
                    325:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
                    326:            TS102_CARD_INT_MASK_CARDDETECT_STATUS);
                    327:
                    328:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
                    329:        if (status & TS102_CARD_STS_PRES) {
                    330:                tadpole_set_pcmcia(td->td_slot, 1);
                    331:                td->td_status = TS_CARD;
                    332:                pcmcia_card_attach(td->td_pcmcia);
                    333:        } else {
                    334:                tadpole_set_pcmcia(td->td_slot, 0);
                    335:                td->td_status = 0;
                    336:        }
                    337: }
                    338:
                    339: /* XXX there ought to be a common function for this... */
                    340: int
                    341: tslot_print(void *aux, const char *description)
                    342: {
                    343:        struct pcmciabus_attach_args *paa = aux;
                    344:        struct tslot_data *td = (struct tslot_data *)paa->pch;
                    345:
                    346:        printf(" socket %d", td->td_slot);
                    347:        return (UNCONF);
                    348: }
                    349:
                    350: /*
                    351:  * PCMCIA Helpers
                    352:  */
                    353:
                    354: int
                    355: tslot_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size,
                    356:     bus_size_t align, struct pcmcia_io_handle *pih)
                    357: {
                    358:        struct tslot_data *td = (struct tslot_data *)pch;
                    359:
                    360: #ifdef TSLOT_DEBUG
                    361:        printf("[io alloc %x-%x]", start, size);
                    362: #endif
                    363:
                    364:        pih->iot = &td->td_rr;
                    365:        pih->ioh = (bus_space_handle_t)(td->td_space[TS102_RANGE_IO]);
                    366:        pih->addr = start;
                    367:        pih->size = size;
                    368:        pih->flags = 0;
                    369:
                    370:        return (0);
                    371: }
                    372:
                    373: void
                    374: tslot_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
                    375: {
                    376: #ifdef TSLOT_DEBUG
                    377:        printf("[io free %x-%x]", pih->start, pih->size);
                    378: #endif
                    379: }
                    380:
                    381: int
                    382: tslot_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
                    383:     bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
                    384: {
                    385:        struct tslot_data *td = (struct tslot_data *)pch;
                    386:
                    387: #ifdef TSLOT_DEBUG
                    388:        printf("[io map %x-%x", offset, size);
                    389: #endif
                    390:
                    391:        pih->iot = &td->td_rr;
                    392:        bus_space_subregion(&td->td_rr, td->td_space[TS102_RANGE_IO],
                    393:            offset, size, &pih->ioh);
                    394:        *windowp = TS102_RANGE_IO;
                    395:
                    396: #ifdef TSLOT_DEBUG
                    397:        printf("->%p/%x]", pih->ioh, size);
                    398: #endif
                    399:
                    400:        return (0);
                    401: }
                    402:
                    403: void
                    404: tslot_io_unmap(pcmcia_chipset_handle_t pch, int win)
                    405: {
                    406: #ifdef TSLOT_DEBUG
                    407:        printf("[io unmap]");
                    408: #endif
                    409: }
                    410:
                    411: int
                    412: tslot_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
                    413:     struct pcmcia_mem_handle *pmh)
                    414: {
                    415:        struct tslot_data *td = (struct tslot_data *)pch;
                    416:
                    417: #ifdef TSLOT_DEBUG
                    418:        printf("[mem alloc %x]", size);
                    419: #endif
                    420:        pmh->memt = &td->td_rr;
                    421:        pmh->size = round_page(size);
                    422:        pmh->addr = 0;
                    423:        pmh->mhandle = 0;
                    424:        pmh->realsize = 0;      /* nothing so far! */
                    425:
                    426:        return (0);
                    427: }
                    428:
                    429: void
                    430: tslot_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
                    431: {
                    432: #ifdef TSLOT_DEBUG
                    433:        printf("[mem free %x]", pmh->size);
                    434: #endif
                    435: }
                    436:
                    437: int
                    438: tslot_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
                    439:     bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
                    440:     int *windowp)
                    441: {
                    442:        struct tslot_data *td = (struct tslot_data *)pch;
                    443:        int slot;
                    444:
                    445:        slot = kind & PCMCIA_MEM_ATTR ? TS102_RANGE_ATTR : TS102_RANGE_COMMON;
                    446: #ifdef TSLOT_DEBUG
                    447:        printf("[mem map %d %x-%x", slot, addr, size);
                    448: #endif
                    449:
                    450:        addr += pmh->addr;
                    451:
                    452:        pmh->memt = &td->td_rr;
                    453:        bus_space_subregion(&td->td_rr, td->td_space[slot],
                    454:            addr, size, &pmh->memh);
                    455:        pmh->realsize = TS102_ARBITRARY_MAP_SIZE - addr;
                    456:        *offsetp = 0;
                    457:        *windowp = slot;
                    458:
                    459: #ifdef TSLOT_DEBUG
                    460:        printf("->%p/%x]", pmh->memh, size);
                    461: #endif
                    462:
                    463:        return (0);
                    464: }
                    465:
                    466: void
                    467: tslot_mem_unmap(pcmcia_chipset_handle_t pch, int win)
                    468: {
                    469: #ifdef TSLOT_DEBUG
                    470:        printf("[mem unmap %d]", win);
                    471: #endif
                    472: }
                    473:
                    474: void
                    475: tslot_slot_disable(pcmcia_chipset_handle_t pch)
                    476: {
                    477:        struct tslot_data *td = (struct tslot_data *)pch;
                    478:
                    479: #ifdef TSLOT_DEBUG
                    480:        printf("%s: disable slot %d\n",
                    481:            td->td_parent->sc_dev.dv_xname, td->td_slot);
                    482: #endif
                    483:
                    484:        /*
                    485:         * Disable card access.
                    486:         */
                    487:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
                    488:            TSLOT_READ(td, TS102_REG_CARD_A_STS) & ~TS102_CARD_STS_ACEN);
                    489:
                    490:        /*
                    491:         * Disable interrupts, except for insertion.
                    492:         */
                    493:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
                    494:            TS102_CARD_INT_MASK_CARDDETECT_STATUS);
                    495: }
                    496:
                    497: void
                    498: tslot_slot_enable(pcmcia_chipset_handle_t pch)
                    499: {
                    500:        struct tslot_data *td = (struct tslot_data *)pch;
                    501:        int status, intr, i;
                    502:
                    503: #ifdef TSLOT_DEBUG
                    504:        printf("%s: enable slot %d\n",
                    505:            td->td_parent->sc_dev.dv_xname, td->td_slot);
                    506: #endif
                    507:
                    508:        /* Power down the socket to reset it */
                    509:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
                    510:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status | TS102_CARD_STS_VCCEN);
                    511:
                    512:        /*
                    513:         * wait 300ms until power fails (Tpf).  Then, wait 100ms since we
                    514:         * are changing Vcc (Toff).
                    515:         */
                    516:        DELAY((300 + 100) * 1000);
                    517:
                    518:        /*
                    519:         * Power on the card if not already done, and enable card access
                    520:         */
                    521:        status |= TS102_CARD_STS_ACEN;
                    522:        status &= ~TS102_CARD_STS_VCCEN;
                    523:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
                    524:
                    525:        /*
                    526:         * wait 100ms until power raise (Tpr) and 20ms to become
                    527:         * stable (Tsu(Vcc)).
                    528:         */
                    529:        DELAY((100 + 20) * 1000);
                    530:
                    531:        status &= ~TS102_CARD_STS_VPP1_MASK;
                    532:        status |= TS102_CARD_STS_VPP1_VCC;
                    533:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS, status);
                    534:
                    535:        /*
                    536:         * hold RESET at least 20us.
                    537:         */
                    538:        intr = TSLOT_READ(td, TS102_REG_CARD_A_INT);
                    539:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, TS102_CARD_INT_SOFT_RESET);
                    540:        DELAY(20);
                    541:        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, intr);
                    542:
                    543:        /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
                    544:        DELAY(20 * 1000);
                    545:
                    546:        /* We need level-triggered interrupts for PC Card hardware */
                    547:        TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
                    548:                TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_LVL);
                    549:
                    550:        /*
                    551:         * Wait until the card is unbusy. If it is still busy after 3 seconds,
                    552:         * give up. We could enable card interrupts and wait for the interrupt
                    553:         * to happen when BUSY is released, but the interrupt could also be
                    554:         * triggered by the card itself if it's an I/O card, so better poll
                    555:         * here.
                    556:         */
                    557:        for (i = 30000; i != 0; i--) {
                    558:                status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
                    559:                /* If the card has been removed, abort */
                    560:                if ((status & TS102_CARD_STS_PRES) == 0) {
                    561:                        tslot_slot_disable(pch);
                    562:                        return;
                    563:                }
                    564:                if (status & TS102_CARD_STS_RDY)
                    565:                        break;
                    566:                else
                    567:                        DELAY(100);
                    568:        }
                    569:
                    570:        if (i == 0) {
                    571:                printf("%s: slot %d still busy after 3 seconds, status 0x%x\n",
                    572:                    td->td_parent->sc_dev.dv_xname, td->td_slot,
                    573:                    TSLOT_READ(td, TS102_REG_CARD_A_STS));
                    574:                return;
                    575:        }
                    576:
                    577:        /*
                    578:         * Enable the card interrupts if this is an I/O card.
                    579:         * Note that the TS102_CARD_STS_IO bit in the status register will
                    580:         * never get set, despite what the documentation says!
                    581:         */
                    582:        if (pcmcia_card_gettype(td->td_pcmcia) == PCMCIA_IFTYPE_IO) {
                    583:                TSLOT_WRITE(td, TS102_REG_CARD_A_STS,
                    584:                    TSLOT_READ(td, TS102_REG_CARD_A_STS) | TS102_CARD_STS_IO);
                    585:                TSLOT_WRITE(td, TS102_REG_CARD_A_INT,
                    586:                    TS102_CARD_INT_MASK_CARDDETECT_STATUS |
                    587:                    TS102_CARD_INT_MASK_IRQ);
                    588:        }
                    589: }
                    590:
                    591: /*
                    592:  * Event management
                    593:  */
                    594: void
                    595: tslot_create_event_thread(void *v)
                    596: {
                    597:        struct tslot_softc *sc = v;
                    598:        const char *name = sc->sc_dev.dv_xname;
                    599:
                    600:        if (kthread_create(tslot_event_thread, sc, &sc->sc_thread, "%s",
                    601:            name) != 0) {
                    602:                panic("%s: unable to create event kthread", name);
                    603:        }
                    604: }
                    605:
                    606: void
                    607: tslot_event_thread(void *v)
                    608: {
                    609:        struct tslot_softc *sc = v;
                    610:        struct tslot_data *td;
                    611:        int s, status;
                    612:        unsigned int socket;
                    613:
                    614:        for (;;) {
                    615:                s = splhigh();
                    616:
                    617:                if ((socket = ffs(sc->sc_events)) == 0) {
                    618:                        splx(s);
                    619:                        tsleep(&sc->sc_events, PWAIT, "tslot_event", 0);
                    620:                        continue;
                    621:                }
                    622:                socket--;
                    623:                sc->sc_events &= ~(1 << socket);
                    624:                splx(s);
                    625:
                    626:                if (socket >= TS102_NUM_SLOTS) {
                    627: #ifdef DEBUG
                    628:                        printf("%s: invalid slot number %d\n",
                    629:                            sc->sc_dev.dv_xname, te->te_slot);
                    630: #endif
                    631:                        continue;
                    632:                }
                    633:
                    634:                td = &sc->sc_slot[socket];
                    635:                status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
                    636:
                    637:                if (status & TS102_CARD_STS_PRES) {
                    638:                        /* Card insertion */
                    639:                        if ((td->td_status & TS_CARD) == 0) {
                    640:                                td->td_status |= TS_CARD;
                    641:                                tadpole_set_pcmcia(td->td_slot, 1);
                    642:                                pcmcia_card_attach(td->td_pcmcia);
                    643:                        }
                    644:                } else {
                    645:                        /* Card removal */
                    646:                        if ((td->td_status & TS_CARD) != 0) {
                    647:                                td->td_status &= ~TS_CARD;
                    648:                                tadpole_set_pcmcia(td->td_slot, 0);
                    649:                                pcmcia_card_detach(td->td_pcmcia,
                    650:                                    DETACH_FORCE);
                    651:                        }
                    652:                }
                    653:        }
                    654: }
                    655:
                    656: /*
                    657:  * Interrupt handling
                    658:  */
                    659:
                    660: int
                    661: tslot_intr(void *v)
                    662: {
                    663:        struct tslot_softc *sc = v;
                    664:        struct tslot_data *td;
                    665:        int intregs[TS102_NUM_SLOTS], *intreg;
                    666:        int i, rc = 0;
                    667:
                    668:        /*
                    669:         * Scan slots, and acknowledge the interrupt if necessary first
                    670:         */
                    671:        for (i = 0; i < TS102_NUM_SLOTS; i++) {
                    672:                td = &sc->sc_slot[i];
                    673:                intreg = &intregs[i];
                    674:                *intreg = TSLOT_READ(td, TS102_REG_CARD_A_INT);
                    675:
                    676:                /*
                    677:                 * Acknowledge all interrupt situations at once, even if they
                    678:                 * did not occur.
                    679:                 */
                    680:                if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
                    681:                    TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
                    682:                    TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
                    683:                    TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0) {
                    684:                        rc = 1;
                    685:                        TSLOT_WRITE(td, TS102_REG_CARD_A_INT, *intreg |
                    686:                            TS102_CARD_INT_RQST_IRQ |
                    687:                            TS102_CARD_INT_RQST_WP_STATUS_CHANGED |
                    688:                            TS102_CARD_INT_RQST_BATTERY_STATUS_CHANGED |
                    689:                            TS102_CARD_INT_RQST_CARDDETECT_STATUS_CHANGED);
                    690:                }
                    691:        }
                    692:
                    693:        /*
                    694:         * Invoke the interrupt handler for each slot
                    695:         */
                    696:        for (i = 0; i < TS102_NUM_SLOTS; i++) {
                    697:                td = &sc->sc_slot[i];
                    698:                intreg = &intregs[i];
                    699:
                    700:                if ((*intreg & (TS102_CARD_INT_STATUS_IRQ |
                    701:                    TS102_CARD_INT_STATUS_WP_STATUS_CHANGED |
                    702:                    TS102_CARD_INT_STATUS_BATTERY_STATUS_CHANGED |
                    703:                    TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED)) != 0)
                    704:                        tslot_slot_intr(td, *intreg);
                    705:        }
                    706:
                    707:        return (rc);
                    708: }
                    709:
                    710: void
                    711: tslot_queue_event(struct tslot_softc *sc, int slot)
                    712: {
                    713:        int s;
                    714:
                    715:        s = splhigh();
                    716:        sc->sc_events |= (1 << slot);
                    717:        splx(s);
                    718:        wakeup(&sc->sc_events);
                    719: }
                    720:
                    721: void
                    722: tslot_slot_intr(struct tslot_data *td, int intreg)
                    723: {
                    724:        struct tslot_softc *sc = td->td_parent;
                    725:        int status, sockstat;
                    726:
                    727:        status = TSLOT_READ(td, TS102_REG_CARD_A_STS);
                    728: #ifdef TSLOT_DEBUG
                    729:        printf("%s: interrupt on socket %d ir %x sts %x\n",
                    730:            sc->sc_dev.dv_xname, td->td_slot, intreg, status);
                    731: #endif
                    732:
                    733:        sockstat = td->td_status;
                    734:
                    735:        /*
                    736:         * The TS102 queues interrupt requests, and may trigger an interrupt
                    737:         * for a condition the driver does not want to receive anymore (for
                    738:         * example, after a card gets removed).
                    739:         * Thus, only proceed if the driver is currently allowing a particular
                    740:         * condition.
                    741:         */
                    742:
                    743:        if ((intreg & TS102_CARD_INT_STATUS_CARDDETECT_STATUS_CHANGED) != 0 &&
                    744:            (intreg & TS102_CARD_INT_MASK_CARDDETECT_STATUS) != 0) {
                    745:                tslot_queue_event(sc, td->td_slot);
                    746: #ifdef TSLOT_DEBUG
                    747:                printf("%s: slot %d status changed from %d to %d\n",
                    748:                    sc->sc_dev.dv_xname, td->td_slot, sockstat, td->td_status);
                    749: #endif
                    750:                /*
                    751:                 * Ignore extra interrupt bits, they are part of the change.
                    752:                 */
                    753:                return;
                    754:        }
                    755:
                    756:        if ((intreg & TS102_CARD_INT_STATUS_IRQ) != 0 &&
                    757:            (intreg & TS102_CARD_INT_MASK_IRQ) != 0) {
                    758:                /* ignore interrupts if we have a pending state change */
                    759:                if (sc->sc_events & (1 << td->td_slot))
                    760:                        return;
                    761:
                    762:                if ((sockstat & TS_CARD) == 0) {
                    763:                        printf("%s: spurious interrupt on slot %d isr %x\n",
                    764:                            sc->sc_dev.dv_xname, td->td_slot, intreg);
                    765:                        return;
                    766:                }
                    767:
                    768:                if (td->td_intr != NULL) {
                    769:                        /*
                    770:                         * XXX There is no way to honour the interrupt handler
                    771:                         * requested IPL level...
                    772:                         */
                    773:                        (*td->td_intr)(td->td_intrarg);
                    774:                }
                    775:        }
                    776: }
                    777:
                    778: void
                    779: tslot_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
                    780: {
                    781:        struct tslot_data *td = (struct tslot_data *)pch;
                    782:
                    783:        td->td_intr = NULL;
                    784:        td->td_intrarg = NULL;
                    785: }
                    786:
                    787: const char *
                    788: tslot_intr_string(pcmcia_chipset_handle_t pch, void *ih)
                    789: {
                    790:        if (ih == NULL)
                    791:                return ("couldn't establish interrupt");
                    792:        else
                    793:                return ("");    /* nothing for now */
                    794: }
                    795:
                    796:
                    797: void *
                    798: tslot_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf,
                    799:     int ipl, int (*handler)(void *), void *arg, char *xname)
                    800: {
                    801:        struct tslot_data *td = (struct tslot_data *)pch;
                    802:
                    803:        td->td_intr = handler;
                    804:        td->td_intrarg = arg;
                    805:
                    806:        return (td);
                    807: }

CVSweb