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