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

Annotation of sys/dev/pcmcia/pcmcia.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pcmcia.c,v 1.37 2006/04/16 20:43:12 miod Exp $        */
        !             2: /*     $NetBSD: pcmcia.c,v 1.9 1998/08/13 02:10:55 eeh Exp $   */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by Marc Horowitz.
        !            18:  * 4. The name of the author may not be used to endorse or promote products
        !            19:  *    derived from this software without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            31:  */
        !            32:
        !            33: #include <sys/types.h>
        !            34: #include <sys/param.h>
        !            35: #include <sys/systm.h>
        !            36: #include <sys/device.h>
        !            37: #include <sys/malloc.h>
        !            38:
        !            39: #include <dev/pcmcia/pcmciareg.h>
        !            40: #include <dev/pcmcia/pcmciachip.h>
        !            41: #include <dev/pcmcia/pcmciavar.h>
        !            42:
        !            43: #ifdef PCMCIADEBUG
        !            44: #define        DPRINTF(arg) printf arg
        !            45: #else
        !            46: #define        DPRINTF(arg)
        !            47: #endif
        !            48:
        !            49: #ifdef PCMCIAVERBOSE
        !            50: int    pcmcia_verbose = 1;
        !            51: #else
        !            52: int    pcmcia_verbose = 0;
        !            53: #endif
        !            54:
        !            55: int    pcmcia_match(struct device *, void *, void *);
        !            56: int    pcmcia_submatch(struct device *, void *, void *);
        !            57: void   pcmcia_attach(struct device *, struct device *, void *);
        !            58: int    pcmcia_print(void *, const char *);
        !            59: void   pcmcia_card_detach_notify(struct device *, void *);
        !            60: void   pcmcia_power(int why, void *arg);
        !            61:
        !            62: static inline void pcmcia_socket_enable(pcmcia_chipset_tag_t,
        !            63:                                             pcmcia_chipset_handle_t *);
        !            64: static inline void pcmcia_socket_disable(pcmcia_chipset_tag_t,
        !            65:                                              pcmcia_chipset_handle_t *);
        !            66:
        !            67: int pcmcia_card_intr(void *);
        !            68:
        !            69: struct cfdriver pcmcia_cd = {
        !            70:        NULL, "pcmcia", DV_DULL
        !            71: };
        !            72:
        !            73: struct cfattach pcmcia_ca = {
        !            74:        sizeof(struct pcmcia_softc), pcmcia_match, pcmcia_attach
        !            75: };
        !            76:
        !            77: int
        !            78: pcmcia_ccr_read(pf, ccr)
        !            79:        struct pcmcia_function *pf;
        !            80:        int ccr;
        !            81: {
        !            82:
        !            83:        return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh,
        !            84:            pf->pf_ccr_offset + ccr));
        !            85: }
        !            86:
        !            87: void
        !            88: pcmcia_ccr_write(pf, ccr, val)
        !            89:        struct pcmcia_function *pf;
        !            90:        int ccr;
        !            91:        int val;
        !            92: {
        !            93:
        !            94:        if ((pf->ccr_mask) & (1 << (ccr / 2))) {
        !            95:                bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh,
        !            96:                    pf->pf_ccr_offset + ccr, val);
        !            97:        }
        !            98: }
        !            99:
        !           100: int
        !           101: pcmcia_match(parent, match, aux)
        !           102:        struct device *parent;
        !           103:        void *match, *aux;
        !           104: {
        !           105:        struct cfdata *cf = match;
        !           106:        struct pcmciabus_attach_args *paa = aux;
        !           107:
        !           108:        if (strcmp(paa->paa_busname, cf->cf_driver->cd_name))
        !           109:                return 0;
        !           110:
        !           111:        /* If the autoconfiguration got this far, there's a socket here. */
        !           112:        return (1);
        !           113: }
        !           114:
        !           115: void
        !           116: pcmcia_attach(parent, self, aux)
        !           117:        struct device *parent, *self;
        !           118:        void *aux;
        !           119: {
        !           120:        struct pcmciabus_attach_args *paa = aux;
        !           121:        struct pcmcia_softc *sc = (struct pcmcia_softc *) self;
        !           122:
        !           123:        printf("\n");
        !           124:
        !           125:        sc->pct = paa->pct;
        !           126:        sc->pch = paa->pch;
        !           127:        sc->iobase = paa->iobase;
        !           128:        sc->iosize = paa->iosize;
        !           129:
        !           130:        sc->ih = NULL;
        !           131:        powerhook_establish(pcmcia_power, sc);
        !           132: }
        !           133:
        !           134: void
        !           135: pcmcia_power(why, arg)
        !           136:        int why;
        !           137:        void *arg;
        !           138: {
        !           139:        struct pcmcia_softc *sc = (struct pcmcia_softc *) arg;
        !           140:        struct pcmcia_function *pf;
        !           141:        struct device *d;
        !           142:        int act = DVACT_ACTIVATE;
        !           143:
        !           144:        if (why != PWR_RESUME)
        !           145:                act = DVACT_DEACTIVATE;
        !           146:
        !           147:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           148:             pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           149:                if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
        !           150:                        continue;
        !           151:                d = pf->child;
        !           152:                if (d == NULL)
        !           153:                        continue;
        !           154:                if (act == DVACT_ACTIVATE)
        !           155:                        config_activate(pf->child);
        !           156:                else
        !           157:                        config_deactivate(pf->child);
        !           158:        }
        !           159: }
        !           160:
        !           161: int
        !           162: pcmcia_card_attach(dev)
        !           163:        struct device *dev;
        !           164: {
        !           165:        struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
        !           166:        struct pcmcia_function *pf;
        !           167:        struct pcmcia_attach_args paa;
        !           168:        int attached;
        !           169:
        !           170:        /*
        !           171:         * this is here so that when socket_enable calls gettype, trt happens
        !           172:         */
        !           173:        SIMPLEQ_FIRST(&sc->card.pf_head) = NULL;
        !           174:
        !           175:        pcmcia_chip_socket_enable(sc->pct, sc->pch);
        !           176:
        !           177:        pcmcia_read_cis(sc);
        !           178:
        !           179:        pcmcia_chip_socket_disable(sc->pct, sc->pch);
        !           180:
        !           181:        pcmcia_check_cis_quirks(sc);
        !           182:
        !           183:        /*
        !           184:         * Bail now if there was an error in the CIS.
        !           185:         */
        !           186:
        !           187:        if (sc->card.error)
        !           188:                return (1);
        !           189:
        !           190: #if 0
        !           191:        if (SIMPLEQ_EMPTY(&sc->card.pf_head))
        !           192:                return (1);
        !           193: #endif
        !           194:
        !           195:        if (pcmcia_verbose)
        !           196:                pcmcia_print_cis(sc);
        !           197:
        !           198:        /*
        !           199:         * If there was no function, this might be CIS-less card we still
        !           200:         * want to probe.  Fixup a function element for it.
        !           201:         */
        !           202:        if (SIMPLEQ_FIRST(&sc->card.pf_head) == NULL) {
        !           203:                pf = malloc(sizeof *pf, M_DEVBUF, M_NOWAIT);
        !           204:                if (pf == NULL)
        !           205:                        panic("pcmcia_card_attach");
        !           206:                bzero(pf, sizeof *pf);
        !           207:                pf->number = 0;
        !           208:                pf->pf_flags = PFF_FAKE;
        !           209:                pf->last_config_index = -1;
        !           210:                SIMPLEQ_INIT(&pf->cfe_head);
        !           211:                SIMPLEQ_INSERT_TAIL(&sc->card.pf_head, pf, pf_list);
        !           212:        }
        !           213:
        !           214:        attached = 0;
        !           215:
        !           216:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           217:            pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           218:                pf->sc = sc;
        !           219:                pf->child = NULL;
        !           220:                pf->cfe = NULL;
        !           221:                pf->ih_fct = NULL;
        !           222:                pf->ih_arg = NULL;
        !           223:        }
        !           224:
        !           225:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           226:            pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           227:                paa.manufacturer = sc->card.manufacturer;
        !           228:                paa.product = sc->card.product;
        !           229:                paa.card = &sc->card;
        !           230:                paa.pf = pf;
        !           231:
        !           232:                pf->child = config_found_sm(&sc->dev, &paa, pcmcia_print,
        !           233:                    pcmcia_submatch);
        !           234:                if (pf->child) {
        !           235:                        attached++;
        !           236:
        !           237:                        if ((pf->pf_flags & PFF_FAKE) == 0)
        !           238:                                DPRINTF(("%s: function %d CCR at %d offset %lx"
        !           239:                                        ": %x %x %x %x, %x %x %x %x, %x\n",
        !           240:                                        sc->dev.dv_xname, pf->number,
        !           241:                                        pf->pf_ccr_window, pf->pf_ccr_offset,
        !           242:                                        pcmcia_ccr_read(pf, 0x00),
        !           243:                                        pcmcia_ccr_read(pf, 0x02),
        !           244:                                        pcmcia_ccr_read(pf, 0x04),
        !           245:                                        pcmcia_ccr_read(pf, 0x06),
        !           246:                                        pcmcia_ccr_read(pf, 0x0A),
        !           247:                                        pcmcia_ccr_read(pf, 0x0C),
        !           248:                                        pcmcia_ccr_read(pf, 0x0E),
        !           249:                                        pcmcia_ccr_read(pf, 0x10),
        !           250:                                        pcmcia_ccr_read(pf, 0x12)));
        !           251:                }
        !           252:        }
        !           253:        return (attached ? 0 : 1);
        !           254: }
        !           255:
        !           256: void
        !           257: pcmcia_card_detach(dev, flags)
        !           258:        struct device *dev;
        !           259:        int flags;              /* DETACH_* flags */
        !           260: {
        !           261:        struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
        !           262:        struct pcmcia_function *pf;
        !           263:        int error;
        !           264:
        !           265:        /*
        !           266:         * We are running on either the PCMCIA socket's event thread
        !           267:         * or in user context detaching a device by user request.
        !           268:         */
        !           269:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           270:             pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           271:                if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
        !           272:                        continue;
        !           273:                if (pf->child == NULL)
        !           274:                        continue;
        !           275:                DPRINTF(("%s: detaching %s (function %d)\n",
        !           276:                    sc->dev.dv_xname, pf->child->dv_xname, pf->number));
        !           277:                if ((error = config_detach(pf->child, flags)) != 0) {
        !           278:                        printf("%s: error %d detaching %s (function %d)\n",
        !           279:                            sc->dev.dv_xname, error, pf->child->dv_xname,
        !           280:                            pf->number);
        !           281:                } else
        !           282:                        pf->child = NULL;
        !           283:        }
        !           284: }
        !           285:
        !           286: void
        !           287: pcmcia_card_deactivate(dev)
        !           288:        struct device *dev;
        !           289: {
        !           290:        struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
        !           291:        struct pcmcia_function *pf;
        !           292:
        !           293:        /*
        !           294:         * We're in the chip's card removal interrupt handler.
        !           295:         * Deactivate the child driver.  The PCMCIA socket's
        !           296:         * event thread will run later to finish the detach.
        !           297:         */
        !           298:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           299:             pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           300:                if (SIMPLEQ_FIRST(&pf->cfe_head) == NULL)
        !           301:                        continue;
        !           302:                if (pf->child == NULL)
        !           303:                        continue;
        !           304:                DPRINTF(("%s: deactivating %s (function %d)\n",
        !           305:                    sc->dev.dv_xname, pf->child->dv_xname, pf->number));
        !           306:                config_deactivate(pf->child);
        !           307:        }
        !           308: }
        !           309:
        !           310: int
        !           311: pcmcia_submatch(parent, match, aux)
        !           312:        struct device *parent;
        !           313:        void *match, *aux;
        !           314: {
        !           315:        struct cfdata *cf = match;
        !           316:        struct pcmcia_attach_args *paa = aux;
        !           317:
        !           318:        if (cf->cf_loc[0 /* PCMCIACF_FUNCTION */] !=
        !           319:            -1 /* PCMCIACF_FUNCTION_DEFAULT */ &&
        !           320:            cf->cf_loc[0 /* PCMCIACF_FUNCTION */] != paa->pf->number)
        !           321:                return (0);
        !           322:
        !           323:        return ((*cf->cf_attach->ca_match)(parent, cf, aux));
        !           324: }
        !           325:
        !           326: int
        !           327: pcmcia_print(arg, pnp)
        !           328:        void *arg;
        !           329:        const char *pnp;
        !           330: {
        !           331:        struct pcmcia_attach_args *pa = arg;
        !           332:        struct pcmcia_softc *sc = pa->pf->sc;
        !           333:        struct pcmcia_card *card = &sc->card;
        !           334:        int i;
        !           335:
        !           336:        if (pnp) {
        !           337:                for (i = 0; i < 4 && card->cis1_info[i]; i++)
        !           338:                        printf("%s%s", i ? ", " : "\"", card->cis1_info[i]);
        !           339:                if (i != 0)
        !           340:                        printf("\"");
        !           341:
        !           342:                if (card->manufacturer != PCMCIA_VENDOR_INVALID &&
        !           343:                    card->product != PCMCIA_PRODUCT_INVALID) {
        !           344:                        if (i != 0)
        !           345:                                printf(" ");
        !           346:                        printf("(");
        !           347:                        if (card->manufacturer != PCMCIA_VENDOR_INVALID)
        !           348:                                printf("manufacturer 0x%x%s",
        !           349:                                    card->manufacturer,
        !           350:                                    card->product == PCMCIA_PRODUCT_INVALID ?
        !           351:                                    "" : ", ");
        !           352:                        if (card->product != PCMCIA_PRODUCT_INVALID)
        !           353:                                printf("product 0x%x",
        !           354:                                    card->product);
        !           355:                        printf(")");
        !           356:                }
        !           357:                if (i != 0)
        !           358:                        printf(" ");
        !           359:                printf("at %s", pnp);
        !           360:        }
        !           361:        printf(" function %d", pa->pf->number);
        !           362:
        !           363:        if (!pnp) {
        !           364:                for (i = 0; i < 3 && card->cis1_info[i]; i++)
        !           365:                        printf("%s%s", i ? ", " : " \"", card->cis1_info[i]);
        !           366:                if (i != 0)
        !           367:                        printf("\"");
        !           368:        }
        !           369:
        !           370:        return (UNCONF);
        !           371: }
        !           372:
        !           373: int
        !           374: pcmcia_card_gettype(dev)
        !           375:        struct device  *dev;
        !           376: {
        !           377:        struct pcmcia_softc *sc = (struct pcmcia_softc *)dev;
        !           378:        struct pcmcia_function *pf;
        !           379:
        !           380:        /*
        !           381:         * Set the iftype to memory if this card has no functions (not yet
        !           382:         * probed), or only one function, and that is not initialized yet or
        !           383:         * that is memory.
        !           384:         */
        !           385:        pf = SIMPLEQ_FIRST(&sc->card.pf_head);
        !           386:        if (pf == NULL || (SIMPLEQ_NEXT(pf, pf_list) == NULL &&
        !           387:            ((pf->pf_flags & PFF_FAKE) ||
        !           388:            pf->cfe == NULL || pf->cfe->iftype == PCMCIA_IFTYPE_MEMORY)))
        !           389:                return (PCMCIA_IFTYPE_MEMORY);
        !           390:        else
        !           391:                return (PCMCIA_IFTYPE_IO);
        !           392: }
        !           393:
        !           394: /*
        !           395:  * Initialize a PCMCIA function.  May be called as long as the function is
        !           396:  * disabled.
        !           397:  */
        !           398: void
        !           399: pcmcia_function_init(pf, cfe)
        !           400:        struct pcmcia_function *pf;
        !           401:        struct pcmcia_config_entry *cfe;
        !           402: {
        !           403:        if (pf->pf_flags & PFF_ENABLED)
        !           404:                panic("pcmcia_function_init: function is enabled");
        !           405:
        !           406:        /* Remember which configuration entry we are using. */
        !           407:        pf->cfe = cfe;
        !           408: }
        !           409:
        !           410: static inline void pcmcia_socket_enable(pct, pch)
        !           411:      pcmcia_chipset_tag_t pct;
        !           412:      pcmcia_chipset_handle_t *pch;
        !           413: {
        !           414:        pcmcia_chip_socket_enable(pct, pch);
        !           415: }
        !           416:
        !           417: static inline void pcmcia_socket_disable(pct, pch)
        !           418:      pcmcia_chipset_tag_t pct;
        !           419:      pcmcia_chipset_handle_t *pch;
        !           420: {
        !           421:        pcmcia_chip_socket_disable(pct, pch);
        !           422: }
        !           423:
        !           424: /* Enable a PCMCIA function */
        !           425: int
        !           426: pcmcia_function_enable(pf)
        !           427:        struct pcmcia_function *pf;
        !           428: {
        !           429:        struct pcmcia_function *tmp;
        !           430:        int reg;
        !           431:
        !           432:        if (pf->cfe == NULL)
        !           433:                panic("pcmcia_function_enable: function not initialized");
        !           434:
        !           435:        /*
        !           436:         * Increase the reference count on the socket, enabling power, if
        !           437:         * necessary.
        !           438:         */
        !           439:        if (pf->sc->sc_enabled_count++ == 0)
        !           440:                pcmcia_chip_socket_enable(pf->sc->pct, pf->sc->pch);
        !           441:        DPRINTF(("%s: ++enabled_count = %d\n", pf->sc->dev.dv_xname,
        !           442:                 pf->sc->sc_enabled_count));
        !           443:
        !           444:        if (pf->pf_flags & PFF_ENABLED) {
        !           445:                /*
        !           446:                 * Don't do anything if we're already enabled.
        !           447:                 */
        !           448:                DPRINTF(("%s: pcmcia_function_enable on enabled func\n"));
        !           449:                return (0);
        !           450:        }
        !           451:
        !           452:        /* If there was no CIS don't mess with CCR */
        !           453:        if (pf->pf_flags & PFF_FAKE)
        !           454:                goto done;
        !           455:
        !           456:        /*
        !           457:         * It's possible for different functions' CCRs to be in the same
        !           458:         * underlying page.  Check for that.
        !           459:         */
        !           460:        SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
        !           461:                if ((tmp->pf_flags & PFF_ENABLED) &&
        !           462:                    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
        !           463:                    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
        !           464:                     (tmp->ccr_base - tmp->pf_ccr_offset +
        !           465:                      tmp->pf_ccr_realsize))) {
        !           466:                        pf->pf_ccrt = tmp->pf_ccrt;
        !           467:                        pf->pf_ccrh = tmp->pf_ccrh;
        !           468:                        pf->pf_ccr_realsize = tmp->pf_ccr_realsize;
        !           469:
        !           470:                        /*
        !           471:                         * pf->pf_ccr_offset = (tmp->pf_ccr_offset -
        !           472:                         * tmp->ccr_base) + pf->ccr_base;
        !           473:                         */
        !           474:                        pf->pf_ccr_offset =
        !           475:                            (tmp->pf_ccr_offset + pf->ccr_base) -
        !           476:                            tmp->ccr_base;
        !           477:                        pf->pf_ccr_window = tmp->pf_ccr_window;
        !           478:                        break;
        !           479:                }
        !           480:        }
        !           481:
        !           482:        if (tmp == NULL) {
        !           483:                if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE, &pf->pf_pcmh))
        !           484:                        goto bad;
        !           485:
        !           486:                if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
        !           487:                    PCMCIA_CCR_SIZE, &pf->pf_pcmh, &pf->pf_ccr_offset,
        !           488:                    &pf->pf_ccr_window)) {
        !           489:                        pcmcia_mem_free(pf, &pf->pf_pcmh);
        !           490:                        goto bad;
        !           491:                }
        !           492:        }
        !           493:
        !           494:        reg = (pf->cfe->number & PCMCIA_CCR_OPTION_CFINDEX);
        !           495:        reg |= PCMCIA_CCR_OPTION_LEVIREQ;
        !           496:        if (pcmcia_mfc(pf->sc)) {
        !           497:                reg |= PCMCIA_CCR_OPTION_FUNC_ENABLE;
        !           498:                if (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))
        !           499:                        reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
        !           500:                if (pf->ih_fct)
        !           501:                        reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
        !           502:
        !           503:        }
        !           504:
        !           505:        pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
        !           506:
        !           507:        reg = 0;
        !           508:
        !           509:        if ((pf->cfe->flags & PCMCIA_CFE_IO16) == 0)
        !           510:                reg |= PCMCIA_CCR_STATUS_IOIS8;
        !           511:        if (pf->cfe->flags & PCMCIA_CFE_AUDIO)
        !           512:                reg |= PCMCIA_CCR_STATUS_AUDIO;
        !           513:        pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
        !           514:
        !           515:        pcmcia_ccr_write(pf, PCMCIA_CCR_SOCKETCOPY, 0);
        !           516:
        !           517:        if (pcmcia_mfc(pf->sc)) {
        !           518:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
        !           519:                                 (pf->pf_mfc_iobase >>  0) & 0xff);
        !           520:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
        !           521:                                 (pf->pf_mfc_iobase >>  8) & 0xff);
        !           522:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
        !           523:                                 (pf->pf_mfc_iobase >> 16) & 0xff);
        !           524:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
        !           525:                                 (pf->pf_mfc_iobase >> 24) & 0xff);
        !           526:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
        !           527:                                 pf->pf_mfc_iomax - pf->pf_mfc_iobase);
        !           528:        }
        !           529:
        !           530: #ifdef PCMCIADEBUG
        !           531:        SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
        !           532:                printf("%s: function %d CCR at %d offset %lx: "
        !           533:                       "%x %x %x %x, %x %x %x %x, %x\n",
        !           534:                       tmp->sc->dev.dv_xname, tmp->number,
        !           535:                       tmp->pf_ccr_window, tmp->pf_ccr_offset,
        !           536:                       pcmcia_ccr_read(tmp, 0x00),
        !           537:                       pcmcia_ccr_read(tmp, 0x02),
        !           538:                       pcmcia_ccr_read(tmp, 0x04),
        !           539:                       pcmcia_ccr_read(tmp, 0x06),
        !           540:
        !           541:                       pcmcia_ccr_read(tmp, 0x0A),
        !           542:                       pcmcia_ccr_read(tmp, 0x0C),
        !           543:                       pcmcia_ccr_read(tmp, 0x0E),
        !           544:                       pcmcia_ccr_read(tmp, 0x10),
        !           545:
        !           546:                       pcmcia_ccr_read(tmp, 0x12));
        !           547:        }
        !           548: #endif
        !           549:
        !           550:  done:
        !           551:        pf->pf_flags |= PFF_ENABLED;
        !           552:        delay(1000);
        !           553:        return (0);
        !           554:
        !           555:  bad:
        !           556:        /*
        !           557:         * Decrement the reference count, and power down the socket, if
        !           558:         * necessary.
        !           559:         */
        !           560:        if (--pf->sc->sc_enabled_count == 0)
        !           561:                pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
        !           562:        DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
        !           563:                 pf->sc->sc_enabled_count));
        !           564:
        !           565:        return (1);
        !           566: }
        !           567:
        !           568: /* Disable PCMCIA function. */
        !           569: void
        !           570: pcmcia_function_disable(pf)
        !           571:        struct pcmcia_function *pf;
        !           572: {
        !           573:        struct pcmcia_function *tmp;
        !           574:
        !           575:        if (pf->cfe == NULL)
        !           576:                panic("pcmcia_function_enable: function not initialized");
        !           577:
        !           578:        if ((pf->pf_flags & PFF_ENABLED) == 0) {
        !           579:                /*
        !           580:                 * Don't do anything if we're already disabled.
        !           581:                 */
        !           582:                return;
        !           583:        }
        !           584:
        !           585:        /* If there was no CIS don't mess with CCR */
        !           586:        if (pf->pf_flags & PFF_FAKE) {
        !           587:                pf->pf_flags &= ~PFF_ENABLED;
        !           588:                goto done;
        !           589:        }
        !           590:
        !           591:        /*
        !           592:         * it's possible for different functions' CCRs to be in the same
        !           593:         * underlying page.  Check for that.  Note we mark us as disabled
        !           594:         * first to avoid matching ourself.
        !           595:         */
        !           596:        pf->pf_flags &= ~PFF_ENABLED;
        !           597:        SIMPLEQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) {
        !           598:                if ((tmp->pf_flags & PFF_ENABLED) &&
        !           599:                    (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) &&
        !           600:                    ((pf->ccr_base + PCMCIA_CCR_SIZE) <=
        !           601:                (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize)))
        !           602:                        break;
        !           603:        }
        !           604:
        !           605:        /* Not used by anyone else; unmap the CCR. */
        !           606:        if (tmp == NULL) {
        !           607:                pcmcia_mem_unmap(pf, pf->pf_ccr_window);
        !           608:                pcmcia_mem_free(pf, &pf->pf_pcmh);
        !           609:        }
        !           610:
        !           611:  done:
        !           612:        /*
        !           613:         * Decrement the reference count, and power down the socket, if
        !           614:         * necessary.
        !           615:         */
        !           616:        if (--pf->sc->sc_enabled_count == 0)
        !           617:                pcmcia_chip_socket_disable(pf->sc->pct, pf->sc->pch);
        !           618:        DPRINTF(("%s: --enabled_count = %d\n", pf->sc->dev.dv_xname,
        !           619:                 pf->sc->sc_enabled_count));
        !           620: }
        !           621:
        !           622: int
        !           623: pcmcia_io_map(pf, width, offset, size, pcihp, windowp)
        !           624:        struct pcmcia_function *pf;
        !           625:        int width;
        !           626:        bus_addr_t offset;
        !           627:        bus_size_t size;
        !           628:        struct pcmcia_io_handle *pcihp;
        !           629:        int *windowp;
        !           630: {
        !           631:        int reg;
        !           632:
        !           633:        if (pcmcia_chip_io_map(pf->sc->pct, pf->sc->pch,
        !           634:            width, offset, size, pcihp, windowp))
        !           635:                return (1);
        !           636:
        !           637:        /*
        !           638:         * XXX In the multifunction multi-iospace-per-function case, this
        !           639:         * needs to cooperate with io_alloc to make sure that the spaces
        !           640:         * don't overlap, and that the ccr's are set correctly.
        !           641:         */
        !           642:
        !           643:        if (pcmcia_mfc(pf->sc) &&
        !           644:            (pf->ccr_mask & (1 << (PCMCIA_CCR_IOBASE0 / 2)))) {
        !           645:                bus_addr_t iobase = pcihp->addr;
        !           646:                bus_addr_t iomax = pcihp->addr + pcihp->size - 1;
        !           647:
        !           648:                if (pf->pf_mfc_iomax == 0) {
        !           649:                        pf->pf_mfc_iobase = iobase;
        !           650:                        pf->pf_mfc_iomax = iomax;
        !           651:                } else {
        !           652:                        if (iobase < pf->pf_mfc_iobase)
        !           653:                                pf->pf_mfc_iobase = iobase;
        !           654:                        if (iomax > pf->pf_mfc_iomax)
        !           655:                                pf->pf_mfc_iomax = iomax;
        !           656:                }
        !           657:
        !           658:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE0,
        !           659:                                 (pf->pf_mfc_iobase >>  0) & 0xff);
        !           660:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE1,
        !           661:                                 (pf->pf_mfc_iobase >>  8) & 0xff);
        !           662:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE2,
        !           663:                                 (pf->pf_mfc_iobase >> 16) & 0xff);
        !           664:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOBASE3,
        !           665:                                 (pf->pf_mfc_iobase >> 24) & 0xff);
        !           666:                pcmcia_ccr_write(pf, PCMCIA_CCR_IOSIZE,
        !           667:                                 pf->pf_mfc_iomax - pf->pf_mfc_iobase);
        !           668:
        !           669:                reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
        !           670:                reg |= PCMCIA_CCR_OPTION_ADDR_DECODE;
        !           671:                pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
        !           672:        }
        !           673:        return (0);
        !           674: }
        !           675:
        !           676: void *
        !           677: pcmcia_intr_establish(pf, ipl, ih_fct, ih_arg, xname)
        !           678:        struct pcmcia_function *pf;
        !           679:        int ipl;
        !           680:        int (*ih_fct)(void *);
        !           681:        void *ih_arg;
        !           682:        char *xname;
        !           683: {
        !           684:        void *ret;
        !           685:        int s, ihcnt, hiipl, reg;
        !           686:        struct pcmcia_function *pf2;
        !           687:
        !           688:        /* Behave differently if this is a multifunction card. */
        !           689:        if (pcmcia_mfc(pf->sc)) {
        !           690:                /*
        !           691:                 * Mask all the ipl's which are already used by this card,
        !           692:                 * and find the highest ipl number (lowest priority).
        !           693:                 */
        !           694:                ihcnt = 0;
        !           695:                SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
        !           696:                        if (pf2->ih_fct) {
        !           697:                                DPRINTF(("%s: function %d has ih_fct %p\n",
        !           698:                                    pf->sc->dev.dv_xname, pf2->number,
        !           699:                                    pf2->ih_fct));
        !           700:
        !           701:                                if (ihcnt == 0)
        !           702:                                        hiipl = pf2->ih_ipl;
        !           703:                                else if (pf2->ih_ipl > hiipl)
        !           704:                                        hiipl = pf2->ih_ipl;
        !           705:
        !           706:                                ihcnt++;
        !           707:                        }
        !           708:                }
        !           709:
        !           710:                /*
        !           711:                 * Establish the real interrupt, changing the ipl if
        !           712:                 * necessary.
        !           713:                 */
        !           714:                if (ihcnt == 0) {
        !           715: #ifdef DIAGNOSTIC
        !           716:                        if (pf->sc->ih != NULL)
        !           717:                                panic("card has intr handler, "
        !           718:                                    "but no function does");
        !           719: #endif
        !           720:                        s = spltty();
        !           721:
        !           722:                        /* Set up the handler for the new function. */
        !           723:                        pf->ih_fct = ih_fct;
        !           724:                        pf->ih_arg = ih_arg;
        !           725:                        pf->ih_ipl = ipl;
        !           726:
        !           727:                        pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
        !           728:                            pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
        !           729:                            xname);
        !           730:                        splx(s);
        !           731:                } else if (ipl > hiipl) {
        !           732: #ifdef DIAGNOSTIC
        !           733:                        if (pf->sc->ih == NULL)
        !           734:                                panic("functions have ih, "
        !           735:                                    "but the card does not");
        !           736: #endif
        !           737:
        !           738:                        s = spltty();
        !           739:
        !           740:                        pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
        !           741:                            pf->sc->ih);
        !           742:
        !           743:                        /* set up the handler for the new function */
        !           744:                        pf->ih_fct = ih_fct;
        !           745:                        pf->ih_arg = ih_arg;
        !           746:                        pf->ih_ipl = ipl;
        !           747:
        !           748:                        pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
        !           749:                            pf->sc->pch, pf, ipl, pcmcia_card_intr, pf->sc,
        !           750:                            xname);
        !           751:
        !           752:                        splx(s);
        !           753:                } else {
        !           754:                        s = spltty();
        !           755:
        !           756:                        /* Set up the handler for the new function. */
        !           757:                        pf->ih_fct = ih_fct;
        !           758:                        pf->ih_arg = ih_arg;
        !           759:                        pf->ih_ipl = ipl;
        !           760:
        !           761:                        splx(s);
        !           762:                }
        !           763:
        !           764:                ret = pf->sc->ih;
        !           765:
        !           766:                if (ret != NULL) {
        !           767:                        reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
        !           768:                        reg |= PCMCIA_CCR_OPTION_IREQ_ENABLE;
        !           769:                        pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
        !           770:
        !           771:                        reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
        !           772:                        reg |= PCMCIA_CCR_STATUS_INTRACK;
        !           773:                        pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS, reg);
        !           774:                }
        !           775:        } else
        !           776:                ret = pcmcia_chip_intr_establish(pf->sc->pct, pf->sc->pch,
        !           777:                    pf, ipl, ih_fct, ih_arg, xname);
        !           778:
        !           779:        return (ret);
        !           780: }
        !           781:
        !           782: void
        !           783: pcmcia_intr_disestablish(pf, ih)
        !           784:        struct pcmcia_function *pf;
        !           785:        void *ih;
        !           786: {
        !           787:        int s, reg, ihcnt, hiipl;
        !           788:        struct pcmcia_function *pf2;
        !           789:
        !           790:        /* Behave differently if this is a multifunction card.  */
        !           791:        if (pcmcia_mfc(pf->sc)) {
        !           792:                /*
        !           793:                 * Mask all the ipl's which are already used by this card,
        !           794:                 * and find the highest ipl number (lowest priority).  Skip
        !           795:                 * the current function.
        !           796:                 */
        !           797:                ihcnt = 0;
        !           798:                SIMPLEQ_FOREACH(pf2, &pf->sc->card.pf_head, pf_list) {
        !           799:                        if (pf2 == pf)
        !           800:                                continue;
        !           801:
        !           802:                        if (pf2->ih_fct) {
        !           803:                                if (ihcnt == 0)
        !           804:                                        hiipl = pf2->ih_ipl;
        !           805:                                else if (pf2->ih_ipl > hiipl)
        !           806:                                        hiipl = pf2->ih_ipl;
        !           807:                                ihcnt++;
        !           808:                        }
        !           809:                }
        !           810:
        !           811:                /*
        !           812:                 * If the ih being removed is lower priority than the lowest
        !           813:                 * priority remaining interrupt, up the priority.
        !           814:                 */
        !           815:
        !           816:                /*
        !           817:                 * ihcnt is the number of interrupt handlers *not* including
        !           818:                 * the one about to be removed.
        !           819:                 */
        !           820:                if (ihcnt == 0) {
        !           821: #ifdef DIAGNOSTIC
        !           822:                        if (pf->sc->ih == NULL)
        !           823:                                panic("disestablishing last function, but card has no ih");
        !           824: #endif
        !           825:                        pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
        !           826:                            pf->sc->ih);
        !           827:
        !           828:                        reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
        !           829:                        reg &= ~PCMCIA_CCR_OPTION_IREQ_ENABLE;
        !           830:                        pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
        !           831:
        !           832:                        pf->ih_fct = NULL;
        !           833:                        pf->ih_arg = NULL;
        !           834:
        !           835:                        pf->sc->ih = NULL;
        !           836:                } else if (pf->ih_ipl > hiipl) {
        !           837: #ifdef DIAGNOSTIC
        !           838:                        if (pf->sc->ih == NULL)
        !           839:                                panic("changing ih ipl, but card has no ih");
        !           840: #endif
        !           841:                        s = spltty();
        !           842:
        !           843:                        pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch,
        !           844:                            pf->sc->ih);
        !           845:                        pf->sc->ih = pcmcia_chip_intr_establish(pf->sc->pct,
        !           846:                            pf->sc->pch, pf, hiipl, pcmcia_card_intr, pf->sc,
        !           847:                            NULL);
        !           848:
        !           849:                        /* Null out the handler for this function. */
        !           850:                        pf->ih_fct = NULL;
        !           851:                        pf->ih_arg = NULL;
        !           852:
        !           853:                        splx(s);
        !           854:                } else {
        !           855:                        s = spltty();
        !           856:
        !           857:                        pf->ih_fct = NULL;
        !           858:                        pf->ih_arg = NULL;
        !           859:
        !           860:                        splx(s);
        !           861:                }
        !           862:        } else
        !           863:                pcmcia_chip_intr_disestablish(pf->sc->pct, pf->sc->pch, ih);
        !           864: }
        !           865:
        !           866: const char *
        !           867: pcmcia_intr_string(pf, ih)
        !           868:        struct pcmcia_function *pf;
        !           869:        void *ih;
        !           870: {
        !           871:        return pcmcia_chip_intr_string(pf->sc->pct, pf->sc->pch, ih);
        !           872: }
        !           873:
        !           874: int
        !           875: pcmcia_card_intr(arg)
        !           876:        void *arg;
        !           877: {
        !           878:        struct pcmcia_softc *sc = arg;
        !           879:        struct pcmcia_function *pf;
        !           880:        int reg, ret, ret2;
        !           881:
        !           882:        ret = 0;
        !           883:
        !           884:        for (pf = SIMPLEQ_FIRST(&sc->card.pf_head); pf != NULL;
        !           885:            pf = SIMPLEQ_NEXT(pf, pf_list)) {
        !           886: #ifdef PCMCIADEBUG
        !           887:                printf("%s: intr flags=%x fct=%d cor=%02x csr=%02x pin=%02x",
        !           888:                       sc->dev.dv_xname, pf->pf_flags, pf->number,
        !           889:                       pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION),
        !           890:                       pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS),
        !           891:                       pcmcia_ccr_read(pf, PCMCIA_CCR_PIN));
        !           892: #endif
        !           893:                if (pf->ih_fct != NULL &&
        !           894:                    (pf->ccr_mask & (1 << (PCMCIA_CCR_STATUS / 2)))) {
        !           895:                        reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
        !           896:                        if (reg & PCMCIA_CCR_STATUS_INTR) {
        !           897:                                ret2 = (*pf->ih_fct)(pf->ih_arg);
        !           898:                                if (ret2 != 0 && ret == 0)
        !           899:                                        ret = ret2;
        !           900:                                reg = pcmcia_ccr_read(pf, PCMCIA_CCR_STATUS);
        !           901: #ifdef PCMCIADEBUG
        !           902:                                printf("; csr %02x->%02x",
        !           903:                                    reg, reg & ~PCMCIA_CCR_STATUS_INTR);
        !           904: #endif
        !           905:                                pcmcia_ccr_write(pf, PCMCIA_CCR_STATUS,
        !           906:                                    reg & ~PCMCIA_CCR_STATUS_INTR);
        !           907:                        }
        !           908:                }
        !           909: #ifdef PCMCIADEBUG
        !           910:                printf("\n");
        !           911: #endif
        !           912:        }
        !           913:
        !           914:        return (ret);
        !           915: }

CVSweb