[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

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