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

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

1.1     ! nbrk        1: /*     $OpenBSD: pci.c,v 1.50 2007/05/21 22:10:45 kettenis Exp $       */
        !             2: /*     $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1995, 1996 Christopher G. Demetriou.  All rights reserved.
        !             6:  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by Charles Hannum.
        !            19:  * 4. The name of the author may not be used to endorse or promote products
        !            20:  *    derived from this software without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: /*
        !            35:  * PCI bus autoconfiguration.
        !            36:  */
        !            37:
        !            38: #include <sys/param.h>
        !            39: #include <sys/systm.h>
        !            40: #include <sys/device.h>
        !            41: #include <sys/malloc.h>
        !            42:
        !            43: #include <dev/pci/pcireg.h>
        !            44: #include <dev/pci/pcivar.h>
        !            45: #include <dev/pci/pcidevs.h>
        !            46:
        !            47: int pcimatch(struct device *, void *, void *);
        !            48: void pciattach(struct device *, struct device *, void *);
        !            49: void pcipower(int, void *);
        !            50:
        !            51: #define NMAPREG                        ((PCI_MAPREG_END - PCI_MAPREG_START) / \
        !            52:                                    sizeof(pcireg_t))
        !            53: struct pci_dev {
        !            54:        LIST_ENTRY(pci_dev) pd_next;
        !            55:        struct device *pd_dev;
        !            56:        pcitag_t pd_tag;        /* pci register tag */
        !            57:        pcireg_t pd_csr;
        !            58:        pcireg_t pd_bhlc;
        !            59:        pcireg_t pd_int;
        !            60:        pcireg_t pd_map[NMAPREG];
        !            61: };
        !            62:
        !            63: #ifdef APERTURE
        !            64: extern int allowaperture;
        !            65: #endif
        !            66:
        !            67: struct cfattach pci_ca = {
        !            68:        sizeof(struct pci_softc), pcimatch, pciattach
        !            69: };
        !            70:
        !            71: struct cfdriver pci_cd = {
        !            72:        NULL, "pci", DV_DULL
        !            73: };
        !            74:
        !            75: int    pci_ndomains;
        !            76:
        !            77: int    pciprint(void *, const char *);
        !            78: int    pcisubmatch(struct device *, void *, void *);
        !            79:
        !            80: #ifdef PCI_MACHDEP_ENUMERATE_BUS
        !            81: #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS
        !            82: #else
        !            83: int pci_enumerate_bus(struct pci_softc *,
        !            84:     int (*)(struct pci_attach_args *), struct pci_attach_args *);
        !            85: #endif
        !            86:
        !            87: /*
        !            88:  * Important note about PCI-ISA bridges:
        !            89:  *
        !            90:  * Callbacks are used to configure these devices so that ISA/EISA bridges
        !            91:  * can attach their child busses after PCI configuration is done.
        !            92:  *
        !            93:  * This works because:
        !            94:  *     (1) there can be at most one ISA/EISA bridge per PCI bus, and
        !            95:  *     (2) any ISA/EISA bridges must be attached to primary PCI
        !            96:  *         busses (i.e. bus zero).
        !            97:  *
        !            98:  * That boils down to: there can only be one of these outstanding
        !            99:  * at a time, it is cleared when configuring PCI bus 0 before any
        !           100:  * subdevices have been found, and it is run after all subdevices
        !           101:  * of PCI bus 0 have been found.
        !           102:  *
        !           103:  * This is needed because there are some (legacy) PCI devices which
        !           104:  * can show up as ISA/EISA devices as well (the prime example of which
        !           105:  * are VGA controllers).  If you attach ISA from a PCI-ISA/EISA bridge,
        !           106:  * and the bridge is seen before the video board is, the board can show
        !           107:  * up as an ISA device, and that can (bogusly) complicate the PCI device's
        !           108:  * attach code, or make the PCI device not be properly attached at all.
        !           109:  *
        !           110:  * We use the generic config_defer() facility to achieve this.
        !           111:  */
        !           112:
        !           113: int
        !           114: pcimatch(struct device *parent, void *match, void *aux)
        !           115: {
        !           116:        struct cfdata *cf = match;
        !           117:        struct pcibus_attach_args *pba = aux;
        !           118:
        !           119:        if (strcmp(pba->pba_busname, cf->cf_driver->cd_name))
        !           120:                return (0);
        !           121:
        !           122:        /* Check the locators */
        !           123:        if (cf->pcibuscf_bus != PCIBUS_UNK_BUS &&
        !           124:            cf->pcibuscf_bus != pba->pba_bus)
        !           125:                return (0);
        !           126:
        !           127:        /* sanity */
        !           128:        if (pba->pba_bus < 0 || pba->pba_bus > 255)
        !           129:                return (0);
        !           130:
        !           131:        /*
        !           132:         * XXX check other (hardware?) indicators
        !           133:         */
        !           134:
        !           135:        return (1);
        !           136: }
        !           137:
        !           138: void
        !           139: pciattach(struct device *parent, struct device *self, void *aux)
        !           140: {
        !           141:        struct pcibus_attach_args *pba = aux;
        !           142:        struct pci_softc *sc = (struct pci_softc *)self;
        !           143:
        !           144:        pci_attach_hook(parent, self, pba);
        !           145:
        !           146:        printf("\n");
        !           147:
        !           148:        LIST_INIT(&sc->sc_devs);
        !           149:        sc->sc_powerhook = powerhook_establish(pcipower, sc);
        !           150:
        !           151:        sc->sc_iot = pba->pba_iot;
        !           152:        sc->sc_memt = pba->pba_memt;
        !           153:        sc->sc_dmat = pba->pba_dmat;
        !           154:        sc->sc_pc = pba->pba_pc;
        !           155:        sc->sc_domain = pba->pba_domain;
        !           156:        sc->sc_bus = pba->pba_bus;
        !           157:        sc->sc_bridgetag = pba->pba_bridgetag;
        !           158:        sc->sc_bridgeih = pba->pba_bridgeih;
        !           159:        sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus);
        !           160:        sc->sc_intrswiz = pba->pba_intrswiz;
        !           161:        sc->sc_intrtag = pba->pba_intrtag;
        !           162:        pci_enumerate_bus(sc, NULL, NULL);
        !           163: }
        !           164:
        !           165: /* save and restore the pci config space */
        !           166: void
        !           167: pcipower(int why, void *arg)
        !           168: {
        !           169:        struct pci_softc *sc = (struct pci_softc *)arg;
        !           170:        struct pci_dev *pd;
        !           171:        pcireg_t reg;
        !           172:        int i;
        !           173:
        !           174:        LIST_FOREACH(pd, &sc->sc_devs, pd_next) {
        !           175:                if (why != PWR_RESUME) {
        !           176:                        for (i = 0; i < NMAPREG; i++)
        !           177:                               pd->pd_map[i] = pci_conf_read(sc->sc_pc,
        !           178:                                   pd->pd_tag, PCI_MAPREG_START + (i * 4));
        !           179:                        pd->pd_csr = pci_conf_read(sc->sc_pc, pd->pd_tag,
        !           180:                           PCI_COMMAND_STATUS_REG);
        !           181:                        pd->pd_bhlc = pci_conf_read(sc->sc_pc, pd->pd_tag,
        !           182:                           PCI_BHLC_REG);
        !           183:                        pd->pd_int = pci_conf_read(sc->sc_pc, pd->pd_tag,
        !           184:                           PCI_INTERRUPT_REG);
        !           185:                } else {
        !           186:                        for (i = 0; i < NMAPREG; i++)
        !           187:                                pci_conf_write(sc->sc_pc, pd->pd_tag,
        !           188:                                    PCI_MAPREG_START + (i * 4),
        !           189:                                        pd->pd_map[i]);
        !           190:                        reg = pci_conf_read(sc->sc_pc, pd->pd_tag,
        !           191:                            PCI_COMMAND_STATUS_REG);
        !           192:                        pci_conf_write(sc->sc_pc, pd->pd_tag,
        !           193:                            PCI_COMMAND_STATUS_REG,
        !           194:                            (reg & 0xffff0000) | (pd->pd_csr & 0x0000ffff));
        !           195:                        pci_conf_write(sc->sc_pc, pd->pd_tag, PCI_BHLC_REG,
        !           196:                            pd->pd_bhlc);
        !           197:                        pci_conf_write(sc->sc_pc, pd->pd_tag, PCI_INTERRUPT_REG,
        !           198:                            pd->pd_int);
        !           199:                }
        !           200:        }
        !           201: }
        !           202:
        !           203: int
        !           204: pciprint(void *aux, const char *pnp)
        !           205: {
        !           206:        struct pci_attach_args *pa = aux;
        !           207:        char devinfo[256];
        !           208:
        !           209:        if (pnp) {
        !           210:                pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo,
        !           211:                    sizeof devinfo);
        !           212:                printf("%s at %s", devinfo, pnp);
        !           213:        }
        !           214:        printf(" dev %d function %d", pa->pa_device, pa->pa_function);
        !           215:        if (!pnp) {
        !           216:                pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo,
        !           217:                    sizeof devinfo);
        !           218:                printf(" %s", devinfo);
        !           219:        }
        !           220:
        !           221:        return (UNCONF);
        !           222: }
        !           223:
        !           224: int
        !           225: pcisubmatch(struct device *parent, void *match,  void *aux)
        !           226: {
        !           227:        struct cfdata *cf = match;
        !           228:        struct pci_attach_args *pa = aux;
        !           229:
        !           230:        if (cf->pcicf_dev != PCI_UNK_DEV &&
        !           231:            cf->pcicf_dev != pa->pa_device)
        !           232:                return (0);
        !           233:        if (cf->pcicf_function != PCI_UNK_FUNCTION &&
        !           234:            cf->pcicf_function != pa->pa_function)
        !           235:                return (0);
        !           236:
        !           237:        return ((*cf->cf_attach->ca_match)(parent, match, aux));
        !           238: }
        !           239:
        !           240: int
        !           241: pci_probe_device(struct pci_softc *sc, pcitag_t tag,
        !           242:     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
        !           243: {
        !           244:        pci_chipset_tag_t pc = sc->sc_pc;
        !           245:        struct pci_attach_args pa;
        !           246:        struct pci_dev *pd;
        !           247:        struct device *dev;
        !           248:        pcireg_t id, csr, class, intr, bhlcr;
        !           249:        int ret, pin, bus, device, function;
        !           250:
        !           251:        pci_decompose_tag(pc, tag, &bus, &device, &function);
        !           252:
        !           253:        bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           254:        if (PCI_HDRTYPE_TYPE(bhlcr) > 2)
        !           255:                return (0);
        !           256:
        !           257:        id = pci_conf_read(pc, tag, PCI_ID_REG);
        !           258:        csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !           259:        class = pci_conf_read(pc, tag, PCI_CLASS_REG);
        !           260:
        !           261:        /* Invalid vendor ID value? */
        !           262:        if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
        !           263:                return (0);
        !           264:        /* XXX Not invalid, but we've done this ~forever. */
        !           265:        if (PCI_VENDOR(id) == 0)
        !           266:                return (0);
        !           267:
        !           268:        pa.pa_iot = sc->sc_iot;
        !           269:        pa.pa_memt = sc->sc_memt;
        !           270:        pa.pa_dmat = sc->sc_dmat;
        !           271:        pa.pa_pc = pc;
        !           272:        pa.pa_domain = sc->sc_domain;
        !           273:        pa.pa_bus = bus;
        !           274:        pa.pa_device = device;
        !           275:        pa.pa_function = function;
        !           276:        pa.pa_tag = tag;
        !           277:        pa.pa_id = id;
        !           278:        pa.pa_class = class;
        !           279:        pa.pa_bridgetag = sc->sc_bridgetag;
        !           280:        pa.pa_bridgeih = sc->sc_bridgeih;
        !           281:
        !           282:        /* This is a simplification of the NetBSD code.
        !           283:           We don't support turning off I/O or memory
        !           284:           on broken hardware. <csapuntz@stanford.edu> */
        !           285:        pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
        !           286:
        !           287: #ifdef __i386__
        !           288:        /*
        !           289:         * on i386 we really need to know the device tag
        !           290:         * and not the pci bridge tag, in intr_map
        !           291:         * to be able to program the device and the
        !           292:         * pci interrupt router.
        !           293:         */
        !           294:        pa.pa_intrtag = tag;
        !           295:        pa.pa_intrswiz = 0;
        !           296: #else
        !           297:        if (sc->sc_bridgetag == NULL) {
        !           298:                pa.pa_intrswiz = 0;
        !           299:                pa.pa_intrtag = tag;
        !           300:        } else {
        !           301:                pa.pa_intrswiz = sc->sc_intrswiz + device;
        !           302:                pa.pa_intrtag = sc->sc_intrtag;
        !           303:        }
        !           304: #endif
        !           305:
        !           306:        intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
        !           307:
        !           308:        pin = PCI_INTERRUPT_PIN(intr);
        !           309:        pa.pa_rawintrpin = pin;
        !           310:        if (pin == PCI_INTERRUPT_PIN_NONE) {
        !           311:                /* no interrupt */
        !           312:                pa.pa_intrpin = 0;
        !           313:        } else {
        !           314:                /*
        !           315:                 * swizzle it based on the number of busses we're
        !           316:                 * behind and our device number.
        !           317:                 */
        !           318:                pa.pa_intrpin =         /* XXX */
        !           319:                    ((pin + pa.pa_intrswiz - 1) % 4) + 1;
        !           320:        }
        !           321:        pa.pa_intrline = PCI_INTERRUPT_LINE(intr);
        !           322:
        !           323:        if (match != NULL) {
        !           324:                ret = (*match)(&pa);
        !           325:                if (ret != 0 && pap != NULL)
        !           326:                        *pap = pa;
        !           327:        } else {
        !           328:                if ((dev = config_found_sm(&sc->sc_dev, &pa, pciprint,
        !           329:                    pcisubmatch))) {
        !           330:                                pcireg_t reg;
        !           331:
        !           332:                                /* skip header type != 0 */
        !           333:                                reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           334:                                if (PCI_HDRTYPE_TYPE(reg) != 0)
        !           335:                                        return(0);
        !           336:                                if (pci_get_capability(pc, tag,
        !           337:                                    PCI_CAP_PWRMGMT, NULL, NULL) == 0)
        !           338:                                        return(0);
        !           339:                                if (!(pd = malloc(sizeof *pd, M_DEVBUF,
        !           340:                                    M_NOWAIT)))
        !           341:                                        return(0);
        !           342:                                pd->pd_tag = tag;
        !           343:                                pd->pd_dev = dev;
        !           344:                                LIST_INSERT_HEAD(&sc->sc_devs, pd, pd_next);
        !           345:                        }
        !           346:        }
        !           347:
        !           348:        return (ret);
        !           349: }
        !           350:
        !           351: int
        !           352: pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid,
        !           353:     int *offset, pcireg_t *value)
        !           354: {
        !           355:        pcireg_t reg;
        !           356:        unsigned int ofs;
        !           357:
        !           358:        reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
        !           359:        if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
        !           360:                return (0);
        !           361:
        !           362:        /* Determine the Capability List Pointer register to start with. */
        !           363:        reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           364:        switch (PCI_HDRTYPE_TYPE(reg)) {
        !           365:        case 0: /* standard device header */
        !           366:                ofs = PCI_CAPLISTPTR_REG;
        !           367:                break;
        !           368:        case 2: /* PCI-CardBus Bridge header */
        !           369:                ofs = PCI_CARDBUS_CAPLISTPTR_REG;
        !           370:                break;
        !           371:        default:
        !           372:                return (0);
        !           373:        }
        !           374:
        !           375:        ofs = PCI_CAPLIST_PTR(pci_conf_read(pc, tag, ofs));
        !           376:        while (ofs != 0) {
        !           377: #ifdef DIAGNOSTIC
        !           378:                if ((ofs & 3) || (ofs < 0x40))
        !           379:                        panic("pci_get_capability");
        !           380: #endif
        !           381:                reg = pci_conf_read(pc, tag, ofs);
        !           382:                if (PCI_CAPLIST_CAP(reg) == capid) {
        !           383:                        if (offset)
        !           384:                                *offset = ofs;
        !           385:                        if (value)
        !           386:                                *value = reg;
        !           387:                        return (1);
        !           388:                }
        !           389:                ofs = PCI_CAPLIST_NEXT(reg);
        !           390:        }
        !           391:
        !           392:        return (0);
        !           393: }
        !           394:
        !           395: int
        !           396: pci_find_device(struct pci_attach_args *pa,
        !           397:                int (*match)(struct pci_attach_args *))
        !           398: {
        !           399:        extern struct cfdriver pci_cd;
        !           400:        struct device *pcidev;
        !           401:        int i;
        !           402:
        !           403:        for (i = 0; i < pci_cd.cd_ndevs; i++) {
        !           404:                pcidev = pci_cd.cd_devs[i];
        !           405:                if (pcidev != NULL &&
        !           406:                    pci_enumerate_bus((struct pci_softc *)pcidev,
        !           407:                                      match, pa) != 0)
        !           408:                        return (1);
        !           409:        }
        !           410:        return (0);
        !           411: }
        !           412:
        !           413: #ifndef PCI_MACHDEP_ENUMERATE_BUS
        !           414: /*
        !           415:  * Generic PCI bus enumeration routine.  Used unless machine-dependent
        !           416:  * code needs to provide something else.
        !           417:  */
        !           418: int
        !           419: pci_enumerate_bus(struct pci_softc *sc,
        !           420:     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
        !           421: {
        !           422:        pci_chipset_tag_t pc = sc->sc_pc;
        !           423:        int device, function, nfunctions, ret;
        !           424:        const struct pci_quirkdata *qd;
        !           425:        pcireg_t id, bhlcr;
        !           426:        pcitag_t tag;
        !           427:
        !           428:        for (device = 0; device < sc->sc_maxndevs; device++) {
        !           429:                tag = pci_make_tag(pc, sc->sc_bus, device, 0);
        !           430:
        !           431:                bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
        !           432:                if (PCI_HDRTYPE_TYPE(bhlcr) > 2)
        !           433:                        continue;
        !           434:
        !           435:                id = pci_conf_read(pc, tag, PCI_ID_REG);
        !           436:
        !           437:                /* Invalid vendor ID value? */
        !           438:                if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
        !           439:                        continue;
        !           440:                /* XXX Not invalid, but we've done this ~forever. */
        !           441:                if (PCI_VENDOR(id) == 0)
        !           442:                        continue;
        !           443:
        !           444:                qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id));
        !           445:
        !           446:                if (qd != NULL &&
        !           447:                      (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)
        !           448:                        nfunctions = 8;
        !           449:                else if (qd != NULL &&
        !           450:                      (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0)
        !           451:                        nfunctions = 1;
        !           452:                else
        !           453:                        nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;
        !           454:
        !           455:                for (function = 0; function < nfunctions; function++) {
        !           456:                        tag = pci_make_tag(pc, sc->sc_bus, device, function);
        !           457:                        ret = pci_probe_device(sc, tag, match, pap);
        !           458:                        if (match != NULL && ret != 0)
        !           459:                                return (ret);
        !           460:                }
        !           461:        }
        !           462:
        !           463:        return (0);
        !           464: }
        !           465: #endif /* PCI_MACHDEP_ENUMERATE_BUS */
        !           466:
        !           467: int
        !           468: pci_matchbyid(struct pci_attach_args *pa, const struct pci_matchid *ids,
        !           469:     int nent)
        !           470: {
        !           471:        const struct pci_matchid *pm;
        !           472:        int i;
        !           473:
        !           474:        for (i = 0, pm = ids; i < nent; i++, pm++)
        !           475:                if (PCI_VENDOR(pa->pa_id) == pm->pm_vid &&
        !           476:                    PCI_PRODUCT(pa->pa_id) == pm->pm_pid)
        !           477:                        return (1);
        !           478:        return (0);
        !           479: }
        !           480:
        !           481: #ifdef USER_PCICONF
        !           482: /*
        !           483:  * This is the user interface to PCI configuration space.
        !           484:  */
        !           485:
        !           486: #include <sys/pciio.h>
        !           487: #include <sys/fcntl.h>
        !           488:
        !           489: #ifdef DEBUG
        !           490: #define PCIDEBUG(x) printf x
        !           491: #else
        !           492: #define PCIDEBUG(x)
        !           493: #endif
        !           494:
        !           495:
        !           496: int pciopen(dev_t dev, int oflags, int devtype, struct proc *p);
        !           497: int pciclose(dev_t dev, int flag, int devtype, struct proc *p);
        !           498: int pciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
        !           499:
        !           500: int
        !           501: pciopen(dev_t dev, int oflags, int devtype, struct proc *p)
        !           502: {
        !           503:        PCIDEBUG(("pciopen ndevs: %d\n" , pci_cd.cd_ndevs));
        !           504:
        !           505:        if (minor(dev) >= pci_ndomains) {
        !           506:                return ENXIO;
        !           507:        }
        !           508:
        !           509: #ifndef APERTURE
        !           510:        if ((oflags & FWRITE) && securelevel > 0) {
        !           511:                return EPERM;
        !           512:        }
        !           513: #else
        !           514:        if ((oflags & FWRITE) && securelevel > 0 && allowaperture == 0) {
        !           515:                return EPERM;
        !           516:        }
        !           517: #endif
        !           518:        return (0);
        !           519: }
        !           520:
        !           521: int
        !           522: pciclose(dev_t dev, int flag, int devtype, struct proc *p)
        !           523: {
        !           524:        PCIDEBUG(("pciclose\n"));
        !           525:        return (0);
        !           526: }
        !           527:
        !           528: int
        !           529: pciioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
        !           530: {
        !           531:        struct pci_io *io;
        !           532:        int i, error;
        !           533:        pcitag_t tag;
        !           534:        struct pci_softc *pci = NULL;
        !           535:        pci_chipset_tag_t pc;
        !           536:
        !           537:        io = (struct pci_io *)data;
        !           538:
        !           539:        PCIDEBUG(("pciioctl cmd %s", cmd == PCIOCREAD ? "pciocread"
        !           540:                  : cmd == PCIOCWRITE ? "pciocwrite" : "unknown"));
        !           541:        PCIDEBUG(("  bus %d dev %d func %d reg %x\n", io->pi_sel.pc_bus,
        !           542:                  io->pi_sel.pc_dev, io->pi_sel.pc_func, io->pi_reg));
        !           543:
        !           544:        for (i = 0; i < pci_cd.cd_ndevs; i++) {
        !           545:                pci = pci_cd.cd_devs[i];
        !           546:                if (pci != NULL && pci->sc_domain == minor(dev) &&
        !           547:                    pci->sc_bus == io->pi_sel.pc_bus)
        !           548:                        break;
        !           549:        }
        !           550:        if (pci != NULL && pci->sc_bus == io->pi_sel.pc_bus) {
        !           551:                pc = pci->sc_pc;
        !           552:        } else {
        !           553:                error = ENXIO;
        !           554:                goto done;
        !           555:        }
        !           556:        /* Check bounds */
        !           557:        if (pci->sc_bus >= 256 ||
        !           558:            io->pi_sel.pc_dev >= pci_bus_maxdevs(pc, pci->sc_bus) ||
        !           559:            io->pi_sel.pc_func >= 8) {
        !           560:                error = EINVAL;
        !           561:                goto done;
        !           562:        }
        !           563:
        !           564:        tag = pci_make_tag(pc, io->pi_sel.pc_bus, io->pi_sel.pc_dev,
        !           565:                           io->pi_sel.pc_func);
        !           566:
        !           567:        switch(cmd) {
        !           568:        case PCIOCGETCONF:
        !           569:                error = ENODEV;
        !           570:                break;
        !           571:
        !           572:        case PCIOCREAD:
        !           573:                switch(io->pi_width) {
        !           574:                case 4:
        !           575:                        /* Make sure the register is properly aligned */
        !           576:                        if (io->pi_reg & 0x3)
        !           577:                                return EINVAL;
        !           578:                        io->pi_data = pci_conf_read(pc, tag, io->pi_reg);
        !           579:                        error = 0;
        !           580:                        break;
        !           581:                default:
        !           582:                        error = ENODEV;
        !           583:                        break;
        !           584:                }
        !           585:                break;
        !           586:
        !           587:        case PCIOCWRITE:
        !           588:                if (!(flag & FWRITE))
        !           589:                        return EPERM;
        !           590:
        !           591:                switch(io->pi_width) {
        !           592:                case 4:
        !           593:                        /* Make sure the register is properly aligned */
        !           594:                        if (io->pi_reg & 0x3)
        !           595:                                return EINVAL;
        !           596:                        pci_conf_write(pc, tag, io->pi_reg, io->pi_data);
        !           597:                        error = 0;
        !           598:                        break;
        !           599:                default:
        !           600:                        error = ENODEV;
        !           601:                        break;
        !           602:                }
        !           603:                break;
        !           604:
        !           605:        default:
        !           606:                error = ENOTTY;
        !           607:                break;
        !           608:        }
        !           609:  done:
        !           610:        return (error);
        !           611: }
        !           612:
        !           613: #endif

CVSweb