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

Cache object: 29bb5b3a5f5da2c4b041c1130c959914


[ 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.