root/dev/pci/pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcimatch
  2. pciattach
  3. pcipower
  4. pciprint
  5. pcisubmatch
  6. pci_probe_device
  7. pci_get_capability
  8. pci_find_device
  9. pci_enumerate_bus
  10. pci_matchbyid
  11. pciopen
  12. pciclose
  13. pciioctl

    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

/* [<][>][^][v][top][bottom][index][help] */