The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/puc/puc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2006 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/bus.h>
   34 #include <sys/conf.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mutex.h>
   37 
   38 #include <machine/bus.h>
   39 #include <machine/resource.h>
   40 #include <sys/rman.h>
   41 
   42 #include <dev/pci/pcireg.h>
   43 #include <dev/pci/pcivar.h>
   44 
   45 #include <dev/puc/puc_bus.h>
   46 #include <dev/puc/puc_cfg.h>
   47 #include <dev/puc/puc_bfe.h>
   48 
   49 #define PUC_ISRCCNT     5
   50 
   51 struct puc_port {
   52         struct puc_bar  *p_bar;
   53         struct resource *p_rres;
   54         struct resource *p_ires;
   55         device_t        p_dev;
   56         int             p_nr;
   57         int             p_type;
   58         int             p_rclk;
   59 
   60         int             p_hasintr:1;
   61 
   62         serdev_intr_t   *p_ihsrc[PUC_ISRCCNT];
   63         void            *p_iharg;
   64 
   65         int             p_ipend;
   66 };
   67 
   68 devclass_t puc_devclass;
   69 const char puc_driver_name[] = "puc";
   70 
   71 static MALLOC_DEFINE(M_PUC, "PUC", "PUC driver");
   72 
   73 struct puc_bar *
   74 puc_get_bar(struct puc_softc *sc, int rid)
   75 {
   76         struct puc_bar *bar;
   77         struct rman *rm;
   78         u_long end, start;
   79         int error, i;
   80 
   81         /* Find the BAR entry with the given RID. */
   82         i = 0;
   83         while (i < PUC_PCI_BARS && sc->sc_bar[i].b_rid != rid)
   84                 i++;
   85         if (i < PUC_PCI_BARS)
   86                 return (&sc->sc_bar[i]);
   87 
   88         /* Not found. If we're looking for an unused entry, return NULL. */
   89         if (rid == -1)
   90                 return (NULL);
   91 
   92         /* Get an unused entry for us to fill.  */
   93         bar = puc_get_bar(sc, -1);
   94         if (bar == NULL)
   95                 return (NULL);
   96         bar->b_rid = rid;
   97         bar->b_type = SYS_RES_IOPORT;
   98         bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
   99             &bar->b_rid, RF_ACTIVE);
  100         if (bar->b_res == NULL) {
  101                 bar->b_rid = rid;
  102                 bar->b_type = SYS_RES_MEMORY;
  103                 bar->b_res = bus_alloc_resource_any(sc->sc_dev, bar->b_type,
  104                     &bar->b_rid, RF_ACTIVE);
  105                 if (bar->b_res == NULL) {
  106                         bar->b_rid = -1;
  107                         return (NULL);
  108                 }
  109         }
  110 
  111         /* Update our managed space. */
  112         rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport : &sc->sc_iomem;
  113         start = rman_get_start(bar->b_res);
  114         end = rman_get_end(bar->b_res);
  115         error = rman_manage_region(rm, start, end);
  116         if (error) {
  117                 bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid,
  118                     bar->b_res);
  119                 bar->b_res = NULL;
  120                 bar->b_rid = -1;
  121                 bar = NULL;
  122         }
  123 
  124         return (bar);
  125 }
  126 
  127 static int
  128 puc_intr(void *arg)
  129 {
  130         struct puc_port *port;
  131         struct puc_softc *sc = arg;
  132         u_long ds, dev, devs;
  133         int i, idx, ipend, isrc, nints;
  134         uint8_t ilr;
  135 
  136         nints = 0;
  137         while (1) {
  138                 /*
  139                  * Obtain the set of devices with pending interrupts.
  140                  */
  141                 devs = sc->sc_serdevs;
  142                 if (sc->sc_ilr == PUC_ILR_DIGI) {
  143                         idx = 0;
  144                         while (devs & (0xfful << idx)) {
  145                                 ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
  146                                 devs &= ~0ul ^ ((u_long)ilr << idx);
  147                                 idx += 8;
  148                         }
  149                 } else if (sc->sc_ilr == PUC_ILR_QUATECH) {
  150                         /*
  151                          * Don't trust the value if it's the same as the option
  152                          * register. It may mean that the ILR is not active and
  153                          * we're reading the option register instead. This may
  154                          * lead to false positives on 8-port boards.
  155                          */
  156                         ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
  157                         if (ilr != (sc->sc_cfg_data & 0xff))
  158                                 devs &= (u_long)ilr;
  159                 }
  160                 if (devs == 0UL)
  161                         break;
  162 
  163                 /*
  164                  * Obtain the set of interrupt sources from those devices
  165                  * that have pending interrupts.
  166                  */
  167                 ipend = 0;
  168                 idx = 0, dev = 1UL;
  169                 ds = devs;
  170                 while (ds != 0UL) {
  171                         while ((ds & dev) == 0UL)
  172                                 idx++, dev <<= 1;
  173                         ds &= ~dev;
  174                         port = &sc->sc_port[idx];
  175                         port->p_ipend = SERDEV_IPEND(port->p_dev);
  176                         ipend |= port->p_ipend;
  177                 }
  178                 if (ipend == 0)
  179                         break;
  180 
  181                 i = 0, isrc = SER_INT_OVERRUN;
  182                 while (ipend) {
  183                         while (i < PUC_ISRCCNT && !(ipend & isrc))
  184                                 i++, isrc <<= 1;
  185                         KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
  186                         ipend &= ~isrc;
  187                         idx = 0, dev = 1UL;
  188                         ds = devs;
  189                         while (ds != 0UL) {
  190                                 while ((ds & dev) == 0UL)
  191                                         idx++, dev <<= 1;
  192                                 ds &= ~dev;
  193                                 port = &sc->sc_port[idx];
  194                                 if (!(port->p_ipend & isrc))
  195                                         continue;
  196                                 if (port->p_ihsrc[i] != NULL)
  197                                         (*port->p_ihsrc[i])(port->p_iharg);
  198                                 nints++;
  199                         }
  200                 }
  201         }
  202 
  203         return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY);
  204 }
  205 
  206 int
  207 puc_bfe_attach(device_t dev)
  208 {
  209         char buffer[64];
  210         struct puc_bar *bar;
  211         struct puc_port *port;
  212         struct puc_softc *sc;
  213         struct rman *rm;
  214         intptr_t res;
  215         bus_addr_t ofs, start;
  216         bus_size_t size;
  217         bus_space_handle_t bsh;
  218         bus_space_tag_t bst;
  219         int error, idx;
  220 
  221         sc = device_get_softc(dev);
  222 
  223         for (idx = 0; idx < PUC_PCI_BARS; idx++)
  224                 sc->sc_bar[idx].b_rid = -1;
  225 
  226         do {
  227                 sc->sc_ioport.rm_type = RMAN_ARRAY;
  228                 error = rman_init(&sc->sc_ioport);
  229                 if (!error) {
  230                         sc->sc_iomem.rm_type = RMAN_ARRAY;
  231                         error = rman_init(&sc->sc_iomem);
  232                         if (!error) {
  233                                 sc->sc_irq.rm_type = RMAN_ARRAY;
  234                                 error = rman_init(&sc->sc_irq);
  235                                 if (!error)
  236                                         break;
  237                                 rman_fini(&sc->sc_iomem);
  238                         }
  239                         rman_fini(&sc->sc_ioport);
  240                 }
  241                 return (error);
  242         } while (0);
  243 
  244         snprintf(buffer, sizeof(buffer), "%s I/O port mapping",
  245             device_get_nameunit(dev));
  246         sc->sc_ioport.rm_descr = strdup(buffer, M_PUC);
  247         snprintf(buffer, sizeof(buffer), "%s I/O memory mapping",
  248             device_get_nameunit(dev));
  249         sc->sc_iomem.rm_descr = strdup(buffer, M_PUC);
  250         snprintf(buffer, sizeof(buffer), "%s port numbers",
  251             device_get_nameunit(dev));
  252         sc->sc_irq.rm_descr = strdup(buffer, M_PUC);
  253 
  254         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
  255         KASSERT(error == 0, ("%s %d", __func__, __LINE__));
  256         sc->sc_nports = (int)res;
  257         sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port),
  258             M_PUC, M_WAITOK|M_ZERO);
  259 
  260         error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports);
  261         if (error)
  262                 goto fail;
  263 
  264         error = puc_config(sc, PUC_CFG_SETUP, 0, &res);
  265         if (error)
  266                 goto fail;
  267 
  268         for (idx = 0; idx < sc->sc_nports; idx++) {
  269                 port = &sc->sc_port[idx];
  270                 port->p_nr = idx + 1;
  271                 error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res);
  272                 if (error)
  273                         goto fail;
  274                 port->p_type = res;
  275                 error = puc_config(sc, PUC_CFG_GET_RID, idx, &res);
  276                 if (error)
  277                         goto fail;
  278                 bar = puc_get_bar(sc, res);
  279                 if (bar == NULL) {
  280                         error = ENXIO;
  281                         goto fail;
  282                 }
  283                 port->p_bar = bar;
  284                 start = rman_get_start(bar->b_res);
  285                 error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res);
  286                 if (error)
  287                         goto fail;
  288                 ofs = res;
  289                 error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res);
  290                 if (error)
  291                         goto fail;
  292                 size = res;
  293                 rm = (bar->b_type == SYS_RES_IOPORT)
  294                     ? &sc->sc_ioport: &sc->sc_iomem;
  295                 port->p_rres = rman_reserve_resource(rm, start + ofs,
  296                     start + ofs + size - 1, size, 0, NULL);
  297                 if (port->p_rres != NULL) {
  298                         bsh = rman_get_bushandle(bar->b_res);
  299                         bst = rman_get_bustag(bar->b_res);
  300                         bus_space_subregion(bst, bsh, ofs, size, &bsh);
  301                         rman_set_bushandle(port->p_rres, bsh);
  302                         rman_set_bustag(port->p_rres, bst);
  303                 }
  304                 port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr,
  305                     port->p_nr, 1, 0, NULL);
  306                 if (port->p_ires == NULL) {
  307                         error = ENXIO;
  308                         goto fail;
  309                 }
  310                 error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res);
  311                 if (error)
  312                         goto fail;
  313                 port->p_rclk = res;
  314 
  315                 port->p_dev = device_add_child(dev, NULL, -1);
  316                 if (port->p_dev != NULL)
  317                         device_set_ivars(port->p_dev, (void *)port);
  318         }
  319 
  320         error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res);
  321         if (error)
  322                 goto fail;
  323         sc->sc_ilr = res;
  324         if (bootverbose && sc->sc_ilr != 0)
  325                 device_printf(dev, "using interrupt latch register\n");
  326 
  327         sc->sc_irid = 0;
  328         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
  329             RF_ACTIVE|RF_SHAREABLE);
  330         if (sc->sc_ires != NULL) {
  331                 error = bus_setup_intr(dev, sc->sc_ires,
  332                     INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie);
  333                 if (error)
  334                         error = bus_setup_intr(dev, sc->sc_ires,
  335                             INTR_TYPE_TTY | INTR_MPSAFE, NULL,
  336                             (driver_intr_t *)puc_intr, sc, &sc->sc_icookie);
  337                 else
  338                         sc->sc_fastintr = 1;
  339 
  340                 if (error) {
  341                         device_printf(dev, "could not activate interrupt\n");
  342                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  343                             sc->sc_ires);
  344                         sc->sc_ires = NULL;
  345                 }
  346         }
  347         if (sc->sc_ires == NULL) {
  348                 /* XXX no interrupt resource. Force polled mode. */
  349                 sc->sc_polled = 1;
  350         }
  351 
  352         /* Probe and attach our children. */
  353         for (idx = 0; idx < sc->sc_nports; idx++) {
  354                 port = &sc->sc_port[idx];
  355                 if (port->p_dev == NULL)
  356                         continue;
  357                 error = device_probe_and_attach(port->p_dev);
  358                 if (error) {
  359                         device_delete_child(dev, port->p_dev);
  360                         port->p_dev = NULL;
  361                 }
  362         }
  363 
  364         /*
  365          * If there are no serdev devices, then our interrupt handler
  366          * will do nothing. Tear it down.
  367          */
  368         if (sc->sc_serdevs == 0UL)
  369                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  370 
  371         return (0);
  372 
  373 fail:
  374         for (idx = 0; idx < sc->sc_nports; idx++) {
  375                 port = &sc->sc_port[idx];
  376                 if (port->p_dev != NULL)
  377                         device_delete_child(dev, port->p_dev);
  378                 if (port->p_rres != NULL)
  379                         rman_release_resource(port->p_rres);
  380                 if (port->p_ires != NULL)
  381                         rman_release_resource(port->p_ires);
  382         }
  383         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
  384                 bar = &sc->sc_bar[idx];
  385                 if (bar->b_res != NULL)
  386                         bus_release_resource(sc->sc_dev, bar->b_type,
  387                             bar->b_rid, bar->b_res);
  388         }
  389         rman_fini(&sc->sc_irq);
  390         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
  391         rman_fini(&sc->sc_iomem);
  392         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
  393         rman_fini(&sc->sc_ioport);
  394         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
  395         free(sc->sc_port, M_PUC);
  396         return (error);
  397 }
  398 
  399 int
  400 puc_bfe_detach(device_t dev)
  401 {
  402         struct puc_bar *bar;
  403         struct puc_port *port;
  404         struct puc_softc *sc;
  405         int error, idx;
  406 
  407         sc = device_get_softc(dev);
  408 
  409         /* Detach our children. */
  410         error = 0;
  411         for (idx = 0; idx < sc->sc_nports; idx++) {
  412                 port = &sc->sc_port[idx];
  413                 if (port->p_dev == NULL)
  414                         continue;
  415                 if (device_delete_child(dev, port->p_dev) == 0) {
  416                         if (port->p_rres != NULL)
  417                                 rman_release_resource(port->p_rres);
  418                         if (port->p_ires != NULL)
  419                                 rman_release_resource(port->p_ires);
  420                 } else
  421                         error = ENXIO;
  422         }
  423         if (error)
  424                 return (error);
  425 
  426         if (sc->sc_serdevs != 0UL)
  427                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  428         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
  429 
  430         for (idx = 0; idx < PUC_PCI_BARS; idx++) {
  431                 bar = &sc->sc_bar[idx];
  432                 if (bar->b_res != NULL)
  433                         bus_release_resource(sc->sc_dev, bar->b_type,
  434                             bar->b_rid, bar->b_res);
  435         }
  436 
  437         rman_fini(&sc->sc_irq);
  438         free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC);
  439         rman_fini(&sc->sc_iomem);
  440         free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC);
  441         rman_fini(&sc->sc_ioport);
  442         free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC);
  443         free(sc->sc_port, M_PUC);
  444         return (0);
  445 }
  446 
  447 int
  448 puc_bfe_probe(device_t dev, const struct puc_cfg *cfg)
  449 {
  450         struct puc_softc *sc;
  451         intptr_t res;
  452         int error;
  453 
  454         sc = device_get_softc(dev);
  455         sc->sc_dev = dev;
  456         sc->sc_cfg = cfg;
  457 
  458         /* We don't attach to single-port serial cards. */
  459         if (cfg->ports == PUC_PORT_1S || cfg->ports == PUC_PORT_1P)
  460                 return (EDOOFUS);
  461         error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res);
  462         if (error)
  463                 return (error);
  464         error = puc_config(sc, PUC_CFG_GET_DESC, 0, &res);
  465         if (error)
  466                 return (error);
  467         if (res != 0)
  468                 device_set_desc(dev, (const char *)res);
  469         return (BUS_PROBE_DEFAULT);
  470 }
  471 
  472 struct resource *
  473 puc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  474     u_long start, u_long end, u_long count, u_int flags)
  475 {
  476         struct puc_port *port;
  477         struct resource *res;
  478         device_t assigned, originator;
  479         int error;
  480 
  481         /* Get our immediate child. */
  482         originator = child;
  483         while (child != NULL && device_get_parent(child) != dev)
  484                 child = device_get_parent(child);
  485         if (child == NULL)
  486                 return (NULL);
  487 
  488         port = device_get_ivars(child);
  489         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  490 
  491         if (rid == NULL || *rid != 0)
  492                 return (NULL);
  493 
  494         /* We only support default allocations. */
  495         if (start != 0UL || end != ~0UL)
  496                 return (NULL);
  497 
  498         if (type == port->p_bar->b_type)
  499                 res = port->p_rres;
  500         else if (type == SYS_RES_IRQ)
  501                 res = port->p_ires;
  502         else
  503                 return (NULL);
  504 
  505         if (res == NULL)
  506                 return (NULL);
  507 
  508         assigned = rman_get_device(res);
  509         if (assigned == NULL)   /* Not allocated */
  510                 rman_set_device(res, originator);
  511         else if (assigned != originator)
  512                 return (NULL);
  513 
  514         if (flags & RF_ACTIVE) {
  515                 error = rman_activate_resource(res);
  516                 if (error) {
  517                         if (assigned == NULL)
  518                                 rman_set_device(res, NULL);
  519                         return (NULL);
  520                 }
  521         }
  522 
  523         return (res);
  524 }
  525 
  526 int
  527 puc_bus_release_resource(device_t dev, device_t child, int type, int rid,
  528     struct resource *res)
  529 {
  530         struct puc_port *port;
  531         device_t originator;
  532 
  533         /* Get our immediate child. */
  534         originator = child;
  535         while (child != NULL && device_get_parent(child) != dev)
  536                 child = device_get_parent(child);
  537         if (child == NULL)
  538                 return (EINVAL);
  539 
  540         port = device_get_ivars(child);
  541         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  542 
  543         if (rid != 0 || res == NULL)
  544                 return (EINVAL);
  545 
  546         if (type == port->p_bar->b_type) {
  547                 if (res != port->p_rres)
  548                         return (EINVAL);
  549         } else if (type == SYS_RES_IRQ) {
  550                 if (res != port->p_ires)
  551                         return (EINVAL);
  552                 if (port->p_hasintr)
  553                         return (EBUSY);
  554         } else
  555                 return (EINVAL);
  556 
  557         if (rman_get_device(res) != originator)
  558                 return (ENXIO);
  559         if (rman_get_flags(res) & RF_ACTIVE)
  560                 rman_deactivate_resource(res);
  561         rman_set_device(res, NULL);
  562         return (0);
  563 }
  564 
  565 int
  566 puc_bus_get_resource(device_t dev, device_t child, int type, int rid,
  567     u_long *startp, u_long *countp)
  568 {
  569         struct puc_port *port;
  570         struct resource *res;
  571         u_long start;
  572 
  573         /* Get our immediate child. */
  574         while (child != NULL && device_get_parent(child) != dev)
  575                 child = device_get_parent(child);
  576         if (child == NULL)
  577                 return (EINVAL);
  578 
  579         port = device_get_ivars(child);
  580         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  581 
  582         if (type == port->p_bar->b_type)
  583                 res = port->p_rres;
  584         else if (type == SYS_RES_IRQ)
  585                 res = port->p_ires;
  586         else
  587                 return (ENXIO);
  588 
  589         if (rid != 0 || res == NULL)
  590                 return (ENXIO);
  591 
  592         start = rman_get_start(res);
  593         if (startp != NULL)
  594                 *startp = start;
  595         if (countp != NULL)
  596                 *countp = rman_get_end(res) - start + 1;
  597         return (0);
  598 }
  599 
  600 int
  601 puc_bus_setup_intr(device_t dev, device_t child, struct resource *res,
  602     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
  603 {
  604         struct puc_port *port;
  605         struct puc_softc *sc;
  606         device_t originator;
  607         int i, isrc, serdev;
  608 
  609         sc = device_get_softc(dev);
  610 
  611         /* Get our immediate child. */
  612         originator = child;
  613         while (child != NULL && device_get_parent(child) != dev)
  614                 child = device_get_parent(child);
  615         if (child == NULL)
  616                 return (EINVAL);
  617 
  618         port = device_get_ivars(child);
  619         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  620 
  621         if (cookiep == NULL || res != port->p_ires)
  622                 return (EINVAL);
  623         /* We demand that serdev devices use filter_only interrupts. */
  624         if (port->p_type == PUC_TYPE_SERIAL && ihand != NULL)
  625                 return (ENXIO);
  626         if (rman_get_device(port->p_ires) != originator)
  627                 return (ENXIO);
  628 
  629         /*
  630          * Have non-serdev ports handled by the bus implementation. It
  631          * supports multiple handlers for a single interrupt as it is,
  632          * so we wouldn't add value if we did it ourselves.
  633          */
  634         serdev = 0;
  635         if (port->p_type == PUC_TYPE_SERIAL) {
  636                 i = 0, isrc = SER_INT_OVERRUN;
  637                 while (i < PUC_ISRCCNT) {
  638                         port->p_ihsrc[i] = SERDEV_IHAND(originator, isrc);
  639                         if (port->p_ihsrc[i] != NULL)
  640                                 serdev = 1;
  641                         i++, isrc <<= 1;
  642                 }
  643         }
  644         if (!serdev)
  645                 return (BUS_SETUP_INTR(device_get_parent(dev), originator,
  646                     sc->sc_ires, flags, filt, ihand, arg, cookiep));
  647 
  648         sc->sc_serdevs |= 1UL << (port->p_nr - 1);
  649 
  650         port->p_hasintr = 1;
  651         port->p_iharg = arg;
  652 
  653         *cookiep = port;
  654         return (0);
  655 }
  656 
  657 int
  658 puc_bus_teardown_intr(device_t dev, device_t child, struct resource *res,
  659     void *cookie)
  660 {
  661         struct puc_port *port;
  662         struct puc_softc *sc;
  663         device_t originator;
  664         int i;
  665 
  666         sc = device_get_softc(dev);
  667 
  668         /* Get our immediate child. */
  669         originator = child;
  670         while (child != NULL && device_get_parent(child) != dev)
  671                 child = device_get_parent(child);
  672         if (child == NULL)
  673                 return (EINVAL);
  674 
  675         port = device_get_ivars(child);
  676         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  677 
  678         if (res != port->p_ires)
  679                 return (EINVAL);
  680         if (rman_get_device(port->p_ires) != originator)
  681                 return (ENXIO);
  682 
  683         if (!port->p_hasintr)
  684                 return (BUS_TEARDOWN_INTR(device_get_parent(dev), originator,
  685                     sc->sc_ires, cookie));
  686 
  687         if (cookie != port)
  688                 return (EINVAL);
  689 
  690         port->p_hasintr = 0;
  691         port->p_iharg = NULL;
  692 
  693         for (i = 0; i < PUC_ISRCCNT; i++)
  694                 port->p_ihsrc[i] = NULL;
  695 
  696         return (0);
  697 }
  698 
  699 int
  700 puc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  701 {
  702         struct puc_port *port;
  703 
  704         /* Get our immediate child. */
  705         while (child != NULL && device_get_parent(child) != dev)
  706                 child = device_get_parent(child);
  707         if (child == NULL)
  708                 return (EINVAL);
  709 
  710         port = device_get_ivars(child);
  711         KASSERT(port != NULL, ("%s %d", __func__, __LINE__));
  712 
  713         if (result == NULL)
  714                 return (EINVAL);
  715 
  716         switch(index) {
  717         case PUC_IVAR_CLOCK:
  718                 *result = port->p_rclk;
  719                 break;
  720         case PUC_IVAR_TYPE:
  721                 *result = port->p_type;
  722                 break;
  723         default:
  724                 return (ENOENT);
  725         }
  726         return (0);
  727 }
  728 
  729 int
  730 puc_bus_print_child(device_t dev, device_t child)
  731 {
  732         struct puc_port *port;
  733         int retval;
  734 
  735         port = device_get_ivars(child);
  736         retval = 0;
  737 
  738         retval += bus_print_child_header(dev, child);
  739         retval += printf(" at port %d", port->p_nr);
  740         retval += bus_print_child_footer(dev, child);
  741 
  742         return (retval);
  743 }
  744 
  745 int
  746 puc_bus_child_location_str(device_t dev, device_t child, char *buf,
  747     size_t buflen)
  748 {
  749         struct puc_port *port;
  750 
  751         port = device_get_ivars(child);
  752         snprintf(buf, buflen, "port=%d", port->p_nr);
  753         return (0);
  754 }
  755 
  756 int
  757 puc_bus_child_pnpinfo_str(device_t dev, device_t child, char *buf,
  758     size_t buflen)
  759 {
  760         struct puc_port *port;
  761 
  762         port = device_get_ivars(child);
  763         snprintf(buf, buflen, "type=%d", port->p_type);
  764         return (0);
  765 }

Cache object: ed88d6c597d102abf7895bb7b6147842


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.